@ngommans/codefocus 0.1.0 → 0.1.4

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.

Potentially problematic release.


This version of @ngommans/codefocus might be problematic. Click here for more details.

@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/indexer.ts","../src/parser.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport { readFileSync } from \"node:fs\";\nimport { resolve, relative, dirname, extname } from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport { IndexDatabase } from \"./db.js\";\nimport { parseSource, findIdentifierUsages, type ImportDef } from \"./parser.js\";\n\nconst require = createRequire(import.meta.url);\nconst fg = require(\"fast-glob\");\n\nconst TS_EXTENSIONS = new Set([\".ts\", \".tsx\", \".js\", \".jsx\"]);\nconst IGNORE_PATTERNS = [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/.codefocus/**\",\n \"**/__tests__/**\",\n \"**/*.test.*\",\n \"**/*.spec.*\",\n \"**/*.d.ts\",\n];\n\nexport interface IndexStats {\n filesIndexed: number;\n filesSkipped: number;\n symbolsExtracted: number;\n importsFound: number;\n referencesCreated: number;\n timeMs: number;\n}\n\nfunction hashContent(content: string): string {\n return createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 16);\n}\n\nfunction resolveImportPath(\n importSource: string,\n fromFile: string,\n rootDir: string,\n allFiles: Set<string>,\n): string | null {\n if (!importSource.startsWith(\".\")) return null;\n\n const fromDir = dirname(fromFile);\n const basePath = resolve(rootDir, fromDir, importSource);\n\n // Strip .js/.jsx extension for ESM-style imports (import from \"./foo.js\" → foo.ts)\n const ext = extname(basePath);\n const strippedBase =\n ext === \".js\" || ext === \".jsx\" ? basePath.slice(0, -ext.length) : null;\n\n const candidates = [\n basePath,\n ...Array.from(TS_EXTENSIONS).map((e) => basePath + e),\n ...Array.from(TS_EXTENSIONS).map((e) => resolve(basePath, \"index\" + e)),\n ];\n\n // Also try stripped base with TS extensions (.js → .ts, .tsx, etc.)\n if (strippedBase) {\n candidates.push(\n ...Array.from(TS_EXTENSIONS).map((e) => strippedBase + e),\n ...Array.from(TS_EXTENSIONS).map((e) =>\n resolve(strippedBase, \"index\" + e),\n ),\n );\n }\n\n for (const candidate of candidates) {\n const rel = relative(rootDir, candidate);\n if (allFiles.has(rel)) return rel;\n }\n\n return null;\n}\n\nexport async function indexProject(\n rootDir: string,\n dbPath: string,\n): Promise<IndexStats> {\n const startTime = Date.now();\n const absRoot = resolve(rootDir);\n\n const files: string[] = await fg(\"**/*.{ts,tsx,js,jsx}\", {\n cwd: absRoot,\n ignore: IGNORE_PATTERNS,\n absolute: false,\n });\n\n const allFiles = new Set(files);\n const db = new IndexDatabase(dbPath);\n\n let filesIndexed = 0;\n let filesSkipped = 0;\n let symbolsExtracted = 0;\n let importsFound = 0;\n let referencesCreated = 0;\n\n // Map from \"filePath:symbolName\" → symbolId for reference creation\n const symbolIdMap = new Map<string, number>();\n // Cache imports per file for the reference-creation pass\n const fileImports = new Map<string, ImportDef[]>();\n // Cache file contents for identifier usage extraction\n const fileContents = new Map<string, string>();\n\n db.transaction(() => {\n // Pass 1: parse files, extract and store symbols, collect imports\n for (const filePath of files) {\n const absPath = resolve(absRoot, filePath);\n let content: string;\n try {\n content = readFileSync(absPath, \"utf-8\");\n } catch {\n filesSkipped++;\n continue;\n }\n\n const hash = hashContent(content);\n const existingHash = db.getFileHash(filePath);\n\n // Always parse to collect imports for reference creation\n const result = parseSource(content);\n if (result.imports.length > 0) {\n fileImports.set(filePath, result.imports);\n fileContents.set(filePath, content);\n }\n\n if (existingHash === hash) {\n filesSkipped++;\n // Load existing symbol IDs into the map\n for (const sym of db.getSymbolsByFile(filePath)) {\n symbolIdMap.set(`${filePath}:${sym.name}`, sym.id!);\n }\n continue;\n }\n\n // Clear old data for this file\n db.clearFile(filePath);\n\n const ext = extname(filePath);\n const language =\n ext === \".js\" || ext === \".jsx\" ? \"javascript\" : \"typescript\";\n\n db.upsertFile({\n path: filePath,\n content_hash: hash,\n language,\n last_indexed: Date.now(),\n });\n\n // Populate FTS5 content index\n db.upsertFileContent(filePath, content);\n\n for (const sym of result.symbols) {\n const id = db.insertSymbol({\n file_path: filePath,\n name: sym.name,\n kind: sym.kind,\n start_byte: sym.startByte,\n end_byte: sym.endByte,\n start_line: sym.startLine,\n end_line: sym.endLine,\n start_column: sym.startColumn,\n end_column: sym.endColumn,\n signature: sym.signature,\n });\n symbolIdMap.set(`${filePath}:${sym.name}`, id);\n symbolsExtracted++;\n }\n\n filesIndexed++;\n }\n\n // Pass 2: clear all imports/references and recreate from cached data\n db.clearAllImports();\n db.clearAllReferences();\n\n for (const [filePath, imports] of fileImports) {\n // Cache symbols for this file once (avoid repeated DB queries)\n const fileSymbolRows = db.getSymbolsByFile(filePath);\n const sourceSymbols = fileSymbolRows.map((sym) => ({\n name: sym.name,\n id: sym.id!,\n startLine: sym.start_line,\n endLine: sym.end_line,\n }));\n\n // Collect all imported names across all imports for this file\n const allImportedNames = new Set<string>();\n for (const imp of imports) {\n for (const specName of imp.specifiers) {\n const cleanName = specName.startsWith(\"* as \")\n ? specName.slice(5)\n : specName;\n allImportedNames.add(cleanName);\n }\n }\n\n // Find identifier usages once per file for all imported names\n const content = fileContents.get(filePath);\n const usages = content\n ? findIdentifierUsages(content, allImportedNames)\n : [];\n\n for (const imp of imports) {\n const targetFile = resolveImportPath(\n imp.source,\n filePath,\n absRoot,\n allFiles,\n );\n\n // Store every import declaration in the imports table\n for (const specName of imp.specifiers) {\n const cleanName = specName.startsWith(\"* as \")\n ? specName.slice(5)\n : specName;\n db.insertImport({\n file_path: filePath,\n specifier: cleanName,\n source_path: targetFile,\n raw_module: imp.source,\n is_type_only: imp.isTypeOnly ? 1 : 0,\n });\n importsFound++;\n }\n\n if (!targetFile) continue;\n\n const refType = imp.isTypeOnly ? \"type_ref\" : \"import\";\n\n for (const specName of imp.specifiers) {\n const cleanName = specName.startsWith(\"* as \")\n ? specName.slice(5)\n : specName;\n\n const targetKey = `${targetFile}:${cleanName}`;\n const targetId = symbolIdMap.get(targetKey);\n if (!targetId) continue;\n\n // Find usages of this specific imported name\n const nameUsages = usages.filter((u) => u.name === cleanName);\n\n if (nameUsages.length > 0) {\n // Create references only from symbols that actually use the import\n const referencingSymbolIds = new Set<number>();\n\n for (const usage of nameUsages) {\n for (const srcSym of sourceSymbols) {\n if (\n srcSym.id !== targetId &&\n usage.line >= srcSym.startLine &&\n usage.line <= srcSym.endLine\n ) {\n referencingSymbolIds.add(srcSym.id);\n }\n }\n }\n\n for (const sourceId of referencingSymbolIds) {\n db.insertReference({\n source_symbol_id: sourceId,\n target_symbol_id: targetId,\n ref_type: refType,\n });\n referencesCreated++;\n }\n } else {\n // No usages in code bodies (e.g., re-exports, or type-only imports\n // used only in type positions). Create references from all source\n // symbols for graph connectivity.\n for (const srcSym of sourceSymbols) {\n if (srcSym.id !== targetId) {\n db.insertReference({\n source_symbol_id: srcSym.id,\n target_symbol_id: targetId,\n ref_type: refType,\n });\n referencesCreated++;\n }\n }\n }\n }\n }\n }\n });\n\n db.close();\n\n return {\n filesIndexed,\n filesSkipped,\n symbolsExtracted,\n importsFound,\n referencesCreated,\n timeMs: Date.now() - startTime,\n };\n}\n","import { createRequire } from \"node:module\";\n\nconst require = createRequire(import.meta.url);\nconst Parser = require(\"tree-sitter\");\nconst TypeScriptLang = require(\"tree-sitter-typescript\").typescript;\n\nexport interface SymbolDef {\n name: string;\n kind: string;\n startByte: number;\n endByte: number;\n startLine: number;\n endLine: number;\n startColumn: number;\n endColumn: number;\n signature: string | null;\n exported: boolean;\n}\n\nexport interface ImportDef {\n specifiers: string[];\n source: string;\n isTypeOnly: boolean;\n}\n\nexport interface IdentifierUsage {\n name: string;\n line: number;\n column: number;\n}\n\nexport interface ParseResult {\n symbols: SymbolDef[];\n imports: ImportDef[];\n}\n\ninterface TreeSitterNode {\n type: string;\n text: string;\n startPosition: { row: number; column: number };\n endPosition: { row: number; column: number };\n startIndex: number;\n endIndex: number;\n childCount: number;\n namedChildCount: number;\n child(index: number): TreeSitterNode | null;\n namedChild(index: number): TreeSitterNode | null;\n childForFieldName(name: string): TreeSitterNode | null;\n children: TreeSitterNode[];\n namedChildren: TreeSitterNode[];\n parent: TreeSitterNode | null;\n}\n\nlet parser: InstanceType<typeof Parser> | null = null;\n\nfunction getParser(): InstanceType<typeof Parser> {\n if (!parser) {\n parser = new Parser();\n parser.setLanguage(TypeScriptLang);\n }\n return parser;\n}\n\nfunction extractSignature(node: TreeSitterNode, source: string): string | null {\n const kind = node.type;\n\n if (kind === \"function_declaration\" || kind === \"arrow_function\") {\n const nameNode = node.childForFieldName(\"name\");\n const paramsNode = node.childForFieldName(\"parameters\");\n const returnType = node.childForFieldName(\"return_type\");\n if (nameNode && paramsNode) {\n let sig = `function ${nameNode.text}${paramsNode.text}`;\n if (returnType) sig += returnType.text;\n return sig;\n }\n }\n\n if (kind === \"class_declaration\") {\n const nameNode = node.childForFieldName(\"name\");\n if (nameNode) return `class ${nameNode.text}`;\n }\n\n if (kind === \"interface_declaration\") {\n const nameNode = node.childForFieldName(\"name\");\n if (nameNode) return `interface ${nameNode.text}`;\n }\n\n if (kind === \"type_alias_declaration\") {\n const text = node.text;\n const semiIdx = text.indexOf(\";\");\n return semiIdx > 0 ? text.slice(0, semiIdx) : text;\n }\n\n if (kind === \"enum_declaration\") {\n const nameNode = node.childForFieldName(\"name\");\n if (nameNode) return `enum ${nameNode.text}`;\n }\n\n if (kind === \"method_definition\") {\n const nameNode = node.childForFieldName(\"name\");\n const paramsNode = node.childForFieldName(\"parameters\");\n const returnType = node.childForFieldName(\"return_type\");\n if (nameNode && paramsNode) {\n let sig = `${nameNode.text}${paramsNode.text}`;\n if (returnType) sig += returnType.text;\n return sig;\n }\n }\n\n return null;\n}\n\nfunction getSymbolName(node: TreeSitterNode): string | null {\n const nameNode =\n node.childForFieldName(\"name\") ?? node.childForFieldName(\"declarator\");\n return nameNode?.text ?? null;\n}\n\nfunction extractDeclaration(node: TreeSitterNode, source: string, exported: boolean): SymbolDef | null {\n const kindMap: Record<string, string> = {\n function_declaration: \"function\",\n class_declaration: \"class\",\n interface_declaration: \"interface\",\n type_alias_declaration: \"type\",\n enum_declaration: \"enum\",\n };\n\n const kind = kindMap[node.type];\n if (!kind) return null;\n\n const name = getSymbolName(node);\n if (!name) return null;\n\n return {\n name,\n kind,\n startByte: node.startIndex,\n endByte: node.endIndex,\n startLine: node.startPosition.row + 1,\n endLine: node.endPosition.row + 1,\n startColumn: node.startPosition.column,\n endColumn: node.endPosition.column,\n signature: extractSignature(node, source),\n exported,\n };\n}\n\nfunction extractMethods(classNode: TreeSitterNode, source: string, exported: boolean): SymbolDef[] {\n const methods: SymbolDef[] = [];\n const body = classNode.childForFieldName(\"body\");\n if (!body) return methods;\n\n for (const child of body.namedChildren) {\n if (child.type === \"method_definition\") {\n const nameNode = child.childForFieldName(\"name\");\n if (!nameNode) continue;\n methods.push({\n name: nameNode.text,\n kind: \"method\",\n startByte: child.startIndex,\n endByte: child.endIndex,\n startLine: child.startPosition.row + 1,\n endLine: child.endPosition.row + 1,\n startColumn: child.startPosition.column,\n endColumn: child.endPosition.column,\n signature: extractSignature(child, source),\n exported,\n });\n }\n }\n return methods;\n}\n\nfunction extractVariableDeclarations(node: TreeSitterNode, exported: boolean): SymbolDef[] {\n const symbols: SymbolDef[] = [];\n for (const child of node.namedChildren) {\n if (child.type === \"variable_declarator\") {\n const nameNode = child.childForFieldName(\"name\");\n if (nameNode) {\n symbols.push({\n name: nameNode.text,\n kind: \"variable\",\n startByte: node.startIndex,\n endByte: node.endIndex,\n startLine: node.startPosition.row + 1,\n endLine: node.endPosition.row + 1,\n startColumn: node.startPosition.column,\n endColumn: node.endPosition.column,\n signature: null,\n exported,\n });\n }\n }\n }\n return symbols;\n}\n\nfunction extractImport(node: TreeSitterNode): ImportDef | null {\n let sourceNode: TreeSitterNode | null = null;\n for (const child of node.children) {\n if (child.type === \"string\") {\n sourceNode = child;\n break;\n }\n }\n if (!sourceNode) return null;\n\n const rawSource = sourceNode.text;\n const source = rawSource.replace(/^['\"]|['\"]$/g, \"\");\n\n const specifiers: string[] = [];\n const isTypeOnly = node.children.some(\n (c: TreeSitterNode) => c.type === \"type\" && c.text === \"type\",\n );\n\n for (const child of node.children) {\n if (child.type === \"import_clause\") {\n for (const clause of child.namedChildren) {\n if (clause.type === \"named_imports\") {\n for (const spec of clause.namedChildren) {\n if (spec.type === \"import_specifier\") {\n const nameNode = spec.childForFieldName(\"name\");\n const aliasNode = spec.childForFieldName(\"alias\");\n specifiers.push(aliasNode?.text ?? nameNode?.text ?? spec.text);\n }\n }\n } else if (clause.type === \"identifier\") {\n specifiers.push(clause.text);\n } else if (clause.type === \"namespace_import\") {\n const nameNode = clause.namedChildren.find(\n (c: TreeSitterNode) => c.type === \"identifier\",\n );\n if (nameNode) specifiers.push(`* as ${nameNode.text}`);\n }\n }\n }\n }\n\n return { specifiers, source, isTypeOnly };\n}\n\nfunction extractReExportSpecifiers(node: TreeSitterNode): string[] {\n const specifiers: string[] = [];\n for (const child of node.children) {\n if (child.type === \"export_clause\") {\n for (const spec of child.namedChildren) {\n if (spec.type === \"export_specifier\") {\n const nameNode = spec.childForFieldName(\"name\");\n if (nameNode) specifiers.push(nameNode.text);\n }\n }\n }\n }\n return specifiers;\n}\n\n/**\n * Find all identifier nodes in the AST that match any of the given names.\n * Used to determine which symbols in a file actually reference imported names.\n */\nexport function findIdentifierUsages(source: string, names: Set<string>): IdentifierUsage[] {\n if (names.size === 0) return [];\n\n const p = getParser();\n const tree = p.parse(source);\n const root: TreeSitterNode = tree.rootNode;\n const usages: IdentifierUsage[] = [];\n\n function walk(node: TreeSitterNode): void {\n if (\n (node.type === \"identifier\" || node.type === \"type_identifier\") &&\n names.has(node.text)\n ) {\n // Skip identifiers that are part of import/export declarations\n let parent = node.parent;\n let isImportExport = false;\n while (parent) {\n if (\n parent.type === \"import_statement\" ||\n parent.type === \"import_clause\" ||\n parent.type === \"import_specifier\" ||\n (parent.type === \"export_statement\" &&\n parent.children.some((c: TreeSitterNode) => c.type === \"from\"))\n ) {\n isImportExport = true;\n break;\n }\n parent = parent.parent;\n }\n if (!isImportExport) {\n usages.push({\n name: node.text,\n line: node.startPosition.row + 1,\n column: node.startPosition.column,\n });\n }\n }\n for (const child of node.children) {\n walk(child);\n }\n }\n\n walk(root);\n return usages;\n}\n\n/**\n * Walk the full AST to find dynamic import() calls and extract them as imports.\n * Handles patterns like:\n * const { foo } = await import('./module.js')\n * import('./module.js').then(m => ...)\n */\nfunction extractDynamicImports(root: TreeSitterNode): ImportDef[] {\n const imports: ImportDef[] = [];\n\n function walk(node: TreeSitterNode): void {\n if (node.type === \"call_expression\") {\n // Check if this is an import() call — first child is the `import` keyword\n const fn = node.child(0);\n if (fn && fn.type === \"import\") {\n const argsNode = node.childForFieldName(\"arguments\");\n if (argsNode) {\n // Extract the module path from the first string argument\n const strArg = argsNode.namedChildren.find(\n (c: TreeSitterNode) => c.type === \"string\",\n );\n if (strArg) {\n const modulePath = strArg.text.replace(/^['\"]|['\"]$/g, \"\");\n const specifiers = extractDynamicImportSpecifiers(node);\n imports.push({ specifiers, source: modulePath, isTypeOnly: false });\n }\n }\n // Don't walk into the import() call's children\n return;\n }\n }\n for (const child of node.children) {\n walk(child);\n }\n }\n\n walk(root);\n return imports;\n}\n\n/**\n * Try to extract destructured specifiers from the context around a\n * dynamic import() call_expression, e.g.:\n * const { runIndex } = await import('./commands/index.js')\n * ^^^^^^^^^^^^ these specifiers\n */\nfunction extractDynamicImportSpecifiers(importCall: TreeSitterNode): string[] {\n // Walk up: import() → await_expression → variable_declarator\n let current: TreeSitterNode | null = importCall.parent;\n\n // Skip await_expression wrapper if present\n if (current && current.type === \"await_expression\") {\n current = current.parent;\n }\n\n if (current && current.type === \"variable_declarator\") {\n const pattern = current.childForFieldName(\"name\");\n if (pattern && pattern.type === \"object_pattern\") {\n const specs: string[] = [];\n for (const child of pattern.namedChildren) {\n if (child.type === \"shorthand_property_identifier_pattern\") {\n specs.push(child.text);\n } else if (child.type === \"pair_pattern\") {\n // { original: alias } destructuring — use the alias\n const value = child.childForFieldName(\"value\");\n if (value) specs.push(value.text);\n }\n }\n return specs;\n }\n }\n\n return [];\n}\n\nexport function parseSource(source: string): ParseResult {\n const p = getParser();\n const tree = p.parse(source);\n const root: TreeSitterNode = tree.rootNode;\n\n const symbols: SymbolDef[] = [];\n const imports: ImportDef[] = [];\n\n for (const node of root.namedChildren) {\n if (node.type === \"import_statement\") {\n const imp = extractImport(node);\n if (imp) imports.push(imp);\n continue;\n }\n\n if (node.type === \"export_statement\") {\n // Re-export: export { X } from './foo'\n const hasFrom = node.children.some(\n (c: TreeSitterNode) => c.type === \"from\",\n );\n if (hasFrom) {\n // Treat re-exports as imports from the source module\n let sourceNode: TreeSitterNode | null = null;\n for (const child of node.children) {\n if (child.type === \"string\") {\n sourceNode = child;\n break;\n }\n }\n if (sourceNode) {\n const rawSource = sourceNode.text;\n const source = rawSource.replace(/^['\"]|['\"]$/g, \"\");\n const specifiers = extractReExportSpecifiers(node);\n const isTypeOnly = node.children.some(\n (c: TreeSitterNode) => c.type === \"type\" && c.text === \"type\",\n );\n imports.push({ specifiers, source, isTypeOnly });\n }\n continue;\n }\n\n // Exported declaration: export function foo() {}\n for (const child of node.namedChildren) {\n const decl = extractDeclaration(child, source, true);\n if (decl) {\n symbols.push(decl);\n if (child.type === \"class_declaration\") {\n symbols.push(...extractMethods(child, source, true));\n }\n }\n\n if (\n child.type === \"lexical_declaration\" ||\n child.type === \"variable_declaration\"\n ) {\n symbols.push(...extractVariableDeclarations(child, true));\n }\n }\n continue;\n }\n\n // Top-level declarations (not exported)\n const decl = extractDeclaration(node, source, false);\n if (decl) {\n symbols.push(decl);\n if (node.type === \"class_declaration\") {\n symbols.push(...extractMethods(node, source, false));\n }\n }\n\n if (\n node.type === \"lexical_declaration\" ||\n node.type === \"variable_declaration\"\n ) {\n symbols.push(...extractVariableDeclarations(node, false));\n }\n }\n\n // Extract dynamic import() calls from the full AST\n imports.push(...extractDynamicImports(root));\n\n return { symbols, imports };\n}\n"],"mappings":";;;;;AAAA,SAAS,iBAAAA,sBAAqB;AAC9B,SAAS,oBAAoB;AAC7B,SAAS,SAAS,UAAU,SAAS,eAAe;AACpD,SAAS,kBAAkB;;;ACH3B,SAAS,qBAAqB;AAE9B,IAAMC,WAAU,cAAc,YAAY,GAAG;AAC7C,IAAM,SAASA,SAAQ,aAAa;AACpC,IAAM,iBAAiBA,SAAQ,wBAAwB,EAAE;AAiDzD,IAAI,SAA6C;AAEjD,SAAS,YAAyC;AAChD,MAAI,CAAC,QAAQ;AACX,aAAS,IAAI,OAAO;AACpB,WAAO,YAAY,cAAc;AAAA,EACnC;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,MAAsB,QAA+B;AAC7E,QAAM,OAAO,KAAK;AAElB,MAAI,SAAS,0BAA0B,SAAS,kBAAkB;AAChE,UAAM,WAAW,KAAK,kBAAkB,MAAM;AAC9C,UAAM,aAAa,KAAK,kBAAkB,YAAY;AACtD,UAAM,aAAa,KAAK,kBAAkB,aAAa;AACvD,QAAI,YAAY,YAAY;AAC1B,UAAI,MAAM,YAAY,SAAS,IAAI,GAAG,WAAW,IAAI;AACrD,UAAI,WAAY,QAAO,WAAW;AAClC,aAAO;AAAA,IACT;AAAA,EACF;AAEA,MAAI,SAAS,qBAAqB;AAChC,UAAM,WAAW,KAAK,kBAAkB,MAAM;AAC9C,QAAI,SAAU,QAAO,SAAS,SAAS,IAAI;AAAA,EAC7C;AAEA,MAAI,SAAS,yBAAyB;AACpC,UAAM,WAAW,KAAK,kBAAkB,MAAM;AAC9C,QAAI,SAAU,QAAO,aAAa,SAAS,IAAI;AAAA,EACjD;AAEA,MAAI,SAAS,0BAA0B;AACrC,UAAM,OAAO,KAAK;AAClB,UAAM,UAAU,KAAK,QAAQ,GAAG;AAChC,WAAO,UAAU,IAAI,KAAK,MAAM,GAAG,OAAO,IAAI;AAAA,EAChD;AAEA,MAAI,SAAS,oBAAoB;AAC/B,UAAM,WAAW,KAAK,kBAAkB,MAAM;AAC9C,QAAI,SAAU,QAAO,QAAQ,SAAS,IAAI;AAAA,EAC5C;AAEA,MAAI,SAAS,qBAAqB;AAChC,UAAM,WAAW,KAAK,kBAAkB,MAAM;AAC9C,UAAM,aAAa,KAAK,kBAAkB,YAAY;AACtD,UAAM,aAAa,KAAK,kBAAkB,aAAa;AACvD,QAAI,YAAY,YAAY;AAC1B,UAAI,MAAM,GAAG,SAAS,IAAI,GAAG,WAAW,IAAI;AAC5C,UAAI,WAAY,QAAO,WAAW;AAClC,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,cAAc,MAAqC;AAC1D,QAAM,WACJ,KAAK,kBAAkB,MAAM,KAAK,KAAK,kBAAkB,YAAY;AACvE,SAAO,UAAU,QAAQ;AAC3B;AAEA,SAAS,mBAAmB,MAAsB,QAAgB,UAAqC;AACrG,QAAM,UAAkC;AAAA,IACtC,sBAAsB;AAAA,IACtB,mBAAmB;AAAA,IACnB,uBAAuB;AAAA,IACvB,wBAAwB;AAAA,IACxB,kBAAkB;AAAA,EACpB;AAEA,QAAM,OAAO,QAAQ,KAAK,IAAI;AAC9B,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,OAAO,cAAc,IAAI;AAC/B,MAAI,CAAC,KAAM,QAAO;AAElB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,WAAW,KAAK;AAAA,IAChB,SAAS,KAAK;AAAA,IACd,WAAW,KAAK,cAAc,MAAM;AAAA,IACpC,SAAS,KAAK,YAAY,MAAM;AAAA,IAChC,aAAa,KAAK,cAAc;AAAA,IAChC,WAAW,KAAK,YAAY;AAAA,IAC5B,WAAW,iBAAiB,MAAM,MAAM;AAAA,IACxC;AAAA,EACF;AACF;AAEA,SAAS,eAAe,WAA2B,QAAgB,UAAgC;AACjG,QAAM,UAAuB,CAAC;AAC9B,QAAM,OAAO,UAAU,kBAAkB,MAAM;AAC/C,MAAI,CAAC,KAAM,QAAO;AAElB,aAAW,SAAS,KAAK,eAAe;AACtC,QAAI,MAAM,SAAS,qBAAqB;AACtC,YAAM,WAAW,MAAM,kBAAkB,MAAM;AAC/C,UAAI,CAAC,SAAU;AACf,cAAQ,KAAK;AAAA,QACX,MAAM,SAAS;AAAA,QACf,MAAM;AAAA,QACN,WAAW,MAAM;AAAA,QACjB,SAAS,MAAM;AAAA,QACf,WAAW,MAAM,cAAc,MAAM;AAAA,QACrC,SAAS,MAAM,YAAY,MAAM;AAAA,QACjC,aAAa,MAAM,cAAc;AAAA,QACjC,WAAW,MAAM,YAAY;AAAA,QAC7B,WAAW,iBAAiB,OAAO,MAAM;AAAA,QACzC;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,4BAA4B,MAAsB,UAAgC;AACzF,QAAM,UAAuB,CAAC;AAC9B,aAAW,SAAS,KAAK,eAAe;AACtC,QAAI,MAAM,SAAS,uBAAuB;AACxC,YAAM,WAAW,MAAM,kBAAkB,MAAM;AAC/C,UAAI,UAAU;AACZ,gBAAQ,KAAK;AAAA,UACX,MAAM,SAAS;AAAA,UACf,MAAM;AAAA,UACN,WAAW,KAAK;AAAA,UAChB,SAAS,KAAK;AAAA,UACd,WAAW,KAAK,cAAc,MAAM;AAAA,UACpC,SAAS,KAAK,YAAY,MAAM;AAAA,UAChC,aAAa,KAAK,cAAc;AAAA,UAChC,WAAW,KAAK,YAAY;AAAA,UAC5B,WAAW;AAAA,UACX;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,cAAc,MAAwC;AAC7D,MAAI,aAAoC;AACxC,aAAW,SAAS,KAAK,UAAU;AACjC,QAAI,MAAM,SAAS,UAAU;AAC3B,mBAAa;AACb;AAAA,IACF;AAAA,EACF;AACA,MAAI,CAAC,WAAY,QAAO;AAExB,QAAM,YAAY,WAAW;AAC7B,QAAM,SAAS,UAAU,QAAQ,gBAAgB,EAAE;AAEnD,QAAM,aAAuB,CAAC;AAC9B,QAAM,aAAa,KAAK,SAAS;AAAA,IAC/B,CAAC,MAAsB,EAAE,SAAS,UAAU,EAAE,SAAS;AAAA,EACzD;AAEA,aAAW,SAAS,KAAK,UAAU;AACjC,QAAI,MAAM,SAAS,iBAAiB;AAClC,iBAAW,UAAU,MAAM,eAAe;AACxC,YAAI,OAAO,SAAS,iBAAiB;AACnC,qBAAW,QAAQ,OAAO,eAAe;AACvC,gBAAI,KAAK,SAAS,oBAAoB;AACpC,oBAAM,WAAW,KAAK,kBAAkB,MAAM;AAC9C,oBAAM,YAAY,KAAK,kBAAkB,OAAO;AAChD,yBAAW,KAAK,WAAW,QAAQ,UAAU,QAAQ,KAAK,IAAI;AAAA,YAChE;AAAA,UACF;AAAA,QACF,WAAW,OAAO,SAAS,cAAc;AACvC,qBAAW,KAAK,OAAO,IAAI;AAAA,QAC7B,WAAW,OAAO,SAAS,oBAAoB;AAC7C,gBAAM,WAAW,OAAO,cAAc;AAAA,YACpC,CAAC,MAAsB,EAAE,SAAS;AAAA,UACpC;AACA,cAAI,SAAU,YAAW,KAAK,QAAQ,SAAS,IAAI,EAAE;AAAA,QACvD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,YAAY,QAAQ,WAAW;AAC1C;AAEA,SAAS,0BAA0B,MAAgC;AACjE,QAAM,aAAuB,CAAC;AAC9B,aAAW,SAAS,KAAK,UAAU;AACjC,QAAI,MAAM,SAAS,iBAAiB;AAClC,iBAAW,QAAQ,MAAM,eAAe;AACtC,YAAI,KAAK,SAAS,oBAAoB;AACpC,gBAAM,WAAW,KAAK,kBAAkB,MAAM;AAC9C,cAAI,SAAU,YAAW,KAAK,SAAS,IAAI;AAAA,QAC7C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,qBAAqB,QAAgB,OAAuC;AAC1F,MAAI,MAAM,SAAS,EAAG,QAAO,CAAC;AAE9B,QAAM,IAAI,UAAU;AACpB,QAAM,OAAO,EAAE,MAAM,MAAM;AAC3B,QAAM,OAAuB,KAAK;AAClC,QAAM,SAA4B,CAAC;AAEnC,WAAS,KAAK,MAA4B;AACxC,SACG,KAAK,SAAS,gBAAgB,KAAK,SAAS,sBAC7C,MAAM,IAAI,KAAK,IAAI,GACnB;AAEA,UAAI,SAAS,KAAK;AAClB,UAAI,iBAAiB;AACrB,aAAO,QAAQ;AACb,YACE,OAAO,SAAS,sBAChB,OAAO,SAAS,mBAChB,OAAO,SAAS,sBACf,OAAO,SAAS,sBACf,OAAO,SAAS,KAAK,CAAC,MAAsB,EAAE,SAAS,MAAM,GAC/D;AACA,2BAAiB;AACjB;AAAA,QACF;AACA,iBAAS,OAAO;AAAA,MAClB;AACA,UAAI,CAAC,gBAAgB;AACnB,eAAO,KAAK;AAAA,UACV,MAAM,KAAK;AAAA,UACX,MAAM,KAAK,cAAc,MAAM;AAAA,UAC/B,QAAQ,KAAK,cAAc;AAAA,QAC7B,CAAC;AAAA,MACH;AAAA,IACF;AACA,eAAW,SAAS,KAAK,UAAU;AACjC,WAAK,KAAK;AAAA,IACZ;AAAA,EACF;AAEA,OAAK,IAAI;AACT,SAAO;AACT;AAQA,SAAS,sBAAsB,MAAmC;AAChE,QAAM,UAAuB,CAAC;AAE9B,WAAS,KAAK,MAA4B;AACxC,QAAI,KAAK,SAAS,mBAAmB;AAEnC,YAAM,KAAK,KAAK,MAAM,CAAC;AACvB,UAAI,MAAM,GAAG,SAAS,UAAU;AAC9B,cAAM,WAAW,KAAK,kBAAkB,WAAW;AACnD,YAAI,UAAU;AAEZ,gBAAM,SAAS,SAAS,cAAc;AAAA,YACpC,CAAC,MAAsB,EAAE,SAAS;AAAA,UACpC;AACA,cAAI,QAAQ;AACV,kBAAM,aAAa,OAAO,KAAK,QAAQ,gBAAgB,EAAE;AACzD,kBAAM,aAAa,+BAA+B,IAAI;AACtD,oBAAQ,KAAK,EAAE,YAAY,QAAQ,YAAY,YAAY,MAAM,CAAC;AAAA,UACpE;AAAA,QACF;AAEA;AAAA,MACF;AAAA,IACF;AACA,eAAW,SAAS,KAAK,UAAU;AACjC,WAAK,KAAK;AAAA,IACZ;AAAA,EACF;AAEA,OAAK,IAAI;AACT,SAAO;AACT;AAQA,SAAS,+BAA+B,YAAsC;AAE5E,MAAI,UAAiC,WAAW;AAGhD,MAAI,WAAW,QAAQ,SAAS,oBAAoB;AAClD,cAAU,QAAQ;AAAA,EACpB;AAEA,MAAI,WAAW,QAAQ,SAAS,uBAAuB;AACrD,UAAM,UAAU,QAAQ,kBAAkB,MAAM;AAChD,QAAI,WAAW,QAAQ,SAAS,kBAAkB;AAChD,YAAM,QAAkB,CAAC;AACzB,iBAAW,SAAS,QAAQ,eAAe;AACzC,YAAI,MAAM,SAAS,yCAAyC;AAC1D,gBAAM,KAAK,MAAM,IAAI;AAAA,QACvB,WAAW,MAAM,SAAS,gBAAgB;AAExC,gBAAM,QAAQ,MAAM,kBAAkB,OAAO;AAC7C,cAAI,MAAO,OAAM,KAAK,MAAM,IAAI;AAAA,QAClC;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO,CAAC;AACV;AAEO,SAAS,YAAY,QAA6B;AACvD,QAAM,IAAI,UAAU;AACpB,QAAM,OAAO,EAAE,MAAM,MAAM;AAC3B,QAAM,OAAuB,KAAK;AAElC,QAAM,UAAuB,CAAC;AAC9B,QAAM,UAAuB,CAAC;AAE9B,aAAW,QAAQ,KAAK,eAAe;AACrC,QAAI,KAAK,SAAS,oBAAoB;AACpC,YAAM,MAAM,cAAc,IAAI;AAC9B,UAAI,IAAK,SAAQ,KAAK,GAAG;AACzB;AAAA,IACF;AAEA,QAAI,KAAK,SAAS,oBAAoB;AAEpC,YAAM,UAAU,KAAK,SAAS;AAAA,QAC5B,CAAC,MAAsB,EAAE,SAAS;AAAA,MACpC;AACA,UAAI,SAAS;AAEX,YAAI,aAAoC;AACxC,mBAAW,SAAS,KAAK,UAAU;AACjC,cAAI,MAAM,SAAS,UAAU;AAC3B,yBAAa;AACb;AAAA,UACF;AAAA,QACF;AACA,YAAI,YAAY;AACd,gBAAM,YAAY,WAAW;AAC7B,gBAAMC,UAAS,UAAU,QAAQ,gBAAgB,EAAE;AACnD,gBAAM,aAAa,0BAA0B,IAAI;AACjD,gBAAM,aAAa,KAAK,SAAS;AAAA,YAC/B,CAAC,MAAsB,EAAE,SAAS,UAAU,EAAE,SAAS;AAAA,UACzD;AACA,kBAAQ,KAAK,EAAE,YAAY,QAAAA,SAAQ,WAAW,CAAC;AAAA,QACjD;AACA;AAAA,MACF;AAGA,iBAAW,SAAS,KAAK,eAAe;AACtC,cAAMC,QAAO,mBAAmB,OAAO,QAAQ,IAAI;AACnD,YAAIA,OAAM;AACR,kBAAQ,KAAKA,KAAI;AACjB,cAAI,MAAM,SAAS,qBAAqB;AACtC,oBAAQ,KAAK,GAAG,eAAe,OAAO,QAAQ,IAAI,CAAC;AAAA,UACrD;AAAA,QACF;AAEA,YACE,MAAM,SAAS,yBACf,MAAM,SAAS,wBACf;AACA,kBAAQ,KAAK,GAAG,4BAA4B,OAAO,IAAI,CAAC;AAAA,QAC1D;AAAA,MACF;AACA;AAAA,IACF;AAGA,UAAM,OAAO,mBAAmB,MAAM,QAAQ,KAAK;AACnD,QAAI,MAAM;AACR,cAAQ,KAAK,IAAI;AACjB,UAAI,KAAK,SAAS,qBAAqB;AACrC,gBAAQ,KAAK,GAAG,eAAe,MAAM,QAAQ,KAAK,CAAC;AAAA,MACrD;AAAA,IACF;AAEA,QACE,KAAK,SAAS,yBACd,KAAK,SAAS,wBACd;AACA,cAAQ,KAAK,GAAG,4BAA4B,MAAM,KAAK,CAAC;AAAA,IAC1D;AAAA,EACF;AAGA,UAAQ,KAAK,GAAG,sBAAsB,IAAI,CAAC;AAE3C,SAAO,EAAE,SAAS,QAAQ;AAC5B;;;ADvcA,IAAMC,WAAUC,eAAc,YAAY,GAAG;AAC7C,IAAM,KAAKD,SAAQ,WAAW;AAE9B,IAAM,gBAAgB,oBAAI,IAAI,CAAC,OAAO,QAAQ,OAAO,MAAM,CAAC;AAC5D,IAAM,kBAAkB;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAWA,SAAS,YAAY,SAAyB;AAC5C,SAAO,WAAW,QAAQ,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AACvE;AAEA,SAAS,kBACP,cACA,UACA,SACA,UACe;AACf,MAAI,CAAC,aAAa,WAAW,GAAG,EAAG,QAAO;AAE1C,QAAM,UAAU,QAAQ,QAAQ;AAChC,QAAM,WAAW,QAAQ,SAAS,SAAS,YAAY;AAGvD,QAAM,MAAM,QAAQ,QAAQ;AAC5B,QAAM,eACJ,QAAQ,SAAS,QAAQ,SAAS,SAAS,MAAM,GAAG,CAAC,IAAI,MAAM,IAAI;AAErE,QAAM,aAAa;AAAA,IACjB;AAAA,IACA,GAAG,MAAM,KAAK,aAAa,EAAE,IAAI,CAAC,MAAM,WAAW,CAAC;AAAA,IACpD,GAAG,MAAM,KAAK,aAAa,EAAE,IAAI,CAAC,MAAM,QAAQ,UAAU,UAAU,CAAC,CAAC;AAAA,EACxE;AAGA,MAAI,cAAc;AAChB,eAAW;AAAA,MACT,GAAG,MAAM,KAAK,aAAa,EAAE,IAAI,CAAC,MAAM,eAAe,CAAC;AAAA,MACxD,GAAG,MAAM,KAAK,aAAa,EAAE;AAAA,QAAI,CAAC,MAChC,QAAQ,cAAc,UAAU,CAAC;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAEA,aAAW,aAAa,YAAY;AAClC,UAAM,MAAM,SAAS,SAAS,SAAS;AACvC,QAAI,SAAS,IAAI,GAAG,EAAG,QAAO;AAAA,EAChC;AAEA,SAAO;AACT;AAEA,eAAsB,aACpB,SACA,QACqB;AACrB,QAAM,YAAY,KAAK,IAAI;AAC3B,QAAM,UAAU,QAAQ,OAAO;AAE/B,QAAM,QAAkB,MAAM,GAAG,wBAAwB;AAAA,IACvD,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,WAAW,IAAI,IAAI,KAAK;AAC9B,QAAM,KAAK,IAAI,cAAc,MAAM;AAEnC,MAAI,eAAe;AACnB,MAAI,eAAe;AACnB,MAAI,mBAAmB;AACvB,MAAI,eAAe;AACnB,MAAI,oBAAoB;AAGxB,QAAM,cAAc,oBAAI,IAAoB;AAE5C,QAAM,cAAc,oBAAI,IAAyB;AAEjD,QAAM,eAAe,oBAAI,IAAoB;AAE7C,KAAG,YAAY,MAAM;AAEnB,eAAW,YAAY,OAAO;AAC5B,YAAM,UAAU,QAAQ,SAAS,QAAQ;AACzC,UAAI;AACJ,UAAI;AACF,kBAAU,aAAa,SAAS,OAAO;AAAA,MACzC,QAAQ;AACN;AACA;AAAA,MACF;AAEA,YAAM,OAAO,YAAY,OAAO;AAChC,YAAM,eAAe,GAAG,YAAY,QAAQ;AAG5C,YAAM,SAAS,YAAY,OAAO;AAClC,UAAI,OAAO,QAAQ,SAAS,GAAG;AAC7B,oBAAY,IAAI,UAAU,OAAO,OAAO;AACxC,qBAAa,IAAI,UAAU,OAAO;AAAA,MACpC;AAEA,UAAI,iBAAiB,MAAM;AACzB;AAEA,mBAAW,OAAO,GAAG,iBAAiB,QAAQ,GAAG;AAC/C,sBAAY,IAAI,GAAG,QAAQ,IAAI,IAAI,IAAI,IAAI,IAAI,EAAG;AAAA,QACpD;AACA;AAAA,MACF;AAGA,SAAG,UAAU,QAAQ;AAErB,YAAM,MAAM,QAAQ,QAAQ;AAC5B,YAAM,WACJ,QAAQ,SAAS,QAAQ,SAAS,eAAe;AAEnD,SAAG,WAAW;AAAA,QACZ,MAAM;AAAA,QACN,cAAc;AAAA,QACd;AAAA,QACA,cAAc,KAAK,IAAI;AAAA,MACzB,CAAC;AAGD,SAAG,kBAAkB,UAAU,OAAO;AAEtC,iBAAW,OAAO,OAAO,SAAS;AAChC,cAAM,KAAK,GAAG,aAAa;AAAA,UACzB,WAAW;AAAA,UACX,MAAM,IAAI;AAAA,UACV,MAAM,IAAI;AAAA,UACV,YAAY,IAAI;AAAA,UAChB,UAAU,IAAI;AAAA,UACd,YAAY,IAAI;AAAA,UAChB,UAAU,IAAI;AAAA,UACd,cAAc,IAAI;AAAA,UAClB,YAAY,IAAI;AAAA,UAChB,WAAW,IAAI;AAAA,QACjB,CAAC;AACD,oBAAY,IAAI,GAAG,QAAQ,IAAI,IAAI,IAAI,IAAI,EAAE;AAC7C;AAAA,MACF;AAEA;AAAA,IACF;AAGA,OAAG,gBAAgB;AACnB,OAAG,mBAAmB;AAEtB,eAAW,CAAC,UAAU,OAAO,KAAK,aAAa;AAE7C,YAAM,iBAAiB,GAAG,iBAAiB,QAAQ;AACnD,YAAM,gBAAgB,eAAe,IAAI,CAAC,SAAS;AAAA,QACjD,MAAM,IAAI;AAAA,QACV,IAAI,IAAI;AAAA,QACR,WAAW,IAAI;AAAA,QACf,SAAS,IAAI;AAAA,MACf,EAAE;AAGF,YAAM,mBAAmB,oBAAI,IAAY;AACzC,iBAAW,OAAO,SAAS;AACzB,mBAAW,YAAY,IAAI,YAAY;AACrC,gBAAM,YAAY,SAAS,WAAW,OAAO,IACzC,SAAS,MAAM,CAAC,IAChB;AACJ,2BAAiB,IAAI,SAAS;AAAA,QAChC;AAAA,MACF;AAGA,YAAM,UAAU,aAAa,IAAI,QAAQ;AACzC,YAAM,SAAS,UACX,qBAAqB,SAAS,gBAAgB,IAC9C,CAAC;AAEL,iBAAW,OAAO,SAAS;AACzB,cAAM,aAAa;AAAA,UACjB,IAAI;AAAA,UACJ;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAGA,mBAAW,YAAY,IAAI,YAAY;AACrC,gBAAM,YAAY,SAAS,WAAW,OAAO,IACzC,SAAS,MAAM,CAAC,IAChB;AACJ,aAAG,aAAa;AAAA,YACd,WAAW;AAAA,YACX,WAAW;AAAA,YACX,aAAa;AAAA,YACb,YAAY,IAAI;AAAA,YAChB,cAAc,IAAI,aAAa,IAAI;AAAA,UACrC,CAAC;AACD;AAAA,QACF;AAEA,YAAI,CAAC,WAAY;AAEjB,cAAM,UAAU,IAAI,aAAa,aAAa;AAE9C,mBAAW,YAAY,IAAI,YAAY;AACrC,gBAAM,YAAY,SAAS,WAAW,OAAO,IACzC,SAAS,MAAM,CAAC,IAChB;AAEJ,gBAAM,YAAY,GAAG,UAAU,IAAI,SAAS;AAC5C,gBAAM,WAAW,YAAY,IAAI,SAAS;AAC1C,cAAI,CAAC,SAAU;AAGf,gBAAM,aAAa,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,SAAS;AAE5D,cAAI,WAAW,SAAS,GAAG;AAEzB,kBAAM,uBAAuB,oBAAI,IAAY;AAE7C,uBAAW,SAAS,YAAY;AAC9B,yBAAW,UAAU,eAAe;AAClC,oBACE,OAAO,OAAO,YACd,MAAM,QAAQ,OAAO,aACrB,MAAM,QAAQ,OAAO,SACrB;AACA,uCAAqB,IAAI,OAAO,EAAE;AAAA,gBACpC;AAAA,cACF;AAAA,YACF;AAEA,uBAAW,YAAY,sBAAsB;AAC3C,iBAAG,gBAAgB;AAAA,gBACjB,kBAAkB;AAAA,gBAClB,kBAAkB;AAAA,gBAClB,UAAU;AAAA,cACZ,CAAC;AACD;AAAA,YACF;AAAA,UACF,OAAO;AAIL,uBAAW,UAAU,eAAe;AAClC,kBAAI,OAAO,OAAO,UAAU;AAC1B,mBAAG,gBAAgB;AAAA,kBACjB,kBAAkB,OAAO;AAAA,kBACzB,kBAAkB;AAAA,kBAClB,UAAU;AAAA,gBACZ,CAAC;AACD;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AAED,KAAG,MAAM;AAET,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,KAAK,IAAI,IAAI;AAAA,EACvB;AACF;","names":["createRequire","require","source","decl","require","createRequire"]}
@@ -0,0 +1,24 @@
1
+ // src/root.ts
2
+ import { existsSync } from "fs";
3
+ import { resolve, dirname } from "path";
4
+ var ROOT_MARKERS = [".git", "package.json"];
5
+ function findProjectRoot(startDir) {
6
+ let dir = resolve(startDir);
7
+ while (true) {
8
+ for (const marker of ROOT_MARKERS) {
9
+ if (existsSync(resolve(dir, marker))) return dir;
10
+ }
11
+ const parent = dirname(dir);
12
+ if (parent === dir) return null;
13
+ dir = parent;
14
+ }
15
+ }
16
+ function resolveRoot(flagRoot) {
17
+ if (typeof flagRoot === "string" && flagRoot) return resolve(flagRoot);
18
+ return findProjectRoot(process.cwd()) ?? resolve(".");
19
+ }
20
+
21
+ export {
22
+ resolveRoot
23
+ };
24
+ //# sourceMappingURL=chunk-ZIVIJRW3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/root.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { resolve, dirname } from \"node:path\";\n\nconst ROOT_MARKERS = [\".git\", \"package.json\"] as const;\n\n/**\n * Walk up from `startDir` looking for a directory that contains a root\n * marker (`.git` directory or `package.json`). Returns the first match,\n * or `null` if the filesystem root is reached without finding one.\n *\n * `.git` is checked first so that in a monorepo the repository root wins\n * over a nested package.json.\n */\nexport function findProjectRoot(startDir: string): string | null {\n let dir = resolve(startDir);\n // eslint-disable-next-line no-constant-condition\n while (true) {\n for (const marker of ROOT_MARKERS) {\n if (existsSync(resolve(dir, marker))) return dir;\n }\n const parent = dirname(dir);\n if (parent === dir) return null; // filesystem root\n dir = parent;\n }\n}\n\n/**\n * Resolve the effective project root:\n * 1. Explicit `--root` flag (highest priority)\n * 2. Auto-detected via `.git` / `package.json` walk-up\n * 3. Current working directory (fallback)\n */\nexport function resolveRoot(flagRoot: string | boolean | undefined): string {\n if (typeof flagRoot === \"string\" && flagRoot) return resolve(flagRoot);\n return findProjectRoot(process.cwd()) ?? resolve(\".\");\n}\n"],"mappings":";AAAA,SAAS,kBAAkB;AAC3B,SAAS,SAAS,eAAe;AAEjC,IAAM,eAAe,CAAC,QAAQ,cAAc;AAUrC,SAAS,gBAAgB,UAAiC;AAC/D,MAAI,MAAM,QAAQ,QAAQ;AAE1B,SAAO,MAAM;AACX,eAAW,UAAU,cAAc;AACjC,UAAI,WAAW,QAAQ,KAAK,MAAM,CAAC,EAAG,QAAO;AAAA,IAC/C;AACA,UAAM,SAAS,QAAQ,GAAG;AAC1B,QAAI,WAAW,IAAK,QAAO;AAC3B,UAAM;AAAA,EACR;AACF;AAQO,SAAS,YAAY,UAAgD;AAC1E,MAAI,OAAO,aAAa,YAAY,SAAU,QAAO,QAAQ,QAAQ;AACrE,SAAO,gBAAgB,QAAQ,IAAI,CAAC,KAAK,QAAQ,GAAG;AACtD;","names":[]}
package/dist/cli.js CHANGED
@@ -91,7 +91,7 @@ async function main() {
91
91
  await runMap(positional, flags);
92
92
  },
93
93
  serve: async () => {
94
- const { runServe } = await import("./mcp-7WYTXIQS.js");
94
+ const { runServe } = await import("./mcp-3YW6JWHG.js");
95
95
  await runServe(positional, flags);
96
96
  },
97
97
  benchmark: async () => {
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ indexProject
4
+ } from "./chunk-X7DRJUEX.js";
2
5
  import {
3
6
  resolveRoot
4
7
  } from "./chunk-7RYHZOYF.js";
@@ -331,17 +334,41 @@ Usage with Claude Code:
331
334
  }
332
335
  const root = resolveRoot(flags.root);
333
336
  const dbPath = resolve(root, ".codefocus", "index.db");
334
- if (!existsSync(dbPath)) {
335
- console.error(
336
- `Error: no index found at ${dbPath}
337
- Run 'codefocus index --root ${root}' first.`
338
- );
337
+ if (!existsSync(root)) {
338
+ console.error(`Error: root directory does not exist: ${root}`);
339
339
  process.exitCode = 1;
340
340
  return;
341
341
  }
342
+ console.error(`[codefocus] Indexing ${root} ...`);
343
+ const stats = await indexProject(root, dbPath);
344
+ console.error(
345
+ `[codefocus] Index complete: ${stats.filesIndexed} files, ${stats.symbolsExtracted} symbols (${stats.timeMs}ms)`
346
+ );
342
347
  getDb(root);
343
348
  console.error(`[codefocus] MCP server starting (root: ${root})`);
344
349
  console.error(`[codefocus] Database: ${dbPath}`);
350
+ const { startWatcher } = await import("./watcher-LFBZAM5E.js");
351
+ const watcher = await startWatcher({
352
+ rootDir: root,
353
+ dbPath,
354
+ onReindex: (stats2) => {
355
+ if (stats2.filesIndexed > 0) {
356
+ if (db) {
357
+ db.close();
358
+ db = null;
359
+ }
360
+ getDb(root);
361
+ console.error(
362
+ `[codefocus] Re-indexed: ${stats2.filesIndexed} files, ${stats2.symbolsExtracted} symbols (${stats2.timeMs}ms)`
363
+ );
364
+ }
365
+ }
366
+ });
367
+ process.on("SIGINT", () => {
368
+ watcher.close();
369
+ if (db) db.close();
370
+ process.exit(0);
371
+ });
345
372
  const server = createMcpServer(root);
346
373
  const transport = new StdioServerTransport();
347
374
  await server.connect(transport);
@@ -351,4 +378,4 @@ export {
351
378
  createMcpServer,
352
379
  runServe
353
380
  };
354
- //# sourceMappingURL=mcp-7WYTXIQS.js.map
381
+ //# sourceMappingURL=mcp-3YW6JWHG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/mcp.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport { resolve } from \"node:path\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport { IndexDatabase } from \"./db.js\";\nimport { indexProject } from \"./indexer.js\";\nimport { resolveRoot } from \"./root.js\";\n\nconst require = createRequire(import.meta.url);\nconst pkg = require(\"../package.json\");\n\n// ── shared state ────────────────────────────────────────────────────────\n// The MCP server keeps the database connection and tiktoken encoder warm\n// so that subsequent tool calls pay ~10ms instead of ~400ms cold start.\n\nlet db: IndexDatabase | null = null;\nlet rootDir: string = \"\";\n\nfunction getDb(root: string): IndexDatabase {\n if (db && rootDir === root) return db;\n const dbPath = resolve(root, \".codefocus\", \"index.db\");\n if (!existsSync(dbPath)) {\n throw new Error(\n `no index found at ${dbPath}\\nRun 'codefocus index --root ${root}' first.`,\n );\n }\n if (db) db.close();\n db = new IndexDatabase(dbPath);\n rootDir = root;\n return db;\n}\n\n// ── MCP server setup ────────────────────────────────────────────────────\n\nexport function createMcpServer(defaultRoot?: string): McpServer {\n const server = new McpServer({\n name: \"codefocus\",\n version: pkg.version,\n });\n\n const effectiveRoot = defaultRoot ?? resolveRoot(undefined);\n\n // ── tool: query ─────────────────────────────────────────────────────\n\n server.tool(\n \"query\",\n \"Search the codebase and return ranked, budget-constrained code context. \" +\n \"Returns YAML front matter with confidence metadata followed by relevant source code sections.\",\n {\n term: z.string().describe(\"Search term (symbol name or keyword)\"),\n budget: z\n .number()\n .int()\n .positive()\n .default(8000)\n .describe(\"Token budget for output (default: 8000)\"),\n depth: z\n .number()\n .int()\n .min(0)\n .default(2)\n .describe(\"Max graph traversal depth (default: 2)\"),\n root: z\n .string()\n .optional()\n .describe(\"Root directory of indexed project\"),\n },\n async ({ term, budget, depth, root }) => {\n const r = root ?? effectiveRoot;\n // Import runQuery's internal logic so we can capture output\n const output = await captureQueryOutput(r, term, budget, depth);\n return { content: [{ type: \"text\" as const, text: output }] };\n },\n );\n\n // ── tool: find ──────────────────────────────────────────────────────\n\n server.tool(\n \"find\",\n \"Quick symbol lookup by name with optional kind filter. \" +\n \"Returns symbol names, kinds, file paths, and line numbers.\",\n {\n symbol: z.string().describe(\"Symbol name to search for\"),\n kind: z\n .enum([\n \"function\",\n \"class\",\n \"interface\",\n \"type\",\n \"enum\",\n \"variable\",\n \"method\",\n \"all\",\n ])\n .default(\"all\")\n .describe(\"Filter by symbol kind (default: all)\"),\n root: z\n .string()\n .optional()\n .describe(\"Root directory of indexed project\"),\n },\n async ({ symbol, kind, root }) => {\n const r = root ?? effectiveRoot;\n const database = getDb(r);\n const results = database.findSymbols(symbol, kind);\n\n if (results.length === 0) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `No symbols found matching \"${symbol}\"${kind !== \"all\" ? ` (kind: ${kind})` : \"\"}`,\n },\n ],\n };\n }\n\n const lines: string[] = [\n `Found ${results.length} symbol${results.length !== 1 ? \"s\" : \"\"} matching \"${symbol}\"${kind !== \"all\" ? ` (kind: ${kind})` : \"\"}:`,\n \"\",\n ];\n\n for (const sym of results) {\n const sig = sym.signature ? ` ${sym.signature}` : \"\";\n lines.push(\n ` ${sym.name} ${sym.kind} ${sym.file_path}:${sym.start_line}${sig}`,\n );\n }\n\n return { content: [{ type: \"text\" as const, text: lines.join(\"\\n\") }] };\n },\n );\n\n // ── tool: graph ─────────────────────────────────────────────────────\n\n server.tool(\n \"graph\",\n \"Show the dependency graph for a file or symbol. \" +\n \"Displays incoming and/or outgoing edges as an indented tree.\",\n {\n target: z\n .string()\n .describe(\"File path or symbol name to show graph for\"),\n direction: z\n .enum([\"both\", \"incoming\", \"outgoing\"])\n .default(\"both\")\n .describe(\"Graph direction (default: both)\"),\n root: z\n .string()\n .optional()\n .describe(\"Root directory of indexed project\"),\n },\n async ({ target, direction, root }) => {\n const r = root ?? effectiveRoot;\n const output = captureGraphOutput(r, target, direction);\n return { content: [{ type: \"text\" as const, text: output }] };\n },\n );\n\n // ── tool: map ───────────────────────────────────────────────────────\n\n server.tool(\n \"map\",\n \"High-level codebase overview ranked by PageRank connectivity. \" +\n \"Returns file paths with their top symbols and signatures.\",\n {\n budget: z\n .number()\n .int()\n .positive()\n .default(2000)\n .describe(\"Token budget for output (default: 2000)\"),\n root: z\n .string()\n .optional()\n .describe(\"Root directory of indexed project\"),\n },\n async ({ budget, root }) => {\n const r = root ?? effectiveRoot;\n const output = captureMapOutput(r, budget);\n return { content: [{ type: \"text\" as const, text: output }] };\n },\n );\n\n return server;\n}\n\n// ── output capture helpers ──────────────────────────────────────────────\n// These re-implement the command logic to return strings instead of\n// writing to stdout, keeping the database connection warm.\n\nasync function captureQueryOutput(\n root: string,\n term: string,\n budget: number,\n depth: number,\n): Promise<string> {\n const { runQueryCore } = await import(\"./commands/query.js\");\n return runQueryCore(root, term, budget, depth);\n}\n\nfunction captureGraphOutput(\n root: string,\n target: string,\n direction: \"both\" | \"incoming\" | \"outgoing\",\n): string {\n const database = getDb(root);\n\n const isFile =\n target.includes(\"/\") || target.includes(\"\\\\\") || /\\.\\w+$/.test(target);\n\n if (isFile) {\n return renderFileGraphToString(database, target, direction);\n } else {\n return renderSymbolGraphToString(database, target, direction);\n }\n}\n\nfunction renderFileGraphToString(\n database: IndexDatabase,\n target: string,\n direction: \"both\" | \"incoming\" | \"outgoing\",\n): string {\n const require = createRequire(import.meta.url);\n const { DirectedGraph } = require(\"graphology\");\n\n const graph = new DirectedGraph();\n for (const file of database.getAllFiles()) {\n graph.addNode(file.path);\n }\n for (const edge of database.getFileImportEdges()) {\n const key = `${edge.source_file}->${edge.target_file}`;\n if (graph.hasEdge(key)) {\n const existing = graph.getEdgeAttributes(key);\n graph.setEdgeAttribute(\n key,\n \"specifiers\",\n `${existing.specifiers}, ${edge.specifiers}`,\n );\n } else {\n graph.addEdgeWithKey(key, edge.source_file, edge.target_file, {\n specifiers: edge.specifiers,\n });\n }\n }\n\n if (!graph.hasNode(target)) {\n return `Error: file \"${target}\" not found in the index`;\n }\n\n const sections: string[] = [];\n\n if (direction === \"outgoing\" || direction === \"both\") {\n const outEdges: string[] = [];\n graph.forEachOutEdge(\n target,\n (\n _edge: string,\n attrs: { specifiers: string },\n _src: string,\n tgt: string,\n ) => {\n outEdges.push(` ${tgt} (imports: ${attrs.specifiers})`);\n },\n );\n sections.push(\n outEdges.length > 0\n ? `Dependencies (outgoing):\\n${outEdges.join(\"\\n\")}`\n : \"Dependencies (outgoing): (none)\",\n );\n }\n\n if (direction === \"incoming\" || direction === \"both\") {\n const inEdges: string[] = [];\n graph.forEachInEdge(\n target,\n (\n _edge: string,\n attrs: { specifiers: string },\n src: string,\n ) => {\n inEdges.push(` ${src} (imports: ${attrs.specifiers})`);\n },\n );\n sections.push(\n inEdges.length > 0\n ? `Dependents (incoming):\\n${inEdges.join(\"\\n\")}`\n : \"Dependents (incoming): (none)\",\n );\n }\n\n return `${target}\\n\\n${sections.join(\"\\n\\n\")}`;\n}\n\nfunction renderSymbolGraphToString(\n database: IndexDatabase,\n target: string,\n direction: \"both\" | \"incoming\" | \"outgoing\",\n): string {\n const symbols = database.findSymbolsByName(target);\n const exactMatch = symbols.find((s) => s.name === target);\n const sym = exactMatch ?? symbols[0];\n\n if (!sym || !sym.id) {\n return `Error: symbol \"${target}\" not found in the index`;\n }\n\n const heading = `${sym.name} (${sym.kind}) — ${sym.file_path}:${sym.start_line}`;\n const sections: string[] = [];\n\n if (direction === \"outgoing\" || direction === \"both\") {\n const refs = database.getOutgoingReferences(sym.id);\n const lines = refs.map(\n (r) =>\n ` ${r.target_name} (${r.target_kind}) — ${r.target_file}:${r.target_line} [${r.ref_type}]`,\n );\n sections.push(\n lines.length > 0\n ? `Dependencies (outgoing):\\n${lines.join(\"\\n\")}`\n : \"Dependencies (outgoing): (none)\",\n );\n }\n\n if (direction === \"incoming\" || direction === \"both\") {\n const refs = database.getIncomingReferences(sym.id);\n const lines = refs.map(\n (r) =>\n ` ${r.source_name} (${r.source_kind}) — ${r.source_file}:${r.source_line} [${r.ref_type}]`,\n );\n sections.push(\n lines.length > 0\n ? `Dependents (incoming):\\n${lines.join(\"\\n\")}`\n : \"Dependents (incoming): (none)\",\n );\n }\n\n return `${heading}\\n\\n${sections.join(\"\\n\\n\")}`;\n}\n\nfunction captureMapOutput(root: string, budget: number): string {\n const require = createRequire(import.meta.url);\n const { DirectedGraph } = require(\"graphology\");\n const pagerank = require(\"graphology-metrics/centrality/pagerank\");\n const { getEncoding } = require(\"js-tiktoken\");\n\n const database = getDb(root);\n const files = database.getAllFiles();\n\n if (files.length === 0) {\n return \"[map] Index is empty — no files to map.\";\n }\n\n // Compute PageRank\n const graph = new DirectedGraph();\n for (const file of files) {\n graph.addNode(file.path);\n }\n for (const edge of database.getFileImportEdges()) {\n const key = `${edge.source_file}->${edge.target_file}`;\n if (!graph.hasEdge(key)) {\n graph.addEdgeWithKey(key, edge.source_file, edge.target_file);\n }\n }\n const ranks: Record<string, number> =\n graph.order > 0 ? pagerank(graph, { getEdgeWeight: null }) : {};\n\n const rankedFiles = files\n .map((f) => ({ path: f.path, rank: ranks[f.path] ?? 0 }))\n .sort((a, b) => b.rank - a.rank || a.path.localeCompare(b.path));\n\n const enc = getEncoding(\"cl100k_base\");\n const blocks: string[] = [];\n let tokenCount = 0;\n let truncated = false;\n\n for (const file of rankedFiles) {\n const symbols = database.getSymbolsByFile(file.path);\n symbols.sort((a, b) => a.start_line - b.start_line);\n const lines: string[] = [file.path];\n for (const sym of symbols) {\n if (sym.kind === \"variable\" && !sym.signature) continue;\n const label = sym.signature ?? `${sym.kind} ${sym.name}`;\n lines.push(` ${label}`);\n }\n const block = lines.join(\"\\n\");\n const blockTokens = enc.encode(block).length;\n\n if (tokenCount + blockTokens <= budget) {\n blocks.push(block);\n tokenCount += blockTokens;\n continue;\n }\n\n const blockLines = block.split(\"\\n\");\n let partial = blockLines[0];\n let partialTokens = enc.encode(partial).length;\n\n if (tokenCount + partialTokens > budget) {\n truncated = true;\n break;\n }\n\n for (let i = 1; i < blockLines.length; i++) {\n const candidate = partial + \"\\n\" + blockLines[i];\n const candidateTokens = enc.encode(candidate).length;\n if (tokenCount + candidateTokens > budget) break;\n partial = candidate;\n partialTokens = candidateTokens;\n }\n\n blocks.push(partial);\n tokenCount += partialTokens;\n truncated = true;\n break;\n }\n\n const shown = blocks.length;\n const total = rankedFiles.length;\n const parts = [`[map] ${shown}/${total} files, ~${tokenCount} tokens`];\n if (truncated) {\n parts.push(`(budget: ${budget}, truncated)`);\n }\n\n return blocks.join(\"\\n\\n\") + `\\n\\n${parts.join(\" \")}`;\n}\n\n// ── serve command entry point ───────────────────────────────────────────\n\nexport async function runServe(\n _positional: string[],\n flags: Record<string, string | boolean>,\n): Promise<void> {\n if (flags.help) {\n console.error(`codefocus serve — Start MCP server (stdio transport)\n\nUsage: codefocus serve [options]\n\nOptions:\n --root <path> Root directory of indexed project (default: auto-detect)\n --help Show this help message\n\nThe MCP server exposes four tools:\n query Search and return ranked code context\n find Quick symbol lookup\n graph Show dependency graph for a file or symbol\n map High-level codebase overview\n\nThe server keeps the database connection and tiktoken encoder warm,\nso subsequent tool calls complete in ~10ms instead of ~400ms.\n\nUsage with Claude Code:\n Add to .mcp.json:\n {\n \"mcpServers\": {\n \"codefocus\": {\n \"command\": \"npx\",\n \"args\": [\"codefocus\", \"serve\", \"--root\", \"/path/to/project\"]\n }\n }\n }`);\n return;\n }\n\n const root = resolveRoot(flags.root);\n const dbPath = resolve(root, \".codefocus\", \"index.db\");\n\n if (!existsSync(root)) {\n console.error(`Error: root directory does not exist: ${root}`);\n process.exitCode = 1;\n return;\n }\n\n // Always re-index on startup to ensure freshness\n console.error(`[codefocus] Indexing ${root} ...`);\n const stats = await indexProject(root, dbPath);\n console.error(\n `[codefocus] Index complete: ${stats.filesIndexed} files, ${stats.symbolsExtracted} symbols (${stats.timeMs}ms)`,\n );\n\n // Pre-warm the database connection\n getDb(root);\n console.error(`[codefocus] MCP server starting (root: ${root})`);\n console.error(`[codefocus] Database: ${dbPath}`);\n\n // Start file watcher to keep the index fresh\n const { startWatcher } = await import(\"./watcher.js\");\n const watcher = await startWatcher({\n rootDir: root,\n dbPath,\n onReindex: (stats) => {\n if (stats.filesIndexed > 0) {\n // Close and re-open the DB so queries see the updated index\n if (db) {\n db.close();\n db = null;\n }\n getDb(root);\n console.error(\n `[codefocus] Re-indexed: ${stats.filesIndexed} files, ` +\n `${stats.symbolsExtracted} symbols (${stats.timeMs}ms)`,\n );\n }\n },\n });\n\n process.on(\"SIGINT\", () => {\n watcher.close();\n if (db) db.close();\n process.exit(0);\n });\n\n const server = createMcpServer(root);\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n console.error(`[codefocus] MCP server ready (4 tools: query, find, graph, map)`);\n}\n"],"mappings":"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","names":["require","stats"]}
@@ -1,8 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- IndexDatabase,
4
3
  resolveRoot
5
- } from "./chunk-ITVAEU6K.js";
4
+ } from "./chunk-ZIVIJRW3.js";
5
+ import {
6
+ indexProject
7
+ } from "./chunk-FQ3L6YEU.js";
8
+ import {
9
+ IndexDatabase
10
+ } from "./chunk-472RLVFC.js";
6
11
 
7
12
  // src/mcp.ts
8
13
  import { createRequire } from "module";
@@ -124,7 +129,7 @@ function createMcpServer(defaultRoot) {
124
129
  return server;
125
130
  }
126
131
  async function captureQueryOutput(root, term, budget, depth) {
127
- const { runQueryCore } = await import("./query-PS6QVPXP.js");
132
+ const { runQueryCore } = await import("./query-64CFCXTD.js");
128
133
  return runQueryCore(root, term, budget, depth);
129
134
  }
130
135
  function captureGraphOutput(root, target, direction) {
@@ -329,17 +334,41 @@ Usage with Claude Code:
329
334
  }
330
335
  const root = resolveRoot(flags2.root);
331
336
  const dbPath = resolve(root, ".codefocus", "index.db");
332
- if (!existsSync(dbPath)) {
333
- console.error(
334
- `Error: no index found at ${dbPath}
335
- Run 'codefocus index --root ${root}' first.`
336
- );
337
+ if (!existsSync(root)) {
338
+ console.error(`Error: root directory does not exist: ${root}`);
337
339
  process.exitCode = 1;
338
340
  return;
339
341
  }
342
+ console.error(`[codefocus] Indexing ${root} ...`);
343
+ const stats = await indexProject(root, dbPath);
344
+ console.error(
345
+ `[codefocus] Index complete: ${stats.filesIndexed} files, ${stats.symbolsExtracted} symbols (${stats.timeMs}ms)`
346
+ );
340
347
  getDb(root);
341
348
  console.error(`[codefocus] MCP server starting (root: ${root})`);
342
349
  console.error(`[codefocus] Database: ${dbPath}`);
350
+ const { startWatcher } = await import("./watcher-6WHIBMPS.js");
351
+ const watcher = await startWatcher({
352
+ rootDir: root,
353
+ dbPath,
354
+ onReindex: (stats2) => {
355
+ if (stats2.filesIndexed > 0) {
356
+ if (db) {
357
+ db.close();
358
+ db = null;
359
+ }
360
+ getDb(root);
361
+ console.error(
362
+ `[codefocus] Re-indexed: ${stats2.filesIndexed} files, ${stats2.symbolsExtracted} symbols (${stats2.timeMs}ms)`
363
+ );
364
+ }
365
+ }
366
+ });
367
+ process.on("SIGINT", () => {
368
+ watcher.close();
369
+ if (db) db.close();
370
+ process.exit(0);
371
+ });
343
372
  const server = createMcpServer(root);
344
373
  const transport = new StdioServerTransport();
345
374
  await server.connect(transport);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/mcp.ts","../src/mcp-entry.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport { resolve } from \"node:path\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport { IndexDatabase } from \"./db.js\";\nimport { resolveRoot } from \"./root.js\";\n\nconst require = createRequire(import.meta.url);\nconst pkg = require(\"../package.json\");\n\n// ── shared state ────────────────────────────────────────────────────────\n// The MCP server keeps the database connection and tiktoken encoder warm\n// so that subsequent tool calls pay ~10ms instead of ~400ms cold start.\n\nlet db: IndexDatabase | null = null;\nlet rootDir: string = \"\";\n\nfunction getDb(root: string): IndexDatabase {\n if (db && rootDir === root) return db;\n const dbPath = resolve(root, \".codefocus\", \"index.db\");\n if (!existsSync(dbPath)) {\n throw new Error(\n `no index found at ${dbPath}\\nRun 'codefocus index --root ${root}' first.`,\n );\n }\n if (db) db.close();\n db = new IndexDatabase(dbPath);\n rootDir = root;\n return db;\n}\n\n// ── MCP server setup ────────────────────────────────────────────────────\n\nexport function createMcpServer(defaultRoot?: string): McpServer {\n const server = new McpServer({\n name: \"codefocus\",\n version: pkg.version,\n });\n\n const effectiveRoot = defaultRoot ?? resolveRoot(undefined);\n\n // ── tool: query ─────────────────────────────────────────────────────\n\n server.tool(\n \"query\",\n \"Search the codebase and return ranked, budget-constrained code context. \" +\n \"Returns YAML front matter with confidence metadata followed by relevant source code sections.\",\n {\n term: z.string().describe(\"Search term (symbol name or keyword)\"),\n budget: z\n .number()\n .int()\n .positive()\n .default(8000)\n .describe(\"Token budget for output (default: 8000)\"),\n depth: z\n .number()\n .int()\n .min(0)\n .default(2)\n .describe(\"Max graph traversal depth (default: 2)\"),\n root: z\n .string()\n .optional()\n .describe(\"Root directory of indexed project\"),\n },\n async ({ term, budget, depth, root }) => {\n const r = root ?? effectiveRoot;\n // Import runQuery's internal logic so we can capture output\n const output = await captureQueryOutput(r, term, budget, depth);\n return { content: [{ type: \"text\" as const, text: output }] };\n },\n );\n\n // ── tool: find ──────────────────────────────────────────────────────\n\n server.tool(\n \"find\",\n \"Quick symbol lookup by name with optional kind filter. \" +\n \"Returns symbol names, kinds, file paths, and line numbers.\",\n {\n symbol: z.string().describe(\"Symbol name to search for\"),\n kind: z\n .enum([\n \"function\",\n \"class\",\n \"interface\",\n \"type\",\n \"enum\",\n \"variable\",\n \"method\",\n \"all\",\n ])\n .default(\"all\")\n .describe(\"Filter by symbol kind (default: all)\"),\n root: z\n .string()\n .optional()\n .describe(\"Root directory of indexed project\"),\n },\n async ({ symbol, kind, root }) => {\n const r = root ?? effectiveRoot;\n const database = getDb(r);\n const results = database.findSymbols(symbol, kind);\n\n if (results.length === 0) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `No symbols found matching \"${symbol}\"${kind !== \"all\" ? ` (kind: ${kind})` : \"\"}`,\n },\n ],\n };\n }\n\n const lines: string[] = [\n `Found ${results.length} symbol${results.length !== 1 ? \"s\" : \"\"} matching \"${symbol}\"${kind !== \"all\" ? ` (kind: ${kind})` : \"\"}:`,\n \"\",\n ];\n\n for (const sym of results) {\n const sig = sym.signature ? ` ${sym.signature}` : \"\";\n lines.push(\n ` ${sym.name} ${sym.kind} ${sym.file_path}:${sym.start_line}${sig}`,\n );\n }\n\n return { content: [{ type: \"text\" as const, text: lines.join(\"\\n\") }] };\n },\n );\n\n // ── tool: graph ─────────────────────────────────────────────────────\n\n server.tool(\n \"graph\",\n \"Show the dependency graph for a file or symbol. \" +\n \"Displays incoming and/or outgoing edges as an indented tree.\",\n {\n target: z\n .string()\n .describe(\"File path or symbol name to show graph for\"),\n direction: z\n .enum([\"both\", \"incoming\", \"outgoing\"])\n .default(\"both\")\n .describe(\"Graph direction (default: both)\"),\n root: z\n .string()\n .optional()\n .describe(\"Root directory of indexed project\"),\n },\n async ({ target, direction, root }) => {\n const r = root ?? effectiveRoot;\n const output = captureGraphOutput(r, target, direction);\n return { content: [{ type: \"text\" as const, text: output }] };\n },\n );\n\n // ── tool: map ───────────────────────────────────────────────────────\n\n server.tool(\n \"map\",\n \"High-level codebase overview ranked by PageRank connectivity. \" +\n \"Returns file paths with their top symbols and signatures.\",\n {\n budget: z\n .number()\n .int()\n .positive()\n .default(2000)\n .describe(\"Token budget for output (default: 2000)\"),\n root: z\n .string()\n .optional()\n .describe(\"Root directory of indexed project\"),\n },\n async ({ budget, root }) => {\n const r = root ?? effectiveRoot;\n const output = captureMapOutput(r, budget);\n return { content: [{ type: \"text\" as const, text: output }] };\n },\n );\n\n return server;\n}\n\n// ── output capture helpers ──────────────────────────────────────────────\n// These re-implement the command logic to return strings instead of\n// writing to stdout, keeping the database connection warm.\n\nasync function captureQueryOutput(\n root: string,\n term: string,\n budget: number,\n depth: number,\n): Promise<string> {\n const { runQueryCore } = await import(\"./commands/query.js\");\n return runQueryCore(root, term, budget, depth);\n}\n\nfunction captureGraphOutput(\n root: string,\n target: string,\n direction: \"both\" | \"incoming\" | \"outgoing\",\n): string {\n const database = getDb(root);\n\n const isFile =\n target.includes(\"/\") || target.includes(\"\\\\\") || /\\.\\w+$/.test(target);\n\n if (isFile) {\n return renderFileGraphToString(database, target, direction);\n } else {\n return renderSymbolGraphToString(database, target, direction);\n }\n}\n\nfunction renderFileGraphToString(\n database: IndexDatabase,\n target: string,\n direction: \"both\" | \"incoming\" | \"outgoing\",\n): string {\n const require = createRequire(import.meta.url);\n const { DirectedGraph } = require(\"graphology\");\n\n const graph = new DirectedGraph();\n for (const file of database.getAllFiles()) {\n graph.addNode(file.path);\n }\n for (const edge of database.getFileImportEdges()) {\n const key = `${edge.source_file}->${edge.target_file}`;\n if (graph.hasEdge(key)) {\n const existing = graph.getEdgeAttributes(key);\n graph.setEdgeAttribute(\n key,\n \"specifiers\",\n `${existing.specifiers}, ${edge.specifiers}`,\n );\n } else {\n graph.addEdgeWithKey(key, edge.source_file, edge.target_file, {\n specifiers: edge.specifiers,\n });\n }\n }\n\n if (!graph.hasNode(target)) {\n return `Error: file \"${target}\" not found in the index`;\n }\n\n const sections: string[] = [];\n\n if (direction === \"outgoing\" || direction === \"both\") {\n const outEdges: string[] = [];\n graph.forEachOutEdge(\n target,\n (\n _edge: string,\n attrs: { specifiers: string },\n _src: string,\n tgt: string,\n ) => {\n outEdges.push(` ${tgt} (imports: ${attrs.specifiers})`);\n },\n );\n sections.push(\n outEdges.length > 0\n ? `Dependencies (outgoing):\\n${outEdges.join(\"\\n\")}`\n : \"Dependencies (outgoing): (none)\",\n );\n }\n\n if (direction === \"incoming\" || direction === \"both\") {\n const inEdges: string[] = [];\n graph.forEachInEdge(\n target,\n (\n _edge: string,\n attrs: { specifiers: string },\n src: string,\n ) => {\n inEdges.push(` ${src} (imports: ${attrs.specifiers})`);\n },\n );\n sections.push(\n inEdges.length > 0\n ? `Dependents (incoming):\\n${inEdges.join(\"\\n\")}`\n : \"Dependents (incoming): (none)\",\n );\n }\n\n return `${target}\\n\\n${sections.join(\"\\n\\n\")}`;\n}\n\nfunction renderSymbolGraphToString(\n database: IndexDatabase,\n target: string,\n direction: \"both\" | \"incoming\" | \"outgoing\",\n): string {\n const symbols = database.findSymbolsByName(target);\n const exactMatch = symbols.find((s) => s.name === target);\n const sym = exactMatch ?? symbols[0];\n\n if (!sym || !sym.id) {\n return `Error: symbol \"${target}\" not found in the index`;\n }\n\n const heading = `${sym.name} (${sym.kind}) — ${sym.file_path}:${sym.start_line}`;\n const sections: string[] = [];\n\n if (direction === \"outgoing\" || direction === \"both\") {\n const refs = database.getOutgoingReferences(sym.id);\n const lines = refs.map(\n (r) =>\n ` ${r.target_name} (${r.target_kind}) — ${r.target_file}:${r.target_line} [${r.ref_type}]`,\n );\n sections.push(\n lines.length > 0\n ? `Dependencies (outgoing):\\n${lines.join(\"\\n\")}`\n : \"Dependencies (outgoing): (none)\",\n );\n }\n\n if (direction === \"incoming\" || direction === \"both\") {\n const refs = database.getIncomingReferences(sym.id);\n const lines = refs.map(\n (r) =>\n ` ${r.source_name} (${r.source_kind}) — ${r.source_file}:${r.source_line} [${r.ref_type}]`,\n );\n sections.push(\n lines.length > 0\n ? `Dependents (incoming):\\n${lines.join(\"\\n\")}`\n : \"Dependents (incoming): (none)\",\n );\n }\n\n return `${heading}\\n\\n${sections.join(\"\\n\\n\")}`;\n}\n\nfunction captureMapOutput(root: string, budget: number): string {\n const require = createRequire(import.meta.url);\n const { DirectedGraph } = require(\"graphology\");\n const pagerank = require(\"graphology-metrics/centrality/pagerank\");\n const { getEncoding } = require(\"js-tiktoken\");\n\n const database = getDb(root);\n const files = database.getAllFiles();\n\n if (files.length === 0) {\n return \"[map] Index is empty — no files to map.\";\n }\n\n // Compute PageRank\n const graph = new DirectedGraph();\n for (const file of files) {\n graph.addNode(file.path);\n }\n for (const edge of database.getFileImportEdges()) {\n const key = `${edge.source_file}->${edge.target_file}`;\n if (!graph.hasEdge(key)) {\n graph.addEdgeWithKey(key, edge.source_file, edge.target_file);\n }\n }\n const ranks: Record<string, number> =\n graph.order > 0 ? pagerank(graph, { getEdgeWeight: null }) : {};\n\n const rankedFiles = files\n .map((f) => ({ path: f.path, rank: ranks[f.path] ?? 0 }))\n .sort((a, b) => b.rank - a.rank || a.path.localeCompare(b.path));\n\n const enc = getEncoding(\"cl100k_base\");\n const blocks: string[] = [];\n let tokenCount = 0;\n let truncated = false;\n\n for (const file of rankedFiles) {\n const symbols = database.getSymbolsByFile(file.path);\n symbols.sort((a, b) => a.start_line - b.start_line);\n const lines: string[] = [file.path];\n for (const sym of symbols) {\n if (sym.kind === \"variable\" && !sym.signature) continue;\n const label = sym.signature ?? `${sym.kind} ${sym.name}`;\n lines.push(` ${label}`);\n }\n const block = lines.join(\"\\n\");\n const blockTokens = enc.encode(block).length;\n\n if (tokenCount + blockTokens <= budget) {\n blocks.push(block);\n tokenCount += blockTokens;\n continue;\n }\n\n const blockLines = block.split(\"\\n\");\n let partial = blockLines[0];\n let partialTokens = enc.encode(partial).length;\n\n if (tokenCount + partialTokens > budget) {\n truncated = true;\n break;\n }\n\n for (let i = 1; i < blockLines.length; i++) {\n const candidate = partial + \"\\n\" + blockLines[i];\n const candidateTokens = enc.encode(candidate).length;\n if (tokenCount + candidateTokens > budget) break;\n partial = candidate;\n partialTokens = candidateTokens;\n }\n\n blocks.push(partial);\n tokenCount += partialTokens;\n truncated = true;\n break;\n }\n\n const shown = blocks.length;\n const total = rankedFiles.length;\n const parts = [`[map] ${shown}/${total} files, ~${tokenCount} tokens`];\n if (truncated) {\n parts.push(`(budget: ${budget}, truncated)`);\n }\n\n return blocks.join(\"\\n\\n\") + `\\n\\n${parts.join(\" \")}`;\n}\n\n// ── serve command entry point ───────────────────────────────────────────\n\nexport async function runServe(\n _positional: string[],\n flags: Record<string, string | boolean>,\n): Promise<void> {\n if (flags.help) {\n console.error(`codefocus serve — Start MCP server (stdio transport)\n\nUsage: codefocus serve [options]\n\nOptions:\n --root <path> Root directory of indexed project (default: auto-detect)\n --help Show this help message\n\nThe MCP server exposes four tools:\n query Search and return ranked code context\n find Quick symbol lookup\n graph Show dependency graph for a file or symbol\n map High-level codebase overview\n\nThe server keeps the database connection and tiktoken encoder warm,\nso subsequent tool calls complete in ~10ms instead of ~400ms.\n\nUsage with Claude Code:\n Add to .mcp.json:\n {\n \"mcpServers\": {\n \"codefocus\": {\n \"command\": \"npx\",\n \"args\": [\"codefocus\", \"serve\", \"--root\", \"/path/to/project\"]\n }\n }\n }`);\n return;\n }\n\n const root = resolveRoot(flags.root);\n const dbPath = resolve(root, \".codefocus\", \"index.db\");\n\n if (!existsSync(dbPath)) {\n console.error(\n `Error: no index found at ${dbPath}\\nRun 'codefocus index --root ${root}' first.`,\n );\n process.exitCode = 1;\n return;\n }\n\n // Pre-warm the database connection\n getDb(root);\n console.error(`[codefocus] MCP server starting (root: ${root})`);\n console.error(`[codefocus] Database: ${dbPath}`);\n\n const server = createMcpServer(root);\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n console.error(`[codefocus] MCP server ready (4 tools: query, find, graph, map)`);\n}\n","#!/usr/bin/env node\n/**\n * Standalone MCP server entry point.\n * Can be used directly: node dist/mcp-server.js --root /path/to/project\n * Or via the CLI: codefocus serve --root /path/to/project\n */\nimport { runServe } from \"./mcp.js\";\n\nconst args = process.argv.slice(2);\nconst flags: Record<string, string | boolean> = {};\n\nfor (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg.startsWith(\"--\")) {\n const key = arg.slice(2);\n const next = args[i + 1];\n if (next && !next.startsWith(\"--\")) {\n flags[key] = next;\n i++;\n } else {\n flags[key] = true;\n }\n }\n}\n\nrunServe([], flags).catch((err) => {\n console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n});\n"],"mappings":"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","names":["require","flags"]}
1
+ {"version":3,"sources":["../src/mcp.ts","../src/mcp-entry.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport { resolve } from \"node:path\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport { IndexDatabase } from \"./db.js\";\nimport { indexProject } from \"./indexer.js\";\nimport { resolveRoot } from \"./root.js\";\n\nconst require = createRequire(import.meta.url);\nconst pkg = require(\"../package.json\");\n\n// ── shared state ────────────────────────────────────────────────────────\n// The MCP server keeps the database connection and tiktoken encoder warm\n// so that subsequent tool calls pay ~10ms instead of ~400ms cold start.\n\nlet db: IndexDatabase | null = null;\nlet rootDir: string = \"\";\n\nfunction getDb(root: string): IndexDatabase {\n if (db && rootDir === root) return db;\n const dbPath = resolve(root, \".codefocus\", \"index.db\");\n if (!existsSync(dbPath)) {\n throw new Error(\n `no index found at ${dbPath}\\nRun 'codefocus index --root ${root}' first.`,\n );\n }\n if (db) db.close();\n db = new IndexDatabase(dbPath);\n rootDir = root;\n return db;\n}\n\n// ── MCP server setup ────────────────────────────────────────────────────\n\nexport function createMcpServer(defaultRoot?: string): McpServer {\n const server = new McpServer({\n name: \"codefocus\",\n version: pkg.version,\n });\n\n const effectiveRoot = defaultRoot ?? resolveRoot(undefined);\n\n // ── tool: query ─────────────────────────────────────────────────────\n\n server.tool(\n \"query\",\n \"Search the codebase and return ranked, budget-constrained code context. \" +\n \"Returns YAML front matter with confidence metadata followed by relevant source code sections.\",\n {\n term: z.string().describe(\"Search term (symbol name or keyword)\"),\n budget: z\n .number()\n .int()\n .positive()\n .default(8000)\n .describe(\"Token budget for output (default: 8000)\"),\n depth: z\n .number()\n .int()\n .min(0)\n .default(2)\n .describe(\"Max graph traversal depth (default: 2)\"),\n root: z\n .string()\n .optional()\n .describe(\"Root directory of indexed project\"),\n },\n async ({ term, budget, depth, root }) => {\n const r = root ?? effectiveRoot;\n // Import runQuery's internal logic so we can capture output\n const output = await captureQueryOutput(r, term, budget, depth);\n return { content: [{ type: \"text\" as const, text: output }] };\n },\n );\n\n // ── tool: find ──────────────────────────────────────────────────────\n\n server.tool(\n \"find\",\n \"Quick symbol lookup by name with optional kind filter. \" +\n \"Returns symbol names, kinds, file paths, and line numbers.\",\n {\n symbol: z.string().describe(\"Symbol name to search for\"),\n kind: z\n .enum([\n \"function\",\n \"class\",\n \"interface\",\n \"type\",\n \"enum\",\n \"variable\",\n \"method\",\n \"all\",\n ])\n .default(\"all\")\n .describe(\"Filter by symbol kind (default: all)\"),\n root: z\n .string()\n .optional()\n .describe(\"Root directory of indexed project\"),\n },\n async ({ symbol, kind, root }) => {\n const r = root ?? effectiveRoot;\n const database = getDb(r);\n const results = database.findSymbols(symbol, kind);\n\n if (results.length === 0) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `No symbols found matching \"${symbol}\"${kind !== \"all\" ? ` (kind: ${kind})` : \"\"}`,\n },\n ],\n };\n }\n\n const lines: string[] = [\n `Found ${results.length} symbol${results.length !== 1 ? \"s\" : \"\"} matching \"${symbol}\"${kind !== \"all\" ? ` (kind: ${kind})` : \"\"}:`,\n \"\",\n ];\n\n for (const sym of results) {\n const sig = sym.signature ? ` ${sym.signature}` : \"\";\n lines.push(\n ` ${sym.name} ${sym.kind} ${sym.file_path}:${sym.start_line}${sig}`,\n );\n }\n\n return { content: [{ type: \"text\" as const, text: lines.join(\"\\n\") }] };\n },\n );\n\n // ── tool: graph ─────────────────────────────────────────────────────\n\n server.tool(\n \"graph\",\n \"Show the dependency graph for a file or symbol. \" +\n \"Displays incoming and/or outgoing edges as an indented tree.\",\n {\n target: z\n .string()\n .describe(\"File path or symbol name to show graph for\"),\n direction: z\n .enum([\"both\", \"incoming\", \"outgoing\"])\n .default(\"both\")\n .describe(\"Graph direction (default: both)\"),\n root: z\n .string()\n .optional()\n .describe(\"Root directory of indexed project\"),\n },\n async ({ target, direction, root }) => {\n const r = root ?? effectiveRoot;\n const output = captureGraphOutput(r, target, direction);\n return { content: [{ type: \"text\" as const, text: output }] };\n },\n );\n\n // ── tool: map ───────────────────────────────────────────────────────\n\n server.tool(\n \"map\",\n \"High-level codebase overview ranked by PageRank connectivity. \" +\n \"Returns file paths with their top symbols and signatures.\",\n {\n budget: z\n .number()\n .int()\n .positive()\n .default(2000)\n .describe(\"Token budget for output (default: 2000)\"),\n root: z\n .string()\n .optional()\n .describe(\"Root directory of indexed project\"),\n },\n async ({ budget, root }) => {\n const r = root ?? effectiveRoot;\n const output = captureMapOutput(r, budget);\n return { content: [{ type: \"text\" as const, text: output }] };\n },\n );\n\n return server;\n}\n\n// ── output capture helpers ──────────────────────────────────────────────\n// These re-implement the command logic to return strings instead of\n// writing to stdout, keeping the database connection warm.\n\nasync function captureQueryOutput(\n root: string,\n term: string,\n budget: number,\n depth: number,\n): Promise<string> {\n const { runQueryCore } = await import(\"./commands/query.js\");\n return runQueryCore(root, term, budget, depth);\n}\n\nfunction captureGraphOutput(\n root: string,\n target: string,\n direction: \"both\" | \"incoming\" | \"outgoing\",\n): string {\n const database = getDb(root);\n\n const isFile =\n target.includes(\"/\") || target.includes(\"\\\\\") || /\\.\\w+$/.test(target);\n\n if (isFile) {\n return renderFileGraphToString(database, target, direction);\n } else {\n return renderSymbolGraphToString(database, target, direction);\n }\n}\n\nfunction renderFileGraphToString(\n database: IndexDatabase,\n target: string,\n direction: \"both\" | \"incoming\" | \"outgoing\",\n): string {\n const require = createRequire(import.meta.url);\n const { DirectedGraph } = require(\"graphology\");\n\n const graph = new DirectedGraph();\n for (const file of database.getAllFiles()) {\n graph.addNode(file.path);\n }\n for (const edge of database.getFileImportEdges()) {\n const key = `${edge.source_file}->${edge.target_file}`;\n if (graph.hasEdge(key)) {\n const existing = graph.getEdgeAttributes(key);\n graph.setEdgeAttribute(\n key,\n \"specifiers\",\n `${existing.specifiers}, ${edge.specifiers}`,\n );\n } else {\n graph.addEdgeWithKey(key, edge.source_file, edge.target_file, {\n specifiers: edge.specifiers,\n });\n }\n }\n\n if (!graph.hasNode(target)) {\n return `Error: file \"${target}\" not found in the index`;\n }\n\n const sections: string[] = [];\n\n if (direction === \"outgoing\" || direction === \"both\") {\n const outEdges: string[] = [];\n graph.forEachOutEdge(\n target,\n (\n _edge: string,\n attrs: { specifiers: string },\n _src: string,\n tgt: string,\n ) => {\n outEdges.push(` ${tgt} (imports: ${attrs.specifiers})`);\n },\n );\n sections.push(\n outEdges.length > 0\n ? `Dependencies (outgoing):\\n${outEdges.join(\"\\n\")}`\n : \"Dependencies (outgoing): (none)\",\n );\n }\n\n if (direction === \"incoming\" || direction === \"both\") {\n const inEdges: string[] = [];\n graph.forEachInEdge(\n target,\n (\n _edge: string,\n attrs: { specifiers: string },\n src: string,\n ) => {\n inEdges.push(` ${src} (imports: ${attrs.specifiers})`);\n },\n );\n sections.push(\n inEdges.length > 0\n ? `Dependents (incoming):\\n${inEdges.join(\"\\n\")}`\n : \"Dependents (incoming): (none)\",\n );\n }\n\n return `${target}\\n\\n${sections.join(\"\\n\\n\")}`;\n}\n\nfunction renderSymbolGraphToString(\n database: IndexDatabase,\n target: string,\n direction: \"both\" | \"incoming\" | \"outgoing\",\n): string {\n const symbols = database.findSymbolsByName(target);\n const exactMatch = symbols.find((s) => s.name === target);\n const sym = exactMatch ?? symbols[0];\n\n if (!sym || !sym.id) {\n return `Error: symbol \"${target}\" not found in the index`;\n }\n\n const heading = `${sym.name} (${sym.kind}) — ${sym.file_path}:${sym.start_line}`;\n const sections: string[] = [];\n\n if (direction === \"outgoing\" || direction === \"both\") {\n const refs = database.getOutgoingReferences(sym.id);\n const lines = refs.map(\n (r) =>\n ` ${r.target_name} (${r.target_kind}) — ${r.target_file}:${r.target_line} [${r.ref_type}]`,\n );\n sections.push(\n lines.length > 0\n ? `Dependencies (outgoing):\\n${lines.join(\"\\n\")}`\n : \"Dependencies (outgoing): (none)\",\n );\n }\n\n if (direction === \"incoming\" || direction === \"both\") {\n const refs = database.getIncomingReferences(sym.id);\n const lines = refs.map(\n (r) =>\n ` ${r.source_name} (${r.source_kind}) — ${r.source_file}:${r.source_line} [${r.ref_type}]`,\n );\n sections.push(\n lines.length > 0\n ? `Dependents (incoming):\\n${lines.join(\"\\n\")}`\n : \"Dependents (incoming): (none)\",\n );\n }\n\n return `${heading}\\n\\n${sections.join(\"\\n\\n\")}`;\n}\n\nfunction captureMapOutput(root: string, budget: number): string {\n const require = createRequire(import.meta.url);\n const { DirectedGraph } = require(\"graphology\");\n const pagerank = require(\"graphology-metrics/centrality/pagerank\");\n const { getEncoding } = require(\"js-tiktoken\");\n\n const database = getDb(root);\n const files = database.getAllFiles();\n\n if (files.length === 0) {\n return \"[map] Index is empty — no files to map.\";\n }\n\n // Compute PageRank\n const graph = new DirectedGraph();\n for (const file of files) {\n graph.addNode(file.path);\n }\n for (const edge of database.getFileImportEdges()) {\n const key = `${edge.source_file}->${edge.target_file}`;\n if (!graph.hasEdge(key)) {\n graph.addEdgeWithKey(key, edge.source_file, edge.target_file);\n }\n }\n const ranks: Record<string, number> =\n graph.order > 0 ? pagerank(graph, { getEdgeWeight: null }) : {};\n\n const rankedFiles = files\n .map((f) => ({ path: f.path, rank: ranks[f.path] ?? 0 }))\n .sort((a, b) => b.rank - a.rank || a.path.localeCompare(b.path));\n\n const enc = getEncoding(\"cl100k_base\");\n const blocks: string[] = [];\n let tokenCount = 0;\n let truncated = false;\n\n for (const file of rankedFiles) {\n const symbols = database.getSymbolsByFile(file.path);\n symbols.sort((a, b) => a.start_line - b.start_line);\n const lines: string[] = [file.path];\n for (const sym of symbols) {\n if (sym.kind === \"variable\" && !sym.signature) continue;\n const label = sym.signature ?? `${sym.kind} ${sym.name}`;\n lines.push(` ${label}`);\n }\n const block = lines.join(\"\\n\");\n const blockTokens = enc.encode(block).length;\n\n if (tokenCount + blockTokens <= budget) {\n blocks.push(block);\n tokenCount += blockTokens;\n continue;\n }\n\n const blockLines = block.split(\"\\n\");\n let partial = blockLines[0];\n let partialTokens = enc.encode(partial).length;\n\n if (tokenCount + partialTokens > budget) {\n truncated = true;\n break;\n }\n\n for (let i = 1; i < blockLines.length; i++) {\n const candidate = partial + \"\\n\" + blockLines[i];\n const candidateTokens = enc.encode(candidate).length;\n if (tokenCount + candidateTokens > budget) break;\n partial = candidate;\n partialTokens = candidateTokens;\n }\n\n blocks.push(partial);\n tokenCount += partialTokens;\n truncated = true;\n break;\n }\n\n const shown = blocks.length;\n const total = rankedFiles.length;\n const parts = [`[map] ${shown}/${total} files, ~${tokenCount} tokens`];\n if (truncated) {\n parts.push(`(budget: ${budget}, truncated)`);\n }\n\n return blocks.join(\"\\n\\n\") + `\\n\\n${parts.join(\" \")}`;\n}\n\n// ── serve command entry point ───────────────────────────────────────────\n\nexport async function runServe(\n _positional: string[],\n flags: Record<string, string | boolean>,\n): Promise<void> {\n if (flags.help) {\n console.error(`codefocus serve — Start MCP server (stdio transport)\n\nUsage: codefocus serve [options]\n\nOptions:\n --root <path> Root directory of indexed project (default: auto-detect)\n --help Show this help message\n\nThe MCP server exposes four tools:\n query Search and return ranked code context\n find Quick symbol lookup\n graph Show dependency graph for a file or symbol\n map High-level codebase overview\n\nThe server keeps the database connection and tiktoken encoder warm,\nso subsequent tool calls complete in ~10ms instead of ~400ms.\n\nUsage with Claude Code:\n Add to .mcp.json:\n {\n \"mcpServers\": {\n \"codefocus\": {\n \"command\": \"npx\",\n \"args\": [\"codefocus\", \"serve\", \"--root\", \"/path/to/project\"]\n }\n }\n }`);\n return;\n }\n\n const root = resolveRoot(flags.root);\n const dbPath = resolve(root, \".codefocus\", \"index.db\");\n\n if (!existsSync(root)) {\n console.error(`Error: root directory does not exist: ${root}`);\n process.exitCode = 1;\n return;\n }\n\n // Always re-index on startup to ensure freshness\n console.error(`[codefocus] Indexing ${root} ...`);\n const stats = await indexProject(root, dbPath);\n console.error(\n `[codefocus] Index complete: ${stats.filesIndexed} files, ${stats.symbolsExtracted} symbols (${stats.timeMs}ms)`,\n );\n\n // Pre-warm the database connection\n getDb(root);\n console.error(`[codefocus] MCP server starting (root: ${root})`);\n console.error(`[codefocus] Database: ${dbPath}`);\n\n // Start file watcher to keep the index fresh\n const { startWatcher } = await import(\"./watcher.js\");\n const watcher = await startWatcher({\n rootDir: root,\n dbPath,\n onReindex: (stats) => {\n if (stats.filesIndexed > 0) {\n // Close and re-open the DB so queries see the updated index\n if (db) {\n db.close();\n db = null;\n }\n getDb(root);\n console.error(\n `[codefocus] Re-indexed: ${stats.filesIndexed} files, ` +\n `${stats.symbolsExtracted} symbols (${stats.timeMs}ms)`,\n );\n }\n },\n });\n\n process.on(\"SIGINT\", () => {\n watcher.close();\n if (db) db.close();\n process.exit(0);\n });\n\n const server = createMcpServer(root);\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n console.error(`[codefocus] MCP server ready (4 tools: query, find, graph, map)`);\n}\n","#!/usr/bin/env node\n/**\n * Standalone MCP server entry point.\n * Can be used directly: node dist/mcp-server.js --root /path/to/project\n * Or via the CLI: codefocus serve --root /path/to/project\n */\nimport { runServe } from \"./mcp.js\";\n\nconst args = process.argv.slice(2);\nconst flags: Record<string, string | boolean> = {};\n\nfor (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg.startsWith(\"--\")) {\n const key = arg.slice(2);\n const next = args[i + 1];\n if (next && !next.startsWith(\"--\")) {\n flags[key] = next;\n i++;\n } else {\n flags[key] = true;\n }\n }\n}\n\nrunServe([], flags).catch((err) => {\n console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n});\n"],"mappings":"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","names":["require","flags","stats"]}
@@ -1,7 +1,9 @@
1
1
  import {
2
- IndexDatabase,
3
2
  resolveRoot
4
- } from "./chunk-ITVAEU6K.js";
3
+ } from "./chunk-ZIVIJRW3.js";
4
+ import {
5
+ IndexDatabase
6
+ } from "./chunk-472RLVFC.js";
5
7
 
6
8
  // src/commands/query.ts
7
9
  import { createRequire } from "module";
@@ -535,4 +537,4 @@ export {
535
537
  runQuery,
536
538
  runQueryCore
537
539
  };
538
- //# sourceMappingURL=query-PS6QVPXP.js.map
540
+ //# sourceMappingURL=query-64CFCXTD.js.map