@ctxo/cli 0.11.1 → 0.11.3
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/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -112,8 +112,10 @@ import { fileURLToPath } from "url";
|
|
|
112
112
|
var DEFAULT_PATTERNS = [
|
|
113
113
|
// AWS Access Key IDs (AKIA...)
|
|
114
114
|
{ regex: /AKIA[0-9A-Z]{16}/g, label: "AWS_KEY" },
|
|
115
|
-
// AWS Secret Access Keys (40 char base64 containing / or +
|
|
116
|
-
|
|
115
|
+
// AWS Secret Access Keys (40 char base64 containing / or +). The `[A-Za-z0-9=]*[/+]`
|
|
116
|
+
// lookahead is scoped to the token itself (not `.*`, which would reach a later `/` in
|
|
117
|
+
// the surrounding text, e.g. a file path in JSON, and wrongly redact hex-only git SHAs).
|
|
118
|
+
{ regex: /(?<![A-Za-z0-9/+])(?=[A-Za-z0-9/+=]{40}(?![A-Za-z0-9/+=]))(?=[A-Za-z0-9=]*[/+])[A-Za-z0-9/+=]{40}/g, label: "AWS_SECRET" },
|
|
117
119
|
// JWT tokens (eyJ...)
|
|
118
120
|
{ regex: /eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g, label: "JWT" },
|
|
119
121
|
// Private IPv4 (10.x.x.x, 172.16-31.x.x, 192.168.x.x)
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/adapters/transport/http-server-transport.ts","../src/core/masking/masking-pipeline.ts","../src/adapters/mcp/get-logic-slice.ts","../src/core/logic-slice/logic-slice-query.ts","../src/core/detail-levels/detail-formatter.ts","../src/core/response-envelope.ts","../src/core/intent-filter.ts","../src/adapters/mcp/get-why-context.ts","../src/core/overlay/snapshot-staleness.ts","../src/adapters/mcp/get-change-intelligence.ts","../src/core/change-intelligence/churn-analyzer.ts","../src/core/change-intelligence/health-scorer.ts","../src/adapters/mcp/get-blast-radius.ts","../src/adapters/mcp/get-architectural-overlay.ts","../src/adapters/mcp/get-dead-code.ts","../src/adapters/mcp/get-context-for-task.ts","../src/core/context-assembly/task-context-strategy.ts","../src/core/context-assembly/context-assembler.ts","../src/adapters/mcp/get-ranked-context.ts","../src/core/search/symbol-tokenizer.ts","../src/core/search/fuzzy-corrector.ts","../src/core/search/search-engine.ts","../src/adapters/mcp/search-symbols.ts","../src/adapters/mcp/get-changed-symbols.ts","../src/adapters/mcp/find-importers.ts","../src/adapters/mcp/get-class-hierarchy.ts","../src/adapters/mcp/get-symbol-importance.ts","../src/adapters/mcp/get-pr-impact.ts","../src/adapters/stats/with-recording.ts","../src/core/overlay/cluster-label-masker.ts"],"sourcesContent":["import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { startHttpTransport } from './adapters/transport/http-server-transport.js';\nimport { z } from 'zod';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { createLogger } from './core/logger.js';\nimport { SqliteStorageAdapter } from './adapters/storage/sqlite-storage-adapter.js';\nimport { MaskingPipeline, type MaskingPatternConfig } from './core/masking/masking-pipeline.js';\nimport { handleGetLogicSlice } from './adapters/mcp/get-logic-slice.js';\nimport { handleGetWhyContext } from './adapters/mcp/get-why-context.js';\nimport { handleGetChangeIntelligence } from './adapters/mcp/get-change-intelligence.js';\nimport { SimpleGitAdapter } from './adapters/git/simple-git-adapter.js';\nimport { handleGetBlastRadius } from './adapters/mcp/get-blast-radius.js';\nimport { handleGetArchitecturalOverlay } from './adapters/mcp/get-architectural-overlay.js';\nimport { handleFindDeadCode } from './adapters/mcp/get-dead-code.js';\nimport { handleGetContextForTask } from './adapters/mcp/get-context-for-task.js';\nimport { handleGetRankedContext } from './adapters/mcp/get-ranked-context.js';\nimport { handleSearchSymbols } from './adapters/mcp/search-symbols.js';\nimport { handleGetChangedSymbols } from './adapters/mcp/get-changed-symbols.js';\nimport { handleFindImporters } from './adapters/mcp/find-importers.js';\nimport { handleGetClassHierarchy } from './adapters/mcp/get-class-hierarchy.js';\nimport { handleGetSymbolImportance } from './adapters/mcp/get-symbol-importance.js';\nimport { handleGetPrImpact } from './adapters/mcp/get-pr-impact.js';\nimport { SessionRecorderAdapter } from './adapters/stats/session-recorder-adapter.js';\nimport { withRecording } from './adapters/stats/with-recording.js';\nimport type { ISessionRecorderPort } from './ports/i-session-recorder-port.js';\nimport { detectWorkspace } from './adapters/workspace/single-package-workspace.js';\nimport { setWorkspaceMeta } from './core/response-envelope.js';\nimport { loadConfig, maskingClusterLabelPatterns, statsEnabled } from './core/config/load-config.js';\nimport { ClusterLabelMasker } from './core/overlay/cluster-label-masker.js';\n\nconst log = createLogger('ctxo:mcp');\n\nfunction loadMaskingConfig(ctxoRoot: string): MaskingPipeline {\n const jsonConfigPath = join(ctxoRoot, 'masking.json');\n\n // Try JSON masking config first\n if (existsSync(jsonConfigPath)) {\n try {\n const raw = readFileSync(jsonConfigPath, 'utf-8');\n const patterns: MaskingPatternConfig[] = JSON.parse(raw);\n log.info(`Loaded ${patterns.length} custom masking pattern(s)`);\n return MaskingPipeline.fromConfig(patterns);\n } catch (err) {\n log.error(`Failed to load masking config: ${(err as Error).message}`);\n }\n }\n\n return new MaskingPipeline();\n}\n\nfunction readStatsEnabled(ctxoRoot: string): boolean {\n return statsEnabled(loadConfig(ctxoRoot).config);\n}\n\nconst PKG_VERSION: string = (() => {\n try {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8')) as { version?: string };\n return pkg.version ?? '0.0.0';\n } catch {\n return '0.0.0';\n }\n})();\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n\n // HTTP mode — check before CLI routing since --http is a server flag, not a CLI command\n const httpPortStr = process.env.CTXO_HTTP_PORT\n || (args.includes('--http') ? (args[args.indexOf('--port') + 1] || '3001') : null);\n\n if (!httpPortStr && args.length > 0) {\n // CLI mode\n const { CliRouter } = await import('./cli/cli-router.js');\n const router = new CliRouter(process.cwd());\n await router.route(args);\n return;\n }\n\n // Initialize adapters\n const ctxoRoot = '.ctxo';\n const workspace = detectWorkspace(process.cwd());\n setWorkspaceMeta({ root: workspace.root });\n const storage = new SqliteStorageAdapter(ctxoRoot, { allowProductionPath: true });\n await storage.init();\n\n const masking = loadMaskingConfig(ctxoRoot);\n const clusterLabelMasker = new ClusterLabelMasker(\n maskingClusterLabelPatterns(loadConfig(ctxoRoot).config),\n );\n const git = new SimpleGitAdapter(process.cwd());\n\n // Session recording (opt-out via config.yaml stats.enabled: false)\n const recorder: ISessionRecorderPort | null = readStatsEnabled(ctxoRoot)\n ? new SessionRecorderAdapter(storage.getDb(), () => storage.persist())\n : null;\n\n // Create MCP server\n const server = new McpServer({ name: 'ctxo', version: PKG_VERSION });\n\n // Staleness detection\n const { StalenessDetector } = await import('./core/staleness/staleness-detector.js');\n const staleness = new StalenessDetector(process.cwd(), ctxoRoot);\n\n registerTools(server, storage, masking, git, staleness, recorder, ctxoRoot, clusterLabelMasker);\n\n // Start MCP server — HTTP mode or stdio mode\n if (httpPortStr) {\n await startHttpTransport(async () => {\n const s = new McpServer({ name: 'ctxo', version: PKG_VERSION });\n registerTools(s, storage, masking, git, staleness, recorder, ctxoRoot, clusterLabelMasker);\n return s;\n }, parseInt(httpPortStr, 10));\n } else {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n }\n}\n\nfunction registerTools(\n server: McpServer,\n storage: SqliteStorageAdapter,\n masking: MaskingPipeline,\n git: SimpleGitAdapter,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n staleness: any,\n recorder: ISessionRecorderPort | null,\n ctxoRoot = '.ctxo',\n clusterLabelMasker?: ClusterLabelMasker,\n) {\n // Tool annotations — all Ctxo tools are read-only index queries\n const toolAnnotations = {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n } as const;\n\n // Register tools — each handler wrapped with session recording\n const logicSliceHandler = withRecording('get_logic_slice', handleGetLogicSlice(storage, masking, staleness, ctxoRoot), recorder);\n const whyContextHandler = withRecording('get_why_context', handleGetWhyContext(storage, git, masking, staleness, ctxoRoot, clusterLabelMasker), recorder);\n const changeIntelligenceHandler = withRecording('get_change_intelligence', handleGetChangeIntelligence(storage, git, masking, staleness, ctxoRoot), recorder);\n\n server.registerTool(\n 'get_logic_slice',\n {\n description: 'Retrieve a symbol and all its transitive dependencies as a Logic-Slice. Use this when you need to UNDERSTAND what a symbol depends on (downstream view). L1=signature only, L2=direct deps, L3=full closure, L4=with token budget. Use `intent` to filter dependencies by keyword (e.g., \"core\", \"adapter\"). All responses include `_meta` with item counts and truncation info. For impact analysis (what BREAKS if this changes), use get_blast_radius instead. For task-specific context, use get_context_for_task.',\n inputSchema: {\n symbolId: z.string().optional().describe('Single symbol ID (format: file::name::kind)'),\n symbolIds: z.array(z.string()).optional().describe('Batch: array of symbol IDs'),\n level: z.number().min(1).max(4).optional().default(3).describe('Detail level (L1=signature, L2=direct deps, L3=full closure, L4=with token budget)'),\n intent: z.string().optional().describe('Filter dependencies by intent keywords (e.g., \"core\", \"adapter\")'),\n },\n annotations: toolAnnotations,\n },\n (args) => logicSliceHandler(args),\n );\n\n server.registerTool(\n 'get_why_context',\n {\n description: 'Retrieve git commit history intent and anti-pattern warnings (reverts, rollbacks) for a symbol. Use this when you need to understand WHY code was written this way or whether it has a history of problems. Pair with get_change_intelligence for complexity/churn scores.',\n inputSchema: {\n symbolId: z.string().min(1).describe('The symbol ID (format: file::name::kind)'),\n maxCommits: z.number().int().min(1).optional().describe('Limit commit history to N most recent commits'),\n },\n annotations: toolAnnotations,\n },\n (args) => whyContextHandler(args),\n );\n\n server.registerTool(\n 'get_change_intelligence',\n {\n description: 'Retrieve complexity x churn composite score for a symbol — identifies hotspots that are both complex and frequently changed. Use this to prioritize refactoring targets or assess risk before modifying code. For git history details, use get_why_context. For impact scope, use get_blast_radius.',\n inputSchema: {\n symbolId: z.string().min(1).describe('The symbol ID (format: file::name::kind)'),\n },\n annotations: toolAnnotations,\n },\n (args) => changeIntelligenceHandler(args),\n );\n\n const blastRadiusHandler = withRecording('get_blast_radius', handleGetBlastRadius(storage, masking, staleness, ctxoRoot, git, clusterLabelMasker), recorder);\n\n server.registerTool(\n 'get_blast_radius',\n {\n description: 'BEFORE modifying any function or class, call this to understand impact. Returns all symbols that would break if the target changes, split into confirmed (direct importers), likely (co-changed), and potential (transitive) tiers with risk scores. Use `confidence` to filter by tier, `intent` to filter by keyword. Large results are auto-truncated with `_meta.hint` for drill-in. For what a symbol DEPENDS ON (downstream), use get_logic_slice instead. For full PR-level analysis, use get_pr_impact.',\n inputSchema: {\n symbolId: z.string().min(1).describe('The symbol ID (format: file::name::kind)'),\n confidence: z.enum(['confirmed', 'likely', 'potential']).optional().describe('Filter by confidence tier'),\n intent: z.string().optional().describe('Filter impacted symbols by intent keywords (e.g., \"test\", \"adapter\")'),\n },\n annotations: toolAnnotations,\n },\n (args) => blastRadiusHandler(args),\n );\n\n const overlayHandler = withRecording('get_architectural_overlay', handleGetArchitecturalOverlay(storage, masking, staleness, git, clusterLabelMasker), recorder);\n\n server.registerTool(\n 'get_architectural_overlay',\n {\n description: 'Get the project architectural layer map — identifies which symbols belong to Domain, Infrastructure, and Adapter layers. Use this when onboarding to a new codebase or validating that a change respects layer boundaries. For symbol-level analysis, use get_logic_slice or get_blast_radius.',\n inputSchema: {\n layer: z.string().optional().describe('Filter by specific layer name'),\n },\n annotations: toolAnnotations,\n },\n (args) => overlayHandler(args),\n );\n\n const deadCodeHandler = withRecording('find_dead_code', handleFindDeadCode(storage, masking, staleness, ctxoRoot), recorder);\n\n server.registerTool(\n 'find_dead_code',\n {\n description: 'Find unreachable symbols and files that are never imported or called anywhere. Use this during cleanup, refactoring, or before deleting code to confirm it is truly unused. Use `intent` to filter results by keyword (e.g., \"adapter\", \"function\"). Large results are auto-truncated with `_meta`. For reverse dependency lookup of a specific symbol, use find_importers instead.',\n inputSchema: {\n includeTests: z.boolean().optional().default(false).describe('Include test files in analysis (default: exclude)'),\n intent: z.string().optional().describe('Filter dead code results by intent keywords (e.g., \"adapter\", \"function\")'),\n },\n annotations: toolAnnotations,\n },\n (args) => deadCodeHandler(args),\n );\n\n const contextForTaskHandler = withRecording('get_context_for_task', handleGetContextForTask(storage, masking, staleness, ctxoRoot), recorder);\n\n server.registerTool(\n 'get_context_for_task',\n {\n description: 'Get task-optimized context for a symbol based on what you are about to do. Specify taskType: \"fix\" (bug investigation — includes history + anti-patterns), \"extend\" (add feature — includes deps + blast radius), \"refactor\" (restructure — includes importers + complexity), or \"understand\" (learn — includes full slice + architecture). This is the BEST starting point when you know both the symbol and your intent.',\n inputSchema: {\n symbolId: z.string().min(1).describe('The symbol ID (format: file::name::kind)'),\n taskType: z.enum(['fix', 'extend', 'refactor', 'understand']).describe('Task type determines which context is most relevant'),\n tokenBudget: z.number().optional().default(4000).describe('Max tokens for context (default 4000)'),\n },\n annotations: toolAnnotations,\n },\n (args) => contextForTaskHandler(args),\n );\n\n const rankedContextHandler = withRecording('get_ranked_context', handleGetRankedContext(storage, masking, staleness, ctxoRoot), recorder);\n\n server.registerTool(\n 'get_ranked_context',\n {\n description: 'Search and rank symbols by relevance to a natural language query, packed within a token budget. Uses BM25 text matching + PageRank importance scoring. Results include `_meta` with truncation info. Use this when you have a question or topic but do not know which specific symbol to look at. For exact symbol name search, use search_symbols instead.',\n inputSchema: {\n query: z.string().min(1).describe('Search query (matches symbol names)'),\n tokenBudget: z.number().optional().default(4000).describe('Max tokens for results (default 4000)'),\n strategy: z.enum(['combined', 'dependency', 'importance']).optional().default('combined').describe('Ranking strategy'),\n },\n annotations: toolAnnotations,\n },\n (args) => rankedContextHandler(args),\n );\n\n const searchSymbolsHandler = withRecording('search_symbols', handleSearchSymbols(storage, masking, staleness, ctxoRoot), recorder);\n\n server.registerTool(\n 'search_symbols',\n {\n description: 'Search symbols by exact name or regex pattern across the codebase index. Use this when you know (part of) the symbol name and need to find its ID for use with other tools. For semantic/relevance-based search, use get_ranked_context instead.',\n inputSchema: {\n pattern: z.string().min(1).describe('Search pattern (substring or regex)'),\n kind: z.enum(['function', 'class', 'interface', 'method', 'variable', 'type']).optional().describe('Filter by symbol kind'),\n filePattern: z.string().optional().describe('Filter by file path substring'),\n limit: z.number().int().min(1).max(100).optional().default(25).describe('Max results (default 25)'),\n },\n annotations: toolAnnotations,\n },\n (args) => searchSymbolsHandler(args),\n );\n\n const changedSymbolsHandler = withRecording('get_changed_symbols', handleGetChangedSymbols(storage, git, masking, staleness, ctxoRoot), recorder);\n\n server.registerTool(\n 'get_changed_symbols',\n {\n description: 'Get symbols in recently changed files based on git diff. Use this to see what was modified in recent commits. For full PR risk assessment (changed symbols + blast radius + co-changes), use get_pr_impact instead.',\n inputSchema: {\n since: z.string().optional().default('HEAD~1').describe('Git ref to diff against (default HEAD~1)'),\n maxFiles: z.number().int().min(1).optional().default(50).describe('Max changed files to process (default 50)'),\n },\n annotations: toolAnnotations,\n },\n (args) => changedSymbolsHandler(args),\n );\n\n const findImportersHandler = withRecording('find_importers', handleFindImporters(storage, masking, staleness, ctxoRoot), recorder);\n\n server.registerTool(\n 'find_importers',\n {\n description: 'Find all symbols that import or depend on a given symbol (reverse dependency / \"who uses this?\"). Use this to check if a symbol is safe to modify or delete. Supports transitive traversal for deep impact chains. Use `intent` to filter by keyword (e.g., \"test\", \"core\"). For forward dependencies (what this symbol uses), use get_logic_slice. For aggregated impact with risk scores, use get_blast_radius.',\n inputSchema: {\n symbolId: z.string().min(1).describe('The symbol ID (format: file::name::kind)'),\n edgeKinds: z.array(z.enum(['imports', 'calls', 'extends', 'implements', 'uses'])).optional().describe('Filter by edge kinds'),\n transitive: z.boolean().optional().default(false).describe('Follow transitive reverse edges (default false)'),\n maxDepth: z.number().int().min(1).max(10).optional().default(5).describe('Max BFS depth for transitive mode (default 5)'),\n intent: z.string().optional().describe('Filter importers by intent keywords (e.g., \"test\", \"core\", \"adapter\")'),\n },\n annotations: toolAnnotations,\n },\n (args) => findImportersHandler(args),\n );\n\n const classHierarchyHandler = withRecording('get_class_hierarchy', handleGetClassHierarchy(storage, masking, staleness, ctxoRoot), recorder);\n\n server.registerTool(\n 'get_class_hierarchy',\n {\n description: 'Get class inheritance hierarchy — ancestors (extends/implements chain) and descendants (subclasses). Use this when working with OOP code to understand type relationships before modifying a base class or interface. For dependency-based relationships (imports/calls), use get_logic_slice or find_importers.',\n inputSchema: {\n symbolId: z.string().min(1).optional().describe('Root symbol ID (omit for full project hierarchy)'),\n direction: z.enum(['ancestors', 'descendants', 'both']).optional().default('both').describe('Traversal direction (default both)'),\n },\n annotations: toolAnnotations,\n },\n (args) => classHierarchyHandler(args),\n );\n\n const symbolImportanceHandler = withRecording('get_symbol_importance', handleGetSymbolImportance(storage, masking, staleness, ctxoRoot), recorder);\n\n server.registerTool(\n 'get_symbol_importance',\n {\n description: 'Rank symbols by structural importance using PageRank centrality on the dependency graph. Use this to identify the most critical symbols in the codebase — high-PageRank symbols are heavily depended upon and risky to change. For finding unused/unimportant code, use find_dead_code instead.',\n inputSchema: {\n limit: z.number().int().min(1).max(200).optional().default(25).describe('Max results (default 25)'),\n kind: z.enum(['function', 'class', 'interface', 'method', 'variable', 'type']).optional().describe('Filter by symbol kind'),\n filePattern: z.string().optional().describe('Filter by file path substring'),\n damping: z.number().min(0).max(1).optional().default(0.85).describe('PageRank damping factor (default 0.85)'),\n },\n annotations: toolAnnotations,\n },\n (args) => symbolImportanceHandler(args),\n );\n\n const prImpactHandler = withRecording('get_pr_impact', handleGetPrImpact(storage, git, masking, staleness, ctxoRoot, clusterLabelMasker), recorder);\n\n server.registerTool(\n 'get_pr_impact',\n {\n description: 'Analyze the full impact of a PR or recent changes in a SINGLE call — combines changed symbols + blast radius + co-change history into one risk assessment. Results include `_meta` with truncation info. Use this FIRST when reviewing a PR or evaluating recent commits. For single-symbol analysis, use get_blast_radius instead.',\n inputSchema: {\n since: z.string().optional().default('HEAD~1').describe('Git ref to diff against (default HEAD~1)'),\n maxFiles: z.number().int().min(1).optional().default(50).describe('Max changed files to analyze'),\n confidence: z.enum(['confirmed', 'likely', 'potential']).optional().describe('Filter impacted symbols by confidence tier'),\n },\n annotations: toolAnnotations,\n },\n (args) => prImpactHandler(args),\n );\n\n // Register empty resource/prompt capabilities to prevent -32601 errors\n // from MCP clients that unconditionally call listResources/listPrompts\n server.resource('ctxo-status', 'ctxo://status', async (uri) => ({\n contents: [{ uri: uri.href, text: 'Ctxo MCP server is running.' }],\n }));\n}\n\nmain().catch((err: unknown) => {\n log.error('Fatal: %s', (err as Error).message);\n process.exit(1);\n});\n","import { createServer, type Server, type IncomingMessage, type ServerResponse } from 'node:http';\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport { randomUUID } from 'node:crypto';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { createLogger } from '../../core/logger.js';\n\nconst log = createLogger('ctxo:http');\n\n/**\n * Factory function that creates and registers all tools on a fresh McpServer.\n * Passed in from the composition root so this adapter doesn't import tool handlers.\n */\nexport type ServerFactory = () => Promise<McpServer>;\n\n/**\n * Starts ctxo MCP over HTTP. Each browser session gets its own McpServer + transport.\n * This avoids the \"already connected\" error when multiple clients connect.\n *\n * Usage:\n * CTXO_HTTP_PORT=3001 ctxo\n * ctxo --http\n */\nexport async function startHttpTransport(\n serverFactory: ServerFactory,\n port: number,\n): Promise<{ httpServer: Server }> {\n // Map of session ID -> { transport, server }\n const sessions = new Map<string, { transport: StreamableHTTPServerTransport; server: McpServer }>();\n\n const httpServer = createServer(async (req: IncomingMessage, res: ServerResponse) => {\n // CORS\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Accept, Mcp-Session-Id');\n res.setHeader('Access-Control-Expose-Headers', 'Mcp-Session-Id');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n const sessionId = req.headers['mcp-session-id'] as string | undefined;\n\n // Existing session\n if (sessionId && sessions.has(sessionId)) {\n try {\n await sessions.get(sessionId)!.transport.handleRequest(req, res);\n } catch (err) {\n log.error('Request error: %s', (err as Error).message);\n if (!res.headersSent) { res.writeHead(500); res.end(); }\n }\n return;\n }\n\n // Invalid session\n if (sessionId && !sessions.has(sessionId)) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ jsonrpc: '2.0', error: { code: -32001, message: 'Session not found' }, id: null }));\n return;\n }\n\n // New session — create fresh server + transport\n try {\n const server = await serverFactory();\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: () => randomUUID(),\n });\n\n transport.onclose = () => {\n if (transport.sessionId) {\n sessions.delete(transport.sessionId);\n log.info('Session closed: %s', transport.sessionId);\n }\n };\n\n await server.connect(transport);\n await transport.handleRequest(req, res);\n\n if (transport.sessionId) {\n sessions.set(transport.sessionId, { transport, server });\n log.info('New session: %s (total: %d)', transport.sessionId, sessions.size);\n }\n } catch (err) {\n log.error('Session creation error: %s', (err as Error).message);\n if (!res.headersSent) { res.writeHead(500); res.end(); }\n }\n });\n\n return new Promise((resolve, reject) => {\n httpServer.on('error', reject);\n httpServer.listen(port, () => {\n log.info('MCP HTTP server listening on http://localhost:%d', port);\n process.stderr.write(`[ctxo] MCP HTTP server running at http://localhost:${port}\\n`);\n resolve({ httpServer });\n });\n });\n}\n","const DEFAULT_PATTERNS: Array<{ regex: RegExp; label: string }> = [\n // AWS Access Key IDs (AKIA...)\n { regex: /AKIA[0-9A-Z]{16}/g, label: 'AWS_KEY' },\n // AWS Secret Access Keys (40 char base64 containing / or + — excludes hex-only git hashes)\n { regex: /(?<![A-Za-z0-9/+])(?=[A-Za-z0-9/+=]{40}(?![A-Za-z0-9/+=]))(?=.*[/+])[A-Za-z0-9/+=]{40}/g, label: 'AWS_SECRET' },\n // JWT tokens (eyJ...)\n { regex: /eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}/g, label: 'JWT' },\n // Private IPv4 (10.x.x.x, 172.16-31.x.x, 192.168.x.x)\n { regex: /\\b(?:10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|172\\.(?:1[6-9]|2\\d|3[01])\\.\\d{1,3}\\.\\d{1,3}|192\\.168\\.\\d{1,3}\\.\\d{1,3})\\b/g, label: 'PRIVATE_IP' },\n // Private IPv6 (fc00::/7)\n { regex: /\\b[fF][cCdD][0-9a-fA-F]{0,2}(?::[0-9a-fA-F]{1,4}){1,7}\\b/g, label: 'PRIVATE_IPV6' },\n // Environment variable assignments for secrets\n { regex: /(?:_SECRET|_KEY|_TOKEN|_PASSWORD)\\s*=\\s*['\"]?[^\\s'\"]{8,}['\"]?/g, label: 'ENV_SECRET' },\n // GCP service account keys\n { regex:/\"private_key\"\\s*:\\s*\"-----BEGIN[^\"]+\"/g, label: 'GCP_KEY' },\n // Azure connection strings\n { regex: /AccountKey=[A-Za-z0-9+/=]{20,}/g, label: 'AZURE_KEY' },\n];\n\nexport interface MaskingPatternConfig {\n readonly pattern: string;\n readonly flags?: string;\n readonly label: string;\n}\n\nexport class MaskingPipeline {\n private readonly patterns: Array<{ regex: RegExp; label: string }>;\n\n constructor(additionalPatterns: Array<{ regex: RegExp; label: string }> = []) {\n // Clone RegExp objects to avoid shared mutable lastIndex state\n this.patterns = [...DEFAULT_PATTERNS, ...additionalPatterns].map(({ regex, label }) => ({\n regex: new RegExp(regex.source, regex.flags),\n label,\n }));\n }\n\n static fromConfig(configPatterns: MaskingPatternConfig[]): MaskingPipeline {\n const additional: Array<{ regex: RegExp; label: string }> = [];\n\n for (const { pattern, flags, label } of configPatterns) {\n try {\n additional.push({ regex: new RegExp(pattern, flags ?? 'g'), label });\n } catch (err) {\n console.error(`[ctxo:masking] Invalid regex pattern \"${pattern}\": ${(err as Error).message}`);\n }\n }\n\n return new MaskingPipeline(additional);\n }\n\n mask(text: string): string {\n if (text.length === 0) return text;\n\n let result = text;\n for (const { regex, label } of this.patterns) {\n result = result.replace(regex, `[REDACTED:${label}]`);\n }\n return result;\n }\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport { SymbolGraph } from '../../core/graph/symbol-graph.js';\nimport { JsonIndexReader } from '../storage/json-index-reader.js';\nimport { LogicSliceQuery } from '../../core/logic-slice/logic-slice-query.js';\nimport { DetailFormatter } from '../../core/detail-levels/detail-formatter.js';\nimport { DetailLevelSchema } from '../../core/types.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\nimport { filterByIntent } from '../../core/intent-filter.js';\n\nconst InputSchema = z.object({\n symbolId: z.string().min(1).optional(),\n symbolIds: z.array(z.string().min(1)).optional(),\n level: DetailLevelSchema.optional().default(3),\n intent: z.string().optional().describe('Filter dependencies by intent keywords (e.g., \"core\", \"adapter\", \"storage\")'),\n}).refine(\n (data) => data.symbolId || (data.symbolIds && data.symbolIds.length > 0),\n { message: 'Either symbolId or symbolIds must be provided' },\n);\n\nexport type GetLogicSliceInput = z.infer<typeof InputSchema>;\n\nexport function getLogicSliceInputSchema() {\n return {\n type: 'object' as const,\n properties: {\n symbolId: { type: 'string' as const, description: 'The symbol ID to retrieve (format: file::name::kind)' },\n level: { type: 'number' as const, enum: [1, 2, 3, 4], description: 'Detail level (1=minimal, 4=full)', default: 3 },\n },\n required: ['symbolId'] as const,\n };\n}\n\nexport function buildGraphFromStorage(storage: IStoragePort): SymbolGraph {\n const graph = new SymbolGraph();\n for (const sym of storage.getAllSymbols()) {\n graph.addNode(sym);\n }\n for (const edge of storage.getAllEdges()) {\n graph.addEdge(edge);\n }\n return graph;\n}\n\n/**\n * Build graph + return file list from a single JSON index read.\n * Returning both from one source prevents staleness warnings from diverging\n * from the graph data (see issue #40).\n */\nexport function buildGraphAndFilesFromJsonIndex(\n ctxoRoot: string,\n): { graph: SymbolGraph; indexedFiles: string[] } {\n const reader = new JsonIndexReader(ctxoRoot);\n const indices = reader.readAll();\n\n const graph = new SymbolGraph();\n const indexedFiles: string[] = [];\n\n for (const fileIndex of indices) {\n indexedFiles.push(fileIndex.file);\n for (const sym of fileIndex.symbols) {\n graph.addNode(sym);\n }\n }\n for (const fileIndex of indices) {\n for (const edge of fileIndex.edges) {\n graph.addEdge(edge);\n }\n }\n return { graph, indexedFiles };\n}\n\n/**\n * Build graph directly from JSON index files (bypasses SQLite cache).\n * Always reads fresh data from disk — works even if ctxo index ran in another process.\n */\nexport function buildGraphFromJsonIndex(ctxoRoot: string): SymbolGraph {\n return buildGraphAndFilesFromJsonIndex(ctxoRoot).graph;\n}\n\n/**\n * Returns graph + indexedFiles from JSON index, falling back to SQLite storage\n * when JSON is empty. Keeps graph data and staleness check file list aligned.\n */\nexport function getGraphAndFiles(\n ctxoRoot: string,\n storage: IStoragePort,\n): { graph: SymbolGraph; indexedFiles: string[] } {\n const json = buildGraphAndFilesFromJsonIndex(ctxoRoot);\n if (json.graph.nodeCount > 0) return json;\n return { graph: buildGraphFromStorage(storage), indexedFiles: storage.listIndexedFiles() };\n}\n\nexport interface StalenessCheck {\n check(indexedFiles: readonly string[]): { message: string } | undefined;\n}\n\nexport function handleGetLogicSlice(\n storage: IStoragePort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n) {\n const query = new LogicSliceQuery();\n const formatter = new DetailFormatter();\n\n // Build graph fresh on each call — try JSON index first (always up to date),\n // fall back to SQLite storage (for tests and when JSON not available).\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n const handler = (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { symbolId, symbolIds, level, intent } = parsed.data;\n const ids = symbolIds ?? (symbolId ? [symbolId] : []);\n\n const { graph, indexedFiles } = getGraph();\n\n // Batch support: query multiple symbols\n const results = [];\n for (const id of ids) {\n const slice = query.getLogicSlice(graph, id);\n if (slice) {\n const formatted = formatter.format(slice, level) as unknown as Record<string, unknown>;\n // Apply intent filter to dependencies if present\n if (intent && Array.isArray(formatted['dependencies'])) {\n formatted['dependencies'] = filterByIntent(\n formatted['dependencies'] as Record<string, unknown>[],\n intent,\n );\n }\n results.push(formatted);\n } else {\n results.push({ found: false, symbolId: id, hint: 'Symbol not found. Run \"ctxo index\".' });\n }\n }\n\n // Single symbol: return directly. Batch: return array.\n const responseData = ids.length === 1 ? results[0] : { batch: true, results };\n\n // Apply masking\n const payload = masking.mask(JSON.stringify(wrapResponse(responseData as Record<string, unknown>)));\n\n // Check staleness\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) {\n content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n\n return handler;\n}\n","import type { SymbolNode, GraphEdge, LogicSliceResult } from '../types.js';\nimport type { SymbolGraph } from '../graph/symbol-graph.js';\n\nexport class LogicSliceQuery {\n getLogicSlice(\n graph: SymbolGraph,\n symbolId: string,\n maxDepth: number = Infinity,\n ): LogicSliceResult | undefined {\n const root = graph.getNode(symbolId);\n if (!root) return undefined;\n\n const visited = new Set<string>([symbolId]);\n const dependencies: SymbolNode[] = [];\n const collectedEdges: GraphEdge[] = [];\n\n // BFS transitive closure\n const queue: Array<{ id: string; depth: number }> = [{ id: symbolId, depth: 0 }];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n\n if (current.depth >= maxDepth) continue;\n\n const edges = graph.getForwardEdges(current.id);\n for (const edge of edges) {\n const depNode = graph.getNode(edge.to);\n // Only include edges whose target node exists in the graph\n if (!depNode) continue;\n\n collectedEdges.push(edge);\n\n if (visited.has(edge.to)) continue;\n visited.add(edge.to);\n\n dependencies.push(depNode);\n queue.push({ id: edge.to, depth: current.depth + 1 });\n }\n }\n\n return { root, dependencies, edges: collectedEdges };\n }\n}\n","import type {\n LogicSliceResult,\n FormattedSlice,\n DetailLevel,\n SymbolNode,\n GraphEdge,\n} from '../types.js';\n\nconst L1_MAX_LINES = 150;\nconst L4_TOKEN_BUDGET = 8000;\n\nexport class DetailFormatter {\n format(slice: LogicSliceResult, level: DetailLevel): FormattedSlice {\n switch (level) {\n case 1:\n return this.formatL1(slice);\n case 2:\n return this.formatL2(slice);\n case 3:\n return this.formatL3(slice);\n case 4:\n return this.formatL4(slice);\n }\n }\n\n private formatL1(slice: LogicSliceResult): FormattedSlice {\n const root = slice.root;\n const lineCount = root.endLine - root.startLine + 1;\n\n const clampedRoot: SymbolNode = lineCount > L1_MAX_LINES\n ? { ...root, endLine: root.startLine + L1_MAX_LINES - 1 }\n : root;\n\n return {\n root: clampedRoot,\n dependencies: [],\n edges: [],\n level: 1,\n levelDescription: 'L1: Root symbol signature only (no dependencies)',\n ...(lineCount > L1_MAX_LINES ? { truncation: { truncated: true as const, reason: 'token_budget_exceeded' as const } } : {}),\n };\n }\n\n private formatL2(slice: LogicSliceResult): FormattedSlice {\n // L2: root + depth-1 direct dependencies\n const directEdges = slice.edges.filter((e) => e.from === slice.root.symbolId);\n const directDepIds = new Set(directEdges.map((e) => e.to));\n const directDeps = slice.dependencies.filter((d) => directDepIds.has(d.symbolId));\n\n return {\n root: slice.root,\n dependencies: directDeps,\n edges: directEdges,\n level: 2,\n levelDescription: 'L2: Root + direct dependencies (depth 1)',\n };\n }\n\n private formatL3(slice: LogicSliceResult): FormattedSlice {\n return {\n root: slice.root,\n dependencies: slice.dependencies,\n edges: slice.edges,\n level: 3,\n levelDescription: 'L3: Full transitive dependency closure',\n };\n }\n\n private formatL4(slice: LogicSliceResult): FormattedSlice {\n // L4: full closure with token budget enforcement\n const estimatedTokens = this.estimateTokens(slice);\n\n if (estimatedTokens > L4_TOKEN_BUDGET) {\n // Truncate dependencies to fit budget\n const truncated = this.truncateToTokenBudget(slice, L4_TOKEN_BUDGET);\n return {\n ...truncated,\n level: 4,\n levelDescription: 'L4: Full closure with 8K token budget (truncated)',\n truncation: {\n truncated: true,\n reason: 'token_budget_exceeded',\n },\n };\n }\n\n return {\n root: slice.root,\n dependencies: slice.dependencies,\n edges: slice.edges,\n level: 4,\n levelDescription: 'L4: Full closure with 8K token budget',\n };\n }\n\n private estimateTokens(slice: LogicSliceResult): number {\n // Rough estimate: ~4 chars per token\n let chars = this.symbolCharEstimate(slice.root);\n for (const dep of slice.dependencies) {\n chars += this.symbolCharEstimate(dep);\n }\n for (const edge of slice.edges) {\n chars += (edge.from.length + edge.to.length + edge.kind.length + 10);\n }\n return Math.ceil(chars / 4);\n }\n\n private symbolCharEstimate(node: SymbolNode): number {\n // Use byte offsets for exact size when available, otherwise estimate from line count\n if (node.startOffset !== undefined && node.endOffset !== undefined) {\n return node.endOffset - node.startOffset;\n }\n return (node.endLine - node.startLine + 1) * 40;\n }\n\n private truncateToTokenBudget(\n slice: LogicSliceResult,\n budget: number,\n ): { root: SymbolNode; dependencies: SymbolNode[]; edges: GraphEdge[] } {\n let currentTokens = this.symbolCharEstimate(slice.root) / 4;\n const deps: SymbolNode[] = [];\n const includedIds = new Set<string>([slice.root.symbolId]);\n\n for (const dep of slice.dependencies) {\n const depTokens = this.symbolCharEstimate(dep) / 4;\n if (currentTokens + depTokens > budget) break;\n currentTokens += depTokens;\n deps.push(dep);\n includedIds.add(dep.symbolId);\n }\n\n const edges = slice.edges.filter(\n (e) => includedIds.has(e.from) && includedIds.has(e.to),\n );\n\n return { root: slice.root, dependencies: deps, edges };\n }\n}\n","/**\n * Response envelope — adds _meta field and truncates large payloads.\n *\n * Applied between payload construction and masking in every MCP handler.\n * Threshold default: 8192 bytes (~8KB). Configurable via CTXO_RESPONSE_LIMIT env.\n */\n\nconst DEFAULT_THRESHOLD = 8192;\n\nexport interface ResponseMeta {\n totalItems: number;\n returnedItems: number;\n truncated: boolean;\n totalBytes: number;\n hint?: string;\n /**\n * Workspace descriptor (forward-compat for Monorepo Workspace PRD).\n * v0.7: `root` is set at startup; `package` is always undefined.\n */\n workspace?: {\n root: string;\n package?: string;\n };\n /**\n * How far the community snapshot has drifted from current git HEAD.\n * Only populated on cluster-aware MCP tools (overlay, blast-radius,\n * why-context, pr-impact). Tells AI agents whether the cluster / drift /\n * boundary data they are about to act on is fresh or N commits stale.\n */\n snapshotStaleness?: {\n snapshotCommit: string;\n currentHeadCommit?: string;\n commitsBehind?: number;\n hint?: string;\n };\n}\n\nlet workspaceMeta: ResponseMeta['workspace'] | undefined;\n\n/**\n * Set the workspace descriptor attached to every subsequent `_meta` envelope.\n * Called once at composition root after `detectWorkspace()` resolves.\n */\nexport function setWorkspaceMeta(workspace: ResponseMeta['workspace']): void {\n workspaceMeta = workspace;\n}\n\nexport function getWorkspaceMeta(): ResponseMeta['workspace'] | undefined {\n return workspaceMeta;\n}\n\n/**\n * Known array field names in tool responses that can be truncated.\n * Maps field name → drill-in hint for the LLM.\n */\nconst TRUNCATABLE_FIELDS: Record<string, string> = {\n impactedSymbols: 'Use search_symbols to find specific impacted symbols, or get_blast_radius with a confidence filter.',\n importers: 'Use find_importers with edgeKinds filter or maxDepth to narrow results.',\n deadSymbols: 'Use search_symbols with kind filter to find specific dead symbols.',\n unusedExports: 'Use find_importers to check specific symbols.',\n results: 'Use search_symbols or get_ranked_context with a narrower query.',\n rankings: 'Use get_symbol_importance with kind or filePattern filter to narrow results.',\n context: 'Use get_context_for_task with a smaller tokenBudget.',\n hierarchies: 'Use get_class_hierarchy with a specific symbolId.',\n scaffolding: 'Review the scaffolding markers directly in the listed files.',\n deadFiles: 'Use find_dead_code with includeTests to adjust scope.',\n files: 'Use get_changed_symbols with a narrower since ref or smaller maxFiles.',\n clusters: 'Use get_architectural_overlay with mode=communities and layer filter for a focused view.',\n clustersAffected: 'Use get_blast_radius on individual changed symbols for per-cluster impact.',\n};\n\nfunction getThreshold(): number {\n const env = process.env['CTXO_RESPONSE_LIMIT'];\n if (env) {\n const n = parseInt(env, 10);\n if (!isNaN(n) && n > 0) return n;\n }\n return DEFAULT_THRESHOLD;\n}\n\n/**\n * Find the largest array field in a payload object that is in our truncatable list.\n */\nfunction findTruncatableArray(data: Record<string, unknown>): { key: string; arr: unknown[] } | null {\n let best: { key: string; arr: unknown[] } | null = null;\n for (const [key, value] of Object.entries(data)) {\n if (Array.isArray(value) && key in TRUNCATABLE_FIELDS) {\n if (!best || value.length > best.arr.length) {\n best = { key, arr: value };\n }\n }\n }\n return best;\n}\n\n/**\n * Wrap a payload object with _meta and truncate if needed.\n *\n * @param data - The raw response object (before JSON.stringify)\n * @returns The data object with _meta added (and arrays truncated if over threshold)\n */\nexport interface WrapResponseExtras {\n snapshotStaleness?: ResponseMeta['snapshotStaleness'];\n}\n\nfunction buildMeta(\n base: Omit<ResponseMeta, 'workspace' | 'snapshotStaleness'>,\n extras?: WrapResponseExtras,\n): ResponseMeta {\n const meta: ResponseMeta = workspaceMeta ? { ...base, workspace: workspaceMeta } : base;\n if (extras?.snapshotStaleness) {\n return { ...meta, snapshotStaleness: extras.snapshotStaleness };\n }\n return meta;\n}\n\nexport function wrapResponse(\n data: Record<string, unknown>,\n extras?: WrapResponseExtras,\n): Record<string, unknown> {\n const threshold = getThreshold();\n const fullJson = JSON.stringify(data);\n const totalBytes = Buffer.byteLength(fullJson, 'utf-8');\n\n const truncatable = findTruncatableArray(data);\n const totalItems = truncatable ? truncatable.arr.length : 0;\n\n // Under threshold — return with _meta, no truncation\n if (totalBytes <= threshold) {\n return {\n ...data,\n _meta: buildMeta(\n {\n totalItems,\n returnedItems: totalItems,\n truncated: false,\n totalBytes,\n },\n extras,\n ),\n };\n }\n\n // Over threshold — truncate the largest array\n if (!truncatable || truncatable.arr.length <= 1) {\n return {\n ...data,\n _meta: buildMeta(\n {\n totalItems,\n returnedItems: totalItems,\n truncated: false,\n totalBytes,\n },\n extras,\n ),\n };\n }\n\n // Binary search for the number of items that fit within threshold\n let lo = 1;\n let hi = truncatable.arr.length;\n\n while (lo < hi) {\n const mid = Math.ceil((lo + hi) / 2);\n const trial = {\n ...data,\n [truncatable.key]: truncatable.arr.slice(0, mid),\n _meta: buildMeta(\n {\n totalItems,\n returnedItems: mid,\n truncated: true,\n totalBytes,\n hint: TRUNCATABLE_FIELDS[truncatable.key],\n },\n extras,\n ),\n };\n const size = Buffer.byteLength(JSON.stringify(trial), 'utf-8');\n if (size <= threshold) {\n lo = mid;\n } else {\n hi = mid - 1;\n }\n }\n\n const hint = TRUNCATABLE_FIELDS[truncatable.key];\n\n return {\n ...data,\n [truncatable.key]: truncatable.arr.slice(0, lo),\n _meta: buildMeta(\n {\n totalItems,\n returnedItems: lo,\n truncated: true,\n totalBytes,\n hint,\n },\n extras,\n ),\n };\n}\n","/**\n * Intent-based result filtering for MCP tool responses.\n *\n * When an `intent` string is provided, filters array results to only include\n * entries whose text fields (symbolId, file, name, kind, edgeKind, reason)\n * match at least one keyword from the intent.\n *\n * Keywords are extracted by splitting the intent on whitespace and lowercasing.\n * A match is found when any keyword appears as a substring of any text field.\n */\n\n/**\n * Extract lowercase keywords from an intent string.\n * Filters out very short words (< 2 chars) to avoid noise.\n */\nfunction extractKeywords(intent: string): string[] {\n return intent\n .toLowerCase()\n .split(/\\s+/)\n .filter(w => w.length >= 2);\n}\n\n/**\n * Check if any keyword matches any of the given text values (case-insensitive substring).\n */\nfunction matchesAny(keywords: string[], values: string[]): boolean {\n const lower = values.map(v => v.toLowerCase());\n return keywords.some(kw => lower.some(v => v.includes(kw)));\n}\n\n/**\n * Collect all string values from a record for matching.\n * Extracts from known fields: symbolId, file, name, kind, edgeKind, edgeKinds, reason, confidence.\n */\nfunction collectMatchableStrings(entry: Record<string, unknown>): string[] {\n const strings: string[] = [];\n for (const key of ['symbolId', 'file', 'name', 'kind', 'edgeKind', 'reason', 'confidence']) {\n const v = entry[key];\n if (typeof v === 'string') strings.push(v);\n }\n const edgeKinds = entry['edgeKinds'];\n if (Array.isArray(edgeKinds)) {\n for (const ek of edgeKinds) {\n if (typeof ek === 'string') strings.push(ek);\n }\n }\n return strings;\n}\n\n/**\n * Filter an array of result entries by intent keywords.\n * Returns only entries where at least one keyword matches a text field.\n *\n * @param items - Array of result objects\n * @param intent - User intent string (e.g., \"test coverage\", \"adapter\", \"security\")\n * @returns Filtered array (empty if no matches)\n */\nexport function filterByIntent<T extends Record<string, unknown>>(\n items: T[],\n intent: string | undefined,\n): T[] {\n if (!intent || intent.trim().length === 0) return items;\n\n const keywords = extractKeywords(intent);\n if (keywords.length === 0) return items;\n\n return items.filter(item => {\n const strings = collectMatchableStrings(item);\n return matchesAny(keywords, strings);\n });\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IGitPort } from '../../ports/i-git-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport { RevertDetector } from '../../core/why-context/revert-detector.js';\nimport { DriftDetector } from '../../core/overlay/drift-detector.js';\nimport { buildSnapshotStaleness } from '../../core/overlay/snapshot-staleness.js';\nimport type { ClusterLabelMasker } from '../../core/overlay/cluster-label-masker.js';\nimport { JsonIndexReader } from '../storage/json-index-reader.js';\nimport type { AntiPattern, CommitIntent } from '../../core/types.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\n\nconst InputSchema = z.object({\n symbolId: z.string().min(1),\n maxCommits: z.number().int().min(1).optional(),\n});\n\nexport function handleGetWhyContext(\n storage: IStoragePort,\n git: IGitPort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n clusterLabelMasker?: ClusterLabelMasker,\n) {\n const revertDetector = new RevertDetector();\n const indexReader = new JsonIndexReader(ctxoRoot);\n const driftDetector = new DriftDetector();\n\n return async (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { symbolId, maxCommits } = parsed.data;\n\n const symbol = storage.getSymbolById(symbolId);\n if (!symbol) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ found: false, hint: 'Symbol not found. Run \"ctxo index\" to build the codebase index.' }) }],\n };\n }\n\n const filePath = symbolId.split('::')[0]!;\n\n // Try committed index first (FR16: anti-patterns persist in committed index)\n const indices = indexReader.readAll();\n const fileIndex = indices.find((i) => i.file === filePath);\n\n let commitHistory: CommitIntent[];\n let antiPatterns: AntiPattern[];\n\n if (fileIndex && fileIndex.intent.length > 0) {\n commitHistory = fileIndex.intent;\n antiPatterns = fileIndex.antiPatterns;\n } else {\n // Fallback: compute on-demand from git\n const commits = await git.getCommitHistory(filePath);\n commitHistory = commits.map((c) => ({\n hash: c.hash,\n message: c.message,\n date: c.date,\n kind: 'commit' as const,\n }));\n antiPatterns = revertDetector.detect(commits);\n }\n\n // Query-time limit: slice to maxCommits if provided\n const limitedHistory = maxCommits ? commitHistory.slice(0, maxCommits) : commitHistory;\n\n // Assemble result — separation of concerns: no changeIntelligence here\n // Use get_change_intelligence tool for complexity/churn scoring\n const responsePayload: Record<string, unknown> = {\n commitHistory: limitedHistory,\n antiPatternWarnings: antiPatterns,\n };\n\n if (antiPatterns.length > 0) {\n responsePayload.warningBadge = '⚠ Anti-pattern detected';\n }\n\n const rawSnapshot = storage.readCommunities();\n const currentSnapshot =\n rawSnapshot && clusterLabelMasker?.isEnabled()\n ? clusterLabelMasker.maskSnapshot(rawSnapshot)\n : rawSnapshot;\n if (currentSnapshot) {\n const history = storage.listCommunityHistory();\n const drift = driftDetector.detect(currentSnapshot, history);\n const relevant = drift.events.filter((event) => event.symbolId === symbolId);\n if (relevant.length > 0 || drift.hint) {\n responsePayload.driftSignals = {\n events: relevant,\n confidence: drift.confidence,\n snapshotsAvailable: drift.snapshotsAvailable,\n stabilitySummary: drift.stability,\n ...(drift.hint ? { hint: drift.hint } : {}),\n };\n }\n }\n\n const stalenessMeta = await buildSnapshotStaleness(storage, git);\n if (stalenessMeta) {\n responsePayload._meta = { snapshotStaleness: stalenessMeta };\n }\n\n const payload = masking.mask(JSON.stringify(responsePayload));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(storage.listIndexedFiles());\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","import type { CommunitySnapshot } from '../types.js';\n\nexport interface SnapshotStaleness {\n readonly snapshotCommit: string;\n readonly currentHeadCommit?: string;\n readonly commitsBehind?: number;\n readonly hint?: string;\n}\n\n/**\n * Narrow structural views of the capabilities this module needs from the\n * storage and git adapters. We declare them here (in core/) rather than\n * importing the full IStoragePort / IGitPort interfaces from ports/ so the\n * hexagonal boundary holds: core/ knows nothing about ports/. Callers pass\n * their existing port-typed adapters — they satisfy these shapes structurally.\n */\nexport interface SnapshotStalenessStorage {\n readCommunities(): CommunitySnapshot | undefined;\n}\n\nexport interface SnapshotStalenessGit {\n getHeadSha?(): Promise<string | undefined> | string | undefined;\n countCommitsBetween?(sha: string): Promise<number | undefined> | number | undefined;\n}\n\n/**\n * Summarise how far the persisted community snapshot has drifted from the\n * current git HEAD. Callers merge this into MCP `_meta` so AI agents know\n * whether cluster / drift / boundary data reflects the HEAD they are about\n * to edit or a stale history point.\n *\n * Returns undefined when no snapshot exists (nothing to report) or when git\n * is unavailable and no comparison is possible.\n */\nexport async function buildSnapshotStaleness(\n storage: SnapshotStalenessStorage,\n git: SnapshotStalenessGit,\n): Promise<SnapshotStaleness | undefined> {\n const snapshot = storage.readCommunities();\n if (!snapshot || !snapshot.commitSha || snapshot.commitSha === 'nocommit') return undefined;\n\n const getHead = git.getHeadSha?.bind(git);\n const countBetween = git.countCommitsBetween?.bind(git);\n const head = getHead ? await getHead() : undefined;\n\n if (!head) {\n // Git unavailable — still report the snapshot anchor so callers know what\n // commit the snapshot was computed against.\n return { snapshotCommit: snapshot.commitSha };\n }\n\n if (head === snapshot.commitSha) {\n return {\n snapshotCommit: snapshot.commitSha,\n currentHeadCommit: head,\n commitsBehind: 0,\n };\n }\n\n const behind = countBetween ? await countBetween(snapshot.commitSha) : undefined;\n\n const result: SnapshotStaleness = {\n snapshotCommit: snapshot.commitSha,\n currentHeadCommit: head,\n ...(typeof behind === 'number' ? { commitsBehind: behind } : {}),\n };\n\n if (typeof behind === 'number' && behind > 0) {\n return {\n ...result,\n hint: `Community snapshot is ${behind} commit${behind === 1 ? '' : 's'} behind HEAD. Run \\`ctxo index\\` to refresh cluster / drift / boundary data.`,\n };\n }\n if (behind === undefined) {\n // HEAD resolved but snapshot sha unknown to git (force-push, rebased, etc.).\n return {\n ...result,\n hint: 'Snapshot commit is not reachable from HEAD — it may have been rebased away. Run `ctxo index` to re-anchor.',\n };\n }\n return result;\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IGitPort } from '../../ports/i-git-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport { ChurnAnalyzer } from '../../core/change-intelligence/churn-analyzer.js';\nimport { JsonIndexReader } from '../storage/json-index-reader.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\nimport { HealthScorer } from '../../core/change-intelligence/health-scorer.js';\n\nconst InputSchema = z.object({\n symbolId: z.string().min(1),\n});\n\nexport function handleGetChangeIntelligence(\n storage: IStoragePort,\n git: IGitPort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n) {\n const churnAnalyzer = new ChurnAnalyzer();\n const healthScorer = new HealthScorer();\n const indexReader = new JsonIndexReader(ctxoRoot);\n\n return async (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { symbolId } = parsed.data;\n\n const symbol = storage.getSymbolById(symbolId);\n if (!symbol) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ found: false, hint: 'Symbol not found. Run \"ctxo index\" to build the codebase index.' }) }],\n };\n }\n\n const filePath = symbolId.split('::')[0]!;\n const normalizePath = (p: string) => p.replace(/\\\\/g, '/');\n\n // Get churn data for all files in parallel\n const allFiles = storage.listIndexedFiles();\n const churnResults = await Promise.all(allFiles.map((f) => git.getFileChurn(f)));\n\n const maxChurn = Math.max(1, ...churnResults.map((c) => c.commitCount));\n const targetChurn = churnResults.find((c) => normalizePath(c.filePath) === normalizePath(filePath));\n const commitCount = targetChurn?.commitCount ?? 0;\n\n const normalizedChurn = churnAnalyzer.normalize(commitCount, maxChurn);\n\n // Read cyclomatic complexity from committed index\n const indices = indexReader.readAll();\n const fileIndex = indices.find((i) => i.file === filePath);\n const complexityEntries = fileIndex?.complexity ?? [];\n\n // Storage knows the symbol but its JSON index is missing on disk — SQLite and\n // `.ctxo/index/` have drifted. Surface it so the caller does not mistake the\n // fallback `complexity: 0` score for a real \"low risk\" verdict.\n const indexMissingWarning = !fileIndex\n ? `JSON index for ${filePath} not found on disk — complexity falls back to 0. Run \"ctxo index\" to resync.`\n : undefined;\n\n // Exact match first, then aggregate (max of methods for class-level queries)\n let cyclomatic = complexityEntries.find((c) => c.symbolId === symbolId)?.cyclomatic;\n if (cyclomatic === undefined) {\n // For class/file: use max complexity of all methods in this file\n const symbolName = symbolId.split('::')[1] ?? '';\n const relatedEntries = complexityEntries.filter((c) =>\n c.symbolId.startsWith(`${filePath}::${symbolName}.`),\n );\n cyclomatic = relatedEntries.length > 0\n ? Math.max(...relatedEntries.map((c) => c.cyclomatic))\n : 1;\n }\n // Normalize: cyclomatic 1=0, 10+=1.0\n const normalizedComplexity = Math.min((cyclomatic - 1) / 9, 1);\n\n const score = healthScorer.score(symbolId, normalizedComplexity, normalizedChurn);\n\n const payload = masking.mask(JSON.stringify(score));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(storage.listIndexedFiles());\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n if (indexMissingWarning) {\n content.push({ type: 'text', text: `⚠️ ${indexMissingWarning}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","export class ChurnAnalyzer {\n normalize(commitCount: number, maxCommitCount: number): number {\n if (maxCommitCount <= 0) return 0;\n if (commitCount < 0) {\n throw new Error(`Invalid commit count: ${commitCount}`);\n }\n return Math.min(commitCount / maxCommitCount, 1);\n }\n}\n","import type { ChangeIntelligenceScore, ScoreBand } from '../types.js';\n\nexport class HealthScorer {\n score(symbolId: string, complexity: number, churn: number): ChangeIntelligenceScore {\n const composite = complexity * churn;\n const band = this.toBand(composite);\n\n return { symbolId, complexity, churn, composite, band };\n }\n\n private toBand(composite: number): ScoreBand {\n if (composite < 0.3) return 'low';\n if (composite < 0.7) return 'medium';\n return 'high';\n }\n}\n","import { z } from 'zod';\nimport type { IGitPort } from '../../ports/i-git-port.js';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport { BlastRadiusCalculator } from '../../core/blast-radius/blast-radius-calculator.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\nimport { buildSnapshotStaleness } from '../../core/overlay/snapshot-staleness.js';\nimport type { ClusterLabelMasker } from '../../core/overlay/cluster-label-masker.js';\nimport { filterByIntent } from '../../core/intent-filter.js';\nimport type { CommunitySnapshot } from '../../core/types.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\nimport { getGraphAndFiles } from './get-logic-slice.js';\n\ninterface ClusterBreakdown {\n readonly byCluster: Record<string, number>;\n readonly crossClusterCount: number;\n readonly multiClusterHint?: string;\n}\n\nfunction computeClusterBreakdown(\n snapshot: CommunitySnapshot,\n rootSymbolId: string,\n impactedSymbolIds: readonly string[],\n): ClusterBreakdown | undefined {\n if (impactedSymbolIds.length === 0) return undefined;\n const assignment = new Map<string, { id: number; label: string }>();\n for (const entry of snapshot.communities) {\n assignment.set(entry.symbolId, { id: entry.communityId, label: entry.communityLabel });\n }\n const rootCluster = assignment.get(rootSymbolId);\n const byCluster: Record<string, number> = {};\n let crossClusterCount = 0;\n for (const symbolId of impactedSymbolIds) {\n const cluster = assignment.get(symbolId);\n if (!cluster) continue;\n const label = cluster.label || `community-${cluster.id}`;\n byCluster[label] = (byCluster[label] ?? 0) + 1;\n if (rootCluster && cluster.id !== rootCluster.id) crossClusterCount++;\n }\n const clusterCount = Object.keys(byCluster).length;\n const multiClusterHint =\n clusterCount >= 3\n ? `Change impacts ${clusterCount} clusters — multi-team review recommended.`\n : undefined;\n return { byCluster, crossClusterCount, multiClusterHint };\n}\n\nconst InputSchema = z.object({\n symbolId: z.string().min(1),\n confidence: z.enum(['confirmed', 'likely', 'potential']).optional(),\n intent: z.string().optional().describe('Filter results by intent keywords (e.g., \"test\", \"adapter\", \"security\")'),\n});\n\nexport function handleGetBlastRadius(\n storage: IStoragePort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n git?: IGitPort,\n clusterLabelMasker?: ClusterLabelMasker,\n) {\n const calculator = new BlastRadiusCalculator();\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n return async (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { symbolId } = parsed.data;\n const { graph, indexedFiles } = getGraph();\n\n if (!graph.hasNode(symbolId)) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ found: false, hint: 'Symbol not found. Run \"ctxo index\" to build the codebase index.' }) }],\n };\n }\n\n const result = calculator.calculate(graph, symbolId);\n\n // Apply confidence filter if requested\n let symbols = result.impactedSymbols;\n if (parsed.data.confidence) {\n symbols = symbols.filter(s => s.confidence === parsed.data.confidence);\n }\n\n // Apply intent filter if requested\n symbols = filterByIntent(symbols as unknown as Record<string, unknown>[], parsed.data.intent) as unknown as typeof symbols;\n\n const confirmedCount = symbols.filter(s => s.confidence === 'confirmed').length;\n const likelyCount = symbols.filter(s => s.confidence === 'likely').length;\n const potentialCount = symbols.filter(s => s.confidence === 'potential').length;\n\n const rawSnapshot = storage.readCommunities();\n const snapshot =\n rawSnapshot && clusterLabelMasker?.isEnabled()\n ? clusterLabelMasker.maskSnapshot(rawSnapshot)\n : rawSnapshot;\n const clusterBreakdown = snapshot\n ? computeClusterBreakdown(snapshot, symbolId, symbols.map((s) => s.symbolId))\n : undefined;\n\n const body: Record<string, unknown> = {\n symbolId,\n impactScore: symbols.length,\n directDependentsCount: result.directDependentsCount,\n confirmedCount,\n likelyCount,\n potentialCount,\n overallRiskScore: result.overallRiskScore,\n impactedSymbols: symbols,\n };\n if (clusterBreakdown) {\n body.byCluster = clusterBreakdown.byCluster;\n body.crossClusterEdges = clusterBreakdown.crossClusterCount;\n if (clusterBreakdown.multiClusterHint) {\n body.multiClusterHint = clusterBreakdown.multiClusterHint;\n }\n }\n\n const stalenessMeta = git ? await buildSnapshotStaleness(storage, git) : undefined;\n const extras = stalenessMeta ? { snapshotStaleness: stalenessMeta } : undefined;\n const payload = masking.mask(JSON.stringify(wrapResponse(body, extras)));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","import { z } from 'zod';\nimport type { IGitPort } from '../../ports/i-git-port.js';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport { ArchitecturalOverlay } from '../../core/overlay/architectural-overlay.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\nimport { buildSnapshotStaleness } from '../../core/overlay/snapshot-staleness.js';\nimport type { ClusterLabelMasker } from '../../core/overlay/cluster-label-masker.js';\nimport type { CommunitySnapshot, GodNode } from '../../core/types.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\n\nconst OVERLAY_MODES = ['regex', 'communities', 'both'] as const;\n\nconst InputSchema = z.object({\n layer: z.string().optional(),\n mode: z.enum(OVERLAY_MODES).optional(),\n});\n\nexport interface CommunityOverlayCluster {\n id: number;\n label: string;\n memberCount: number;\n members: string[];\n godNodes: string[];\n}\n\nexport interface CommunityOverlay {\n clusters: CommunityOverlayCluster[];\n modularity: number;\n edgeQuality: CommunitySnapshot['edgeQuality'];\n crossClusterEdges: number;\n computedAt: string;\n commitSha: string;\n}\n\nexport function buildCommunityOverlay(\n snapshot: CommunitySnapshot,\n options: { memberPreviewLimit?: number } = {},\n): CommunityOverlay {\n const previewLimit = options.memberPreviewLimit ?? 15;\n const byCluster = new Map<number, string[]>();\n for (const entry of snapshot.communities) {\n const list = byCluster.get(entry.communityId) ?? [];\n list.push(entry.symbolId);\n byCluster.set(entry.communityId, list);\n }\n const labelFor = new Map<number, string>();\n for (const entry of snapshot.communities) {\n if (!labelFor.has(entry.communityId)) {\n labelFor.set(entry.communityId, entry.communityLabel);\n }\n }\n const godNodesByCommunity = new Map<number, Set<string>>();\n for (const god of snapshot.godNodes as readonly GodNode[]) {\n for (const communityId of god.bridgedCommunities) {\n const set = godNodesByCommunity.get(communityId) ?? new Set<string>();\n set.add(god.symbolId);\n godNodesByCommunity.set(communityId, set);\n }\n }\n\n const clusters: CommunityOverlayCluster[] = [];\n for (const [id, members] of byCluster) {\n members.sort();\n clusters.push({\n id,\n label: labelFor.get(id) ?? `community-${id}`,\n memberCount: members.length,\n members: members.slice(0, previewLimit),\n godNodes: [...(godNodesByCommunity.get(id) ?? [])].sort(),\n });\n }\n clusters.sort((a, b) => b.memberCount - a.memberCount || a.id - b.id);\n\n return {\n clusters,\n modularity: snapshot.modularity,\n edgeQuality: snapshot.edgeQuality,\n crossClusterEdges: snapshot.crossClusterEdges,\n computedAt: snapshot.computedAt,\n commitSha: snapshot.commitSha,\n };\n}\n\nexport function handleGetArchitecturalOverlay(\n storage: IStoragePort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n git?: IGitPort,\n clusterLabelMasker?: ClusterLabelMasker,\n) {\n const overlay = new ArchitecturalOverlay();\n\n return async (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const files = storage.listIndexedFiles();\n const result = overlay.classify(files);\n const mode = parsed.data.mode ?? 'both';\n\n const buildContent = (payloadStr: string) => {\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(files);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payloadStr });\n return content;\n };\n\n const stalenessMeta = git ? await buildSnapshotStaleness(storage, git) : undefined;\n const extras = stalenessMeta ? { snapshotStaleness: stalenessMeta } : undefined;\n\n // Filter by layer if specified (regex-mode semantics always apply here)\n if (parsed.data.layer) {\n const filtered = result.layers[parsed.data.layer];\n const payload = masking.mask(\n JSON.stringify(wrapResponse({ layer: parsed.data.layer, files: filtered ?? [] }, extras)),\n );\n return { content: buildContent(payload) };\n }\n\n const rawSnapshot = mode === 'regex' ? undefined : storage.readCommunities();\n const snapshot =\n rawSnapshot && clusterLabelMasker?.isEnabled()\n ? clusterLabelMasker.maskSnapshot(rawSnapshot)\n : rawSnapshot;\n const community = snapshot ? buildCommunityOverlay(snapshot) : undefined;\n\n const body: Record<string, unknown> = {};\n if (mode !== 'communities') body.layers = result.layers;\n if (community) body.communities = community;\n if (mode === 'communities' && !community) {\n body.hint = 'No community snapshot available. Run `ctxo index` to generate one.';\n }\n\n const payload = masking.mask(JSON.stringify(wrapResponse(body, extras)));\n return { content: buildContent(payload) };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport { DeadCodeDetector } from '../../core/dead-code/dead-code-detector.js';\nimport { getGraphAndFiles } from './get-logic-slice.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\nimport { filterByIntent } from '../../core/intent-filter.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\n\nconst InputSchema = z.object({\n includeTests: z.boolean().optional().default(false),\n intent: z.string().optional().describe('Filter dead code results by intent keywords (e.g., \"adapter\", \"core\", \"function\")'),\n});\n\nexport function handleFindDeadCode(\n storage: IStoragePort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n) {\n const detector = new DeadCodeDetector();\n\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n return (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { graph, indexedFiles } = getGraph();\n const result = detector.detect(graph, { includeTests: parsed.data.includeTests });\n\n // Apply intent filter to deadSymbols if requested\n const filtered = {\n ...result,\n deadSymbols: filterByIntent(result.deadSymbols as unknown as Record<string, unknown>[], parsed.data.intent) as unknown as typeof result.deadSymbols,\n };\n\n const payload = masking.mask(JSON.stringify(wrapResponse(filtered as unknown as Record<string, unknown>)));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport { ContextAssembler } from '../../core/context-assembly/context-assembler.js';\nimport { JsonIndexReader } from '../storage/json-index-reader.js';\nimport { getGraphAndFiles } from './get-logic-slice.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\n\nconst TaskTypeSchema = z.enum(['fix', 'extend', 'refactor', 'understand']);\n\nconst InputSchema = z.object({\n symbolId: z.string().min(1),\n taskType: TaskTypeSchema,\n tokenBudget: z.number().min(100).optional().default(4000),\n});\n\nexport function handleGetContextForTask(\n storage: IStoragePort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n) {\n const assembler = new ContextAssembler();\n const indexReader = new JsonIndexReader(ctxoRoot);\n\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n return (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { symbolId, taskType, tokenBudget } = parsed.data;\n const { graph, indexedFiles } = getGraph();\n const indices = indexReader.readAll();\n\n const result = assembler.assembleForTask(graph, symbolId, taskType, indices, tokenBudget);\n\n if (!result) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ found: false, hint: 'Symbol not found. Run \"ctxo index\".' }) }],\n };\n }\n\n const payload = masking.mask(JSON.stringify(wrapResponse(result as unknown as Record<string, unknown>)));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","export type TaskType = 'fix' | 'extend' | 'refactor' | 'understand';\n\nexport interface ScoringWeights {\n readonly directDependency: number;\n readonly interfaceTypeDef: number;\n readonly blastRadiusDependent: number;\n readonly highComplexity: number;\n readonly antiPatternHistory: number;\n}\n\nconst TASK_WEIGHTS: Record<TaskType, ScoringWeights> = {\n fix: {\n directDependency: 0.3,\n interfaceTypeDef: 0.1,\n blastRadiusDependent: 0.1,\n highComplexity: 0.2,\n antiPatternHistory: 0.3,\n },\n extend: {\n directDependency: 0.4,\n interfaceTypeDef: 0.5,\n blastRadiusDependent: 0.1,\n highComplexity: 0.0,\n antiPatternHistory: 0.0,\n },\n refactor: {\n directDependency: 0.2,\n interfaceTypeDef: 0.1,\n blastRadiusDependent: 0.5,\n highComplexity: 0.1,\n antiPatternHistory: 0.1,\n },\n understand: {\n directDependency: 0.5,\n interfaceTypeDef: 0.3,\n blastRadiusDependent: 0.1,\n highComplexity: 0.1,\n antiPatternHistory: 0.0,\n },\n};\n\nexport function getWeightsForTask(taskType: TaskType): ScoringWeights {\n return TASK_WEIGHTS[taskType];\n}\n","import type { SymbolGraph } from '../graph/symbol-graph.js';\nimport type { SymbolNode, SymbolKind, FileIndex } from '../types.js';\nimport { LogicSliceQuery } from '../logic-slice/logic-slice-query.js';\nimport { BlastRadiusCalculator } from '../blast-radius/blast-radius-calculator.js';\nimport { type TaskType, type ScoringWeights, getWeightsForTask } from './task-context-strategy.js';\n\nexport interface ContextEntry {\n readonly symbolId: string;\n readonly name: string;\n readonly kind: SymbolKind;\n readonly file: string;\n readonly relevanceScore: number;\n readonly reason: string;\n readonly lines: number;\n readonly tokens: number;\n}\n\nexport interface TaskContextResult {\n readonly target: SymbolNode;\n readonly taskType: TaskType;\n readonly context: ContextEntry[];\n readonly totalTokens: number;\n readonly tokenBudget: number;\n readonly warnings: string[];\n}\n\nexport interface RankedContextResult {\n readonly query: string;\n readonly strategy: string;\n readonly results: Array<{\n readonly symbolId: string;\n readonly name: string;\n readonly kind: SymbolKind;\n readonly file: string;\n readonly relevanceScore: number;\n readonly importanceScore: number;\n readonly combinedScore: number;\n readonly tokens: number;\n }>;\n readonly totalTokens: number;\n readonly tokenBudget: number;\n}\n\nconst DEFAULT_TOKEN_BUDGET = 4000;\n\nexport class ContextAssembler {\n private readonly logicSlice = new LogicSliceQuery();\n private readonly blastRadius = new BlastRadiusCalculator();\n\n assembleForTask(\n graph: SymbolGraph,\n symbolId: string,\n taskType: TaskType,\n indices: readonly FileIndex[],\n tokenBudget = DEFAULT_TOKEN_BUDGET,\n ): TaskContextResult | undefined {\n const target = graph.getNode(symbolId);\n if (!target) return undefined;\n\n const weights = getWeightsForTask(taskType);\n\n // Gather forward deps + reverse deps\n const slice = this.logicSlice.getLogicSlice(graph, symbolId);\n const blastResult = this.blastRadius.calculate(graph, symbolId);\n\n // Build candidate pool (deduplicated)\n const candidateMap = new Map<string, { node: SymbolNode; signals: Signals }>();\n\n // Forward dependencies\n if (slice) {\n for (const dep of slice.dependencies) {\n candidateMap.set(dep.symbolId, {\n node: dep,\n signals: { isDirectDep: true, isInterfaceOrType: this.isInterfaceOrType(dep.kind), isDependent: false, complexity: 0, hasAntiPattern: false },\n });\n }\n }\n\n // Reverse dependents (blast radius) — fall back to a synthetic node when\n // the edge source has no matching symbols[] entry (e.g. test files that\n // only import). Without this, symbols whose importers are all such files\n // would produce an empty context even when reverse edges clearly exist.\n for (const entry of blastResult.impactedSymbols) {\n const node = graph.getNode(entry.symbolId) ?? synthesizeNodeFromId(entry.symbolId);\n if (!node) continue;\n\n const existing = candidateMap.get(entry.symbolId);\n if (existing) {\n existing.signals.isDependent = true;\n } else {\n candidateMap.set(entry.symbolId, {\n node,\n signals: { isDirectDep: false, isInterfaceOrType: this.isInterfaceOrType(node.kind), isDependent: true, complexity: 0, hasAntiPattern: false },\n });\n }\n }\n\n // Enrich with complexity + anti-patterns from index\n const fileIndexMap = new Map(indices.map((i) => [i.file, i]));\n for (const [sid, candidate] of candidateMap) {\n const file = sid.split('::')[0] ?? '';\n const fileIndex = fileIndexMap.get(file);\n\n if (fileIndex) {\n const complexity = fileIndex.complexity?.find((c) => c.symbolId === sid);\n candidate.signals.complexity = complexity?.cyclomatic ?? 0;\n candidate.signals.hasAntiPattern = fileIndex.antiPatterns.length > 0;\n }\n }\n\n // Score and rank\n const scored = [...candidateMap.entries()].map(([, { node, signals }]) => ({\n entry: this.buildContextEntry(node, signals, weights),\n score: this.computeScore(signals, weights),\n }));\n\n scored.sort((a, b) => b.score - a.score);\n\n // Greedy pack within token budget\n const context: ContextEntry[] = [];\n let totalTokens = 0;\n\n for (const { entry } of scored) {\n if (totalTokens + entry.tokens > tokenBudget) continue;\n context.push(entry);\n totalTokens += entry.tokens;\n }\n\n // Warnings\n const warnings: string[] = [];\n const targetFile = symbolId.split('::')[0] ?? '';\n const targetIndex = fileIndexMap.get(targetFile);\n if (targetIndex && targetIndex.antiPatterns.length > 0) {\n warnings.push(`⚠ Target symbol has ${targetIndex.antiPatterns.length} anti-pattern(s) in file history`);\n }\n\n return { target, taskType, context, totalTokens, tokenBudget, warnings };\n }\n\n assembleRanked(\n graph: SymbolGraph,\n query: string,\n strategy: 'combined' | 'dependency' | 'importance' = 'combined',\n tokenBudget = DEFAULT_TOKEN_BUDGET,\n ): RankedContextResult {\n const allNodes = graph.allNodes();\n const queryLower = query.toLowerCase();\n\n // Compute max reverse edges for importance normalization\n let maxReverseEdges = 1;\n for (const node of allNodes) {\n const count = graph.getReverseEdges(node.symbolId).length;\n if (count > maxReverseEdges) maxReverseEdges = count;\n }\n\n // Score each symbol\n const scored = allNodes.map((node) => {\n const relevanceScore = this.computeTextRelevance(node.name, queryLower);\n const importanceScore = graph.getReverseEdges(node.symbolId).length / maxReverseEdges;\n\n let combinedScore: number;\n switch (strategy) {\n case 'dependency':\n combinedScore = relevanceScore;\n break;\n case 'importance':\n combinedScore = importanceScore;\n break;\n default:\n combinedScore = relevanceScore * 0.6 + importanceScore * 0.4;\n }\n\n return {\n symbolId: node.symbolId,\n name: node.name,\n kind: node.kind,\n file: node.symbolId.split('::')[0] ?? '',\n relevanceScore: Math.round(relevanceScore * 1000) / 1000,\n importanceScore: Math.round(importanceScore * 1000) / 1000,\n combinedScore: Math.round(combinedScore * 1000) / 1000,\n tokens: this.estimateTokens(node),\n };\n });\n\n // Filter zero-relevance for text-based strategies\n const filtered = strategy === 'importance'\n ? scored\n : scored.filter((s) => s.relevanceScore > 0 || s.importanceScore > 0.1);\n\n filtered.sort((a, b) => b.combinedScore - a.combinedScore);\n\n // Greedy pack\n const results: typeof filtered = [];\n let totalTokens = 0;\n\n for (const item of filtered) {\n if (totalTokens + item.tokens > tokenBudget) continue;\n results.push(item);\n totalTokens += item.tokens;\n }\n\n return { query, strategy, results, totalTokens, tokenBudget };\n }\n\n private computeTextRelevance(name: string, queryLower: string): number {\n const nameLower = name.toLowerCase();\n if (nameLower === queryLower) return 1.0;\n if (nameLower.includes(queryLower)) return 0.7;\n if (queryLower.split(/\\s+/).some((word) => nameLower.includes(word))) return 0.4;\n return 0;\n }\n\n private computeScore(signals: Signals, weights: ScoringWeights): number {\n let score = 0;\n if (signals.isDirectDep) score += weights.directDependency;\n if (signals.isInterfaceOrType) score += weights.interfaceTypeDef;\n if (signals.isDependent) score += weights.blastRadiusDependent;\n if (signals.complexity > 5) score += weights.highComplexity;\n if (signals.hasAntiPattern) score += weights.antiPatternHistory;\n return Math.round(score * 1000) / 1000;\n }\n\n private buildContextEntry(node: SymbolNode, signals: Signals, weights: ScoringWeights): ContextEntry {\n const reasons: string[] = [];\n if (signals.isDirectDep) reasons.push('direct dependency');\n if (signals.isInterfaceOrType) reasons.push('type/interface definition');\n if (signals.isDependent) reasons.push('blast radius dependent');\n if (signals.complexity > 5) reasons.push(`high complexity (CC=${signals.complexity})`);\n if (signals.hasAntiPattern) reasons.push('anti-pattern history');\n\n return {\n symbolId: node.symbolId,\n name: node.name,\n kind: node.kind,\n file: node.symbolId.split('::')[0] ?? '',\n relevanceScore: this.computeScore(signals, weights),\n reason: reasons.join(', ') || 'related symbol',\n lines: node.endLine - node.startLine + 1,\n tokens: this.estimateTokens(node),\n };\n }\n\n private isInterfaceOrType(kind: SymbolKind): boolean {\n return kind === 'interface' || kind === 'type';\n }\n\n estimateTokensPublic(node: SymbolNode): number {\n return this.estimateTokens(node);\n }\n\n private estimateTokens(node: SymbolNode): number {\n // Use byte offsets for accurate estimation when available (~4 chars per token)\n if (node.startOffset !== undefined && node.endOffset !== undefined) {\n return Math.ceil((node.endOffset - node.startOffset) / 4);\n }\n return (node.endLine - node.startLine + 1) * 10;\n }\n}\n\ninterface Signals {\n isDirectDep: boolean;\n isInterfaceOrType: boolean;\n isDependent: boolean;\n complexity: number;\n hasAntiPattern: boolean;\n}\n\nconst VALID_SYMBOL_KINDS = new Set<SymbolKind>([\n 'function', 'class', 'interface', 'method', 'variable', 'type',\n]);\n\n/**\n * Build a minimal SymbolNode from a symbolId string. Used when a blast-radius\n * entry points at an orphan edge source (no matching symbols[] entry in the\n * index). startLine/endLine are 0 so token estimation falls back to a small\n * default without over-counting missing source ranges.\n */\nfunction synthesizeNodeFromId(symbolId: string): SymbolNode | undefined {\n const parts = symbolId.split('::');\n if (parts.length !== 3) return undefined;\n const [file, name, kindRaw] = parts;\n if (!file || !name || !kindRaw) return undefined;\n const kind = VALID_SYMBOL_KINDS.has(kindRaw as SymbolKind) ? (kindRaw as SymbolKind) : 'variable';\n return { symbolId, name, kind, startLine: 0, endLine: 0 };\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport { ContextAssembler } from '../../core/context-assembly/context-assembler.js';\nimport { getGraphAndFiles } from './get-logic-slice.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\nimport { SearchEngine } from '../../core/search/search-engine.js';\nimport type { ISearchPort } from '../../ports/i-search-port.js';\nimport { createLogger } from '../../core/logger.js';\n\nconst log = createLogger('ctxo:search');\n\nconst InputSchema = z.object({\n query: z.string().min(1),\n tokenBudget: z.number().min(100).optional().default(4000),\n strategy: z.enum(['combined', 'dependency', 'importance']).optional().default('combined'),\n fuzzy: z.boolean().optional().default(true),\n searchMode: z.enum(['fts', 'legacy']).optional().default('fts'),\n});\n\nexport function handleGetRankedContext(\n storage: IStoragePort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n searchEngine?: ISearchPort,\n) {\n const assembler = new ContextAssembler();\n const engine: ISearchPort = searchEngine ?? new SearchEngine();\n\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n let lastNodeCount = -1;\n\n return (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { query, tokenBudget, strategy, searchMode } = parsed.data;\n const { graph, indexedFiles } = getGraph();\n\n // Use new search engine when mode is 'fts'\n if (searchMode === 'fts' && strategy !== 'importance') {\n // Rebuild search index when graph changes (detected by node count change)\n const currentNodeCount = graph.nodeCount;\n if (currentNodeCount !== lastNodeCount) {\n const allNodes = graph.allNodes();\n // Compute PageRank scores (normalized reverse edge count)\n const pageRankScores = new Map<string, number>();\n let maxReverseEdges = 1;\n for (const node of allNodes) {\n const count = graph.getReverseEdges(node.symbolId).length;\n if (count > maxReverseEdges) maxReverseEdges = count;\n }\n for (const node of allNodes) {\n const count = graph.getReverseEdges(node.symbolId).length;\n pageRankScores.set(node.symbolId, count / maxReverseEdges);\n }\n\n engine.buildIndex(allNodes, pageRankScores);\n lastNodeCount = currentNodeCount;\n log.info(`Search engine: ${engine.getTier()} (${allNodes.length} symbols)`);\n }\n\n const searchResult = engine.search(query, 100);\n\n // Greedy pack within token budget\n const results: Array<{\n symbolId: string;\n name: string;\n kind: string;\n file: string;\n relevanceScore: number;\n importanceScore: number;\n combinedScore: number;\n tokens: number;\n }> = [];\n let totalTokens = 0;\n\n for (const sr of searchResult.results) {\n const node = graph.getNode(sr.symbolId);\n const tokens = node ? assembler.estimateTokensPublic(node) : 90;\n\n if (totalTokens + tokens > tokenBudget) continue;\n results.push({\n symbolId: sr.symbolId,\n name: sr.name,\n kind: sr.kind,\n file: sr.filePath,\n relevanceScore: Math.round(sr.relevanceScore * 1000) / 1000,\n importanceScore: Math.round(sr.importanceScore * 1000) / 1000,\n combinedScore: Math.round(sr.combinedScore * 1000) / 1000,\n tokens,\n });\n totalTokens += tokens;\n }\n\n const payload = masking.mask(JSON.stringify(wrapResponse({\n query,\n strategy,\n results,\n totalTokens,\n tokenBudget,\n searchMetrics: searchResult.metrics,\n ...(searchResult.fuzzyCorrection ? { fuzzyCorrection: searchResult.fuzzyCorrection } : {}),\n })));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n }\n\n // Legacy mode: use existing substring matching\n const result = assembler.assembleRanked(graph, query, strategy, tokenBudget);\n\n const payload = masking.mask(JSON.stringify(wrapResponse(result as unknown as Record<string, unknown>)));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","/**\n * Symbol Tokenizer — splits symbol names into searchable tokens.\n *\n * Handles camelCase, PascalCase, snake_case, kebab-case, and digit boundaries.\n * Used to populate FTS5 `tokenized_name` columns and to tokenize search queries.\n */\n\nconst STOP_WORDS = new Set([\n 'get', 'set', 'is', 'has', 'can', 'do', 'the', 'a', 'an', 'of', 'to', 'in',\n 'for', 'on', 'with', 'at', 'by', 'from', 'as', 'into', 'not', 'no', 'or',\n]);\n\nexport interface TokenizerOptions {\n /** Include stop-word tokens in output (default: false) */\n includeStopWords?: boolean;\n /** Include the full original name as an additional token (default: true) */\n includeOriginal?: boolean;\n /** Include file path segments as tokens (default: false) */\n includeFilePath?: boolean;\n}\n\nconst DEFAULT_OPTIONS: Required<TokenizerOptions> = {\n includeStopWords: false,\n includeOriginal: true,\n includeFilePath: false,\n};\n\nexport class SymbolTokenizer {\n private readonly options: Required<TokenizerOptions>;\n\n constructor(options?: TokenizerOptions) {\n this.options = { ...DEFAULT_OPTIONS, ...options };\n }\n\n /**\n * Tokenize a symbol name into searchable tokens.\n *\n * Examples:\n * \"getCoChangeMetrics\" → [\"get\", \"co\", \"change\", \"metrics\"] (or without stop words: [\"co\", \"change\", \"metrics\"])\n * \"SqliteStorageAdapter\" → [\"sqlite\", \"storage\", \"adapter\"]\n * \"i_storage_port\" → [\"i\", \"storage\", \"port\"]\n * \"BM25Scorer\" → [\"bm\", \"25\", \"scorer\"]\n * \"DB_PASSWORD\" → [\"db\", \"password\"]\n */\n tokenize(symbolName: string, filePath?: string): string[] {\n const splitTokens = SymbolTokenizer.splitName(symbolName);\n const lowered = splitTokens.map((t) => t.toLowerCase());\n\n const tokens: string[] = this.options.includeStopWords\n ? lowered\n : lowered.filter((t) => !STOP_WORDS.has(t));\n\n // Preserve original name as a token for exact matching\n if (this.options.includeOriginal) {\n const original = symbolName.toLowerCase();\n if (!tokens.includes(original)) {\n tokens.unshift(original);\n }\n }\n\n // Include file path segments\n if (this.options.includeFilePath && filePath) {\n const pathTokens = SymbolTokenizer.tokenizeFilePath(filePath);\n for (const pt of pathTokens) {\n if (!tokens.includes(pt)) {\n tokens.push(pt);\n }\n }\n }\n\n return tokens;\n }\n\n /**\n * Tokenize a search query. Queries use stop words and don't include originals.\n */\n tokenizeQuery(query: string): string[] {\n const words = query.trim().split(/\\s+/);\n const tokens: string[] = [];\n for (const word of words) {\n const split = SymbolTokenizer.splitName(word);\n for (const t of split) {\n const lowered = t.toLowerCase();\n if (lowered.length > 0 && !tokens.includes(lowered)) {\n tokens.push(lowered);\n }\n }\n }\n return tokens;\n }\n\n /**\n * Split a name into constituent words based on naming convention boundaries.\n *\n * Rules:\n * 1. Split on underscores and hyphens (snake_case, kebab-case)\n * 2. Split on camelCase/PascalCase boundaries (uppercase after lowercase)\n * 3. Split acronym boundaries (e.g., \"HTMLParser\" → [\"HTML\", \"Parser\"])\n * 4. Split on digit ↔ letter boundaries\n */\n static splitName(name: string): string[] {\n if (!name || name.length === 0) return [];\n\n // Step 1: Split on underscores, hyphens, dots, slashes\n const segments = name.split(/[_\\-./\\\\]+/).filter((s) => s.length > 0);\n\n const tokens: string[] = [];\n for (const segment of segments) {\n tokens.push(...SymbolTokenizer.splitCamelCase(segment));\n }\n\n return tokens.filter((t) => t.length > 0);\n }\n\n /**\n * Split a single segment on camelCase/PascalCase/digit boundaries.\n */\n private static splitCamelCase(segment: string): string[] {\n const tokens: string[] = [];\n let current = '';\n\n for (let i = 0; i < segment.length; i++) {\n const ch = segment[i]!;\n const prev = i > 0 ? segment[i - 1]! : '';\n\n // Boundary: letter → digit or digit → letter\n if (current.length > 0) {\n const prevIsDigit = isDigit(prev);\n const currIsDigit = isDigit(ch);\n if (prevIsDigit !== currIsDigit) {\n tokens.push(current);\n current = ch;\n continue;\n }\n }\n\n // Boundary: lowercase → uppercase (camelCase boundary)\n if (current.length > 0 && isLower(prev) && isUpper(ch)) {\n tokens.push(current);\n current = ch;\n continue;\n }\n\n // Acronym boundary: multiple uppercase followed by lowercase\n // \"HTMLParser\": H-T-M-L-P-a → when we hit 'a', current=\"HTMLP\"\n // We should split to \"HTML\" + \"Pa...\"\n if (current.length > 1 && isUpper(ch) === false && isUpper(prev) && !isDigit(ch)) {\n // prev is uppercase, current char is lowercase → split before prev\n const lastChar = current[current.length - 1]!;\n if (isUpper(lastChar)) {\n tokens.push(current.slice(0, -1));\n current = lastChar + ch;\n continue;\n }\n }\n\n current += ch;\n }\n\n if (current.length > 0) {\n tokens.push(current);\n }\n\n return tokens;\n }\n\n /**\n * Extract searchable tokens from a file path.\n * \"src/core/search/symbol-tokenizer.ts\" → [\"src\", \"core\", \"search\", \"symbol\", \"tokenizer\", \"ts\"]\n */\n static tokenizeFilePath(filePath: string): string[] {\n // Remove extension, split on separators\n const withoutExt = filePath.replace(/\\.[^.]+$/, '');\n const segments = withoutExt.split(/[/\\\\]+/);\n const tokens: string[] = [];\n for (const seg of segments) {\n const parts = seg.split(/[_\\-.]+/).filter((s) => s.length > 0);\n for (const p of parts) {\n const lowered = p.toLowerCase();\n if (lowered.length > 0 && !tokens.includes(lowered)) {\n tokens.push(lowered);\n }\n }\n }\n return tokens;\n }\n\n /** Check if a token is a stop word */\n static isStopWord(token: string): boolean {\n return STOP_WORDS.has(token.toLowerCase());\n }\n}\n\nfunction isUpper(ch: string): boolean {\n return ch >= 'A' && ch <= 'Z';\n}\n\nfunction isLower(ch: string): boolean {\n return ch >= 'a' && ch <= 'z';\n}\n\nfunction isDigit(ch: string): boolean {\n return ch >= '0' && ch <= '9';\n}\n","/**\n * Fuzzy Corrector — Damerau-Levenshtein based typo correction.\n *\n * Uses adaptive thresholds: d≤1 for terms ≤5 chars, d≤2 for longer terms.\n * Vocabulary is built from tokenized symbol names during index build.\n */\n\nimport type { FuzzyCorrection } from '../types.js';\n\nexport class FuzzyCorrector {\n /** term → frequency (for tie-breaking) */\n private vocabulary: Map<string, number> = new Map();\n\n buildVocabulary(termFrequencies: Map<string, number>): void {\n this.vocabulary = new Map(termFrequencies);\n }\n\n /**\n * Attempt to correct query tokens.\n * Returns null if no correction found or no improvement possible.\n */\n correct(queryTokens: string[]): FuzzyCorrection | null {\n if (this.vocabulary.size === 0) return null;\n\n const corrections: FuzzyCorrection['corrections'] = [];\n const correctedTokens: string[] = [];\n let anyChanged = false;\n\n for (const token of queryTokens) {\n // Skip very short tokens (1-2 chars) — too many false matches\n if (token.length <= 2) {\n correctedTokens.push(token);\n continue;\n }\n\n // Check if token exists in vocabulary (exact match)\n if (this.vocabulary.has(token)) {\n correctedTokens.push(token);\n continue;\n }\n\n const maxDist = token.length <= 5 ? 1 : 2;\n const best = this.findClosest(token, maxDist);\n\n if (best) {\n corrections.push({\n original: token,\n corrected: best.term,\n distance: best.distance,\n });\n correctedTokens.push(best.term);\n anyChanged = true;\n } else {\n correctedTokens.push(token);\n }\n }\n\n if (!anyChanged) return null;\n\n return {\n originalQuery: queryTokens.join(' '),\n correctedQuery: correctedTokens.join(' '),\n corrections,\n };\n }\n\n /**\n * Find the closest vocabulary term within maxDistance.\n * Tie-breaks by frequency (higher = preferred).\n */\n private findClosest(\n token: string,\n maxDistance: number,\n ): { term: string; distance: number } | null {\n let bestTerm: string | null = null;\n let bestDist = maxDistance + 1;\n let bestFreq = -1;\n\n for (const [vocabTerm, freq] of this.vocabulary) {\n // Quick length filter: Damerau-Levenshtein ≥ |len difference|\n if (Math.abs(vocabTerm.length - token.length) > maxDistance) continue;\n\n const dist = damerauLevenshtein(token, vocabTerm);\n if (dist <= maxDistance) {\n if (dist < bestDist || (dist === bestDist && freq > bestFreq)) {\n bestTerm = vocabTerm;\n bestDist = dist;\n bestFreq = freq;\n }\n }\n }\n\n return bestTerm !== null ? { term: bestTerm, distance: bestDist } : null;\n }\n}\n\n/**\n * Damerau-Levenshtein distance.\n * Includes transpositions as a single edit operation.\n * \"tokne\" → \"token\" = distance 1 (transposition), not 2 (delete + insert).\n */\nexport function damerauLevenshtein(a: string, b: string): number {\n const lenA = a.length;\n const lenB = b.length;\n\n if (lenA === 0) return lenB;\n if (lenB === 0) return lenA;\n\n // Optimal string alignment distance (restricted edit distance)\n const d: number[][] = Array.from({ length: lenA + 1 }, () => new Array<number>(lenB + 1).fill(0));\n\n for (let i = 0; i <= lenA; i++) d[i]![0] = i;\n for (let j = 0; j <= lenB; j++) d[0]![j] = j;\n\n for (let i = 1; i <= lenA; i++) {\n for (let j = 1; j <= lenB; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n d[i]![j] = Math.min(\n d[i - 1]![j]! + 1, // deletion\n d[i]![j - 1]! + 1, // insertion\n d[i - 1]![j - 1]! + cost, // substitution\n );\n\n // Transposition\n if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {\n d[i]![j] = Math.min(d[i]![j]!, d[i - 2]![j - 2]! + cost);\n }\n }\n }\n\n return d[lenA]![lenB]!;\n}\n","/**\n * In-memory BM25 Search Engine (Tier 2)\n *\n * Implements two-phase cascade search:\n * Phase 1: Exact + tokenized matching with BM25 scoring\n * Phase 2: Trigram/partial matching (activated when Phase 1 returns < threshold results)\n * Phase 3: Fuzzy correction (activated when Phase 1+2 return < threshold results)\n *\n * Scoring: BM25 * (1 + pageRankWeight * pageRankScore) * bigramBoost\n */\n\nimport type { SymbolNode, SearchResponse, SearchResult, SearchMetrics } from '../types.js';\nimport { SymbolTokenizer } from './symbol-tokenizer.js';\nimport { FuzzyCorrector } from './fuzzy-corrector.js';\nimport { createLogger } from '../logger.js';\n\nconst log = createLogger('ctxo:search');\n\n/** BM25 parameters tuned for code search (short documents) */\ninterface BM25Config {\n k1: number; // term frequency saturation (default: 1.2)\n b: number; // length normalization (default: 0.25 — low for short symbol names)\n}\n\ninterface SearchEngineConfig {\n bm25: BM25Config;\n /** Weight of PageRank boost: finalScore = bm25 * (1 + pageRankWeight * pr) */\n pageRankWeight: number;\n /** Score penalty for Phase 2 (trigram) results */\n trigramPenalty: number;\n /** Threshold: if Phase 1 returns fewer results, activate Phase 2 */\n phase2Threshold: number;\n /** Threshold: if Phase 1+2 return fewer results, activate fuzzy correction */\n fuzzyThreshold: number;\n /** Maximum results per phase */\n maxPerPhase: number;\n}\n\nconst DEFAULT_CONFIG: SearchEngineConfig = {\n bm25: { k1: 1.2, b: 0.25 },\n pageRankWeight: 0.5,\n trigramPenalty: 0.8,\n phase2Threshold: 3,\n fuzzyThreshold: 3,\n maxPerPhase: 50,\n};\n\n/** A document in the inverted index (one per symbol) */\ninterface IndexedDocument {\n symbolId: string;\n name: string;\n kind: string;\n filePath: string;\n /** Tokenized name (from SymbolTokenizer) */\n tokens: string[];\n /** Token count (document length for BM25) */\n length: number;\n}\n\n/** Posting list entry */\ninterface Posting {\n docIndex: number;\n termFrequency: number;\n}\n\nexport class SearchEngine {\n private readonly config: SearchEngineConfig;\n private readonly tokenizer: SymbolTokenizer;\n private readonly fuzzy: FuzzyCorrector;\n\n // Primary index (exact + tokenized)\n private documents: IndexedDocument[] = [];\n private primaryIndex: Map<string, Posting[]> = new Map();\n private avgDocLength = 0;\n\n // Trigram index (character 3-grams)\n private trigramIndex: Map<string, Posting[]> = new Map();\n\n // PageRank scores\n private pageRankScores: Map<string, number> = new Map();\n\n constructor(config?: Partial<SearchEngineConfig>) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.tokenizer = new SymbolTokenizer({ includeOriginal: true, includeFilePath: true });\n this.fuzzy = new FuzzyCorrector();\n }\n\n getTier(): 'fts5' | 'in-memory' | 'legacy' {\n return 'in-memory';\n }\n\n buildIndex(symbols: SymbolNode[], pageRankScores?: Map<string, number>): void {\n const start = performance.now();\n this.documents = [];\n this.primaryIndex = new Map();\n this.trigramIndex = new Map();\n this.pageRankScores = pageRankScores ?? new Map();\n\n let totalLength = 0;\n const vocabFreq = new Map<string, number>();\n\n for (const sym of symbols) {\n const filePath = sym.symbolId.split('::')[0] ?? '';\n const tokens = this.tokenizer.tokenize(sym.name, filePath);\n const doc: IndexedDocument = {\n symbolId: sym.symbolId,\n name: sym.name,\n kind: sym.kind,\n filePath,\n tokens,\n length: tokens.length,\n };\n const docIndex = this.documents.length;\n this.documents.push(doc);\n totalLength += tokens.length;\n\n // Build primary inverted index\n const termFreqs = new Map<string, number>();\n for (const token of tokens) {\n termFreqs.set(token, (termFreqs.get(token) ?? 0) + 1);\n vocabFreq.set(token, (vocabFreq.get(token) ?? 0) + 1);\n }\n for (const [term, tf] of termFreqs) {\n let postings = this.primaryIndex.get(term);\n if (!postings) {\n postings = [];\n this.primaryIndex.set(term, postings);\n }\n postings.push({ docIndex, termFrequency: tf });\n }\n\n // Build trigram index from symbol name (lowercased)\n const nameLower = sym.name.toLowerCase();\n const trigrams = this.extractTrigrams(nameLower);\n const trigramFreqs = new Map<string, number>();\n for (const tri of trigrams) {\n trigramFreqs.set(tri, (trigramFreqs.get(tri) ?? 0) + 1);\n }\n for (const [tri, tf] of trigramFreqs) {\n let postings = this.trigramIndex.get(tri);\n if (!postings) {\n postings = [];\n this.trigramIndex.set(tri, postings);\n }\n postings.push({ docIndex, termFrequency: tf });\n }\n }\n\n this.avgDocLength = this.documents.length > 0 ? totalLength / this.documents.length : 1;\n\n // Build vocabulary for fuzzy corrector\n this.fuzzy.buildVocabulary(vocabFreq);\n\n const elapsed = performance.now() - start;\n log.info(`Index built: ${symbols.length} symbols, ${this.primaryIndex.size} terms, ${this.trigramIndex.size} trigrams (${elapsed.toFixed(0)}ms)`);\n }\n\n search(query: string, limit = 50): SearchResponse {\n const start = performance.now();\n const queryTokens = this.tokenizer.tokenizeQuery(query);\n\n if (queryTokens.length === 0) {\n return this.emptyResponse(query, start);\n }\n\n const metrics: SearchMetrics = {\n porterHits: 0,\n trigramHits: 0,\n phase2Activated: false,\n fuzzyApplied: false,\n latencyMs: 0,\n };\n\n // Phase 1: Primary index search (exact + tokenized)\n const phase1Scores = this.bm25Search(queryTokens, this.primaryIndex);\n metrics.porterHits = phase1Scores.size;\n\n let allScores = phase1Scores;\n\n // Phase 2: Trigram search (if Phase 1 insufficient)\n if (phase1Scores.size < this.config.phase2Threshold) {\n metrics.phase2Activated = true;\n const queryLower = query.toLowerCase();\n\n // Skip trigram for very short queries (< 3 chars produces no useful trigrams)\n if (queryLower.length >= 3) {\n const queryTrigrams = this.extractTrigrams(queryLower);\n const phase2Scores = this.bm25Search(queryTrigrams, this.trigramIndex);\n metrics.trigramHits = phase2Scores.size;\n\n // Merge: union by symbolId, Phase 2 with penalty\n allScores = this.mergeScores(phase1Scores, phase2Scores, this.config.trigramPenalty);\n }\n }\n\n // Phase 3: Fuzzy correction (if still insufficient)\n let fuzzyCorrection: SearchResponse['fuzzyCorrection'];\n if (allScores.size < this.config.fuzzyThreshold) {\n const correction = this.fuzzy.correct(queryTokens);\n if (correction) {\n metrics.fuzzyApplied = true;\n fuzzyCorrection = correction;\n const correctedTokens = this.tokenizer.tokenizeQuery(correction.correctedQuery);\n const fuzzyScores = this.bm25Search(correctedTokens, this.primaryIndex);\n\n // Merge fuzzy results (with slight penalty)\n allScores = this.mergeScores(allScores, fuzzyScores, 0.9);\n\n // Also try trigram on corrected query\n if (allScores.size < this.config.fuzzyThreshold && correction.correctedQuery.length >= 3) {\n const correctedTrigrams = this.extractTrigrams(correction.correctedQuery.toLowerCase());\n const fuzzyTrigramScores = this.bm25Search(correctedTrigrams, this.trigramIndex);\n allScores = this.mergeScores(allScores, fuzzyTrigramScores, this.config.trigramPenalty * 0.9);\n }\n }\n }\n\n // Snapshot raw BM25 relevance scores before boosts\n const rawRelevance = new Map(allScores);\n\n // Apply bigram boost for multi-word queries (applies to ALL paths including fuzzy)\n const effectiveQueryTerms = fuzzyCorrection\n ? this.tokenizer.tokenizeQuery(fuzzyCorrection.correctedQuery)\n : queryTokens;\n\n if (effectiveQueryTerms.length >= 2) {\n for (const [docIdx, score] of allScores) {\n const doc = this.documents[docIdx]!;\n const boost = this.bigramBoost(effectiveQueryTerms, doc.tokens);\n allScores.set(docIdx, score * boost);\n }\n }\n\n // Apply PageRank boost (applies to ALL paths including fuzzy)\n for (const [docIdx, score] of allScores) {\n const doc = this.documents[docIdx]!;\n const pr = this.pageRankScores.get(doc.symbolId) ?? 0;\n allScores.set(docIdx, score * (1 + this.config.pageRankWeight * pr));\n }\n\n metrics.latencyMs = performance.now() - start;\n const results = this.buildResults(allScores, rawRelevance, limit);\n\n const phaseInfo = metrics.phase2Activated ? 'phase2=yes' : 'phase2=no';\n if (fuzzyCorrection) {\n log.info(`search \"${query}\" → fuzzy \"${fuzzyCorrection.correctedQuery}\": ${results.length} results (${metrics.latencyMs.toFixed(0)}ms)`);\n } else {\n log.info(`search \"${query}\": ${results.length} results, porter=${metrics.porterHits} trigram=${metrics.trigramHits} ${phaseInfo} (${metrics.latencyMs.toFixed(0)}ms)`);\n }\n\n return { query, results, metrics, ...(fuzzyCorrection ? { fuzzyCorrection } : {}) };\n }\n\n updateFile(filePath: string, symbols: SymbolNode[]): void {\n // Remove old documents for this file\n const oldIndices = new Set<number>();\n for (let i = 0; i < this.documents.length; i++) {\n if (this.documents[i]!.filePath === filePath) {\n oldIndices.add(i);\n }\n }\n\n if (oldIndices.size === 0 && symbols.length === 0) return;\n\n // Full rebuild (simpler and correct for incremental updates)\n const allSymbols: SymbolNode[] = [];\n for (let i = 0; i < this.documents.length; i++) {\n if (!oldIndices.has(i)) {\n const doc = this.documents[i]!;\n allSymbols.push({\n symbolId: doc.symbolId,\n name: doc.name,\n kind: doc.kind as SymbolNode['kind'],\n startLine: 0,\n endLine: 0,\n });\n }\n }\n allSymbols.push(...symbols);\n this.buildIndex(allSymbols, this.pageRankScores);\n }\n\n /**\n * BM25 scoring over an inverted index.\n * Returns Map<docIndex, score>\n */\n private bm25Search(queryTerms: string[], index: Map<string, Posting[]>): Map<number, number> {\n const scores = new Map<number, number>();\n const N = this.documents.length;\n const { k1, b } = this.config.bm25;\n\n for (const term of queryTerms) {\n const postings = index.get(term);\n if (!postings) continue;\n\n const df = postings.length; // document frequency\n // IDF: log((N - df + 0.5) / (df + 0.5) + 1)\n const idf = Math.log((N - df + 0.5) / (df + 0.5) + 1);\n\n for (const { docIndex, termFrequency } of postings) {\n const doc = this.documents[docIndex]!;\n const tf = termFrequency;\n const docLen = doc.length;\n\n // BM25 term score\n const numerator = tf * (k1 + 1);\n const denominator = tf + k1 * (1 - b + b * (docLen / this.avgDocLength));\n const termScore = idf * (numerator / denominator);\n\n scores.set(docIndex, (scores.get(docIndex) ?? 0) + termScore);\n }\n }\n\n // Boost exact name matches (FR-1.9: 3-5x higher)\n const queryJoined = queryTerms.join('');\n for (const [docIdx, score] of scores) {\n const doc = this.documents[docIdx]!;\n const nameLower = doc.name.toLowerCase();\n if (nameLower === queryJoined || nameLower === queryTerms.join(' ')) {\n scores.set(docIdx, score * 5.0);\n }\n }\n\n return scores;\n }\n\n /**\n * Merge two score maps. Phase 2 scores are penalized.\n */\n private mergeScores(\n primary: Map<number, number>,\n secondary: Map<number, number>,\n penalty: number,\n ): Map<number, number> {\n const merged = new Map(primary);\n for (const [docIdx, score] of secondary) {\n const existing = merged.get(docIdx);\n const penalized = score * penalty;\n if (existing !== undefined) {\n merged.set(docIdx, Math.max(existing, penalized));\n } else {\n merged.set(docIdx, penalized);\n }\n }\n return merged;\n }\n\n /**\n * Bigram boost for multi-word queries.\n * Each adjacent query term pair found adjacent in symbol tokens → 2x boost.\n */\n private bigramBoost(queryTerms: string[], symbolTokens: string[]): number {\n if (queryTerms.length < 2) return 1.0;\n\n let adjacentPairs = 0;\n for (let i = 0; i < queryTerms.length - 1; i++) {\n const idxA = symbolTokens.findIndex((t) => t.includes(queryTerms[i]!));\n const idxB = symbolTokens.findIndex((t) => t.includes(queryTerms[i + 1]!));\n if (idxA >= 0 && idxB >= 0 && Math.abs(idxA - idxB) === 1) {\n adjacentPairs++;\n }\n }\n\n return 1 + adjacentPairs * 2.0;\n }\n\n /**\n * Extract character trigrams from a string.\n * \"sqlite\" → [\"sql\", \"qli\", \"lit\", \"ite\"]\n */\n private extractTrigrams(text: string): string[] {\n const trigrams: string[] = [];\n for (let i = 0; i <= text.length - 3; i++) {\n trigrams.push(text.substring(i, i + 3));\n }\n return trigrams;\n }\n\n private buildResults(\n combinedScores: Map<number, number>,\n rawRelevance: Map<number, number>,\n limit: number,\n ): SearchResult[] {\n const entries = [...combinedScores.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, limit);\n\n return entries.map(([docIdx, combined]) => {\n const doc = this.documents[docIdx]!;\n const pr = this.pageRankScores.get(doc.symbolId) ?? 0;\n return {\n symbolId: doc.symbolId,\n name: doc.name,\n kind: doc.kind,\n filePath: doc.filePath,\n relevanceScore: rawRelevance.get(docIdx) ?? 0,\n importanceScore: pr,\n combinedScore: combined,\n };\n });\n }\n\n private emptyResponse(query: string, start: number): SearchResponse {\n return {\n query,\n results: [],\n metrics: {\n porterHits: 0,\n trigramHits: 0,\n phase2Activated: false,\n fuzzyApplied: false,\n latencyMs: performance.now() - start,\n },\n };\n }\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\nimport { getGraphAndFiles } from './get-logic-slice.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\nimport { SearchEngine } from '../../core/search/search-engine.js';\nimport type { ISearchPort } from '../../ports/i-search-port.js';\n\nconst InputSchema = z.object({\n pattern: z.string().min(1),\n kind: z.enum(['function', 'class', 'interface', 'method', 'variable', 'type']).optional(),\n filePattern: z.string().optional(),\n limit: z.number().int().min(1).max(100).optional().default(25),\n mode: z.enum(['regex', 'fts']).optional().default('regex'),\n});\n\nexport function handleSearchSymbols(\n storage: IStoragePort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n searchEngine?: ISearchPort,\n) {\n const engine: ISearchPort = searchEngine ?? new SearchEngine();\n let lastFtsNodeCount = -1;\n\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n return (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { pattern, kind, filePattern, limit, mode } = parsed.data;\n const { graph, indexedFiles } = getGraph();\n const allNodes = graph.allNodes();\n\n // FTS mode: use search engine\n if (mode === 'fts') {\n if (allNodes.length !== lastFtsNodeCount) {\n engine.buildIndex(allNodes);\n lastFtsNodeCount = allNodes.length;\n }\n\n const searchResult = engine.search(pattern, limit);\n let ftsResults = searchResult.results;\n\n // Apply kind filter\n if (kind) {\n ftsResults = ftsResults.filter((r) => r.kind === kind);\n }\n // Apply file pattern filter\n if (filePattern) {\n const fp = filePattern.toLowerCase();\n ftsResults = ftsResults.filter((r) => r.filePath.toLowerCase().includes(fp));\n }\n\n const results = ftsResults.slice(0, limit).map((r) => {\n const node = graph.getNode(r.symbolId);\n return {\n symbolId: r.symbolId,\n name: r.name,\n kind: r.kind,\n file: r.filePath,\n startLine: node?.startLine ?? 0,\n endLine: node?.endLine ?? 0,\n relevanceScore: Math.round(r.relevanceScore * 1000) / 1000,\n };\n });\n\n const payload = masking.mask(JSON.stringify(wrapResponse({\n totalMatches: ftsResults.length,\n results,\n searchMetrics: searchResult.metrics,\n ...(searchResult.fuzzyCorrection ? { fuzzyCorrection: searchResult.fuzzyCorrection } : {}),\n })));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n }\n\n // Legacy regex mode (default)\n let matcher: (name: string) => boolean;\n try {\n const regex = new RegExp(pattern, 'i');\n matcher = (name: string) => regex.test(name);\n } catch {\n const lowerPattern = pattern.toLowerCase();\n matcher = (name: string) => name.toLowerCase().includes(lowerPattern);\n }\n\n const matches = allNodes.filter((node) => {\n if (!matcher(node.name)) return false;\n if (kind && node.kind !== kind) return false;\n if (filePattern) {\n const file = node.symbolId.split('::')[0] ?? '';\n if (!file.toLowerCase().includes(filePattern.toLowerCase())) return false;\n }\n return true;\n });\n\n const results = matches.slice(0, limit).map((node) => ({\n symbolId: node.symbolId,\n name: node.name,\n kind: node.kind,\n file: node.symbolId.split('::')[0],\n startLine: node.startLine,\n endLine: node.endLine,\n }));\n\n const payload = masking.mask(JSON.stringify(wrapResponse({\n totalMatches: matches.length,\n results,\n })));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IGitPort } from '../../ports/i-git-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\nimport { getGraphAndFiles } from './get-logic-slice.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\n\nconst InputSchema = z.object({\n since: z.string().optional().default('HEAD~1'),\n maxFiles: z.number().int().min(1).optional().default(50),\n});\n\nexport function handleGetChangedSymbols(\n storage: IStoragePort,\n git: IGitPort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n) {\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n return async (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { since, maxFiles } = parsed.data;\n const changedPaths = await git.getChangedFiles(since);\n const { graph, indexedFiles } = getGraph();\n\n // Index all nodes by file for fast lookup\n const nodesByFile = new Map<string, Array<{ symbolId: string; name: string; kind: string; startLine: number; endLine: number }>>();\n for (const node of graph.allNodes()) {\n const file = node.symbolId.split('::')[0] ?? '';\n const existing = nodesByFile.get(file) ?? [];\n existing.push({ symbolId: node.symbolId, name: node.name, kind: node.kind, startLine: node.startLine, endLine: node.endLine });\n nodesByFile.set(file, existing);\n }\n\n const files: Array<{ file: string; symbols: Array<{ symbolId: string; name: string; kind: string; startLine: number; endLine: number }> }> = [];\n let totalSymbols = 0;\n\n for (const filePath of changedPaths.slice(0, maxFiles)) {\n const symbols = nodesByFile.get(filePath);\n if (symbols && symbols.length > 0) {\n files.push({ file: filePath, symbols });\n totalSymbols += symbols.length;\n }\n }\n\n const payload = masking.mask(JSON.stringify(wrapResponse({\n since,\n changedFiles: files.length,\n changedSymbols: totalSymbols,\n files,\n })));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\nimport { getGraphAndFiles } from './get-logic-slice.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\nimport { filterByIntent } from '../../core/intent-filter.js';\n\nconst InputSchema = z.object({\n symbolId: z.string().min(1),\n edgeKinds: z.array(z.enum(['imports', 'calls', 'extends', 'implements', 'uses'])).optional(),\n transitive: z.boolean().optional().default(false),\n maxDepth: z.number().int().min(1).max(10).optional().default(5),\n intent: z.string().optional().describe('Filter results by intent keywords (e.g., \"test\", \"adapter\", \"core\")'),\n});\n\nexport function handleFindImporters(\n storage: IStoragePort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n) {\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n return (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { symbolId, edgeKinds, transitive, maxDepth } = parsed.data;\n const { graph, indexedFiles } = getGraph();\n\n if (!graph.hasNode(symbolId)) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ found: false, hint: 'Symbol not found. Run \"ctxo index\" to build the codebase index.' }) }],\n };\n }\n\n const importers: Array<{\n symbolId: string;\n name: string;\n kind: string;\n file: string;\n edgeKind: string;\n edgeKinds?: string[];\n depth: number;\n }> = [];\n\n if (!transitive) {\n // Direct importers only — deduplicate by symbolId, aggregate edgeKinds\n const reverseEdges = graph.getReverseEdges(symbolId);\n const seen = new Map<string, typeof importers[0]>();\n for (const edge of reverseEdges) {\n if (edgeKinds && !edgeKinds.includes(edge.kind as 'imports' | 'calls' | 'extends' | 'implements' | 'uses')) continue;\n const node = graph.getNode(edge.from);\n if (node) {\n const existing = seen.get(node.symbolId);\n if (existing) {\n if (!existing.edgeKinds!.includes(edge.kind)) {\n existing.edgeKinds!.push(edge.kind);\n }\n } else {\n const entry = {\n symbolId: node.symbolId,\n name: node.name,\n kind: node.kind,\n file: node.symbolId.split('::')[0] ?? '',\n edgeKind: edge.kind,\n edgeKinds: [edge.kind],\n depth: 1,\n };\n seen.set(node.symbolId, entry);\n importers.push(entry);\n }\n }\n }\n } else {\n // BFS for transitive importers\n const visited = new Set<string>([symbolId]);\n const queue: Array<{ id: string; depth: number }> = [{ id: symbolId, depth: 0 }];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n if (current.depth >= maxDepth) continue;\n\n const reverseEdges = graph.getReverseEdges(current.id);\n for (const edge of reverseEdges) {\n if (edgeKinds && !edgeKinds.includes(edge.kind as 'imports' | 'calls' | 'extends' | 'implements' | 'uses')) continue;\n if (visited.has(edge.from)) continue;\n visited.add(edge.from);\n\n const node = graph.getNode(edge.from);\n if (node) {\n const depth = current.depth + 1;\n importers.push({\n symbolId: node.symbolId,\n name: node.name,\n kind: node.kind,\n file: node.symbolId.split('::')[0] ?? '',\n edgeKind: edge.kind,\n depth,\n });\n queue.push({ id: edge.from, depth });\n }\n }\n }\n }\n\n // Sort by depth ascending\n importers.sort((a, b) => a.depth - b.depth);\n\n // Apply intent filter if requested\n const filtered = filterByIntent(importers, parsed.data.intent);\n\n const payload = masking.mask(JSON.stringify(wrapResponse({\n symbolId,\n importerCount: filtered.length,\n importers: filtered,\n })));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\nimport { getGraphAndFiles } from './get-logic-slice.js';\nimport type { SymbolGraph } from '../../core/graph/symbol-graph.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\n\nconst InputSchema = z.object({\n symbolId: z.string().min(1).optional(),\n direction: z.enum(['ancestors', 'descendants', 'both']).optional().default('both'),\n});\n\nexport function handleGetClassHierarchy(\n storage: IStoragePort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n) {\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n return (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { symbolId, direction } = parsed.data;\n const { graph, indexedFiles } = getGraph();\n\n if (symbolId) {\n return handleRooted(graph, symbolId, direction, masking, staleness, indexedFiles);\n }\n\n return handleFull(graph, masking, staleness, indexedFiles);\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n\n function handleRooted(\n graph: SymbolGraph,\n symbolId: string,\n direction: 'ancestors' | 'descendants' | 'both',\n maskingPort: IMaskingPort,\n stalenessCheck: StalenessCheck | undefined,\n indexedFiles: string[],\n ) {\n if (!graph.hasNode(symbolId)) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ found: false, hint: 'Symbol not found. Run \"ctxo index\" to build the codebase index.' }) }],\n };\n }\n\n type HierarchyEntry = { symbolId: string; name: string; kind: string; file: string; edgeKind: string; depth: number };\n const ancestors: HierarchyEntry[] = [];\n const descendants: HierarchyEntry[] = [];\n\n const isHierarchyEdge = (kind: string) => kind === 'extends' || kind === 'implements';\n\n // Ancestors: follow forward edges (this symbol extends/implements X)\n if (direction === 'ancestors' || direction === 'both') {\n const visited = new Set<string>([symbolId]);\n const queue: Array<{ id: string; depth: number }> = [{ id: symbolId, depth: 0 }];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n for (const edge of graph.getForwardEdges(current.id)) {\n if (!isHierarchyEdge(edge.kind)) continue;\n if (visited.has(edge.to)) continue;\n visited.add(edge.to);\n\n const node = graph.getNode(edge.to);\n if (node) {\n const depth = current.depth + 1;\n ancestors.push({\n symbolId: node.symbolId,\n name: node.name,\n kind: node.kind,\n file: node.symbolId.split('::')[0] ?? '',\n edgeKind: edge.kind,\n depth,\n });\n queue.push({ id: edge.to, depth });\n }\n }\n }\n }\n\n // Descendants: follow reverse edges (X extends/implements this symbol)\n if (direction === 'descendants' || direction === 'both') {\n const visited = new Set<string>([symbolId]);\n const queue: Array<{ id: string; depth: number }> = [{ id: symbolId, depth: 0 }];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n for (const edge of graph.getReverseEdges(current.id)) {\n if (!isHierarchyEdge(edge.kind)) continue;\n if (visited.has(edge.from)) continue;\n visited.add(edge.from);\n\n const node = graph.getNode(edge.from);\n if (node) {\n const depth = current.depth + 1;\n descendants.push({\n symbolId: node.symbolId,\n name: node.name,\n kind: node.kind,\n file: node.symbolId.split('::')[0] ?? '',\n edgeKind: edge.kind,\n depth,\n });\n queue.push({ id: edge.from, depth });\n }\n }\n }\n }\n\n const result: Record<string, unknown> = { symbolId };\n if (direction === 'ancestors' || direction === 'both') result.ancestors = ancestors;\n if (direction === 'descendants' || direction === 'both') result.descendants = descendants;\n\n const payload = maskingPort.mask(JSON.stringify(wrapResponse(result)));\n const content: Array<{ type: 'text'; text: string }> = [];\n if (stalenessCheck) {\n const warning = stalenessCheck.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n }\n\n function handleFull(\n graph: SymbolGraph,\n maskingPort: IMaskingPort,\n stalenessCheck: StalenessCheck | undefined,\n indexedFiles: string[],\n ) {\n const isHierarchyEdge = (kind: string) => kind === 'extends' || kind === 'implements';\n const hierarchyEdges = graph.allEdges().filter((e) => isHierarchyEdge(e.kind));\n\n // Collect all nodes involved in hierarchy edges\n const involved = new Set<string>();\n for (const edge of hierarchyEdges) {\n involved.add(edge.from);\n involved.add(edge.to);\n }\n\n // Find roots: nodes that are targets but never sources of extends/implements (true base classes/interfaces)\n const sources = new Set(hierarchyEdges.map((e) => e.from));\n const roots = [...involved].filter((id) => !sources.has(id));\n\n // If no clear roots, use all involved nodes as potential roots (handles cycles)\n const rootSet = roots.length > 0 ? roots : [...involved];\n\n type TreeNode = { symbolId: string; name: string; kind: string; file: string; edgeKind?: string; children: TreeNode[] };\n\n function buildTree(rootId: string, visited: Set<string>): TreeNode | undefined {\n const node = graph.getNode(rootId);\n if (!node) return undefined;\n visited.add(rootId);\n\n const children: TreeNode[] = [];\n for (const edge of graph.getReverseEdges(rootId)) {\n if (!isHierarchyEdge(edge.kind)) continue;\n if (visited.has(edge.from)) continue;\n const child = buildTree(edge.from, visited);\n if (child) {\n child.edgeKind = edge.kind;\n children.push(child);\n }\n }\n\n return {\n symbolId: node.symbolId,\n name: node.name,\n kind: node.kind,\n file: node.symbolId.split('::')[0] ?? '',\n children,\n };\n }\n\n const visited = new Set<string>();\n const hierarchies: TreeNode[] = [];\n for (const rootId of rootSet) {\n if (visited.has(rootId)) continue;\n const tree = buildTree(rootId, visited);\n if (tree) hierarchies.push(tree);\n }\n\n const payload = maskingPort.mask(JSON.stringify(wrapResponse({\n hierarchies,\n totalClasses: involved.size,\n totalEdges: hierarchyEdges.length,\n })));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (stalenessCheck) {\n const warning = stalenessCheck.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n }\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport { PageRankCalculator } from '../../core/importance/pagerank-calculator.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\nimport { getGraphAndFiles } from './get-logic-slice.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\n\nconst InputSchema = z.object({\n limit: z.number().int().min(1).max(200).optional().default(25),\n kind: z.enum(['function', 'class', 'interface', 'method', 'variable', 'type']).optional(),\n filePattern: z.string().optional(),\n damping: z.number().min(0).max(1).optional().default(0.85),\n});\n\nexport function handleGetSymbolImportance(\n storage: IStoragePort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n) {\n const calculator = new PageRankCalculator();\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n return (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { limit, kind, filePattern, damping } = parsed.data;\n const { graph, indexedFiles } = getGraph();\n\n const result = calculator.calculate(graph, { damping, limit: graph.nodeCount, maxIterations: 100 });\n\n // Filter after full PageRank computation (filtering before would distort scores)\n let filtered = result.rankings;\n if (kind) {\n filtered = filtered.filter((e) => e.kind === kind);\n }\n if (filePattern) {\n const lowerPattern = filePattern.toLowerCase();\n filtered = filtered.filter((e) => e.file.toLowerCase().includes(lowerPattern));\n }\n filtered = filtered.slice(0, limit);\n\n const payload = masking.mask(JSON.stringify(wrapResponse({\n rankings: filtered,\n totalSymbols: result.totalSymbols,\n iterations: result.iterations,\n converged: result.converged,\n damping,\n })));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","import { z } from 'zod';\nimport { readFileSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IGitPort } from '../../ports/i-git-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\nimport { getGraphAndFiles } from './get-logic-slice.js';\nimport { BlastRadiusCalculator } from '../../core/blast-radius/blast-radius-calculator.js';\nimport { BoundaryViolationDetector } from '../../core/overlay/boundary-violation-detector.js';\nimport { buildSnapshotStaleness } from '../../core/overlay/snapshot-staleness.js';\nimport type { ClusterLabelMasker } from '../../core/overlay/cluster-label-masker.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\nimport { loadCoChangeMap } from '../../core/co-change/co-change-analyzer.js';\nimport type { CoChangeMatrix, CoChangeEntry, CommunitySnapshot } from '../../core/types.js';\n\nconst InputSchema = z.object({\n since: z.string().optional().default('HEAD~1'),\n maxFiles: z.number().int().min(1).optional().default(50),\n confidence: z.enum(['confirmed', 'likely', 'potential']).optional(),\n});\n\nfunction loadCoChanges(ctxoRoot: string): Map<string, CoChangeEntry[]> | undefined {\n const path = join(ctxoRoot, 'index', 'co-changes.json');\n if (!existsSync(path)) return undefined;\n try {\n const matrix: CoChangeMatrix = JSON.parse(readFileSync(path, 'utf-8'));\n return loadCoChangeMap(matrix);\n } catch {\n return undefined;\n }\n}\n\nfunction computeClustersAffected(\n snapshot: CommunitySnapshot,\n changedSymbolIds: ReadonlySet<string>,\n): Array<{ id: number; label: string; symbolCount: number }> {\n const totals = new Map<number, { label: string; count: number }>();\n for (const entry of snapshot.communities) {\n if (!changedSymbolIds.has(entry.symbolId)) continue;\n const existing = totals.get(entry.communityId);\n if (existing) {\n existing.count += 1;\n } else {\n totals.set(entry.communityId, { label: entry.communityLabel, count: 1 });\n }\n }\n return [...totals.entries()]\n .map(([id, { label, count }]) => ({ id, label, symbolCount: count }))\n .sort((a, b) => b.symbolCount - a.symbolCount || a.id - b.id);\n}\n\nexport function handleGetPrImpact(\n storage: IStoragePort,\n git: IGitPort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n clusterLabelMasker?: ClusterLabelMasker,\n) {\n const calculator = new BlastRadiusCalculator();\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n return async (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { since, maxFiles, confidence: confFilter } = parsed.data;\n\n // Step 1: Get changed files\n const changedPaths = await git.getChangedFiles(since);\n if (changedPaths.length === 0) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ since, changedFiles: 0, changedSymbols: 0, totalImpact: 0, riskLevel: 'low', files: [], summary: { confirmedTotal: 0, likelyTotal: 0, potentialTotal: 0, highRiskSymbols: [] } }) }],\n };\n }\n\n // Step 2: Build graph + load co-changes\n const { graph, indexedFiles } = getGraph();\n const coChangeMap = loadCoChanges(ctxoRoot);\n\n // Step 3: Map files → symbols\n const allNodes = graph.allNodes();\n const nodesByFile = new Map<string, typeof allNodes>();\n for (const node of allNodes) {\n const file = node.symbolId.split('::')[0]!;\n let list = nodesByFile.get(file);\n if (!list) { list = []; nodesByFile.set(file, list); }\n list.push(node);\n }\n\n // Step 4: For each changed file, compute blast radius per symbol\n const limitedPaths = changedPaths.slice(0, maxFiles);\n let totalImpact = 0;\n let confirmedTotal = 0;\n let likelyTotal = 0;\n let potentialTotal = 0;\n const highRiskSymbols: string[] = [];\n\n const files: Array<{\n file: string;\n symbols: Array<{\n symbolId: string;\n name: string;\n kind: string;\n blast: {\n impactScore: number;\n confirmedCount: number;\n likelyCount: number;\n potentialCount: number;\n riskScore: number;\n topImpacted: Array<unknown>;\n };\n }>;\n coChangedWith?: string[];\n }> = [];\n\n for (const filePath of limitedPaths) {\n const symbols = nodesByFile.get(filePath);\n if (!symbols || symbols.length === 0) continue;\n\n const fileSymbols: typeof files[0]['symbols'] = [];\n\n for (const sym of symbols) {\n const result = calculator.calculate(graph, sym.symbolId, coChangeMap);\n\n let impacted = result.impactedSymbols;\n if (confFilter) {\n impacted = impacted.filter(s => s.confidence === confFilter);\n }\n\n const impactScore = impacted.length;\n const confirmed = impacted.filter(s => s.confidence === 'confirmed').length;\n const likely = impacted.filter(s => s.confidence === 'likely').length;\n const potential = impacted.filter(s => s.confidence === 'potential').length;\n\n totalImpact += impactScore;\n confirmedTotal += confirmed;\n likelyTotal += likely;\n potentialTotal += potential;\n\n if (result.overallRiskScore > 0.7) {\n highRiskSymbols.push(sym.symbolId);\n }\n\n const topImpacted = impacted\n .sort((a, b) => b.riskScore - a.riskScore)\n .slice(0, 10);\n\n fileSymbols.push({\n symbolId: sym.symbolId,\n name: sym.name,\n kind: sym.kind,\n blast: {\n impactScore,\n confirmedCount: confirmed,\n likelyCount: likely,\n potentialCount: potential,\n riskScore: result.overallRiskScore,\n topImpacted,\n },\n });\n }\n\n // Co-changed files for this file\n let coChangedWith: string[] | undefined;\n if (coChangeMap) {\n const entries = coChangeMap.get(filePath);\n if (entries && entries.length > 0) {\n coChangedWith = entries\n .sort((a, b) => b.frequency - a.frequency)\n .slice(0, 5)\n .map(e => e.file1 === filePath ? e.file2 : e.file1);\n }\n }\n\n files.push({\n file: filePath,\n symbols: fileSymbols,\n ...(coChangedWith ? { coChangedWith } : {}),\n });\n }\n\n // Step 5: Compute risk level\n const maxRisk = files.reduce((max, f) => {\n const fileMax = f.symbols.reduce((m, s) => Math.max(m, s.blast.riskScore), 0);\n return Math.max(max, fileMax);\n }, 0);\n const riskLevel = maxRisk > 0.7 ? 'high' : maxRisk > 0.3 ? 'medium' : 'low';\n\n const changedSymbols = files.reduce((sum, f) => sum + f.symbols.length, 0);\n\n const rawSnapshot = storage.readCommunities();\n const snapshot =\n rawSnapshot && clusterLabelMasker?.isEnabled()\n ? clusterLabelMasker.maskSnapshot(rawSnapshot)\n : rawSnapshot;\n const history = snapshot ? storage.listCommunityHistory() : [];\n let boundarySection: Record<string, unknown> | undefined;\n let clustersAffected: Array<{ id: number; label: string; symbolCount: number }> | undefined;\n\n if (snapshot) {\n const detector = new BoundaryViolationDetector();\n const violationResult = detector.detect(graph, snapshot, history);\n const changedSymbolIds = new Set<string>();\n for (const file of files) {\n for (const sym of file.symbols) changedSymbolIds.add(sym.symbolId);\n }\n const relevant = violationResult.violations.filter(\n (v) => changedSymbolIds.has(v.from.symbolId) || changedSymbolIds.has(v.to.symbolId),\n );\n boundarySection = {\n violations: relevant,\n confidence: violationResult.confidence,\n snapshotsAvailable: violationResult.snapshotsAvailable,\n ...(violationResult.hint ? { hint: violationResult.hint } : {}),\n };\n clustersAffected = computeClustersAffected(snapshot, changedSymbolIds);\n }\n\n const body: Record<string, unknown> = {\n since,\n changedFiles: files.length,\n changedSymbols,\n totalImpact,\n riskLevel,\n files,\n summary: {\n confirmedTotal,\n likelyTotal,\n potentialTotal,\n highRiskSymbols: highRiskSymbols.slice(0, 10),\n },\n };\n if (boundarySection) body.boundaryViolations = boundarySection;\n if (clustersAffected && clustersAffected.length > 0) body.clustersAffected = clustersAffected;\n\n const stalenessMeta = await buildSnapshotStaleness(storage, git);\n const extras = stalenessMeta ? { snapshotStaleness: stalenessMeta } : undefined;\n const payload = masking.mask(JSON.stringify(wrapResponse(body, extras)));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","import type { ISessionRecorderPort, SessionEvent } from '../../ports/i-session-recorder-port.js';\n\ntype McpToolResult = { content: Array<{ type: 'text'; text: string }> };\ntype McpHandler = (args: Record<string, unknown>) => McpToolResult | Promise<McpToolResult>;\n\n/**\n * Wraps an MCP handler with session recording.\n * Recording is fire-and-forget — errors are swallowed, never affect tool response.\n *\n * @param toolName - MCP tool name (e.g., 'get_logic_slice')\n * @param handler - Original handler function (sync or async)\n * @param recorder - Session recorder (null = recording disabled, zero overhead)\n */\nexport function withRecording(\n toolName: string,\n handler: McpHandler,\n recorder: ISessionRecorderPort | null,\n): McpHandler {\n if (!recorder) return handler;\n\n return (args: Record<string, unknown>) => {\n const start = performance.now();\n const resultOrPromise = handler(args);\n\n // Handle async handlers\n if (resultOrPromise instanceof Promise) {\n return resultOrPromise.then((result) => {\n recordEvent(toolName, args, result, performance.now() - start, recorder);\n return result;\n });\n }\n\n // Sync handler\n const latencyMs = performance.now() - start;\n recordEvent(toolName, args, resultOrPromise, latencyMs, recorder);\n return resultOrPromise;\n };\n}\n\nfunction recordEvent(\n toolName: string,\n args: Record<string, unknown>,\n result: McpToolResult,\n latencyMs: number,\n recorder: ISessionRecorderPort,\n): void {\n try {\n const responseText = result.content\n .filter((c) => c.type === 'text')\n .map((c) => c.text)\n .join('');\n\n let truncated = false;\n try {\n const parsed = JSON.parse(responseText);\n truncated = parsed?._meta?.truncated ?? false;\n } catch { /* non-JSON response, ignore */ }\n\n const responseBytes = Buffer.byteLength(responseText, 'utf-8');\n\n // Extract detail level: args.level (number) → 'L1'...'L4'\n const rawLevel = args['level'];\n let detailLevel: SessionEvent['detailLevel'] = null;\n if (typeof rawLevel === 'number' && rawLevel >= 1 && rawLevel <= 4) {\n detailLevel = `L${rawLevel}` as SessionEvent['detailLevel'];\n }\n\n const event: SessionEvent = {\n tool: toolName,\n symbolId: (typeof args['symbolId'] === 'string' ? args['symbolId'] : null),\n detailLevel,\n responseTokens: Math.ceil(responseBytes / 4),\n responseBytes,\n latencyMs,\n truncated,\n };\n\n recorder.record(event);\n } catch {\n // Recording failure must never affect tool response\n }\n}\n","import type { CommunityEntry, CommunitySnapshot, GodNode } from '../types.js';\nimport { makeGlobMatcher } from '../config/load-config.js';\n\n/**\n * Replace sensitive cluster labels with `[masked-cluster-N]`. Labels matching\n * any configured glob (e.g. `internal-*`, `*-vault`, `src/payment-*`) are\n * rewritten deterministically so MCP tool responses never leak org-sensitive\n * directory names to AI agents over the stdio channel.\n *\n * Determinism matters: drift-detector compares labels across snapshots, so\n * the same input label must always produce the same mask. We seed the mask\n * counter from the snapshot's sorted, unique label set.\n */\nexport class ClusterLabelMasker {\n private readonly matcher: (input: string) => boolean;\n private readonly enabled: boolean;\n private readonly labelCache = new Map<string, string>();\n\n constructor(patterns: readonly string[]) {\n this.enabled = patterns.length > 0;\n this.matcher = this.enabled ? makeGlobMatcher([...patterns]) : () => false;\n }\n\n isEnabled(): boolean {\n return this.enabled;\n }\n\n mask(label: string): string {\n if (!this.enabled) return label;\n if (!this.matcher(label)) return label;\n const cached = this.labelCache.get(label);\n if (cached) return cached;\n const masked = `[masked-cluster-${this.labelCache.size + 1}]`;\n this.labelCache.set(label, masked);\n return masked;\n }\n\n maskSnapshot(snapshot: CommunitySnapshot): CommunitySnapshot {\n if (!this.enabled) return snapshot;\n // Seed the cache in sorted order so output is stable across runs.\n const uniqueLabels = [...new Set(snapshot.communities.map((c) => c.communityLabel))].sort();\n for (const label of uniqueLabels) this.mask(label);\n\n const maskedCommunities: CommunityEntry[] = snapshot.communities.map((entry) => ({\n ...entry,\n communityLabel: this.mask(entry.communityLabel),\n }));\n const maskedGodNodes: GodNode[] = snapshot.godNodes.map((g) => ({ ...g }));\n return { ...snapshot, communities: maskedCommunities, godNodes: maskedGodNodes };\n }\n}\n"],"mappings":"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","names":["z","existsSync","readFileSync","join","z","InputSchema","z","z","InputSchema","z","z","InputSchema","z","z","InputSchema","z","payload","z","InputSchema","z","z","z","InputSchema","z","log","log","InputSchema","z","payload","content","z","InputSchema","z","results","payload","content","z","InputSchema","z","z","InputSchema","z","z","InputSchema","z","visited","z","InputSchema","z","z","InputSchema","z","log","join","existsSync","readFileSync","z"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/adapters/transport/http-server-transport.ts","../src/core/masking/masking-pipeline.ts","../src/adapters/mcp/get-logic-slice.ts","../src/core/logic-slice/logic-slice-query.ts","../src/core/detail-levels/detail-formatter.ts","../src/core/response-envelope.ts","../src/core/intent-filter.ts","../src/adapters/mcp/get-why-context.ts","../src/core/overlay/snapshot-staleness.ts","../src/adapters/mcp/get-change-intelligence.ts","../src/core/change-intelligence/churn-analyzer.ts","../src/core/change-intelligence/health-scorer.ts","../src/adapters/mcp/get-blast-radius.ts","../src/adapters/mcp/get-architectural-overlay.ts","../src/adapters/mcp/get-dead-code.ts","../src/adapters/mcp/get-context-for-task.ts","../src/core/context-assembly/task-context-strategy.ts","../src/core/context-assembly/context-assembler.ts","../src/adapters/mcp/get-ranked-context.ts","../src/core/search/symbol-tokenizer.ts","../src/core/search/fuzzy-corrector.ts","../src/core/search/search-engine.ts","../src/adapters/mcp/search-symbols.ts","../src/adapters/mcp/get-changed-symbols.ts","../src/adapters/mcp/find-importers.ts","../src/adapters/mcp/get-class-hierarchy.ts","../src/adapters/mcp/get-symbol-importance.ts","../src/adapters/mcp/get-pr-impact.ts","../src/adapters/stats/with-recording.ts","../src/core/overlay/cluster-label-masker.ts"],"sourcesContent":["import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { startHttpTransport } from './adapters/transport/http-server-transport.js';\nimport { z } from 'zod';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { createLogger } from './core/logger.js';\nimport { SqliteStorageAdapter } from './adapters/storage/sqlite-storage-adapter.js';\nimport { MaskingPipeline, type MaskingPatternConfig } from './core/masking/masking-pipeline.js';\nimport { handleGetLogicSlice } from './adapters/mcp/get-logic-slice.js';\nimport { handleGetWhyContext } from './adapters/mcp/get-why-context.js';\nimport { handleGetChangeIntelligence } from './adapters/mcp/get-change-intelligence.js';\nimport { SimpleGitAdapter } from './adapters/git/simple-git-adapter.js';\nimport { handleGetBlastRadius } from './adapters/mcp/get-blast-radius.js';\nimport { handleGetArchitecturalOverlay } from './adapters/mcp/get-architectural-overlay.js';\nimport { handleFindDeadCode } from './adapters/mcp/get-dead-code.js';\nimport { handleGetContextForTask } from './adapters/mcp/get-context-for-task.js';\nimport { handleGetRankedContext } from './adapters/mcp/get-ranked-context.js';\nimport { handleSearchSymbols } from './adapters/mcp/search-symbols.js';\nimport { handleGetChangedSymbols } from './adapters/mcp/get-changed-symbols.js';\nimport { handleFindImporters } from './adapters/mcp/find-importers.js';\nimport { handleGetClassHierarchy } from './adapters/mcp/get-class-hierarchy.js';\nimport { handleGetSymbolImportance } from './adapters/mcp/get-symbol-importance.js';\nimport { handleGetPrImpact } from './adapters/mcp/get-pr-impact.js';\nimport { SessionRecorderAdapter } from './adapters/stats/session-recorder-adapter.js';\nimport { withRecording } from './adapters/stats/with-recording.js';\nimport type { ISessionRecorderPort } from './ports/i-session-recorder-port.js';\nimport { detectWorkspace } from './adapters/workspace/single-package-workspace.js';\nimport { setWorkspaceMeta } from './core/response-envelope.js';\nimport { loadConfig, maskingClusterLabelPatterns, statsEnabled } from './core/config/load-config.js';\nimport { ClusterLabelMasker } from './core/overlay/cluster-label-masker.js';\n\nconst log = createLogger('ctxo:mcp');\n\nfunction loadMaskingConfig(ctxoRoot: string): MaskingPipeline {\n const jsonConfigPath = join(ctxoRoot, 'masking.json');\n\n // Try JSON masking config first\n if (existsSync(jsonConfigPath)) {\n try {\n const raw = readFileSync(jsonConfigPath, 'utf-8');\n const patterns: MaskingPatternConfig[] = JSON.parse(raw);\n log.info(`Loaded ${patterns.length} custom masking pattern(s)`);\n return MaskingPipeline.fromConfig(patterns);\n } catch (err) {\n log.error(`Failed to load masking config: ${(err as Error).message}`);\n }\n }\n\n return new MaskingPipeline();\n}\n\nfunction readStatsEnabled(ctxoRoot: string): boolean {\n return statsEnabled(loadConfig(ctxoRoot).config);\n}\n\nconst PKG_VERSION: string = (() => {\n try {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8')) as { version?: string };\n return pkg.version ?? '0.0.0';\n } catch {\n return '0.0.0';\n }\n})();\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n\n // HTTP mode — check before CLI routing since --http is a server flag, not a CLI command\n const httpPortStr = process.env.CTXO_HTTP_PORT\n || (args.includes('--http') ? (args[args.indexOf('--port') + 1] || '3001') : null);\n\n if (!httpPortStr && args.length > 0) {\n // CLI mode\n const { CliRouter } = await import('./cli/cli-router.js');\n const router = new CliRouter(process.cwd());\n await router.route(args);\n return;\n }\n\n // Initialize adapters\n const ctxoRoot = '.ctxo';\n const workspace = detectWorkspace(process.cwd());\n setWorkspaceMeta({ root: workspace.root });\n const storage = new SqliteStorageAdapter(ctxoRoot, { allowProductionPath: true });\n await storage.init();\n\n const masking = loadMaskingConfig(ctxoRoot);\n const clusterLabelMasker = new ClusterLabelMasker(\n maskingClusterLabelPatterns(loadConfig(ctxoRoot).config),\n );\n const git = new SimpleGitAdapter(process.cwd());\n\n // Session recording (opt-out via config.yaml stats.enabled: false)\n const recorder: ISessionRecorderPort | null = readStatsEnabled(ctxoRoot)\n ? new SessionRecorderAdapter(storage.getDb(), () => storage.persist())\n : null;\n\n // Create MCP server\n const server = new McpServer({ name: 'ctxo', version: PKG_VERSION });\n\n // Staleness detection\n const { StalenessDetector } = await import('./core/staleness/staleness-detector.js');\n const staleness = new StalenessDetector(process.cwd(), ctxoRoot);\n\n registerTools(server, storage, masking, git, staleness, recorder, ctxoRoot, clusterLabelMasker);\n\n // Start MCP server — HTTP mode or stdio mode\n if (httpPortStr) {\n await startHttpTransport(async () => {\n const s = new McpServer({ name: 'ctxo', version: PKG_VERSION });\n registerTools(s, storage, masking, git, staleness, recorder, ctxoRoot, clusterLabelMasker);\n return s;\n }, parseInt(httpPortStr, 10));\n } else {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n }\n}\n\nfunction registerTools(\n server: McpServer,\n storage: SqliteStorageAdapter,\n masking: MaskingPipeline,\n git: SimpleGitAdapter,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n staleness: any,\n recorder: ISessionRecorderPort | null,\n ctxoRoot = '.ctxo',\n clusterLabelMasker?: ClusterLabelMasker,\n) {\n // Tool annotations — all Ctxo tools are read-only index queries\n const toolAnnotations = {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n } as const;\n\n // Register tools — each handler wrapped with session recording\n const logicSliceHandler = withRecording('get_logic_slice', handleGetLogicSlice(storage, masking, staleness, ctxoRoot), recorder);\n const whyContextHandler = withRecording('get_why_context', handleGetWhyContext(storage, git, masking, staleness, ctxoRoot, clusterLabelMasker), recorder);\n const changeIntelligenceHandler = withRecording('get_change_intelligence', handleGetChangeIntelligence(storage, git, masking, staleness, ctxoRoot), recorder);\n\n server.registerTool(\n 'get_logic_slice',\n {\n description: 'Retrieve a symbol and all its transitive dependencies as a Logic-Slice. Use this when you need to UNDERSTAND what a symbol depends on (downstream view). L1=signature only, L2=direct deps, L3=full closure, L4=with token budget. Use `intent` to filter dependencies by keyword (e.g., \"core\", \"adapter\"). All responses include `_meta` with item counts and truncation info. For impact analysis (what BREAKS if this changes), use get_blast_radius instead. For task-specific context, use get_context_for_task.',\n inputSchema: {\n symbolId: z.string().optional().describe('Single symbol ID (format: file::name::kind)'),\n symbolIds: z.array(z.string()).optional().describe('Batch: array of symbol IDs'),\n level: z.number().min(1).max(4).optional().default(3).describe('Detail level (L1=signature, L2=direct deps, L3=full closure, L4=with token budget)'),\n intent: z.string().optional().describe('Filter dependencies by intent keywords (e.g., \"core\", \"adapter\")'),\n },\n annotations: toolAnnotations,\n },\n (args) => logicSliceHandler(args),\n );\n\n server.registerTool(\n 'get_why_context',\n {\n description: 'Retrieve git commit history intent and anti-pattern warnings (reverts, rollbacks) for a symbol. Use this when you need to understand WHY code was written this way or whether it has a history of problems. Pair with get_change_intelligence for complexity/churn scores.',\n inputSchema: {\n symbolId: z.string().min(1).describe('The symbol ID (format: file::name::kind)'),\n maxCommits: z.number().int().min(1).optional().describe('Limit commit history to N most recent commits'),\n },\n annotations: toolAnnotations,\n },\n (args) => whyContextHandler(args),\n );\n\n server.registerTool(\n 'get_change_intelligence',\n {\n description: 'Retrieve complexity x churn composite score for a symbol — identifies hotspots that are both complex and frequently changed. Use this to prioritize refactoring targets or assess risk before modifying code. For git history details, use get_why_context. For impact scope, use get_blast_radius.',\n inputSchema: {\n symbolId: z.string().min(1).describe('The symbol ID (format: file::name::kind)'),\n },\n annotations: toolAnnotations,\n },\n (args) => changeIntelligenceHandler(args),\n );\n\n const blastRadiusHandler = withRecording('get_blast_radius', handleGetBlastRadius(storage, masking, staleness, ctxoRoot, git, clusterLabelMasker), recorder);\n\n server.registerTool(\n 'get_blast_radius',\n {\n description: 'BEFORE modifying any function or class, call this to understand impact. Returns all symbols that would break if the target changes, split into confirmed (direct importers), likely (co-changed), and potential (transitive) tiers with risk scores. Use `confidence` to filter by tier, `intent` to filter by keyword. Large results are auto-truncated with `_meta.hint` for drill-in. For what a symbol DEPENDS ON (downstream), use get_logic_slice instead. For full PR-level analysis, use get_pr_impact.',\n inputSchema: {\n symbolId: z.string().min(1).describe('The symbol ID (format: file::name::kind)'),\n confidence: z.enum(['confirmed', 'likely', 'potential']).optional().describe('Filter by confidence tier'),\n intent: z.string().optional().describe('Filter impacted symbols by intent keywords (e.g., \"test\", \"adapter\")'),\n },\n annotations: toolAnnotations,\n },\n (args) => blastRadiusHandler(args),\n );\n\n const overlayHandler = withRecording('get_architectural_overlay', handleGetArchitecturalOverlay(storage, masking, staleness, git, clusterLabelMasker), recorder);\n\n server.registerTool(\n 'get_architectural_overlay',\n {\n description: 'Get the project architectural layer map — identifies which symbols belong to Domain, Infrastructure, and Adapter layers. Use this when onboarding to a new codebase or validating that a change respects layer boundaries. For symbol-level analysis, use get_logic_slice or get_blast_radius.',\n inputSchema: {\n layer: z.string().optional().describe('Filter by specific layer name'),\n },\n annotations: toolAnnotations,\n },\n (args) => overlayHandler(args),\n );\n\n const deadCodeHandler = withRecording('find_dead_code', handleFindDeadCode(storage, masking, staleness, ctxoRoot), recorder);\n\n server.registerTool(\n 'find_dead_code',\n {\n description: 'Find unreachable symbols and files that are never imported or called anywhere. Use this during cleanup, refactoring, or before deleting code to confirm it is truly unused. Use `intent` to filter results by keyword (e.g., \"adapter\", \"function\"). Large results are auto-truncated with `_meta`. For reverse dependency lookup of a specific symbol, use find_importers instead.',\n inputSchema: {\n includeTests: z.boolean().optional().default(false).describe('Include test files in analysis (default: exclude)'),\n intent: z.string().optional().describe('Filter dead code results by intent keywords (e.g., \"adapter\", \"function\")'),\n },\n annotations: toolAnnotations,\n },\n (args) => deadCodeHandler(args),\n );\n\n const contextForTaskHandler = withRecording('get_context_for_task', handleGetContextForTask(storage, masking, staleness, ctxoRoot), recorder);\n\n server.registerTool(\n 'get_context_for_task',\n {\n description: 'Get task-optimized context for a symbol based on what you are about to do. Specify taskType: \"fix\" (bug investigation — includes history + anti-patterns), \"extend\" (add feature — includes deps + blast radius), \"refactor\" (restructure — includes importers + complexity), or \"understand\" (learn — includes full slice + architecture). This is the BEST starting point when you know both the symbol and your intent.',\n inputSchema: {\n symbolId: z.string().min(1).describe('The symbol ID (format: file::name::kind)'),\n taskType: z.enum(['fix', 'extend', 'refactor', 'understand']).describe('Task type determines which context is most relevant'),\n tokenBudget: z.number().optional().default(4000).describe('Max tokens for context (default 4000)'),\n },\n annotations: toolAnnotations,\n },\n (args) => contextForTaskHandler(args),\n );\n\n const rankedContextHandler = withRecording('get_ranked_context', handleGetRankedContext(storage, masking, staleness, ctxoRoot), recorder);\n\n server.registerTool(\n 'get_ranked_context',\n {\n description: 'Search and rank symbols by relevance to a natural language query, packed within a token budget. Uses BM25 text matching + PageRank importance scoring. Results include `_meta` with truncation info. Use this when you have a question or topic but do not know which specific symbol to look at. For exact symbol name search, use search_symbols instead.',\n inputSchema: {\n query: z.string().min(1).describe('Search query (matches symbol names)'),\n tokenBudget: z.number().optional().default(4000).describe('Max tokens for results (default 4000)'),\n strategy: z.enum(['combined', 'dependency', 'importance']).optional().default('combined').describe('Ranking strategy'),\n },\n annotations: toolAnnotations,\n },\n (args) => rankedContextHandler(args),\n );\n\n const searchSymbolsHandler = withRecording('search_symbols', handleSearchSymbols(storage, masking, staleness, ctxoRoot), recorder);\n\n server.registerTool(\n 'search_symbols',\n {\n description: 'Search symbols by exact name or regex pattern across the codebase index. Use this when you know (part of) the symbol name and need to find its ID for use with other tools. For semantic/relevance-based search, use get_ranked_context instead.',\n inputSchema: {\n pattern: z.string().min(1).describe('Search pattern (substring or regex)'),\n kind: z.enum(['function', 'class', 'interface', 'method', 'variable', 'type']).optional().describe('Filter by symbol kind'),\n filePattern: z.string().optional().describe('Filter by file path substring'),\n limit: z.number().int().min(1).max(100).optional().default(25).describe('Max results (default 25)'),\n },\n annotations: toolAnnotations,\n },\n (args) => searchSymbolsHandler(args),\n );\n\n const changedSymbolsHandler = withRecording('get_changed_symbols', handleGetChangedSymbols(storage, git, masking, staleness, ctxoRoot), recorder);\n\n server.registerTool(\n 'get_changed_symbols',\n {\n description: 'Get symbols in recently changed files based on git diff. Use this to see what was modified in recent commits. For full PR risk assessment (changed symbols + blast radius + co-changes), use get_pr_impact instead.',\n inputSchema: {\n since: z.string().optional().default('HEAD~1').describe('Git ref to diff against (default HEAD~1)'),\n maxFiles: z.number().int().min(1).optional().default(50).describe('Max changed files to process (default 50)'),\n },\n annotations: toolAnnotations,\n },\n (args) => changedSymbolsHandler(args),\n );\n\n const findImportersHandler = withRecording('find_importers', handleFindImporters(storage, masking, staleness, ctxoRoot), recorder);\n\n server.registerTool(\n 'find_importers',\n {\n description: 'Find all symbols that import or depend on a given symbol (reverse dependency / \"who uses this?\"). Use this to check if a symbol is safe to modify or delete. Supports transitive traversal for deep impact chains. Use `intent` to filter by keyword (e.g., \"test\", \"core\"). For forward dependencies (what this symbol uses), use get_logic_slice. For aggregated impact with risk scores, use get_blast_radius.',\n inputSchema: {\n symbolId: z.string().min(1).describe('The symbol ID (format: file::name::kind)'),\n edgeKinds: z.array(z.enum(['imports', 'calls', 'extends', 'implements', 'uses'])).optional().describe('Filter by edge kinds'),\n transitive: z.boolean().optional().default(false).describe('Follow transitive reverse edges (default false)'),\n maxDepth: z.number().int().min(1).max(10).optional().default(5).describe('Max BFS depth for transitive mode (default 5)'),\n intent: z.string().optional().describe('Filter importers by intent keywords (e.g., \"test\", \"core\", \"adapter\")'),\n },\n annotations: toolAnnotations,\n },\n (args) => findImportersHandler(args),\n );\n\n const classHierarchyHandler = withRecording('get_class_hierarchy', handleGetClassHierarchy(storage, masking, staleness, ctxoRoot), recorder);\n\n server.registerTool(\n 'get_class_hierarchy',\n {\n description: 'Get class inheritance hierarchy — ancestors (extends/implements chain) and descendants (subclasses). Use this when working with OOP code to understand type relationships before modifying a base class or interface. For dependency-based relationships (imports/calls), use get_logic_slice or find_importers.',\n inputSchema: {\n symbolId: z.string().min(1).optional().describe('Root symbol ID (omit for full project hierarchy)'),\n direction: z.enum(['ancestors', 'descendants', 'both']).optional().default('both').describe('Traversal direction (default both)'),\n },\n annotations: toolAnnotations,\n },\n (args) => classHierarchyHandler(args),\n );\n\n const symbolImportanceHandler = withRecording('get_symbol_importance', handleGetSymbolImportance(storage, masking, staleness, ctxoRoot), recorder);\n\n server.registerTool(\n 'get_symbol_importance',\n {\n description: 'Rank symbols by structural importance using PageRank centrality on the dependency graph. Use this to identify the most critical symbols in the codebase — high-PageRank symbols are heavily depended upon and risky to change. For finding unused/unimportant code, use find_dead_code instead.',\n inputSchema: {\n limit: z.number().int().min(1).max(200).optional().default(25).describe('Max results (default 25)'),\n kind: z.enum(['function', 'class', 'interface', 'method', 'variable', 'type']).optional().describe('Filter by symbol kind'),\n filePattern: z.string().optional().describe('Filter by file path substring'),\n damping: z.number().min(0).max(1).optional().default(0.85).describe('PageRank damping factor (default 0.85)'),\n },\n annotations: toolAnnotations,\n },\n (args) => symbolImportanceHandler(args),\n );\n\n const prImpactHandler = withRecording('get_pr_impact', handleGetPrImpact(storage, git, masking, staleness, ctxoRoot, clusterLabelMasker), recorder);\n\n server.registerTool(\n 'get_pr_impact',\n {\n description: 'Analyze the full impact of a PR or recent changes in a SINGLE call — combines changed symbols + blast radius + co-change history into one risk assessment. Results include `_meta` with truncation info. Use this FIRST when reviewing a PR or evaluating recent commits. For single-symbol analysis, use get_blast_radius instead.',\n inputSchema: {\n since: z.string().optional().default('HEAD~1').describe('Git ref to diff against (default HEAD~1)'),\n maxFiles: z.number().int().min(1).optional().default(50).describe('Max changed files to analyze'),\n confidence: z.enum(['confirmed', 'likely', 'potential']).optional().describe('Filter impacted symbols by confidence tier'),\n },\n annotations: toolAnnotations,\n },\n (args) => prImpactHandler(args),\n );\n\n // Register empty resource/prompt capabilities to prevent -32601 errors\n // from MCP clients that unconditionally call listResources/listPrompts\n server.resource('ctxo-status', 'ctxo://status', async (uri) => ({\n contents: [{ uri: uri.href, text: 'Ctxo MCP server is running.' }],\n }));\n}\n\nmain().catch((err: unknown) => {\n log.error('Fatal: %s', (err as Error).message);\n process.exit(1);\n});\n","import { createServer, type Server, type IncomingMessage, type ServerResponse } from 'node:http';\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport { randomUUID } from 'node:crypto';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { createLogger } from '../../core/logger.js';\n\nconst log = createLogger('ctxo:http');\n\n/**\n * Factory function that creates and registers all tools on a fresh McpServer.\n * Passed in from the composition root so this adapter doesn't import tool handlers.\n */\nexport type ServerFactory = () => Promise<McpServer>;\n\n/**\n * Starts ctxo MCP over HTTP. Each browser session gets its own McpServer + transport.\n * This avoids the \"already connected\" error when multiple clients connect.\n *\n * Usage:\n * CTXO_HTTP_PORT=3001 ctxo\n * ctxo --http\n */\nexport async function startHttpTransport(\n serverFactory: ServerFactory,\n port: number,\n): Promise<{ httpServer: Server }> {\n // Map of session ID -> { transport, server }\n const sessions = new Map<string, { transport: StreamableHTTPServerTransport; server: McpServer }>();\n\n const httpServer = createServer(async (req: IncomingMessage, res: ServerResponse) => {\n // CORS\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Accept, Mcp-Session-Id');\n res.setHeader('Access-Control-Expose-Headers', 'Mcp-Session-Id');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n const sessionId = req.headers['mcp-session-id'] as string | undefined;\n\n // Existing session\n if (sessionId && sessions.has(sessionId)) {\n try {\n await sessions.get(sessionId)!.transport.handleRequest(req, res);\n } catch (err) {\n log.error('Request error: %s', (err as Error).message);\n if (!res.headersSent) { res.writeHead(500); res.end(); }\n }\n return;\n }\n\n // Invalid session\n if (sessionId && !sessions.has(sessionId)) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ jsonrpc: '2.0', error: { code: -32001, message: 'Session not found' }, id: null }));\n return;\n }\n\n // New session — create fresh server + transport\n try {\n const server = await serverFactory();\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: () => randomUUID(),\n });\n\n transport.onclose = () => {\n if (transport.sessionId) {\n sessions.delete(transport.sessionId);\n log.info('Session closed: %s', transport.sessionId);\n }\n };\n\n await server.connect(transport);\n await transport.handleRequest(req, res);\n\n if (transport.sessionId) {\n sessions.set(transport.sessionId, { transport, server });\n log.info('New session: %s (total: %d)', transport.sessionId, sessions.size);\n }\n } catch (err) {\n log.error('Session creation error: %s', (err as Error).message);\n if (!res.headersSent) { res.writeHead(500); res.end(); }\n }\n });\n\n return new Promise((resolve, reject) => {\n httpServer.on('error', reject);\n httpServer.listen(port, () => {\n log.info('MCP HTTP server listening on http://localhost:%d', port);\n process.stderr.write(`[ctxo] MCP HTTP server running at http://localhost:${port}\\n`);\n resolve({ httpServer });\n });\n });\n}\n","const DEFAULT_PATTERNS: Array<{ regex: RegExp; label: string }> = [\n // AWS Access Key IDs (AKIA...)\n { regex: /AKIA[0-9A-Z]{16}/g, label: 'AWS_KEY' },\n // AWS Secret Access Keys (40 char base64 containing / or +). The `[A-Za-z0-9=]*[/+]`\n // lookahead is scoped to the token itself (not `.*`, which would reach a later `/` in\n // the surrounding text, e.g. a file path in JSON, and wrongly redact hex-only git SHAs).\n { regex: /(?<![A-Za-z0-9/+])(?=[A-Za-z0-9/+=]{40}(?![A-Za-z0-9/+=]))(?=[A-Za-z0-9=]*[/+])[A-Za-z0-9/+=]{40}/g, label: 'AWS_SECRET' },\n // JWT tokens (eyJ...)\n { regex: /eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}/g, label: 'JWT' },\n // Private IPv4 (10.x.x.x, 172.16-31.x.x, 192.168.x.x)\n { regex: /\\b(?:10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|172\\.(?:1[6-9]|2\\d|3[01])\\.\\d{1,3}\\.\\d{1,3}|192\\.168\\.\\d{1,3}\\.\\d{1,3})\\b/g, label: 'PRIVATE_IP' },\n // Private IPv6 (fc00::/7)\n { regex: /\\b[fF][cCdD][0-9a-fA-F]{0,2}(?::[0-9a-fA-F]{1,4}){1,7}\\b/g, label: 'PRIVATE_IPV6' },\n // Environment variable assignments for secrets\n { regex: /(?:_SECRET|_KEY|_TOKEN|_PASSWORD)\\s*=\\s*['\"]?[^\\s'\"]{8,}['\"]?/g, label: 'ENV_SECRET' },\n // GCP service account keys\n { regex:/\"private_key\"\\s*:\\s*\"-----BEGIN[^\"]+\"/g, label: 'GCP_KEY' },\n // Azure connection strings\n { regex: /AccountKey=[A-Za-z0-9+/=]{20,}/g, label: 'AZURE_KEY' },\n];\n\nexport interface MaskingPatternConfig {\n readonly pattern: string;\n readonly flags?: string;\n readonly label: string;\n}\n\nexport class MaskingPipeline {\n private readonly patterns: Array<{ regex: RegExp; label: string }>;\n\n constructor(additionalPatterns: Array<{ regex: RegExp; label: string }> = []) {\n // Clone RegExp objects to avoid shared mutable lastIndex state\n this.patterns = [...DEFAULT_PATTERNS, ...additionalPatterns].map(({ regex, label }) => ({\n regex: new RegExp(regex.source, regex.flags),\n label,\n }));\n }\n\n static fromConfig(configPatterns: MaskingPatternConfig[]): MaskingPipeline {\n const additional: Array<{ regex: RegExp; label: string }> = [];\n\n for (const { pattern, flags, label } of configPatterns) {\n try {\n additional.push({ regex: new RegExp(pattern, flags ?? 'g'), label });\n } catch (err) {\n console.error(`[ctxo:masking] Invalid regex pattern \"${pattern}\": ${(err as Error).message}`);\n }\n }\n\n return new MaskingPipeline(additional);\n }\n\n mask(text: string): string {\n if (text.length === 0) return text;\n\n let result = text;\n for (const { regex, label } of this.patterns) {\n result = result.replace(regex, `[REDACTED:${label}]`);\n }\n return result;\n }\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport { SymbolGraph } from '../../core/graph/symbol-graph.js';\nimport { JsonIndexReader } from '../storage/json-index-reader.js';\nimport { LogicSliceQuery } from '../../core/logic-slice/logic-slice-query.js';\nimport { DetailFormatter } from '../../core/detail-levels/detail-formatter.js';\nimport { DetailLevelSchema } from '../../core/types.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\nimport { filterByIntent } from '../../core/intent-filter.js';\n\nconst InputSchema = z.object({\n symbolId: z.string().min(1).optional(),\n symbolIds: z.array(z.string().min(1)).optional(),\n level: DetailLevelSchema.optional().default(3),\n intent: z.string().optional().describe('Filter dependencies by intent keywords (e.g., \"core\", \"adapter\", \"storage\")'),\n}).refine(\n (data) => data.symbolId || (data.symbolIds && data.symbolIds.length > 0),\n { message: 'Either symbolId or symbolIds must be provided' },\n);\n\nexport type GetLogicSliceInput = z.infer<typeof InputSchema>;\n\nexport function getLogicSliceInputSchema() {\n return {\n type: 'object' as const,\n properties: {\n symbolId: { type: 'string' as const, description: 'The symbol ID to retrieve (format: file::name::kind)' },\n level: { type: 'number' as const, enum: [1, 2, 3, 4], description: 'Detail level (1=minimal, 4=full)', default: 3 },\n },\n required: ['symbolId'] as const,\n };\n}\n\nexport function buildGraphFromStorage(storage: IStoragePort): SymbolGraph {\n const graph = new SymbolGraph();\n for (const sym of storage.getAllSymbols()) {\n graph.addNode(sym);\n }\n for (const edge of storage.getAllEdges()) {\n graph.addEdge(edge);\n }\n return graph;\n}\n\n/**\n * Build graph + return file list from a single JSON index read.\n * Returning both from one source prevents staleness warnings from diverging\n * from the graph data (see issue #40).\n */\nexport function buildGraphAndFilesFromJsonIndex(\n ctxoRoot: string,\n): { graph: SymbolGraph; indexedFiles: string[] } {\n const reader = new JsonIndexReader(ctxoRoot);\n const indices = reader.readAll();\n\n const graph = new SymbolGraph();\n const indexedFiles: string[] = [];\n\n for (const fileIndex of indices) {\n indexedFiles.push(fileIndex.file);\n for (const sym of fileIndex.symbols) {\n graph.addNode(sym);\n }\n }\n for (const fileIndex of indices) {\n for (const edge of fileIndex.edges) {\n graph.addEdge(edge);\n }\n }\n return { graph, indexedFiles };\n}\n\n/**\n * Build graph directly from JSON index files (bypasses SQLite cache).\n * Always reads fresh data from disk — works even if ctxo index ran in another process.\n */\nexport function buildGraphFromJsonIndex(ctxoRoot: string): SymbolGraph {\n return buildGraphAndFilesFromJsonIndex(ctxoRoot).graph;\n}\n\n/**\n * Returns graph + indexedFiles from JSON index, falling back to SQLite storage\n * when JSON is empty. Keeps graph data and staleness check file list aligned.\n */\nexport function getGraphAndFiles(\n ctxoRoot: string,\n storage: IStoragePort,\n): { graph: SymbolGraph; indexedFiles: string[] } {\n const json = buildGraphAndFilesFromJsonIndex(ctxoRoot);\n if (json.graph.nodeCount > 0) return json;\n return { graph: buildGraphFromStorage(storage), indexedFiles: storage.listIndexedFiles() };\n}\n\nexport interface StalenessCheck {\n check(indexedFiles: readonly string[]): { message: string } | undefined;\n}\n\nexport function handleGetLogicSlice(\n storage: IStoragePort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n) {\n const query = new LogicSliceQuery();\n const formatter = new DetailFormatter();\n\n // Build graph fresh on each call — try JSON index first (always up to date),\n // fall back to SQLite storage (for tests and when JSON not available).\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n const handler = (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { symbolId, symbolIds, level, intent } = parsed.data;\n const ids = symbolIds ?? (symbolId ? [symbolId] : []);\n\n const { graph, indexedFiles } = getGraph();\n\n // Batch support: query multiple symbols\n const results = [];\n for (const id of ids) {\n const slice = query.getLogicSlice(graph, id);\n if (slice) {\n const formatted = formatter.format(slice, level) as unknown as Record<string, unknown>;\n // Apply intent filter to dependencies if present\n if (intent && Array.isArray(formatted['dependencies'])) {\n formatted['dependencies'] = filterByIntent(\n formatted['dependencies'] as Record<string, unknown>[],\n intent,\n );\n }\n results.push(formatted);\n } else {\n results.push({ found: false, symbolId: id, hint: 'Symbol not found. Run \"ctxo index\".' });\n }\n }\n\n // Single symbol: return directly. Batch: return array.\n const responseData = ids.length === 1 ? results[0] : { batch: true, results };\n\n // Apply masking\n const payload = masking.mask(JSON.stringify(wrapResponse(responseData as Record<string, unknown>)));\n\n // Check staleness\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) {\n content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n\n return handler;\n}\n","import type { SymbolNode, GraphEdge, LogicSliceResult } from '../types.js';\nimport type { SymbolGraph } from '../graph/symbol-graph.js';\n\nexport class LogicSliceQuery {\n getLogicSlice(\n graph: SymbolGraph,\n symbolId: string,\n maxDepth: number = Infinity,\n ): LogicSliceResult | undefined {\n const root = graph.getNode(symbolId);\n if (!root) return undefined;\n\n const visited = new Set<string>([symbolId]);\n const dependencies: SymbolNode[] = [];\n const collectedEdges: GraphEdge[] = [];\n\n // BFS transitive closure\n const queue: Array<{ id: string; depth: number }> = [{ id: symbolId, depth: 0 }];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n\n if (current.depth >= maxDepth) continue;\n\n const edges = graph.getForwardEdges(current.id);\n for (const edge of edges) {\n const depNode = graph.getNode(edge.to);\n // Only include edges whose target node exists in the graph\n if (!depNode) continue;\n\n collectedEdges.push(edge);\n\n if (visited.has(edge.to)) continue;\n visited.add(edge.to);\n\n dependencies.push(depNode);\n queue.push({ id: edge.to, depth: current.depth + 1 });\n }\n }\n\n return { root, dependencies, edges: collectedEdges };\n }\n}\n","import type {\n LogicSliceResult,\n FormattedSlice,\n DetailLevel,\n SymbolNode,\n GraphEdge,\n} from '../types.js';\n\nconst L1_MAX_LINES = 150;\nconst L4_TOKEN_BUDGET = 8000;\n\nexport class DetailFormatter {\n format(slice: LogicSliceResult, level: DetailLevel): FormattedSlice {\n switch (level) {\n case 1:\n return this.formatL1(slice);\n case 2:\n return this.formatL2(slice);\n case 3:\n return this.formatL3(slice);\n case 4:\n return this.formatL4(slice);\n }\n }\n\n private formatL1(slice: LogicSliceResult): FormattedSlice {\n const root = slice.root;\n const lineCount = root.endLine - root.startLine + 1;\n\n const clampedRoot: SymbolNode = lineCount > L1_MAX_LINES\n ? { ...root, endLine: root.startLine + L1_MAX_LINES - 1 }\n : root;\n\n return {\n root: clampedRoot,\n dependencies: [],\n edges: [],\n level: 1,\n levelDescription: 'L1: Root symbol signature only (no dependencies)',\n ...(lineCount > L1_MAX_LINES ? { truncation: { truncated: true as const, reason: 'token_budget_exceeded' as const } } : {}),\n };\n }\n\n private formatL2(slice: LogicSliceResult): FormattedSlice {\n // L2: root + depth-1 direct dependencies\n const directEdges = slice.edges.filter((e) => e.from === slice.root.symbolId);\n const directDepIds = new Set(directEdges.map((e) => e.to));\n const directDeps = slice.dependencies.filter((d) => directDepIds.has(d.symbolId));\n\n return {\n root: slice.root,\n dependencies: directDeps,\n edges: directEdges,\n level: 2,\n levelDescription: 'L2: Root + direct dependencies (depth 1)',\n };\n }\n\n private formatL3(slice: LogicSliceResult): FormattedSlice {\n return {\n root: slice.root,\n dependencies: slice.dependencies,\n edges: slice.edges,\n level: 3,\n levelDescription: 'L3: Full transitive dependency closure',\n };\n }\n\n private formatL4(slice: LogicSliceResult): FormattedSlice {\n // L4: full closure with token budget enforcement\n const estimatedTokens = this.estimateTokens(slice);\n\n if (estimatedTokens > L4_TOKEN_BUDGET) {\n // Truncate dependencies to fit budget\n const truncated = this.truncateToTokenBudget(slice, L4_TOKEN_BUDGET);\n return {\n ...truncated,\n level: 4,\n levelDescription: 'L4: Full closure with 8K token budget (truncated)',\n truncation: {\n truncated: true,\n reason: 'token_budget_exceeded',\n },\n };\n }\n\n return {\n root: slice.root,\n dependencies: slice.dependencies,\n edges: slice.edges,\n level: 4,\n levelDescription: 'L4: Full closure with 8K token budget',\n };\n }\n\n private estimateTokens(slice: LogicSliceResult): number {\n // Rough estimate: ~4 chars per token\n let chars = this.symbolCharEstimate(slice.root);\n for (const dep of slice.dependencies) {\n chars += this.symbolCharEstimate(dep);\n }\n for (const edge of slice.edges) {\n chars += (edge.from.length + edge.to.length + edge.kind.length + 10);\n }\n return Math.ceil(chars / 4);\n }\n\n private symbolCharEstimate(node: SymbolNode): number {\n // Use byte offsets for exact size when available, otherwise estimate from line count\n if (node.startOffset !== undefined && node.endOffset !== undefined) {\n return node.endOffset - node.startOffset;\n }\n return (node.endLine - node.startLine + 1) * 40;\n }\n\n private truncateToTokenBudget(\n slice: LogicSliceResult,\n budget: number,\n ): { root: SymbolNode; dependencies: SymbolNode[]; edges: GraphEdge[] } {\n let currentTokens = this.symbolCharEstimate(slice.root) / 4;\n const deps: SymbolNode[] = [];\n const includedIds = new Set<string>([slice.root.symbolId]);\n\n for (const dep of slice.dependencies) {\n const depTokens = this.symbolCharEstimate(dep) / 4;\n if (currentTokens + depTokens > budget) break;\n currentTokens += depTokens;\n deps.push(dep);\n includedIds.add(dep.symbolId);\n }\n\n const edges = slice.edges.filter(\n (e) => includedIds.has(e.from) && includedIds.has(e.to),\n );\n\n return { root: slice.root, dependencies: deps, edges };\n }\n}\n","/**\n * Response envelope — adds _meta field and truncates large payloads.\n *\n * Applied between payload construction and masking in every MCP handler.\n * Threshold default: 8192 bytes (~8KB). Configurable via CTXO_RESPONSE_LIMIT env.\n */\n\nconst DEFAULT_THRESHOLD = 8192;\n\nexport interface ResponseMeta {\n totalItems: number;\n returnedItems: number;\n truncated: boolean;\n totalBytes: number;\n hint?: string;\n /**\n * Workspace descriptor (forward-compat for Monorepo Workspace PRD).\n * v0.7: `root` is set at startup; `package` is always undefined.\n */\n workspace?: {\n root: string;\n package?: string;\n };\n /**\n * How far the community snapshot has drifted from current git HEAD.\n * Only populated on cluster-aware MCP tools (overlay, blast-radius,\n * why-context, pr-impact). Tells AI agents whether the cluster / drift /\n * boundary data they are about to act on is fresh or N commits stale.\n */\n snapshotStaleness?: {\n snapshotCommit: string;\n currentHeadCommit?: string;\n commitsBehind?: number;\n hint?: string;\n };\n}\n\nlet workspaceMeta: ResponseMeta['workspace'] | undefined;\n\n/**\n * Set the workspace descriptor attached to every subsequent `_meta` envelope.\n * Called once at composition root after `detectWorkspace()` resolves.\n */\nexport function setWorkspaceMeta(workspace: ResponseMeta['workspace']): void {\n workspaceMeta = workspace;\n}\n\nexport function getWorkspaceMeta(): ResponseMeta['workspace'] | undefined {\n return workspaceMeta;\n}\n\n/**\n * Known array field names in tool responses that can be truncated.\n * Maps field name → drill-in hint for the LLM.\n */\nconst TRUNCATABLE_FIELDS: Record<string, string> = {\n impactedSymbols: 'Use search_symbols to find specific impacted symbols, or get_blast_radius with a confidence filter.',\n importers: 'Use find_importers with edgeKinds filter or maxDepth to narrow results.',\n deadSymbols: 'Use search_symbols with kind filter to find specific dead symbols.',\n unusedExports: 'Use find_importers to check specific symbols.',\n results: 'Use search_symbols or get_ranked_context with a narrower query.',\n rankings: 'Use get_symbol_importance with kind or filePattern filter to narrow results.',\n context: 'Use get_context_for_task with a smaller tokenBudget.',\n hierarchies: 'Use get_class_hierarchy with a specific symbolId.',\n scaffolding: 'Review the scaffolding markers directly in the listed files.',\n deadFiles: 'Use find_dead_code with includeTests to adjust scope.',\n files: 'Use get_changed_symbols with a narrower since ref or smaller maxFiles.',\n clusters: 'Use get_architectural_overlay with mode=communities and layer filter for a focused view.',\n clustersAffected: 'Use get_blast_radius on individual changed symbols for per-cluster impact.',\n};\n\nfunction getThreshold(): number {\n const env = process.env['CTXO_RESPONSE_LIMIT'];\n if (env) {\n const n = parseInt(env, 10);\n if (!isNaN(n) && n > 0) return n;\n }\n return DEFAULT_THRESHOLD;\n}\n\n/**\n * Find the largest array field in a payload object that is in our truncatable list.\n */\nfunction findTruncatableArray(data: Record<string, unknown>): { key: string; arr: unknown[] } | null {\n let best: { key: string; arr: unknown[] } | null = null;\n for (const [key, value] of Object.entries(data)) {\n if (Array.isArray(value) && key in TRUNCATABLE_FIELDS) {\n if (!best || value.length > best.arr.length) {\n best = { key, arr: value };\n }\n }\n }\n return best;\n}\n\n/**\n * Wrap a payload object with _meta and truncate if needed.\n *\n * @param data - The raw response object (before JSON.stringify)\n * @returns The data object with _meta added (and arrays truncated if over threshold)\n */\nexport interface WrapResponseExtras {\n snapshotStaleness?: ResponseMeta['snapshotStaleness'];\n}\n\nfunction buildMeta(\n base: Omit<ResponseMeta, 'workspace' | 'snapshotStaleness'>,\n extras?: WrapResponseExtras,\n): ResponseMeta {\n const meta: ResponseMeta = workspaceMeta ? { ...base, workspace: workspaceMeta } : base;\n if (extras?.snapshotStaleness) {\n return { ...meta, snapshotStaleness: extras.snapshotStaleness };\n }\n return meta;\n}\n\nexport function wrapResponse(\n data: Record<string, unknown>,\n extras?: WrapResponseExtras,\n): Record<string, unknown> {\n const threshold = getThreshold();\n const fullJson = JSON.stringify(data);\n const totalBytes = Buffer.byteLength(fullJson, 'utf-8');\n\n const truncatable = findTruncatableArray(data);\n const totalItems = truncatable ? truncatable.arr.length : 0;\n\n // Under threshold — return with _meta, no truncation\n if (totalBytes <= threshold) {\n return {\n ...data,\n _meta: buildMeta(\n {\n totalItems,\n returnedItems: totalItems,\n truncated: false,\n totalBytes,\n },\n extras,\n ),\n };\n }\n\n // Over threshold — truncate the largest array\n if (!truncatable || truncatable.arr.length <= 1) {\n return {\n ...data,\n _meta: buildMeta(\n {\n totalItems,\n returnedItems: totalItems,\n truncated: false,\n totalBytes,\n },\n extras,\n ),\n };\n }\n\n // Binary search for the number of items that fit within threshold\n let lo = 1;\n let hi = truncatable.arr.length;\n\n while (lo < hi) {\n const mid = Math.ceil((lo + hi) / 2);\n const trial = {\n ...data,\n [truncatable.key]: truncatable.arr.slice(0, mid),\n _meta: buildMeta(\n {\n totalItems,\n returnedItems: mid,\n truncated: true,\n totalBytes,\n hint: TRUNCATABLE_FIELDS[truncatable.key],\n },\n extras,\n ),\n };\n const size = Buffer.byteLength(JSON.stringify(trial), 'utf-8');\n if (size <= threshold) {\n lo = mid;\n } else {\n hi = mid - 1;\n }\n }\n\n const hint = TRUNCATABLE_FIELDS[truncatable.key];\n\n return {\n ...data,\n [truncatable.key]: truncatable.arr.slice(0, lo),\n _meta: buildMeta(\n {\n totalItems,\n returnedItems: lo,\n truncated: true,\n totalBytes,\n hint,\n },\n extras,\n ),\n };\n}\n","/**\n * Intent-based result filtering for MCP tool responses.\n *\n * When an `intent` string is provided, filters array results to only include\n * entries whose text fields (symbolId, file, name, kind, edgeKind, reason)\n * match at least one keyword from the intent.\n *\n * Keywords are extracted by splitting the intent on whitespace and lowercasing.\n * A match is found when any keyword appears as a substring of any text field.\n */\n\n/**\n * Extract lowercase keywords from an intent string.\n * Filters out very short words (< 2 chars) to avoid noise.\n */\nfunction extractKeywords(intent: string): string[] {\n return intent\n .toLowerCase()\n .split(/\\s+/)\n .filter(w => w.length >= 2);\n}\n\n/**\n * Check if any keyword matches any of the given text values (case-insensitive substring).\n */\nfunction matchesAny(keywords: string[], values: string[]): boolean {\n const lower = values.map(v => v.toLowerCase());\n return keywords.some(kw => lower.some(v => v.includes(kw)));\n}\n\n/**\n * Collect all string values from a record for matching.\n * Extracts from known fields: symbolId, file, name, kind, edgeKind, edgeKinds, reason, confidence.\n */\nfunction collectMatchableStrings(entry: Record<string, unknown>): string[] {\n const strings: string[] = [];\n for (const key of ['symbolId', 'file', 'name', 'kind', 'edgeKind', 'reason', 'confidence']) {\n const v = entry[key];\n if (typeof v === 'string') strings.push(v);\n }\n const edgeKinds = entry['edgeKinds'];\n if (Array.isArray(edgeKinds)) {\n for (const ek of edgeKinds) {\n if (typeof ek === 'string') strings.push(ek);\n }\n }\n return strings;\n}\n\n/**\n * Filter an array of result entries by intent keywords.\n * Returns only entries where at least one keyword matches a text field.\n *\n * @param items - Array of result objects\n * @param intent - User intent string (e.g., \"test coverage\", \"adapter\", \"security\")\n * @returns Filtered array (empty if no matches)\n */\nexport function filterByIntent<T extends Record<string, unknown>>(\n items: T[],\n intent: string | undefined,\n): T[] {\n if (!intent || intent.trim().length === 0) return items;\n\n const keywords = extractKeywords(intent);\n if (keywords.length === 0) return items;\n\n return items.filter(item => {\n const strings = collectMatchableStrings(item);\n return matchesAny(keywords, strings);\n });\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IGitPort } from '../../ports/i-git-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport { RevertDetector } from '../../core/why-context/revert-detector.js';\nimport { DriftDetector } from '../../core/overlay/drift-detector.js';\nimport { buildSnapshotStaleness } from '../../core/overlay/snapshot-staleness.js';\nimport type { ClusterLabelMasker } from '../../core/overlay/cluster-label-masker.js';\nimport { JsonIndexReader } from '../storage/json-index-reader.js';\nimport type { AntiPattern, CommitIntent } from '../../core/types.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\n\nconst InputSchema = z.object({\n symbolId: z.string().min(1),\n maxCommits: z.number().int().min(1).optional(),\n});\n\nexport function handleGetWhyContext(\n storage: IStoragePort,\n git: IGitPort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n clusterLabelMasker?: ClusterLabelMasker,\n) {\n const revertDetector = new RevertDetector();\n const indexReader = new JsonIndexReader(ctxoRoot);\n const driftDetector = new DriftDetector();\n\n return async (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { symbolId, maxCommits } = parsed.data;\n\n const symbol = storage.getSymbolById(symbolId);\n if (!symbol) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ found: false, hint: 'Symbol not found. Run \"ctxo index\" to build the codebase index.' }) }],\n };\n }\n\n const filePath = symbolId.split('::')[0]!;\n\n // Try committed index first (FR16: anti-patterns persist in committed index)\n const indices = indexReader.readAll();\n const fileIndex = indices.find((i) => i.file === filePath);\n\n let commitHistory: CommitIntent[];\n let antiPatterns: AntiPattern[];\n\n if (fileIndex && fileIndex.intent.length > 0) {\n commitHistory = fileIndex.intent;\n antiPatterns = fileIndex.antiPatterns;\n } else {\n // Fallback: compute on-demand from git\n const commits = await git.getCommitHistory(filePath);\n commitHistory = commits.map((c) => ({\n hash: c.hash,\n message: c.message,\n date: c.date,\n kind: 'commit' as const,\n }));\n antiPatterns = revertDetector.detect(commits);\n }\n\n // Query-time limit: slice to maxCommits if provided\n const limitedHistory = maxCommits ? commitHistory.slice(0, maxCommits) : commitHistory;\n\n // Assemble result — separation of concerns: no changeIntelligence here\n // Use get_change_intelligence tool for complexity/churn scoring\n const responsePayload: Record<string, unknown> = {\n commitHistory: limitedHistory,\n antiPatternWarnings: antiPatterns,\n };\n\n if (antiPatterns.length > 0) {\n responsePayload.warningBadge = '⚠ Anti-pattern detected';\n }\n\n const rawSnapshot = storage.readCommunities();\n const currentSnapshot =\n rawSnapshot && clusterLabelMasker?.isEnabled()\n ? clusterLabelMasker.maskSnapshot(rawSnapshot)\n : rawSnapshot;\n if (currentSnapshot) {\n const history = storage.listCommunityHistory();\n const drift = driftDetector.detect(currentSnapshot, history);\n const relevant = drift.events.filter((event) => event.symbolId === symbolId);\n if (relevant.length > 0 || drift.hint) {\n responsePayload.driftSignals = {\n events: relevant,\n confidence: drift.confidence,\n snapshotsAvailable: drift.snapshotsAvailable,\n stabilitySummary: drift.stability,\n ...(drift.hint ? { hint: drift.hint } : {}),\n };\n }\n }\n\n const stalenessMeta = await buildSnapshotStaleness(storage, git);\n if (stalenessMeta) {\n responsePayload._meta = { snapshotStaleness: stalenessMeta };\n }\n\n const payload = masking.mask(JSON.stringify(responsePayload));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(storage.listIndexedFiles());\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","import type { CommunitySnapshot } from '../types.js';\n\nexport interface SnapshotStaleness {\n readonly snapshotCommit: string;\n readonly currentHeadCommit?: string;\n readonly commitsBehind?: number;\n readonly hint?: string;\n}\n\n/**\n * Narrow structural views of the capabilities this module needs from the\n * storage and git adapters. We declare them here (in core/) rather than\n * importing the full IStoragePort / IGitPort interfaces from ports/ so the\n * hexagonal boundary holds: core/ knows nothing about ports/. Callers pass\n * their existing port-typed adapters — they satisfy these shapes structurally.\n */\nexport interface SnapshotStalenessStorage {\n readCommunities(): CommunitySnapshot | undefined;\n}\n\nexport interface SnapshotStalenessGit {\n getHeadSha?(): Promise<string | undefined> | string | undefined;\n countCommitsBetween?(sha: string): Promise<number | undefined> | number | undefined;\n}\n\n/**\n * Summarise how far the persisted community snapshot has drifted from the\n * current git HEAD. Callers merge this into MCP `_meta` so AI agents know\n * whether cluster / drift / boundary data reflects the HEAD they are about\n * to edit or a stale history point.\n *\n * Returns undefined when no snapshot exists (nothing to report) or when git\n * is unavailable and no comparison is possible.\n */\nexport async function buildSnapshotStaleness(\n storage: SnapshotStalenessStorage,\n git: SnapshotStalenessGit,\n): Promise<SnapshotStaleness | undefined> {\n const snapshot = storage.readCommunities();\n if (!snapshot || !snapshot.commitSha || snapshot.commitSha === 'nocommit') return undefined;\n\n const getHead = git.getHeadSha?.bind(git);\n const countBetween = git.countCommitsBetween?.bind(git);\n const head = getHead ? await getHead() : undefined;\n\n if (!head) {\n // Git unavailable — still report the snapshot anchor so callers know what\n // commit the snapshot was computed against.\n return { snapshotCommit: snapshot.commitSha };\n }\n\n if (head === snapshot.commitSha) {\n return {\n snapshotCommit: snapshot.commitSha,\n currentHeadCommit: head,\n commitsBehind: 0,\n };\n }\n\n const behind = countBetween ? await countBetween(snapshot.commitSha) : undefined;\n\n const result: SnapshotStaleness = {\n snapshotCommit: snapshot.commitSha,\n currentHeadCommit: head,\n ...(typeof behind === 'number' ? { commitsBehind: behind } : {}),\n };\n\n if (typeof behind === 'number' && behind > 0) {\n return {\n ...result,\n hint: `Community snapshot is ${behind} commit${behind === 1 ? '' : 's'} behind HEAD. Run \\`ctxo index\\` to refresh cluster / drift / boundary data.`,\n };\n }\n if (behind === undefined) {\n // HEAD resolved but snapshot sha unknown to git (force-push, rebased, etc.).\n return {\n ...result,\n hint: 'Snapshot commit is not reachable from HEAD — it may have been rebased away. Run `ctxo index` to re-anchor.',\n };\n }\n return result;\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IGitPort } from '../../ports/i-git-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport { ChurnAnalyzer } from '../../core/change-intelligence/churn-analyzer.js';\nimport { JsonIndexReader } from '../storage/json-index-reader.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\nimport { HealthScorer } from '../../core/change-intelligence/health-scorer.js';\n\nconst InputSchema = z.object({\n symbolId: z.string().min(1),\n});\n\nexport function handleGetChangeIntelligence(\n storage: IStoragePort,\n git: IGitPort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n) {\n const churnAnalyzer = new ChurnAnalyzer();\n const healthScorer = new HealthScorer();\n const indexReader = new JsonIndexReader(ctxoRoot);\n\n return async (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { symbolId } = parsed.data;\n\n const symbol = storage.getSymbolById(symbolId);\n if (!symbol) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ found: false, hint: 'Symbol not found. Run \"ctxo index\" to build the codebase index.' }) }],\n };\n }\n\n const filePath = symbolId.split('::')[0]!;\n const normalizePath = (p: string) => p.replace(/\\\\/g, '/');\n\n // Get churn data for all files in parallel\n const allFiles = storage.listIndexedFiles();\n const churnResults = await Promise.all(allFiles.map((f) => git.getFileChurn(f)));\n\n const maxChurn = Math.max(1, ...churnResults.map((c) => c.commitCount));\n const targetChurn = churnResults.find((c) => normalizePath(c.filePath) === normalizePath(filePath));\n const commitCount = targetChurn?.commitCount ?? 0;\n\n const normalizedChurn = churnAnalyzer.normalize(commitCount, maxChurn);\n\n // Read cyclomatic complexity from committed index\n const indices = indexReader.readAll();\n const fileIndex = indices.find((i) => i.file === filePath);\n const complexityEntries = fileIndex?.complexity ?? [];\n\n // Storage knows the symbol but its JSON index is missing on disk — SQLite and\n // `.ctxo/index/` have drifted. Surface it so the caller does not mistake the\n // fallback `complexity: 0` score for a real \"low risk\" verdict.\n const indexMissingWarning = !fileIndex\n ? `JSON index for ${filePath} not found on disk — complexity falls back to 0. Run \"ctxo index\" to resync.`\n : undefined;\n\n // Exact match first, then aggregate (max of methods for class-level queries)\n let cyclomatic = complexityEntries.find((c) => c.symbolId === symbolId)?.cyclomatic;\n if (cyclomatic === undefined) {\n // For class/file: use max complexity of all methods in this file\n const symbolName = symbolId.split('::')[1] ?? '';\n const relatedEntries = complexityEntries.filter((c) =>\n c.symbolId.startsWith(`${filePath}::${symbolName}.`),\n );\n cyclomatic = relatedEntries.length > 0\n ? Math.max(...relatedEntries.map((c) => c.cyclomatic))\n : 1;\n }\n // Normalize: cyclomatic 1=0, 10+=1.0\n const normalizedComplexity = Math.min((cyclomatic - 1) / 9, 1);\n\n const score = healthScorer.score(symbolId, normalizedComplexity, normalizedChurn);\n\n const payload = masking.mask(JSON.stringify(score));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(storage.listIndexedFiles());\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n if (indexMissingWarning) {\n content.push({ type: 'text', text: `⚠️ ${indexMissingWarning}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","export class ChurnAnalyzer {\n normalize(commitCount: number, maxCommitCount: number): number {\n if (maxCommitCount <= 0) return 0;\n if (commitCount < 0) {\n throw new Error(`Invalid commit count: ${commitCount}`);\n }\n return Math.min(commitCount / maxCommitCount, 1);\n }\n}\n","import type { ChangeIntelligenceScore, ScoreBand } from '../types.js';\n\nexport class HealthScorer {\n score(symbolId: string, complexity: number, churn: number): ChangeIntelligenceScore {\n const composite = complexity * churn;\n const band = this.toBand(composite);\n\n return { symbolId, complexity, churn, composite, band };\n }\n\n private toBand(composite: number): ScoreBand {\n if (composite < 0.3) return 'low';\n if (composite < 0.7) return 'medium';\n return 'high';\n }\n}\n","import { z } from 'zod';\nimport type { IGitPort } from '../../ports/i-git-port.js';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport { BlastRadiusCalculator } from '../../core/blast-radius/blast-radius-calculator.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\nimport { buildSnapshotStaleness } from '../../core/overlay/snapshot-staleness.js';\nimport type { ClusterLabelMasker } from '../../core/overlay/cluster-label-masker.js';\nimport { filterByIntent } from '../../core/intent-filter.js';\nimport type { CommunitySnapshot } from '../../core/types.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\nimport { getGraphAndFiles } from './get-logic-slice.js';\n\ninterface ClusterBreakdown {\n readonly byCluster: Record<string, number>;\n readonly crossClusterCount: number;\n readonly multiClusterHint?: string;\n}\n\nfunction computeClusterBreakdown(\n snapshot: CommunitySnapshot,\n rootSymbolId: string,\n impactedSymbolIds: readonly string[],\n): ClusterBreakdown | undefined {\n if (impactedSymbolIds.length === 0) return undefined;\n const assignment = new Map<string, { id: number; label: string }>();\n for (const entry of snapshot.communities) {\n assignment.set(entry.symbolId, { id: entry.communityId, label: entry.communityLabel });\n }\n const rootCluster = assignment.get(rootSymbolId);\n const byCluster: Record<string, number> = {};\n let crossClusterCount = 0;\n for (const symbolId of impactedSymbolIds) {\n const cluster = assignment.get(symbolId);\n if (!cluster) continue;\n const label = cluster.label || `community-${cluster.id}`;\n byCluster[label] = (byCluster[label] ?? 0) + 1;\n if (rootCluster && cluster.id !== rootCluster.id) crossClusterCount++;\n }\n const clusterCount = Object.keys(byCluster).length;\n const multiClusterHint =\n clusterCount >= 3\n ? `Change impacts ${clusterCount} clusters — multi-team review recommended.`\n : undefined;\n return { byCluster, crossClusterCount, multiClusterHint };\n}\n\nconst InputSchema = z.object({\n symbolId: z.string().min(1),\n confidence: z.enum(['confirmed', 'likely', 'potential']).optional(),\n intent: z.string().optional().describe('Filter results by intent keywords (e.g., \"test\", \"adapter\", \"security\")'),\n});\n\nexport function handleGetBlastRadius(\n storage: IStoragePort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n git?: IGitPort,\n clusterLabelMasker?: ClusterLabelMasker,\n) {\n const calculator = new BlastRadiusCalculator();\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n return async (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { symbolId } = parsed.data;\n const { graph, indexedFiles } = getGraph();\n\n if (!graph.hasNode(symbolId)) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ found: false, hint: 'Symbol not found. Run \"ctxo index\" to build the codebase index.' }) }],\n };\n }\n\n const result = calculator.calculate(graph, symbolId);\n\n // Apply confidence filter if requested\n let symbols = result.impactedSymbols;\n if (parsed.data.confidence) {\n symbols = symbols.filter(s => s.confidence === parsed.data.confidence);\n }\n\n // Apply intent filter if requested\n symbols = filterByIntent(symbols as unknown as Record<string, unknown>[], parsed.data.intent) as unknown as typeof symbols;\n\n const confirmedCount = symbols.filter(s => s.confidence === 'confirmed').length;\n const likelyCount = symbols.filter(s => s.confidence === 'likely').length;\n const potentialCount = symbols.filter(s => s.confidence === 'potential').length;\n\n const rawSnapshot = storage.readCommunities();\n const snapshot =\n rawSnapshot && clusterLabelMasker?.isEnabled()\n ? clusterLabelMasker.maskSnapshot(rawSnapshot)\n : rawSnapshot;\n const clusterBreakdown = snapshot\n ? computeClusterBreakdown(snapshot, symbolId, symbols.map((s) => s.symbolId))\n : undefined;\n\n const body: Record<string, unknown> = {\n symbolId,\n impactScore: symbols.length,\n directDependentsCount: result.directDependentsCount,\n confirmedCount,\n likelyCount,\n potentialCount,\n overallRiskScore: result.overallRiskScore,\n impactedSymbols: symbols,\n };\n if (clusterBreakdown) {\n body.byCluster = clusterBreakdown.byCluster;\n body.crossClusterEdges = clusterBreakdown.crossClusterCount;\n if (clusterBreakdown.multiClusterHint) {\n body.multiClusterHint = clusterBreakdown.multiClusterHint;\n }\n }\n\n const stalenessMeta = git ? await buildSnapshotStaleness(storage, git) : undefined;\n const extras = stalenessMeta ? { snapshotStaleness: stalenessMeta } : undefined;\n const payload = masking.mask(JSON.stringify(wrapResponse(body, extras)));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","import { z } from 'zod';\nimport type { IGitPort } from '../../ports/i-git-port.js';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport { ArchitecturalOverlay } from '../../core/overlay/architectural-overlay.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\nimport { buildSnapshotStaleness } from '../../core/overlay/snapshot-staleness.js';\nimport type { ClusterLabelMasker } from '../../core/overlay/cluster-label-masker.js';\nimport type { CommunitySnapshot, GodNode } from '../../core/types.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\n\nconst OVERLAY_MODES = ['regex', 'communities', 'both'] as const;\n\nconst InputSchema = z.object({\n layer: z.string().optional(),\n mode: z.enum(OVERLAY_MODES).optional(),\n});\n\nexport interface CommunityOverlayCluster {\n id: number;\n label: string;\n memberCount: number;\n members: string[];\n godNodes: string[];\n}\n\nexport interface CommunityOverlay {\n clusters: CommunityOverlayCluster[];\n modularity: number;\n edgeQuality: CommunitySnapshot['edgeQuality'];\n crossClusterEdges: number;\n computedAt: string;\n commitSha: string;\n}\n\nexport function buildCommunityOverlay(\n snapshot: CommunitySnapshot,\n options: { memberPreviewLimit?: number } = {},\n): CommunityOverlay {\n const previewLimit = options.memberPreviewLimit ?? 15;\n const byCluster = new Map<number, string[]>();\n for (const entry of snapshot.communities) {\n const list = byCluster.get(entry.communityId) ?? [];\n list.push(entry.symbolId);\n byCluster.set(entry.communityId, list);\n }\n const labelFor = new Map<number, string>();\n for (const entry of snapshot.communities) {\n if (!labelFor.has(entry.communityId)) {\n labelFor.set(entry.communityId, entry.communityLabel);\n }\n }\n const godNodesByCommunity = new Map<number, Set<string>>();\n for (const god of snapshot.godNodes as readonly GodNode[]) {\n for (const communityId of god.bridgedCommunities) {\n const set = godNodesByCommunity.get(communityId) ?? new Set<string>();\n set.add(god.symbolId);\n godNodesByCommunity.set(communityId, set);\n }\n }\n\n const clusters: CommunityOverlayCluster[] = [];\n for (const [id, members] of byCluster) {\n members.sort();\n clusters.push({\n id,\n label: labelFor.get(id) ?? `community-${id}`,\n memberCount: members.length,\n members: members.slice(0, previewLimit),\n godNodes: [...(godNodesByCommunity.get(id) ?? [])].sort(),\n });\n }\n clusters.sort((a, b) => b.memberCount - a.memberCount || a.id - b.id);\n\n return {\n clusters,\n modularity: snapshot.modularity,\n edgeQuality: snapshot.edgeQuality,\n crossClusterEdges: snapshot.crossClusterEdges,\n computedAt: snapshot.computedAt,\n commitSha: snapshot.commitSha,\n };\n}\n\nexport function handleGetArchitecturalOverlay(\n storage: IStoragePort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n git?: IGitPort,\n clusterLabelMasker?: ClusterLabelMasker,\n) {\n const overlay = new ArchitecturalOverlay();\n\n return async (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const files = storage.listIndexedFiles();\n const result = overlay.classify(files);\n const mode = parsed.data.mode ?? 'both';\n\n const buildContent = (payloadStr: string) => {\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(files);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payloadStr });\n return content;\n };\n\n const stalenessMeta = git ? await buildSnapshotStaleness(storage, git) : undefined;\n const extras = stalenessMeta ? { snapshotStaleness: stalenessMeta } : undefined;\n\n // Filter by layer if specified (regex-mode semantics always apply here)\n if (parsed.data.layer) {\n const filtered = result.layers[parsed.data.layer];\n const payload = masking.mask(\n JSON.stringify(wrapResponse({ layer: parsed.data.layer, files: filtered ?? [] }, extras)),\n );\n return { content: buildContent(payload) };\n }\n\n const rawSnapshot = mode === 'regex' ? undefined : storage.readCommunities();\n const snapshot =\n rawSnapshot && clusterLabelMasker?.isEnabled()\n ? clusterLabelMasker.maskSnapshot(rawSnapshot)\n : rawSnapshot;\n const community = snapshot ? buildCommunityOverlay(snapshot) : undefined;\n\n const body: Record<string, unknown> = {};\n if (mode !== 'communities') body.layers = result.layers;\n if (community) body.communities = community;\n if (mode === 'communities' && !community) {\n body.hint = 'No community snapshot available. Run `ctxo index` to generate one.';\n }\n\n const payload = masking.mask(JSON.stringify(wrapResponse(body, extras)));\n return { content: buildContent(payload) };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport { DeadCodeDetector } from '../../core/dead-code/dead-code-detector.js';\nimport { getGraphAndFiles } from './get-logic-slice.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\nimport { filterByIntent } from '../../core/intent-filter.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\n\nconst InputSchema = z.object({\n includeTests: z.boolean().optional().default(false),\n intent: z.string().optional().describe('Filter dead code results by intent keywords (e.g., \"adapter\", \"core\", \"function\")'),\n});\n\nexport function handleFindDeadCode(\n storage: IStoragePort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n) {\n const detector = new DeadCodeDetector();\n\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n return (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { graph, indexedFiles } = getGraph();\n const result = detector.detect(graph, { includeTests: parsed.data.includeTests });\n\n // Apply intent filter to deadSymbols if requested\n const filtered = {\n ...result,\n deadSymbols: filterByIntent(result.deadSymbols as unknown as Record<string, unknown>[], parsed.data.intent) as unknown as typeof result.deadSymbols,\n };\n\n const payload = masking.mask(JSON.stringify(wrapResponse(filtered as unknown as Record<string, unknown>)));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport { ContextAssembler } from '../../core/context-assembly/context-assembler.js';\nimport { JsonIndexReader } from '../storage/json-index-reader.js';\nimport { getGraphAndFiles } from './get-logic-slice.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\n\nconst TaskTypeSchema = z.enum(['fix', 'extend', 'refactor', 'understand']);\n\nconst InputSchema = z.object({\n symbolId: z.string().min(1),\n taskType: TaskTypeSchema,\n tokenBudget: z.number().min(100).optional().default(4000),\n});\n\nexport function handleGetContextForTask(\n storage: IStoragePort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n) {\n const assembler = new ContextAssembler();\n const indexReader = new JsonIndexReader(ctxoRoot);\n\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n return (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { symbolId, taskType, tokenBudget } = parsed.data;\n const { graph, indexedFiles } = getGraph();\n const indices = indexReader.readAll();\n\n const result = assembler.assembleForTask(graph, symbolId, taskType, indices, tokenBudget);\n\n if (!result) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ found: false, hint: 'Symbol not found. Run \"ctxo index\".' }) }],\n };\n }\n\n const payload = masking.mask(JSON.stringify(wrapResponse(result as unknown as Record<string, unknown>)));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","export type TaskType = 'fix' | 'extend' | 'refactor' | 'understand';\n\nexport interface ScoringWeights {\n readonly directDependency: number;\n readonly interfaceTypeDef: number;\n readonly blastRadiusDependent: number;\n readonly highComplexity: number;\n readonly antiPatternHistory: number;\n}\n\nconst TASK_WEIGHTS: Record<TaskType, ScoringWeights> = {\n fix: {\n directDependency: 0.3,\n interfaceTypeDef: 0.1,\n blastRadiusDependent: 0.1,\n highComplexity: 0.2,\n antiPatternHistory: 0.3,\n },\n extend: {\n directDependency: 0.4,\n interfaceTypeDef: 0.5,\n blastRadiusDependent: 0.1,\n highComplexity: 0.0,\n antiPatternHistory: 0.0,\n },\n refactor: {\n directDependency: 0.2,\n interfaceTypeDef: 0.1,\n blastRadiusDependent: 0.5,\n highComplexity: 0.1,\n antiPatternHistory: 0.1,\n },\n understand: {\n directDependency: 0.5,\n interfaceTypeDef: 0.3,\n blastRadiusDependent: 0.1,\n highComplexity: 0.1,\n antiPatternHistory: 0.0,\n },\n};\n\nexport function getWeightsForTask(taskType: TaskType): ScoringWeights {\n return TASK_WEIGHTS[taskType];\n}\n","import type { SymbolGraph } from '../graph/symbol-graph.js';\nimport type { SymbolNode, SymbolKind, FileIndex } from '../types.js';\nimport { LogicSliceQuery } from '../logic-slice/logic-slice-query.js';\nimport { BlastRadiusCalculator } from '../blast-radius/blast-radius-calculator.js';\nimport { type TaskType, type ScoringWeights, getWeightsForTask } from './task-context-strategy.js';\n\nexport interface ContextEntry {\n readonly symbolId: string;\n readonly name: string;\n readonly kind: SymbolKind;\n readonly file: string;\n readonly relevanceScore: number;\n readonly reason: string;\n readonly lines: number;\n readonly tokens: number;\n}\n\nexport interface TaskContextResult {\n readonly target: SymbolNode;\n readonly taskType: TaskType;\n readonly context: ContextEntry[];\n readonly totalTokens: number;\n readonly tokenBudget: number;\n readonly warnings: string[];\n}\n\nexport interface RankedContextResult {\n readonly query: string;\n readonly strategy: string;\n readonly results: Array<{\n readonly symbolId: string;\n readonly name: string;\n readonly kind: SymbolKind;\n readonly file: string;\n readonly relevanceScore: number;\n readonly importanceScore: number;\n readonly combinedScore: number;\n readonly tokens: number;\n }>;\n readonly totalTokens: number;\n readonly tokenBudget: number;\n}\n\nconst DEFAULT_TOKEN_BUDGET = 4000;\n\nexport class ContextAssembler {\n private readonly logicSlice = new LogicSliceQuery();\n private readonly blastRadius = new BlastRadiusCalculator();\n\n assembleForTask(\n graph: SymbolGraph,\n symbolId: string,\n taskType: TaskType,\n indices: readonly FileIndex[],\n tokenBudget = DEFAULT_TOKEN_BUDGET,\n ): TaskContextResult | undefined {\n const target = graph.getNode(symbolId);\n if (!target) return undefined;\n\n const weights = getWeightsForTask(taskType);\n\n // Gather forward deps + reverse deps\n const slice = this.logicSlice.getLogicSlice(graph, symbolId);\n const blastResult = this.blastRadius.calculate(graph, symbolId);\n\n // Build candidate pool (deduplicated)\n const candidateMap = new Map<string, { node: SymbolNode; signals: Signals }>();\n\n // Forward dependencies\n if (slice) {\n for (const dep of slice.dependencies) {\n candidateMap.set(dep.symbolId, {\n node: dep,\n signals: { isDirectDep: true, isInterfaceOrType: this.isInterfaceOrType(dep.kind), isDependent: false, complexity: 0, hasAntiPattern: false },\n });\n }\n }\n\n // Reverse dependents (blast radius) — fall back to a synthetic node when\n // the edge source has no matching symbols[] entry (e.g. test files that\n // only import). Without this, symbols whose importers are all such files\n // would produce an empty context even when reverse edges clearly exist.\n for (const entry of blastResult.impactedSymbols) {\n const node = graph.getNode(entry.symbolId) ?? synthesizeNodeFromId(entry.symbolId);\n if (!node) continue;\n\n const existing = candidateMap.get(entry.symbolId);\n if (existing) {\n existing.signals.isDependent = true;\n } else {\n candidateMap.set(entry.symbolId, {\n node,\n signals: { isDirectDep: false, isInterfaceOrType: this.isInterfaceOrType(node.kind), isDependent: true, complexity: 0, hasAntiPattern: false },\n });\n }\n }\n\n // Enrich with complexity + anti-patterns from index\n const fileIndexMap = new Map(indices.map((i) => [i.file, i]));\n for (const [sid, candidate] of candidateMap) {\n const file = sid.split('::')[0] ?? '';\n const fileIndex = fileIndexMap.get(file);\n\n if (fileIndex) {\n const complexity = fileIndex.complexity?.find((c) => c.symbolId === sid);\n candidate.signals.complexity = complexity?.cyclomatic ?? 0;\n candidate.signals.hasAntiPattern = fileIndex.antiPatterns.length > 0;\n }\n }\n\n // Score and rank\n const scored = [...candidateMap.entries()].map(([, { node, signals }]) => ({\n entry: this.buildContextEntry(node, signals, weights),\n score: this.computeScore(signals, weights),\n }));\n\n scored.sort((a, b) => b.score - a.score);\n\n // Greedy pack within token budget\n const context: ContextEntry[] = [];\n let totalTokens = 0;\n\n for (const { entry } of scored) {\n if (totalTokens + entry.tokens > tokenBudget) continue;\n context.push(entry);\n totalTokens += entry.tokens;\n }\n\n // Warnings\n const warnings: string[] = [];\n const targetFile = symbolId.split('::')[0] ?? '';\n const targetIndex = fileIndexMap.get(targetFile);\n if (targetIndex && targetIndex.antiPatterns.length > 0) {\n warnings.push(`⚠ Target symbol has ${targetIndex.antiPatterns.length} anti-pattern(s) in file history`);\n }\n\n return { target, taskType, context, totalTokens, tokenBudget, warnings };\n }\n\n assembleRanked(\n graph: SymbolGraph,\n query: string,\n strategy: 'combined' | 'dependency' | 'importance' = 'combined',\n tokenBudget = DEFAULT_TOKEN_BUDGET,\n ): RankedContextResult {\n const allNodes = graph.allNodes();\n const queryLower = query.toLowerCase();\n\n // Compute max reverse edges for importance normalization\n let maxReverseEdges = 1;\n for (const node of allNodes) {\n const count = graph.getReverseEdges(node.symbolId).length;\n if (count > maxReverseEdges) maxReverseEdges = count;\n }\n\n // Score each symbol\n const scored = allNodes.map((node) => {\n const relevanceScore = this.computeTextRelevance(node.name, queryLower);\n const importanceScore = graph.getReverseEdges(node.symbolId).length / maxReverseEdges;\n\n let combinedScore: number;\n switch (strategy) {\n case 'dependency':\n combinedScore = relevanceScore;\n break;\n case 'importance':\n combinedScore = importanceScore;\n break;\n default:\n combinedScore = relevanceScore * 0.6 + importanceScore * 0.4;\n }\n\n return {\n symbolId: node.symbolId,\n name: node.name,\n kind: node.kind,\n file: node.symbolId.split('::')[0] ?? '',\n relevanceScore: Math.round(relevanceScore * 1000) / 1000,\n importanceScore: Math.round(importanceScore * 1000) / 1000,\n combinedScore: Math.round(combinedScore * 1000) / 1000,\n tokens: this.estimateTokens(node),\n };\n });\n\n // Filter zero-relevance for text-based strategies\n const filtered = strategy === 'importance'\n ? scored\n : scored.filter((s) => s.relevanceScore > 0 || s.importanceScore > 0.1);\n\n filtered.sort((a, b) => b.combinedScore - a.combinedScore);\n\n // Greedy pack\n const results: typeof filtered = [];\n let totalTokens = 0;\n\n for (const item of filtered) {\n if (totalTokens + item.tokens > tokenBudget) continue;\n results.push(item);\n totalTokens += item.tokens;\n }\n\n return { query, strategy, results, totalTokens, tokenBudget };\n }\n\n private computeTextRelevance(name: string, queryLower: string): number {\n const nameLower = name.toLowerCase();\n if (nameLower === queryLower) return 1.0;\n if (nameLower.includes(queryLower)) return 0.7;\n if (queryLower.split(/\\s+/).some((word) => nameLower.includes(word))) return 0.4;\n return 0;\n }\n\n private computeScore(signals: Signals, weights: ScoringWeights): number {\n let score = 0;\n if (signals.isDirectDep) score += weights.directDependency;\n if (signals.isInterfaceOrType) score += weights.interfaceTypeDef;\n if (signals.isDependent) score += weights.blastRadiusDependent;\n if (signals.complexity > 5) score += weights.highComplexity;\n if (signals.hasAntiPattern) score += weights.antiPatternHistory;\n return Math.round(score * 1000) / 1000;\n }\n\n private buildContextEntry(node: SymbolNode, signals: Signals, weights: ScoringWeights): ContextEntry {\n const reasons: string[] = [];\n if (signals.isDirectDep) reasons.push('direct dependency');\n if (signals.isInterfaceOrType) reasons.push('type/interface definition');\n if (signals.isDependent) reasons.push('blast radius dependent');\n if (signals.complexity > 5) reasons.push(`high complexity (CC=${signals.complexity})`);\n if (signals.hasAntiPattern) reasons.push('anti-pattern history');\n\n return {\n symbolId: node.symbolId,\n name: node.name,\n kind: node.kind,\n file: node.symbolId.split('::')[0] ?? '',\n relevanceScore: this.computeScore(signals, weights),\n reason: reasons.join(', ') || 'related symbol',\n lines: node.endLine - node.startLine + 1,\n tokens: this.estimateTokens(node),\n };\n }\n\n private isInterfaceOrType(kind: SymbolKind): boolean {\n return kind === 'interface' || kind === 'type';\n }\n\n estimateTokensPublic(node: SymbolNode): number {\n return this.estimateTokens(node);\n }\n\n private estimateTokens(node: SymbolNode): number {\n // Use byte offsets for accurate estimation when available (~4 chars per token)\n if (node.startOffset !== undefined && node.endOffset !== undefined) {\n return Math.ceil((node.endOffset - node.startOffset) / 4);\n }\n return (node.endLine - node.startLine + 1) * 10;\n }\n}\n\ninterface Signals {\n isDirectDep: boolean;\n isInterfaceOrType: boolean;\n isDependent: boolean;\n complexity: number;\n hasAntiPattern: boolean;\n}\n\nconst VALID_SYMBOL_KINDS = new Set<SymbolKind>([\n 'function', 'class', 'interface', 'method', 'variable', 'type',\n]);\n\n/**\n * Build a minimal SymbolNode from a symbolId string. Used when a blast-radius\n * entry points at an orphan edge source (no matching symbols[] entry in the\n * index). startLine/endLine are 0 so token estimation falls back to a small\n * default without over-counting missing source ranges.\n */\nfunction synthesizeNodeFromId(symbolId: string): SymbolNode | undefined {\n const parts = symbolId.split('::');\n if (parts.length !== 3) return undefined;\n const [file, name, kindRaw] = parts;\n if (!file || !name || !kindRaw) return undefined;\n const kind = VALID_SYMBOL_KINDS.has(kindRaw as SymbolKind) ? (kindRaw as SymbolKind) : 'variable';\n return { symbolId, name, kind, startLine: 0, endLine: 0 };\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport { ContextAssembler } from '../../core/context-assembly/context-assembler.js';\nimport { getGraphAndFiles } from './get-logic-slice.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\nimport { SearchEngine } from '../../core/search/search-engine.js';\nimport type { ISearchPort } from '../../ports/i-search-port.js';\nimport { createLogger } from '../../core/logger.js';\n\nconst log = createLogger('ctxo:search');\n\nconst InputSchema = z.object({\n query: z.string().min(1),\n tokenBudget: z.number().min(100).optional().default(4000),\n strategy: z.enum(['combined', 'dependency', 'importance']).optional().default('combined'),\n fuzzy: z.boolean().optional().default(true),\n searchMode: z.enum(['fts', 'legacy']).optional().default('fts'),\n});\n\nexport function handleGetRankedContext(\n storage: IStoragePort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n searchEngine?: ISearchPort,\n) {\n const assembler = new ContextAssembler();\n const engine: ISearchPort = searchEngine ?? new SearchEngine();\n\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n let lastNodeCount = -1;\n\n return (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { query, tokenBudget, strategy, searchMode } = parsed.data;\n const { graph, indexedFiles } = getGraph();\n\n // Use new search engine when mode is 'fts'\n if (searchMode === 'fts' && strategy !== 'importance') {\n // Rebuild search index when graph changes (detected by node count change)\n const currentNodeCount = graph.nodeCount;\n if (currentNodeCount !== lastNodeCount) {\n const allNodes = graph.allNodes();\n // Compute PageRank scores (normalized reverse edge count)\n const pageRankScores = new Map<string, number>();\n let maxReverseEdges = 1;\n for (const node of allNodes) {\n const count = graph.getReverseEdges(node.symbolId).length;\n if (count > maxReverseEdges) maxReverseEdges = count;\n }\n for (const node of allNodes) {\n const count = graph.getReverseEdges(node.symbolId).length;\n pageRankScores.set(node.symbolId, count / maxReverseEdges);\n }\n\n engine.buildIndex(allNodes, pageRankScores);\n lastNodeCount = currentNodeCount;\n log.info(`Search engine: ${engine.getTier()} (${allNodes.length} symbols)`);\n }\n\n const searchResult = engine.search(query, 100);\n\n // Greedy pack within token budget\n const results: Array<{\n symbolId: string;\n name: string;\n kind: string;\n file: string;\n relevanceScore: number;\n importanceScore: number;\n combinedScore: number;\n tokens: number;\n }> = [];\n let totalTokens = 0;\n\n for (const sr of searchResult.results) {\n const node = graph.getNode(sr.symbolId);\n const tokens = node ? assembler.estimateTokensPublic(node) : 90;\n\n if (totalTokens + tokens > tokenBudget) continue;\n results.push({\n symbolId: sr.symbolId,\n name: sr.name,\n kind: sr.kind,\n file: sr.filePath,\n relevanceScore: Math.round(sr.relevanceScore * 1000) / 1000,\n importanceScore: Math.round(sr.importanceScore * 1000) / 1000,\n combinedScore: Math.round(sr.combinedScore * 1000) / 1000,\n tokens,\n });\n totalTokens += tokens;\n }\n\n const payload = masking.mask(JSON.stringify(wrapResponse({\n query,\n strategy,\n results,\n totalTokens,\n tokenBudget,\n searchMetrics: searchResult.metrics,\n ...(searchResult.fuzzyCorrection ? { fuzzyCorrection: searchResult.fuzzyCorrection } : {}),\n })));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n }\n\n // Legacy mode: use existing substring matching\n const result = assembler.assembleRanked(graph, query, strategy, tokenBudget);\n\n const payload = masking.mask(JSON.stringify(wrapResponse(result as unknown as Record<string, unknown>)));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","/**\n * Symbol Tokenizer — splits symbol names into searchable tokens.\n *\n * Handles camelCase, PascalCase, snake_case, kebab-case, and digit boundaries.\n * Used to populate FTS5 `tokenized_name` columns and to tokenize search queries.\n */\n\nconst STOP_WORDS = new Set([\n 'get', 'set', 'is', 'has', 'can', 'do', 'the', 'a', 'an', 'of', 'to', 'in',\n 'for', 'on', 'with', 'at', 'by', 'from', 'as', 'into', 'not', 'no', 'or',\n]);\n\nexport interface TokenizerOptions {\n /** Include stop-word tokens in output (default: false) */\n includeStopWords?: boolean;\n /** Include the full original name as an additional token (default: true) */\n includeOriginal?: boolean;\n /** Include file path segments as tokens (default: false) */\n includeFilePath?: boolean;\n}\n\nconst DEFAULT_OPTIONS: Required<TokenizerOptions> = {\n includeStopWords: false,\n includeOriginal: true,\n includeFilePath: false,\n};\n\nexport class SymbolTokenizer {\n private readonly options: Required<TokenizerOptions>;\n\n constructor(options?: TokenizerOptions) {\n this.options = { ...DEFAULT_OPTIONS, ...options };\n }\n\n /**\n * Tokenize a symbol name into searchable tokens.\n *\n * Examples:\n * \"getCoChangeMetrics\" → [\"get\", \"co\", \"change\", \"metrics\"] (or without stop words: [\"co\", \"change\", \"metrics\"])\n * \"SqliteStorageAdapter\" → [\"sqlite\", \"storage\", \"adapter\"]\n * \"i_storage_port\" → [\"i\", \"storage\", \"port\"]\n * \"BM25Scorer\" → [\"bm\", \"25\", \"scorer\"]\n * \"DB_PASSWORD\" → [\"db\", \"password\"]\n */\n tokenize(symbolName: string, filePath?: string): string[] {\n const splitTokens = SymbolTokenizer.splitName(symbolName);\n const lowered = splitTokens.map((t) => t.toLowerCase());\n\n const tokens: string[] = this.options.includeStopWords\n ? lowered\n : lowered.filter((t) => !STOP_WORDS.has(t));\n\n // Preserve original name as a token for exact matching\n if (this.options.includeOriginal) {\n const original = symbolName.toLowerCase();\n if (!tokens.includes(original)) {\n tokens.unshift(original);\n }\n }\n\n // Include file path segments\n if (this.options.includeFilePath && filePath) {\n const pathTokens = SymbolTokenizer.tokenizeFilePath(filePath);\n for (const pt of pathTokens) {\n if (!tokens.includes(pt)) {\n tokens.push(pt);\n }\n }\n }\n\n return tokens;\n }\n\n /**\n * Tokenize a search query. Queries use stop words and don't include originals.\n */\n tokenizeQuery(query: string): string[] {\n const words = query.trim().split(/\\s+/);\n const tokens: string[] = [];\n for (const word of words) {\n const split = SymbolTokenizer.splitName(word);\n for (const t of split) {\n const lowered = t.toLowerCase();\n if (lowered.length > 0 && !tokens.includes(lowered)) {\n tokens.push(lowered);\n }\n }\n }\n return tokens;\n }\n\n /**\n * Split a name into constituent words based on naming convention boundaries.\n *\n * Rules:\n * 1. Split on underscores and hyphens (snake_case, kebab-case)\n * 2. Split on camelCase/PascalCase boundaries (uppercase after lowercase)\n * 3. Split acronym boundaries (e.g., \"HTMLParser\" → [\"HTML\", \"Parser\"])\n * 4. Split on digit ↔ letter boundaries\n */\n static splitName(name: string): string[] {\n if (!name || name.length === 0) return [];\n\n // Step 1: Split on underscores, hyphens, dots, slashes\n const segments = name.split(/[_\\-./\\\\]+/).filter((s) => s.length > 0);\n\n const tokens: string[] = [];\n for (const segment of segments) {\n tokens.push(...SymbolTokenizer.splitCamelCase(segment));\n }\n\n return tokens.filter((t) => t.length > 0);\n }\n\n /**\n * Split a single segment on camelCase/PascalCase/digit boundaries.\n */\n private static splitCamelCase(segment: string): string[] {\n const tokens: string[] = [];\n let current = '';\n\n for (let i = 0; i < segment.length; i++) {\n const ch = segment[i]!;\n const prev = i > 0 ? segment[i - 1]! : '';\n\n // Boundary: letter → digit or digit → letter\n if (current.length > 0) {\n const prevIsDigit = isDigit(prev);\n const currIsDigit = isDigit(ch);\n if (prevIsDigit !== currIsDigit) {\n tokens.push(current);\n current = ch;\n continue;\n }\n }\n\n // Boundary: lowercase → uppercase (camelCase boundary)\n if (current.length > 0 && isLower(prev) && isUpper(ch)) {\n tokens.push(current);\n current = ch;\n continue;\n }\n\n // Acronym boundary: multiple uppercase followed by lowercase\n // \"HTMLParser\": H-T-M-L-P-a → when we hit 'a', current=\"HTMLP\"\n // We should split to \"HTML\" + \"Pa...\"\n if (current.length > 1 && isUpper(ch) === false && isUpper(prev) && !isDigit(ch)) {\n // prev is uppercase, current char is lowercase → split before prev\n const lastChar = current[current.length - 1]!;\n if (isUpper(lastChar)) {\n tokens.push(current.slice(0, -1));\n current = lastChar + ch;\n continue;\n }\n }\n\n current += ch;\n }\n\n if (current.length > 0) {\n tokens.push(current);\n }\n\n return tokens;\n }\n\n /**\n * Extract searchable tokens from a file path.\n * \"src/core/search/symbol-tokenizer.ts\" → [\"src\", \"core\", \"search\", \"symbol\", \"tokenizer\", \"ts\"]\n */\n static tokenizeFilePath(filePath: string): string[] {\n // Remove extension, split on separators\n const withoutExt = filePath.replace(/\\.[^.]+$/, '');\n const segments = withoutExt.split(/[/\\\\]+/);\n const tokens: string[] = [];\n for (const seg of segments) {\n const parts = seg.split(/[_\\-.]+/).filter((s) => s.length > 0);\n for (const p of parts) {\n const lowered = p.toLowerCase();\n if (lowered.length > 0 && !tokens.includes(lowered)) {\n tokens.push(lowered);\n }\n }\n }\n return tokens;\n }\n\n /** Check if a token is a stop word */\n static isStopWord(token: string): boolean {\n return STOP_WORDS.has(token.toLowerCase());\n }\n}\n\nfunction isUpper(ch: string): boolean {\n return ch >= 'A' && ch <= 'Z';\n}\n\nfunction isLower(ch: string): boolean {\n return ch >= 'a' && ch <= 'z';\n}\n\nfunction isDigit(ch: string): boolean {\n return ch >= '0' && ch <= '9';\n}\n","/**\n * Fuzzy Corrector — Damerau-Levenshtein based typo correction.\n *\n * Uses adaptive thresholds: d≤1 for terms ≤5 chars, d≤2 for longer terms.\n * Vocabulary is built from tokenized symbol names during index build.\n */\n\nimport type { FuzzyCorrection } from '../types.js';\n\nexport class FuzzyCorrector {\n /** term → frequency (for tie-breaking) */\n private vocabulary: Map<string, number> = new Map();\n\n buildVocabulary(termFrequencies: Map<string, number>): void {\n this.vocabulary = new Map(termFrequencies);\n }\n\n /**\n * Attempt to correct query tokens.\n * Returns null if no correction found or no improvement possible.\n */\n correct(queryTokens: string[]): FuzzyCorrection | null {\n if (this.vocabulary.size === 0) return null;\n\n const corrections: FuzzyCorrection['corrections'] = [];\n const correctedTokens: string[] = [];\n let anyChanged = false;\n\n for (const token of queryTokens) {\n // Skip very short tokens (1-2 chars) — too many false matches\n if (token.length <= 2) {\n correctedTokens.push(token);\n continue;\n }\n\n // Check if token exists in vocabulary (exact match)\n if (this.vocabulary.has(token)) {\n correctedTokens.push(token);\n continue;\n }\n\n const maxDist = token.length <= 5 ? 1 : 2;\n const best = this.findClosest(token, maxDist);\n\n if (best) {\n corrections.push({\n original: token,\n corrected: best.term,\n distance: best.distance,\n });\n correctedTokens.push(best.term);\n anyChanged = true;\n } else {\n correctedTokens.push(token);\n }\n }\n\n if (!anyChanged) return null;\n\n return {\n originalQuery: queryTokens.join(' '),\n correctedQuery: correctedTokens.join(' '),\n corrections,\n };\n }\n\n /**\n * Find the closest vocabulary term within maxDistance.\n * Tie-breaks by frequency (higher = preferred).\n */\n private findClosest(\n token: string,\n maxDistance: number,\n ): { term: string; distance: number } | null {\n let bestTerm: string | null = null;\n let bestDist = maxDistance + 1;\n let bestFreq = -1;\n\n for (const [vocabTerm, freq] of this.vocabulary) {\n // Quick length filter: Damerau-Levenshtein ≥ |len difference|\n if (Math.abs(vocabTerm.length - token.length) > maxDistance) continue;\n\n const dist = damerauLevenshtein(token, vocabTerm);\n if (dist <= maxDistance) {\n if (dist < bestDist || (dist === bestDist && freq > bestFreq)) {\n bestTerm = vocabTerm;\n bestDist = dist;\n bestFreq = freq;\n }\n }\n }\n\n return bestTerm !== null ? { term: bestTerm, distance: bestDist } : null;\n }\n}\n\n/**\n * Damerau-Levenshtein distance.\n * Includes transpositions as a single edit operation.\n * \"tokne\" → \"token\" = distance 1 (transposition), not 2 (delete + insert).\n */\nexport function damerauLevenshtein(a: string, b: string): number {\n const lenA = a.length;\n const lenB = b.length;\n\n if (lenA === 0) return lenB;\n if (lenB === 0) return lenA;\n\n // Optimal string alignment distance (restricted edit distance)\n const d: number[][] = Array.from({ length: lenA + 1 }, () => new Array<number>(lenB + 1).fill(0));\n\n for (let i = 0; i <= lenA; i++) d[i]![0] = i;\n for (let j = 0; j <= lenB; j++) d[0]![j] = j;\n\n for (let i = 1; i <= lenA; i++) {\n for (let j = 1; j <= lenB; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n d[i]![j] = Math.min(\n d[i - 1]![j]! + 1, // deletion\n d[i]![j - 1]! + 1, // insertion\n d[i - 1]![j - 1]! + cost, // substitution\n );\n\n // Transposition\n if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {\n d[i]![j] = Math.min(d[i]![j]!, d[i - 2]![j - 2]! + cost);\n }\n }\n }\n\n return d[lenA]![lenB]!;\n}\n","/**\n * In-memory BM25 Search Engine (Tier 2)\n *\n * Implements two-phase cascade search:\n * Phase 1: Exact + tokenized matching with BM25 scoring\n * Phase 2: Trigram/partial matching (activated when Phase 1 returns < threshold results)\n * Phase 3: Fuzzy correction (activated when Phase 1+2 return < threshold results)\n *\n * Scoring: BM25 * (1 + pageRankWeight * pageRankScore) * bigramBoost\n */\n\nimport type { SymbolNode, SearchResponse, SearchResult, SearchMetrics } from '../types.js';\nimport { SymbolTokenizer } from './symbol-tokenizer.js';\nimport { FuzzyCorrector } from './fuzzy-corrector.js';\nimport { createLogger } from '../logger.js';\n\nconst log = createLogger('ctxo:search');\n\n/** BM25 parameters tuned for code search (short documents) */\ninterface BM25Config {\n k1: number; // term frequency saturation (default: 1.2)\n b: number; // length normalization (default: 0.25 — low for short symbol names)\n}\n\ninterface SearchEngineConfig {\n bm25: BM25Config;\n /** Weight of PageRank boost: finalScore = bm25 * (1 + pageRankWeight * pr) */\n pageRankWeight: number;\n /** Score penalty for Phase 2 (trigram) results */\n trigramPenalty: number;\n /** Threshold: if Phase 1 returns fewer results, activate Phase 2 */\n phase2Threshold: number;\n /** Threshold: if Phase 1+2 return fewer results, activate fuzzy correction */\n fuzzyThreshold: number;\n /** Maximum results per phase */\n maxPerPhase: number;\n}\n\nconst DEFAULT_CONFIG: SearchEngineConfig = {\n bm25: { k1: 1.2, b: 0.25 },\n pageRankWeight: 0.5,\n trigramPenalty: 0.8,\n phase2Threshold: 3,\n fuzzyThreshold: 3,\n maxPerPhase: 50,\n};\n\n/** A document in the inverted index (one per symbol) */\ninterface IndexedDocument {\n symbolId: string;\n name: string;\n kind: string;\n filePath: string;\n /** Tokenized name (from SymbolTokenizer) */\n tokens: string[];\n /** Token count (document length for BM25) */\n length: number;\n}\n\n/** Posting list entry */\ninterface Posting {\n docIndex: number;\n termFrequency: number;\n}\n\nexport class SearchEngine {\n private readonly config: SearchEngineConfig;\n private readonly tokenizer: SymbolTokenizer;\n private readonly fuzzy: FuzzyCorrector;\n\n // Primary index (exact + tokenized)\n private documents: IndexedDocument[] = [];\n private primaryIndex: Map<string, Posting[]> = new Map();\n private avgDocLength = 0;\n\n // Trigram index (character 3-grams)\n private trigramIndex: Map<string, Posting[]> = new Map();\n\n // PageRank scores\n private pageRankScores: Map<string, number> = new Map();\n\n constructor(config?: Partial<SearchEngineConfig>) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.tokenizer = new SymbolTokenizer({ includeOriginal: true, includeFilePath: true });\n this.fuzzy = new FuzzyCorrector();\n }\n\n getTier(): 'fts5' | 'in-memory' | 'legacy' {\n return 'in-memory';\n }\n\n buildIndex(symbols: SymbolNode[], pageRankScores?: Map<string, number>): void {\n const start = performance.now();\n this.documents = [];\n this.primaryIndex = new Map();\n this.trigramIndex = new Map();\n this.pageRankScores = pageRankScores ?? new Map();\n\n let totalLength = 0;\n const vocabFreq = new Map<string, number>();\n\n for (const sym of symbols) {\n const filePath = sym.symbolId.split('::')[0] ?? '';\n const tokens = this.tokenizer.tokenize(sym.name, filePath);\n const doc: IndexedDocument = {\n symbolId: sym.symbolId,\n name: sym.name,\n kind: sym.kind,\n filePath,\n tokens,\n length: tokens.length,\n };\n const docIndex = this.documents.length;\n this.documents.push(doc);\n totalLength += tokens.length;\n\n // Build primary inverted index\n const termFreqs = new Map<string, number>();\n for (const token of tokens) {\n termFreqs.set(token, (termFreqs.get(token) ?? 0) + 1);\n vocabFreq.set(token, (vocabFreq.get(token) ?? 0) + 1);\n }\n for (const [term, tf] of termFreqs) {\n let postings = this.primaryIndex.get(term);\n if (!postings) {\n postings = [];\n this.primaryIndex.set(term, postings);\n }\n postings.push({ docIndex, termFrequency: tf });\n }\n\n // Build trigram index from symbol name (lowercased)\n const nameLower = sym.name.toLowerCase();\n const trigrams = this.extractTrigrams(nameLower);\n const trigramFreqs = new Map<string, number>();\n for (const tri of trigrams) {\n trigramFreqs.set(tri, (trigramFreqs.get(tri) ?? 0) + 1);\n }\n for (const [tri, tf] of trigramFreqs) {\n let postings = this.trigramIndex.get(tri);\n if (!postings) {\n postings = [];\n this.trigramIndex.set(tri, postings);\n }\n postings.push({ docIndex, termFrequency: tf });\n }\n }\n\n this.avgDocLength = this.documents.length > 0 ? totalLength / this.documents.length : 1;\n\n // Build vocabulary for fuzzy corrector\n this.fuzzy.buildVocabulary(vocabFreq);\n\n const elapsed = performance.now() - start;\n log.info(`Index built: ${symbols.length} symbols, ${this.primaryIndex.size} terms, ${this.trigramIndex.size} trigrams (${elapsed.toFixed(0)}ms)`);\n }\n\n search(query: string, limit = 50): SearchResponse {\n const start = performance.now();\n const queryTokens = this.tokenizer.tokenizeQuery(query);\n\n if (queryTokens.length === 0) {\n return this.emptyResponse(query, start);\n }\n\n const metrics: SearchMetrics = {\n porterHits: 0,\n trigramHits: 0,\n phase2Activated: false,\n fuzzyApplied: false,\n latencyMs: 0,\n };\n\n // Phase 1: Primary index search (exact + tokenized)\n const phase1Scores = this.bm25Search(queryTokens, this.primaryIndex);\n metrics.porterHits = phase1Scores.size;\n\n let allScores = phase1Scores;\n\n // Phase 2: Trigram search (if Phase 1 insufficient)\n if (phase1Scores.size < this.config.phase2Threshold) {\n metrics.phase2Activated = true;\n const queryLower = query.toLowerCase();\n\n // Skip trigram for very short queries (< 3 chars produces no useful trigrams)\n if (queryLower.length >= 3) {\n const queryTrigrams = this.extractTrigrams(queryLower);\n const phase2Scores = this.bm25Search(queryTrigrams, this.trigramIndex);\n metrics.trigramHits = phase2Scores.size;\n\n // Merge: union by symbolId, Phase 2 with penalty\n allScores = this.mergeScores(phase1Scores, phase2Scores, this.config.trigramPenalty);\n }\n }\n\n // Phase 3: Fuzzy correction (if still insufficient)\n let fuzzyCorrection: SearchResponse['fuzzyCorrection'];\n if (allScores.size < this.config.fuzzyThreshold) {\n const correction = this.fuzzy.correct(queryTokens);\n if (correction) {\n metrics.fuzzyApplied = true;\n fuzzyCorrection = correction;\n const correctedTokens = this.tokenizer.tokenizeQuery(correction.correctedQuery);\n const fuzzyScores = this.bm25Search(correctedTokens, this.primaryIndex);\n\n // Merge fuzzy results (with slight penalty)\n allScores = this.mergeScores(allScores, fuzzyScores, 0.9);\n\n // Also try trigram on corrected query\n if (allScores.size < this.config.fuzzyThreshold && correction.correctedQuery.length >= 3) {\n const correctedTrigrams = this.extractTrigrams(correction.correctedQuery.toLowerCase());\n const fuzzyTrigramScores = this.bm25Search(correctedTrigrams, this.trigramIndex);\n allScores = this.mergeScores(allScores, fuzzyTrigramScores, this.config.trigramPenalty * 0.9);\n }\n }\n }\n\n // Snapshot raw BM25 relevance scores before boosts\n const rawRelevance = new Map(allScores);\n\n // Apply bigram boost for multi-word queries (applies to ALL paths including fuzzy)\n const effectiveQueryTerms = fuzzyCorrection\n ? this.tokenizer.tokenizeQuery(fuzzyCorrection.correctedQuery)\n : queryTokens;\n\n if (effectiveQueryTerms.length >= 2) {\n for (const [docIdx, score] of allScores) {\n const doc = this.documents[docIdx]!;\n const boost = this.bigramBoost(effectiveQueryTerms, doc.tokens);\n allScores.set(docIdx, score * boost);\n }\n }\n\n // Apply PageRank boost (applies to ALL paths including fuzzy)\n for (const [docIdx, score] of allScores) {\n const doc = this.documents[docIdx]!;\n const pr = this.pageRankScores.get(doc.symbolId) ?? 0;\n allScores.set(docIdx, score * (1 + this.config.pageRankWeight * pr));\n }\n\n metrics.latencyMs = performance.now() - start;\n const results = this.buildResults(allScores, rawRelevance, limit);\n\n const phaseInfo = metrics.phase2Activated ? 'phase2=yes' : 'phase2=no';\n if (fuzzyCorrection) {\n log.info(`search \"${query}\" → fuzzy \"${fuzzyCorrection.correctedQuery}\": ${results.length} results (${metrics.latencyMs.toFixed(0)}ms)`);\n } else {\n log.info(`search \"${query}\": ${results.length} results, porter=${metrics.porterHits} trigram=${metrics.trigramHits} ${phaseInfo} (${metrics.latencyMs.toFixed(0)}ms)`);\n }\n\n return { query, results, metrics, ...(fuzzyCorrection ? { fuzzyCorrection } : {}) };\n }\n\n updateFile(filePath: string, symbols: SymbolNode[]): void {\n // Remove old documents for this file\n const oldIndices = new Set<number>();\n for (let i = 0; i < this.documents.length; i++) {\n if (this.documents[i]!.filePath === filePath) {\n oldIndices.add(i);\n }\n }\n\n if (oldIndices.size === 0 && symbols.length === 0) return;\n\n // Full rebuild (simpler and correct for incremental updates)\n const allSymbols: SymbolNode[] = [];\n for (let i = 0; i < this.documents.length; i++) {\n if (!oldIndices.has(i)) {\n const doc = this.documents[i]!;\n allSymbols.push({\n symbolId: doc.symbolId,\n name: doc.name,\n kind: doc.kind as SymbolNode['kind'],\n startLine: 0,\n endLine: 0,\n });\n }\n }\n allSymbols.push(...symbols);\n this.buildIndex(allSymbols, this.pageRankScores);\n }\n\n /**\n * BM25 scoring over an inverted index.\n * Returns Map<docIndex, score>\n */\n private bm25Search(queryTerms: string[], index: Map<string, Posting[]>): Map<number, number> {\n const scores = new Map<number, number>();\n const N = this.documents.length;\n const { k1, b } = this.config.bm25;\n\n for (const term of queryTerms) {\n const postings = index.get(term);\n if (!postings) continue;\n\n const df = postings.length; // document frequency\n // IDF: log((N - df + 0.5) / (df + 0.5) + 1)\n const idf = Math.log((N - df + 0.5) / (df + 0.5) + 1);\n\n for (const { docIndex, termFrequency } of postings) {\n const doc = this.documents[docIndex]!;\n const tf = termFrequency;\n const docLen = doc.length;\n\n // BM25 term score\n const numerator = tf * (k1 + 1);\n const denominator = tf + k1 * (1 - b + b * (docLen / this.avgDocLength));\n const termScore = idf * (numerator / denominator);\n\n scores.set(docIndex, (scores.get(docIndex) ?? 0) + termScore);\n }\n }\n\n // Boost exact name matches (FR-1.9: 3-5x higher)\n const queryJoined = queryTerms.join('');\n for (const [docIdx, score] of scores) {\n const doc = this.documents[docIdx]!;\n const nameLower = doc.name.toLowerCase();\n if (nameLower === queryJoined || nameLower === queryTerms.join(' ')) {\n scores.set(docIdx, score * 5.0);\n }\n }\n\n return scores;\n }\n\n /**\n * Merge two score maps. Phase 2 scores are penalized.\n */\n private mergeScores(\n primary: Map<number, number>,\n secondary: Map<number, number>,\n penalty: number,\n ): Map<number, number> {\n const merged = new Map(primary);\n for (const [docIdx, score] of secondary) {\n const existing = merged.get(docIdx);\n const penalized = score * penalty;\n if (existing !== undefined) {\n merged.set(docIdx, Math.max(existing, penalized));\n } else {\n merged.set(docIdx, penalized);\n }\n }\n return merged;\n }\n\n /**\n * Bigram boost for multi-word queries.\n * Each adjacent query term pair found adjacent in symbol tokens → 2x boost.\n */\n private bigramBoost(queryTerms: string[], symbolTokens: string[]): number {\n if (queryTerms.length < 2) return 1.0;\n\n let adjacentPairs = 0;\n for (let i = 0; i < queryTerms.length - 1; i++) {\n const idxA = symbolTokens.findIndex((t) => t.includes(queryTerms[i]!));\n const idxB = symbolTokens.findIndex((t) => t.includes(queryTerms[i + 1]!));\n if (idxA >= 0 && idxB >= 0 && Math.abs(idxA - idxB) === 1) {\n adjacentPairs++;\n }\n }\n\n return 1 + adjacentPairs * 2.0;\n }\n\n /**\n * Extract character trigrams from a string.\n * \"sqlite\" → [\"sql\", \"qli\", \"lit\", \"ite\"]\n */\n private extractTrigrams(text: string): string[] {\n const trigrams: string[] = [];\n for (let i = 0; i <= text.length - 3; i++) {\n trigrams.push(text.substring(i, i + 3));\n }\n return trigrams;\n }\n\n private buildResults(\n combinedScores: Map<number, number>,\n rawRelevance: Map<number, number>,\n limit: number,\n ): SearchResult[] {\n const entries = [...combinedScores.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, limit);\n\n return entries.map(([docIdx, combined]) => {\n const doc = this.documents[docIdx]!;\n const pr = this.pageRankScores.get(doc.symbolId) ?? 0;\n return {\n symbolId: doc.symbolId,\n name: doc.name,\n kind: doc.kind,\n filePath: doc.filePath,\n relevanceScore: rawRelevance.get(docIdx) ?? 0,\n importanceScore: pr,\n combinedScore: combined,\n };\n });\n }\n\n private emptyResponse(query: string, start: number): SearchResponse {\n return {\n query,\n results: [],\n metrics: {\n porterHits: 0,\n trigramHits: 0,\n phase2Activated: false,\n fuzzyApplied: false,\n latencyMs: performance.now() - start,\n },\n };\n }\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\nimport { getGraphAndFiles } from './get-logic-slice.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\nimport { SearchEngine } from '../../core/search/search-engine.js';\nimport type { ISearchPort } from '../../ports/i-search-port.js';\n\nconst InputSchema = z.object({\n pattern: z.string().min(1),\n kind: z.enum(['function', 'class', 'interface', 'method', 'variable', 'type']).optional(),\n filePattern: z.string().optional(),\n limit: z.number().int().min(1).max(100).optional().default(25),\n mode: z.enum(['regex', 'fts']).optional().default('regex'),\n});\n\nexport function handleSearchSymbols(\n storage: IStoragePort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n searchEngine?: ISearchPort,\n) {\n const engine: ISearchPort = searchEngine ?? new SearchEngine();\n let lastFtsNodeCount = -1;\n\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n return (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { pattern, kind, filePattern, limit, mode } = parsed.data;\n const { graph, indexedFiles } = getGraph();\n const allNodes = graph.allNodes();\n\n // FTS mode: use search engine\n if (mode === 'fts') {\n if (allNodes.length !== lastFtsNodeCount) {\n engine.buildIndex(allNodes);\n lastFtsNodeCount = allNodes.length;\n }\n\n const searchResult = engine.search(pattern, limit);\n let ftsResults = searchResult.results;\n\n // Apply kind filter\n if (kind) {\n ftsResults = ftsResults.filter((r) => r.kind === kind);\n }\n // Apply file pattern filter\n if (filePattern) {\n const fp = filePattern.toLowerCase();\n ftsResults = ftsResults.filter((r) => r.filePath.toLowerCase().includes(fp));\n }\n\n const results = ftsResults.slice(0, limit).map((r) => {\n const node = graph.getNode(r.symbolId);\n return {\n symbolId: r.symbolId,\n name: r.name,\n kind: r.kind,\n file: r.filePath,\n startLine: node?.startLine ?? 0,\n endLine: node?.endLine ?? 0,\n relevanceScore: Math.round(r.relevanceScore * 1000) / 1000,\n };\n });\n\n const payload = masking.mask(JSON.stringify(wrapResponse({\n totalMatches: ftsResults.length,\n results,\n searchMetrics: searchResult.metrics,\n ...(searchResult.fuzzyCorrection ? { fuzzyCorrection: searchResult.fuzzyCorrection } : {}),\n })));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n }\n\n // Legacy regex mode (default)\n let matcher: (name: string) => boolean;\n try {\n const regex = new RegExp(pattern, 'i');\n matcher = (name: string) => regex.test(name);\n } catch {\n const lowerPattern = pattern.toLowerCase();\n matcher = (name: string) => name.toLowerCase().includes(lowerPattern);\n }\n\n const matches = allNodes.filter((node) => {\n if (!matcher(node.name)) return false;\n if (kind && node.kind !== kind) return false;\n if (filePattern) {\n const file = node.symbolId.split('::')[0] ?? '';\n if (!file.toLowerCase().includes(filePattern.toLowerCase())) return false;\n }\n return true;\n });\n\n const results = matches.slice(0, limit).map((node) => ({\n symbolId: node.symbolId,\n name: node.name,\n kind: node.kind,\n file: node.symbolId.split('::')[0],\n startLine: node.startLine,\n endLine: node.endLine,\n }));\n\n const payload = masking.mask(JSON.stringify(wrapResponse({\n totalMatches: matches.length,\n results,\n })));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IGitPort } from '../../ports/i-git-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\nimport { getGraphAndFiles } from './get-logic-slice.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\n\nconst InputSchema = z.object({\n since: z.string().optional().default('HEAD~1'),\n maxFiles: z.number().int().min(1).optional().default(50),\n});\n\nexport function handleGetChangedSymbols(\n storage: IStoragePort,\n git: IGitPort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n) {\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n return async (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { since, maxFiles } = parsed.data;\n const changedPaths = await git.getChangedFiles(since);\n const { graph, indexedFiles } = getGraph();\n\n // Index all nodes by file for fast lookup\n const nodesByFile = new Map<string, Array<{ symbolId: string; name: string; kind: string; startLine: number; endLine: number }>>();\n for (const node of graph.allNodes()) {\n const file = node.symbolId.split('::')[0] ?? '';\n const existing = nodesByFile.get(file) ?? [];\n existing.push({ symbolId: node.symbolId, name: node.name, kind: node.kind, startLine: node.startLine, endLine: node.endLine });\n nodesByFile.set(file, existing);\n }\n\n const files: Array<{ file: string; symbols: Array<{ symbolId: string; name: string; kind: string; startLine: number; endLine: number }> }> = [];\n let totalSymbols = 0;\n\n for (const filePath of changedPaths.slice(0, maxFiles)) {\n const symbols = nodesByFile.get(filePath);\n if (symbols && symbols.length > 0) {\n files.push({ file: filePath, symbols });\n totalSymbols += symbols.length;\n }\n }\n\n const payload = masking.mask(JSON.stringify(wrapResponse({\n since,\n changedFiles: files.length,\n changedSymbols: totalSymbols,\n files,\n })));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\nimport { getGraphAndFiles } from './get-logic-slice.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\nimport { filterByIntent } from '../../core/intent-filter.js';\n\nconst InputSchema = z.object({\n symbolId: z.string().min(1),\n edgeKinds: z.array(z.enum(['imports', 'calls', 'extends', 'implements', 'uses'])).optional(),\n transitive: z.boolean().optional().default(false),\n maxDepth: z.number().int().min(1).max(10).optional().default(5),\n intent: z.string().optional().describe('Filter results by intent keywords (e.g., \"test\", \"adapter\", \"core\")'),\n});\n\nexport function handleFindImporters(\n storage: IStoragePort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n) {\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n return (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { symbolId, edgeKinds, transitive, maxDepth } = parsed.data;\n const { graph, indexedFiles } = getGraph();\n\n if (!graph.hasNode(symbolId)) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ found: false, hint: 'Symbol not found. Run \"ctxo index\" to build the codebase index.' }) }],\n };\n }\n\n const importers: Array<{\n symbolId: string;\n name: string;\n kind: string;\n file: string;\n edgeKind: string;\n edgeKinds?: string[];\n depth: number;\n }> = [];\n\n if (!transitive) {\n // Direct importers only — deduplicate by symbolId, aggregate edgeKinds\n const reverseEdges = graph.getReverseEdges(symbolId);\n const seen = new Map<string, typeof importers[0]>();\n for (const edge of reverseEdges) {\n if (edgeKinds && !edgeKinds.includes(edge.kind as 'imports' | 'calls' | 'extends' | 'implements' | 'uses')) continue;\n const node = graph.getNode(edge.from);\n if (node) {\n const existing = seen.get(node.symbolId);\n if (existing) {\n if (!existing.edgeKinds!.includes(edge.kind)) {\n existing.edgeKinds!.push(edge.kind);\n }\n } else {\n const entry = {\n symbolId: node.symbolId,\n name: node.name,\n kind: node.kind,\n file: node.symbolId.split('::')[0] ?? '',\n edgeKind: edge.kind,\n edgeKinds: [edge.kind],\n depth: 1,\n };\n seen.set(node.symbolId, entry);\n importers.push(entry);\n }\n }\n }\n } else {\n // BFS for transitive importers\n const visited = new Set<string>([symbolId]);\n const queue: Array<{ id: string; depth: number }> = [{ id: symbolId, depth: 0 }];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n if (current.depth >= maxDepth) continue;\n\n const reverseEdges = graph.getReverseEdges(current.id);\n for (const edge of reverseEdges) {\n if (edgeKinds && !edgeKinds.includes(edge.kind as 'imports' | 'calls' | 'extends' | 'implements' | 'uses')) continue;\n if (visited.has(edge.from)) continue;\n visited.add(edge.from);\n\n const node = graph.getNode(edge.from);\n if (node) {\n const depth = current.depth + 1;\n importers.push({\n symbolId: node.symbolId,\n name: node.name,\n kind: node.kind,\n file: node.symbolId.split('::')[0] ?? '',\n edgeKind: edge.kind,\n depth,\n });\n queue.push({ id: edge.from, depth });\n }\n }\n }\n }\n\n // Sort by depth ascending\n importers.sort((a, b) => a.depth - b.depth);\n\n // Apply intent filter if requested\n const filtered = filterByIntent(importers, parsed.data.intent);\n\n const payload = masking.mask(JSON.stringify(wrapResponse({\n symbolId,\n importerCount: filtered.length,\n importers: filtered,\n })));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\nimport { getGraphAndFiles } from './get-logic-slice.js';\nimport type { SymbolGraph } from '../../core/graph/symbol-graph.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\n\nconst InputSchema = z.object({\n symbolId: z.string().min(1).optional(),\n direction: z.enum(['ancestors', 'descendants', 'both']).optional().default('both'),\n});\n\nexport function handleGetClassHierarchy(\n storage: IStoragePort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n) {\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n return (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { symbolId, direction } = parsed.data;\n const { graph, indexedFiles } = getGraph();\n\n if (symbolId) {\n return handleRooted(graph, symbolId, direction, masking, staleness, indexedFiles);\n }\n\n return handleFull(graph, masking, staleness, indexedFiles);\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n\n function handleRooted(\n graph: SymbolGraph,\n symbolId: string,\n direction: 'ancestors' | 'descendants' | 'both',\n maskingPort: IMaskingPort,\n stalenessCheck: StalenessCheck | undefined,\n indexedFiles: string[],\n ) {\n if (!graph.hasNode(symbolId)) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ found: false, hint: 'Symbol not found. Run \"ctxo index\" to build the codebase index.' }) }],\n };\n }\n\n type HierarchyEntry = { symbolId: string; name: string; kind: string; file: string; edgeKind: string; depth: number };\n const ancestors: HierarchyEntry[] = [];\n const descendants: HierarchyEntry[] = [];\n\n const isHierarchyEdge = (kind: string) => kind === 'extends' || kind === 'implements';\n\n // Ancestors: follow forward edges (this symbol extends/implements X)\n if (direction === 'ancestors' || direction === 'both') {\n const visited = new Set<string>([symbolId]);\n const queue: Array<{ id: string; depth: number }> = [{ id: symbolId, depth: 0 }];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n for (const edge of graph.getForwardEdges(current.id)) {\n if (!isHierarchyEdge(edge.kind)) continue;\n if (visited.has(edge.to)) continue;\n visited.add(edge.to);\n\n const node = graph.getNode(edge.to);\n if (node) {\n const depth = current.depth + 1;\n ancestors.push({\n symbolId: node.symbolId,\n name: node.name,\n kind: node.kind,\n file: node.symbolId.split('::')[0] ?? '',\n edgeKind: edge.kind,\n depth,\n });\n queue.push({ id: edge.to, depth });\n }\n }\n }\n }\n\n // Descendants: follow reverse edges (X extends/implements this symbol)\n if (direction === 'descendants' || direction === 'both') {\n const visited = new Set<string>([symbolId]);\n const queue: Array<{ id: string; depth: number }> = [{ id: symbolId, depth: 0 }];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n for (const edge of graph.getReverseEdges(current.id)) {\n if (!isHierarchyEdge(edge.kind)) continue;\n if (visited.has(edge.from)) continue;\n visited.add(edge.from);\n\n const node = graph.getNode(edge.from);\n if (node) {\n const depth = current.depth + 1;\n descendants.push({\n symbolId: node.symbolId,\n name: node.name,\n kind: node.kind,\n file: node.symbolId.split('::')[0] ?? '',\n edgeKind: edge.kind,\n depth,\n });\n queue.push({ id: edge.from, depth });\n }\n }\n }\n }\n\n const result: Record<string, unknown> = { symbolId };\n if (direction === 'ancestors' || direction === 'both') result.ancestors = ancestors;\n if (direction === 'descendants' || direction === 'both') result.descendants = descendants;\n\n const payload = maskingPort.mask(JSON.stringify(wrapResponse(result)));\n const content: Array<{ type: 'text'; text: string }> = [];\n if (stalenessCheck) {\n const warning = stalenessCheck.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n }\n\n function handleFull(\n graph: SymbolGraph,\n maskingPort: IMaskingPort,\n stalenessCheck: StalenessCheck | undefined,\n indexedFiles: string[],\n ) {\n const isHierarchyEdge = (kind: string) => kind === 'extends' || kind === 'implements';\n const hierarchyEdges = graph.allEdges().filter((e) => isHierarchyEdge(e.kind));\n\n // Collect all nodes involved in hierarchy edges\n const involved = new Set<string>();\n for (const edge of hierarchyEdges) {\n involved.add(edge.from);\n involved.add(edge.to);\n }\n\n // Find roots: nodes that are targets but never sources of extends/implements (true base classes/interfaces)\n const sources = new Set(hierarchyEdges.map((e) => e.from));\n const roots = [...involved].filter((id) => !sources.has(id));\n\n // If no clear roots, use all involved nodes as potential roots (handles cycles)\n const rootSet = roots.length > 0 ? roots : [...involved];\n\n type TreeNode = { symbolId: string; name: string; kind: string; file: string; edgeKind?: string; children: TreeNode[] };\n\n function buildTree(rootId: string, visited: Set<string>): TreeNode | undefined {\n const node = graph.getNode(rootId);\n if (!node) return undefined;\n visited.add(rootId);\n\n const children: TreeNode[] = [];\n for (const edge of graph.getReverseEdges(rootId)) {\n if (!isHierarchyEdge(edge.kind)) continue;\n if (visited.has(edge.from)) continue;\n const child = buildTree(edge.from, visited);\n if (child) {\n child.edgeKind = edge.kind;\n children.push(child);\n }\n }\n\n return {\n symbolId: node.symbolId,\n name: node.name,\n kind: node.kind,\n file: node.symbolId.split('::')[0] ?? '',\n children,\n };\n }\n\n const visited = new Set<string>();\n const hierarchies: TreeNode[] = [];\n for (const rootId of rootSet) {\n if (visited.has(rootId)) continue;\n const tree = buildTree(rootId, visited);\n if (tree) hierarchies.push(tree);\n }\n\n const payload = maskingPort.mask(JSON.stringify(wrapResponse({\n hierarchies,\n totalClasses: involved.size,\n totalEdges: hierarchyEdges.length,\n })));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (stalenessCheck) {\n const warning = stalenessCheck.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n }\n}\n","import { z } from 'zod';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport { PageRankCalculator } from '../../core/importance/pagerank-calculator.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\nimport { getGraphAndFiles } from './get-logic-slice.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\n\nconst InputSchema = z.object({\n limit: z.number().int().min(1).max(200).optional().default(25),\n kind: z.enum(['function', 'class', 'interface', 'method', 'variable', 'type']).optional(),\n filePattern: z.string().optional(),\n damping: z.number().min(0).max(1).optional().default(0.85),\n});\n\nexport function handleGetSymbolImportance(\n storage: IStoragePort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n) {\n const calculator = new PageRankCalculator();\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n return (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { limit, kind, filePattern, damping } = parsed.data;\n const { graph, indexedFiles } = getGraph();\n\n const result = calculator.calculate(graph, { damping, limit: graph.nodeCount, maxIterations: 100 });\n\n // Filter after full PageRank computation (filtering before would distort scores)\n let filtered = result.rankings;\n if (kind) {\n filtered = filtered.filter((e) => e.kind === kind);\n }\n if (filePattern) {\n const lowerPattern = filePattern.toLowerCase();\n filtered = filtered.filter((e) => e.file.toLowerCase().includes(lowerPattern));\n }\n filtered = filtered.slice(0, limit);\n\n const payload = masking.mask(JSON.stringify(wrapResponse({\n rankings: filtered,\n totalSymbols: result.totalSymbols,\n iterations: result.iterations,\n converged: result.converged,\n damping,\n })));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","import { z } from 'zod';\nimport { readFileSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { IStoragePort } from '../../ports/i-storage-port.js';\nimport type { IGitPort } from '../../ports/i-git-port.js';\nimport type { IMaskingPort } from '../../ports/i-masking-port.js';\nimport type { StalenessCheck } from './get-logic-slice.js';\nimport { getGraphAndFiles } from './get-logic-slice.js';\nimport { BlastRadiusCalculator } from '../../core/blast-radius/blast-radius-calculator.js';\nimport { BoundaryViolationDetector } from '../../core/overlay/boundary-violation-detector.js';\nimport { buildSnapshotStaleness } from '../../core/overlay/snapshot-staleness.js';\nimport type { ClusterLabelMasker } from '../../core/overlay/cluster-label-masker.js';\nimport { wrapResponse } from '../../core/response-envelope.js';\nimport { loadCoChangeMap } from '../../core/co-change/co-change-analyzer.js';\nimport type { CoChangeMatrix, CoChangeEntry, CommunitySnapshot } from '../../core/types.js';\n\nconst InputSchema = z.object({\n since: z.string().optional().default('HEAD~1'),\n maxFiles: z.number().int().min(1).optional().default(50),\n confidence: z.enum(['confirmed', 'likely', 'potential']).optional(),\n});\n\nfunction loadCoChanges(ctxoRoot: string): Map<string, CoChangeEntry[]> | undefined {\n const path = join(ctxoRoot, 'index', 'co-changes.json');\n if (!existsSync(path)) return undefined;\n try {\n const matrix: CoChangeMatrix = JSON.parse(readFileSync(path, 'utf-8'));\n return loadCoChangeMap(matrix);\n } catch {\n return undefined;\n }\n}\n\nfunction computeClustersAffected(\n snapshot: CommunitySnapshot,\n changedSymbolIds: ReadonlySet<string>,\n): Array<{ id: number; label: string; symbolCount: number }> {\n const totals = new Map<number, { label: string; count: number }>();\n for (const entry of snapshot.communities) {\n if (!changedSymbolIds.has(entry.symbolId)) continue;\n const existing = totals.get(entry.communityId);\n if (existing) {\n existing.count += 1;\n } else {\n totals.set(entry.communityId, { label: entry.communityLabel, count: 1 });\n }\n }\n return [...totals.entries()]\n .map(([id, { label, count }]) => ({ id, label, symbolCount: count }))\n .sort((a, b) => b.symbolCount - a.symbolCount || a.id - b.id);\n}\n\nexport function handleGetPrImpact(\n storage: IStoragePort,\n git: IGitPort,\n masking: IMaskingPort,\n staleness?: StalenessCheck,\n ctxoRoot = '.ctxo',\n clusterLabelMasker?: ClusterLabelMasker,\n) {\n const calculator = new BlastRadiusCalculator();\n const getGraph = () => getGraphAndFiles(ctxoRoot, storage);\n\n return async (args: Record<string, unknown>) => {\n try {\n const parsed = InputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: parsed.error.message }) }],\n };\n }\n\n const { since, maxFiles, confidence: confFilter } = parsed.data;\n\n // Step 1: Get changed files\n const changedPaths = await git.getChangedFiles(since);\n if (changedPaths.length === 0) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ since, changedFiles: 0, changedSymbols: 0, totalImpact: 0, riskLevel: 'low', files: [], summary: { confirmedTotal: 0, likelyTotal: 0, potentialTotal: 0, highRiskSymbols: [] } }) }],\n };\n }\n\n // Step 2: Build graph + load co-changes\n const { graph, indexedFiles } = getGraph();\n const coChangeMap = loadCoChanges(ctxoRoot);\n\n // Step 3: Map files → symbols\n const allNodes = graph.allNodes();\n const nodesByFile = new Map<string, typeof allNodes>();\n for (const node of allNodes) {\n const file = node.symbolId.split('::')[0]!;\n let list = nodesByFile.get(file);\n if (!list) { list = []; nodesByFile.set(file, list); }\n list.push(node);\n }\n\n // Step 4: For each changed file, compute blast radius per symbol\n const limitedPaths = changedPaths.slice(0, maxFiles);\n let totalImpact = 0;\n let confirmedTotal = 0;\n let likelyTotal = 0;\n let potentialTotal = 0;\n const highRiskSymbols: string[] = [];\n\n const files: Array<{\n file: string;\n symbols: Array<{\n symbolId: string;\n name: string;\n kind: string;\n blast: {\n impactScore: number;\n confirmedCount: number;\n likelyCount: number;\n potentialCount: number;\n riskScore: number;\n topImpacted: Array<unknown>;\n };\n }>;\n coChangedWith?: string[];\n }> = [];\n\n for (const filePath of limitedPaths) {\n const symbols = nodesByFile.get(filePath);\n if (!symbols || symbols.length === 0) continue;\n\n const fileSymbols: typeof files[0]['symbols'] = [];\n\n for (const sym of symbols) {\n const result = calculator.calculate(graph, sym.symbolId, coChangeMap);\n\n let impacted = result.impactedSymbols;\n if (confFilter) {\n impacted = impacted.filter(s => s.confidence === confFilter);\n }\n\n const impactScore = impacted.length;\n const confirmed = impacted.filter(s => s.confidence === 'confirmed').length;\n const likely = impacted.filter(s => s.confidence === 'likely').length;\n const potential = impacted.filter(s => s.confidence === 'potential').length;\n\n totalImpact += impactScore;\n confirmedTotal += confirmed;\n likelyTotal += likely;\n potentialTotal += potential;\n\n if (result.overallRiskScore > 0.7) {\n highRiskSymbols.push(sym.symbolId);\n }\n\n const topImpacted = impacted\n .sort((a, b) => b.riskScore - a.riskScore)\n .slice(0, 10);\n\n fileSymbols.push({\n symbolId: sym.symbolId,\n name: sym.name,\n kind: sym.kind,\n blast: {\n impactScore,\n confirmedCount: confirmed,\n likelyCount: likely,\n potentialCount: potential,\n riskScore: result.overallRiskScore,\n topImpacted,\n },\n });\n }\n\n // Co-changed files for this file\n let coChangedWith: string[] | undefined;\n if (coChangeMap) {\n const entries = coChangeMap.get(filePath);\n if (entries && entries.length > 0) {\n coChangedWith = entries\n .sort((a, b) => b.frequency - a.frequency)\n .slice(0, 5)\n .map(e => e.file1 === filePath ? e.file2 : e.file1);\n }\n }\n\n files.push({\n file: filePath,\n symbols: fileSymbols,\n ...(coChangedWith ? { coChangedWith } : {}),\n });\n }\n\n // Step 5: Compute risk level\n const maxRisk = files.reduce((max, f) => {\n const fileMax = f.symbols.reduce((m, s) => Math.max(m, s.blast.riskScore), 0);\n return Math.max(max, fileMax);\n }, 0);\n const riskLevel = maxRisk > 0.7 ? 'high' : maxRisk > 0.3 ? 'medium' : 'low';\n\n const changedSymbols = files.reduce((sum, f) => sum + f.symbols.length, 0);\n\n const rawSnapshot = storage.readCommunities();\n const snapshot =\n rawSnapshot && clusterLabelMasker?.isEnabled()\n ? clusterLabelMasker.maskSnapshot(rawSnapshot)\n : rawSnapshot;\n const history = snapshot ? storage.listCommunityHistory() : [];\n let boundarySection: Record<string, unknown> | undefined;\n let clustersAffected: Array<{ id: number; label: string; symbolCount: number }> | undefined;\n\n if (snapshot) {\n const detector = new BoundaryViolationDetector();\n const violationResult = detector.detect(graph, snapshot, history);\n const changedSymbolIds = new Set<string>();\n for (const file of files) {\n for (const sym of file.symbols) changedSymbolIds.add(sym.symbolId);\n }\n const relevant = violationResult.violations.filter(\n (v) => changedSymbolIds.has(v.from.symbolId) || changedSymbolIds.has(v.to.symbolId),\n );\n boundarySection = {\n violations: relevant,\n confidence: violationResult.confidence,\n snapshotsAvailable: violationResult.snapshotsAvailable,\n ...(violationResult.hint ? { hint: violationResult.hint } : {}),\n };\n clustersAffected = computeClustersAffected(snapshot, changedSymbolIds);\n }\n\n const body: Record<string, unknown> = {\n since,\n changedFiles: files.length,\n changedSymbols,\n totalImpact,\n riskLevel,\n files,\n summary: {\n confirmedTotal,\n likelyTotal,\n potentialTotal,\n highRiskSymbols: highRiskSymbols.slice(0, 10),\n },\n };\n if (boundarySection) body.boundaryViolations = boundarySection;\n if (clustersAffected && clustersAffected.length > 0) body.clustersAffected = clustersAffected;\n\n const stalenessMeta = await buildSnapshotStaleness(storage, git);\n const extras = stalenessMeta ? { snapshotStaleness: stalenessMeta } : undefined;\n const payload = masking.mask(JSON.stringify(wrapResponse(body, extras)));\n\n const content: Array<{ type: 'text'; text: string }> = [];\n if (staleness) {\n const warning = staleness.check(indexedFiles);\n if (warning) content.push({ type: 'text', text: `⚠️ ${warning.message}` });\n }\n content.push({ type: 'text', text: payload });\n\n return { content };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ error: true, message: (err as Error).message }) }],\n };\n }\n };\n}\n","import type { ISessionRecorderPort, SessionEvent } from '../../ports/i-session-recorder-port.js';\n\ntype McpToolResult = { content: Array<{ type: 'text'; text: string }> };\ntype McpHandler = (args: Record<string, unknown>) => McpToolResult | Promise<McpToolResult>;\n\n/**\n * Wraps an MCP handler with session recording.\n * Recording is fire-and-forget — errors are swallowed, never affect tool response.\n *\n * @param toolName - MCP tool name (e.g., 'get_logic_slice')\n * @param handler - Original handler function (sync or async)\n * @param recorder - Session recorder (null = recording disabled, zero overhead)\n */\nexport function withRecording(\n toolName: string,\n handler: McpHandler,\n recorder: ISessionRecorderPort | null,\n): McpHandler {\n if (!recorder) return handler;\n\n return (args: Record<string, unknown>) => {\n const start = performance.now();\n const resultOrPromise = handler(args);\n\n // Handle async handlers\n if (resultOrPromise instanceof Promise) {\n return resultOrPromise.then((result) => {\n recordEvent(toolName, args, result, performance.now() - start, recorder);\n return result;\n });\n }\n\n // Sync handler\n const latencyMs = performance.now() - start;\n recordEvent(toolName, args, resultOrPromise, latencyMs, recorder);\n return resultOrPromise;\n };\n}\n\nfunction recordEvent(\n toolName: string,\n args: Record<string, unknown>,\n result: McpToolResult,\n latencyMs: number,\n recorder: ISessionRecorderPort,\n): void {\n try {\n const responseText = result.content\n .filter((c) => c.type === 'text')\n .map((c) => c.text)\n .join('');\n\n let truncated = false;\n try {\n const parsed = JSON.parse(responseText);\n truncated = parsed?._meta?.truncated ?? false;\n } catch { /* non-JSON response, ignore */ }\n\n const responseBytes = Buffer.byteLength(responseText, 'utf-8');\n\n // Extract detail level: args.level (number) → 'L1'...'L4'\n const rawLevel = args['level'];\n let detailLevel: SessionEvent['detailLevel'] = null;\n if (typeof rawLevel === 'number' && rawLevel >= 1 && rawLevel <= 4) {\n detailLevel = `L${rawLevel}` as SessionEvent['detailLevel'];\n }\n\n const event: SessionEvent = {\n tool: toolName,\n symbolId: (typeof args['symbolId'] === 'string' ? args['symbolId'] : null),\n detailLevel,\n responseTokens: Math.ceil(responseBytes / 4),\n responseBytes,\n latencyMs,\n truncated,\n };\n\n recorder.record(event);\n } catch {\n // Recording failure must never affect tool response\n }\n}\n","import type { CommunityEntry, CommunitySnapshot, GodNode } from '../types.js';\nimport { makeGlobMatcher } from '../config/load-config.js';\n\n/**\n * Replace sensitive cluster labels with `[masked-cluster-N]`. Labels matching\n * any configured glob (e.g. `internal-*`, `*-vault`, `src/payment-*`) are\n * rewritten deterministically so MCP tool responses never leak org-sensitive\n * directory names to AI agents over the stdio channel.\n *\n * Determinism matters: drift-detector compares labels across snapshots, so\n * the same input label must always produce the same mask. We seed the mask\n * counter from the snapshot's sorted, unique label set.\n */\nexport class ClusterLabelMasker {\n private readonly matcher: (input: string) => boolean;\n private readonly enabled: boolean;\n private readonly labelCache = new Map<string, string>();\n\n constructor(patterns: readonly string[]) {\n this.enabled = patterns.length > 0;\n this.matcher = this.enabled ? makeGlobMatcher([...patterns]) : () => false;\n }\n\n isEnabled(): boolean {\n return this.enabled;\n }\n\n mask(label: string): string {\n if (!this.enabled) return label;\n if (!this.matcher(label)) return label;\n const cached = this.labelCache.get(label);\n if (cached) return cached;\n const masked = `[masked-cluster-${this.labelCache.size + 1}]`;\n this.labelCache.set(label, masked);\n return masked;\n }\n\n maskSnapshot(snapshot: CommunitySnapshot): CommunitySnapshot {\n if (!this.enabled) return snapshot;\n // Seed the cache in sorted order so output is stable across runs.\n const uniqueLabels = [...new Set(snapshot.communities.map((c) => c.communityLabel))].sort();\n for (const label of uniqueLabels) this.mask(label);\n\n const maskedCommunities: CommunityEntry[] = snapshot.communities.map((entry) => ({\n ...entry,\n communityLabel: this.mask(entry.communityLabel),\n }));\n const maskedGodNodes: GodNode[] = snapshot.godNodes.map((g) => ({ ...g }));\n return { ...snapshot, communities: maskedCommunities, godNodes: maskedGodNodes };\n }\n}\n"],"mappings":"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","names":["z","existsSync","readFileSync","join","z","InputSchema","z","z","InputSchema","z","z","InputSchema","z","z","InputSchema","z","payload","z","InputSchema","z","z","z","InputSchema","z","log","log","InputSchema","z","payload","content","z","InputSchema","z","results","payload","content","z","InputSchema","z","z","InputSchema","z","z","InputSchema","z","visited","z","InputSchema","z","z","InputSchema","z","log","join","existsSync","readFileSync","z"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ctxo/cli",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.3",
|
|
4
4
|
"description": "MCP server delivering dependency-aware, history-enriched context for codebases",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -52,8 +52,9 @@
|
|
|
52
52
|
"typescript": "^5.8.3",
|
|
53
53
|
"typescript-eslint": "^8.57.2",
|
|
54
54
|
"vitest": "^3.1.3",
|
|
55
|
-
"@ctxo/lang-go": "0.8.0",
|
|
56
55
|
"@ctxo/lang-csharp": "0.7.3",
|
|
56
|
+
"@ctxo/lang-go": "0.8.0",
|
|
57
|
+
"@ctxo/lang-java": "0.8.0",
|
|
57
58
|
"@ctxo/lang-typescript": "0.7.1"
|
|
58
59
|
},
|
|
59
60
|
"repository": {
|