sdl-mcp 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +132 -0
- package/config/benchmark.ci.config.json +86 -0
- package/config/benchmark.ci.windows.config.json +86 -0
- package/config/benchmark.config.example.json +86 -0
- package/config/benchmark.config.json +86 -0
- package/config/sdlmcp.config.example.json +139 -0
- package/config/sdlmcp.config.json +48 -0
- package/config/sdlmcp.config.schema.json +381 -0
- package/dist/agent/evidence.d.ts +18 -0
- package/dist/agent/evidence.d.ts.map +1 -0
- package/dist/agent/evidence.js +107 -0
- package/dist/agent/evidence.js.map +1 -0
- package/dist/agent/executor.d.ts +28 -0
- package/dist/agent/executor.d.ts.map +1 -0
- package/dist/agent/executor.js +261 -0
- package/dist/agent/executor.js.map +1 -0
- package/dist/agent/index.d.ts +6 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +6 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/orchestrator.d.ts +14 -0
- package/dist/agent/orchestrator.d.ts.map +1 -0
- package/dist/agent/orchestrator.js +108 -0
- package/dist/agent/orchestrator.js.map +1 -0
- package/dist/agent/planner.d.ts +21 -0
- package/dist/agent/planner.d.ts.map +1 -0
- package/dist/agent/planner.js +153 -0
- package/dist/agent/planner.js.map +1 -0
- package/dist/agent/types.d.ts +86 -0
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent/types.js +2 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/benchmark/index.d.ts +4 -0
- package/dist/benchmark/index.d.ts.map +1 -0
- package/dist/benchmark/index.js +4 -0
- package/dist/benchmark/index.js.map +1 -0
- package/dist/benchmark/regression.d.ts +40 -0
- package/dist/benchmark/regression.d.ts.map +1 -0
- package/dist/benchmark/regression.js +199 -0
- package/dist/benchmark/regression.js.map +1 -0
- package/dist/benchmark/smoothing.d.ts +40 -0
- package/dist/benchmark/smoothing.d.ts.map +1 -0
- package/dist/benchmark/smoothing.js +121 -0
- package/dist/benchmark/smoothing.js.map +1 -0
- package/dist/benchmark/threshold.d.ts +64 -0
- package/dist/benchmark/threshold.d.ts.map +1 -0
- package/dist/benchmark/threshold.js +173 -0
- package/dist/benchmark/threshold.js.map +1 -0
- package/dist/cli/argParsing.d.ts +34 -0
- package/dist/cli/argParsing.d.ts.map +1 -0
- package/dist/cli/argParsing.js +329 -0
- package/dist/cli/argParsing.js.map +1 -0
- package/dist/cli/commands/benchmark.d.ts +16 -0
- package/dist/cli/commands/benchmark.d.ts.map +1 -0
- package/dist/cli/commands/benchmark.js +412 -0
- package/dist/cli/commands/benchmark.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +3 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +218 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/export.d.ts +12 -0
- package/dist/cli/commands/export.d.ts.map +1 -0
- package/dist/cli/commands/export.js +70 -0
- package/dist/cli/commands/export.js.map +1 -0
- package/dist/cli/commands/import.d.ts +10 -0
- package/dist/cli/commands/import.d.ts.map +1 -0
- package/dist/cli/commands/import.js +40 -0
- package/dist/cli/commands/import.js.map +1 -0
- package/dist/cli/commands/index.d.ts +3 -0
- package/dist/cli/commands/index.d.ts.map +1 -0
- package/dist/cli/commands/index.js +89 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/init.d.ts +3 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +221 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/pull.d.ts +11 -0
- package/dist/cli/commands/pull.d.ts.map +1 -0
- package/dist/cli/commands/pull.js +47 -0
- package/dist/cli/commands/pull.js.map +1 -0
- package/dist/cli/commands/serve.d.ts +3 -0
- package/dist/cli/commands/serve.d.ts.map +1 -0
- package/dist/cli/commands/serve.js +72 -0
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/commands/version.d.ts +3 -0
- package/dist/cli/commands/version.d.ts.map +1 -0
- package/dist/cli/commands/version.js +24 -0
- package/dist/cli/commands/version.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +213 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/logging.d.ts +10 -0
- package/dist/cli/logging.d.ts.map +1 -0
- package/dist/cli/logging.js +48 -0
- package/dist/cli/logging.js.map +1 -0
- package/dist/cli/transport/http.d.ts +3 -0
- package/dist/cli/transport/http.d.ts.map +1 -0
- package/dist/cli/transport/http.js +106 -0
- package/dist/cli/transport/http.js.map +1 -0
- package/dist/cli/transport/stdio.d.ts +3 -0
- package/dist/cli/transport/stdio.d.ts.map +1 -0
- package/dist/cli/transport/stdio.js +6 -0
- package/dist/cli/transport/stdio.js.map +1 -0
- package/dist/cli/types.d.ts +41 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +2 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/code/gate.d.ts +11 -0
- package/dist/code/gate.d.ts.map +1 -0
- package/dist/code/gate.js +134 -0
- package/dist/code/gate.js.map +1 -0
- package/dist/code/hotpath.d.ts +17 -0
- package/dist/code/hotpath.d.ts.map +1 -0
- package/dist/code/hotpath.js +200 -0
- package/dist/code/hotpath.js.map +1 -0
- package/dist/code/redact.d.ts +19 -0
- package/dist/code/redact.d.ts.map +1 -0
- package/dist/code/redact.js +92 -0
- package/dist/code/redact.js.map +1 -0
- package/dist/code/skeleton.d.ts +32 -0
- package/dist/code/skeleton.d.ts.map +1 -0
- package/dist/code/skeleton.js +610 -0
- package/dist/code/skeleton.js.map +1 -0
- package/dist/code/windows.d.ts +18 -0
- package/dist/code/windows.d.ts.map +1 -0
- package/dist/code/windows.js +236 -0
- package/dist/code/windows.js.map +1 -0
- package/dist/config/constants.d.ts +340 -0
- package/dist/config/constants.d.ts.map +1 -0
- package/dist/config/constants.js +379 -0
- package/dist/config/constants.js.map +1 -0
- package/dist/config/loadConfig.d.ts +3 -0
- package/dist/config/loadConfig.d.ts.map +1 -0
- package/dist/config/loadConfig.js +71 -0
- package/dist/config/loadConfig.js.map +1 -0
- package/dist/config/types.d.ts +509 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +139 -0
- package/dist/config/types.js.map +1 -0
- package/dist/db/db.d.ts +4 -0
- package/dist/db/db.d.ts.map +1 -0
- package/dist/db/db.js +47 -0
- package/dist/db/db.js.map +1 -0
- package/dist/db/migrations.d.ts +15 -0
- package/dist/db/migrations.d.ts.map +1 -0
- package/dist/db/migrations.js +81 -0
- package/dist/db/migrations.js.map +1 -0
- package/dist/db/queries.d.ts +440 -0
- package/dist/db/queries.d.ts.map +1 -0
- package/dist/db/queries.js +1054 -0
- package/dist/db/queries.js.map +1 -0
- package/dist/db/schema.d.ts +132 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +2 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/delta/blastRadius.d.ts +24 -0
- package/dist/delta/blastRadius.d.ts.map +1 -0
- package/dist/delta/blastRadius.js +239 -0
- package/dist/delta/blastRadius.js.map +1 -0
- package/dist/delta/diff.d.ts +16 -0
- package/dist/delta/diff.d.ts.map +1 -0
- package/dist/delta/diff.js +236 -0
- package/dist/delta/diff.js.map +1 -0
- package/dist/delta/versioning.d.ts +11 -0
- package/dist/delta/versioning.d.ts.map +1 -0
- package/dist/delta/versioning.js +68 -0
- package/dist/delta/versioning.js.map +1 -0
- package/dist/graph/buildGraph.d.ts +12 -0
- package/dist/graph/buildGraph.d.ts.map +1 -0
- package/dist/graph/buildGraph.js +81 -0
- package/dist/graph/buildGraph.js.map +1 -0
- package/dist/graph/cache.d.ts +111 -0
- package/dist/graph/cache.d.ts.map +1 -0
- package/dist/graph/cache.js +237 -0
- package/dist/graph/cache.js.map +1 -0
- package/dist/graph/metrics.d.ts +12 -0
- package/dist/graph/metrics.d.ts.map +1 -0
- package/dist/graph/metrics.js +253 -0
- package/dist/graph/metrics.js.map +1 -0
- package/dist/graph/minHeap.d.ts +91 -0
- package/dist/graph/minHeap.d.ts.map +1 -0
- package/dist/graph/minHeap.js +159 -0
- package/dist/graph/minHeap.js.map +1 -0
- package/dist/graph/overview.d.ts +22 -0
- package/dist/graph/overview.d.ts.map +1 -0
- package/dist/graph/overview.js +379 -0
- package/dist/graph/overview.js.map +1 -0
- package/dist/graph/score.d.ts +27 -0
- package/dist/graph/score.d.ts.map +1 -0
- package/dist/graph/score.js +214 -0
- package/dist/graph/score.js.map +1 -0
- package/dist/graph/slice.d.ts +51 -0
- package/dist/graph/slice.d.ts.map +1 -0
- package/dist/graph/slice.js +1047 -0
- package/dist/graph/slice.js.map +1 -0
- package/dist/graph/sliceCache.d.ts +33 -0
- package/dist/graph/sliceCache.d.ts.map +1 -0
- package/dist/graph/sliceCache.js +140 -0
- package/dist/graph/sliceCache.js.map +1 -0
- package/dist/indexer/adapter/BaseAdapter.d.ts +29 -0
- package/dist/indexer/adapter/BaseAdapter.d.ts.map +1 -0
- package/dist/indexer/adapter/BaseAdapter.js +97 -0
- package/dist/indexer/adapter/BaseAdapter.js.map +1 -0
- package/dist/indexer/adapter/LanguageAdapter.d.ts +20 -0
- package/dist/indexer/adapter/LanguageAdapter.d.ts.map +1 -0
- package/dist/indexer/adapter/LanguageAdapter.js +2 -0
- package/dist/indexer/adapter/LanguageAdapter.js.map +1 -0
- package/dist/indexer/adapter/adapters.d.ts +57 -0
- package/dist/indexer/adapter/adapters.d.ts.map +1 -0
- package/dist/indexer/adapter/adapters.js +129 -0
- package/dist/indexer/adapter/adapters.js.map +1 -0
- package/dist/indexer/adapter/c.d.ts +18 -0
- package/dist/indexer/adapter/c.d.ts.map +1 -0
- package/dist/indexer/adapter/c.js +443 -0
- package/dist/indexer/adapter/c.js.map +1 -0
- package/dist/indexer/adapter/cpp.d.ts +18 -0
- package/dist/indexer/adapter/cpp.d.ts.map +1 -0
- package/dist/indexer/adapter/cpp.js +493 -0
- package/dist/indexer/adapter/cpp.js.map +1 -0
- package/dist/indexer/adapter/csharp.d.ts +48 -0
- package/dist/indexer/adapter/csharp.d.ts.map +1 -0
- package/dist/indexer/adapter/csharp.js +638 -0
- package/dist/indexer/adapter/csharp.js.map +1 -0
- package/dist/indexer/adapter/go.d.ts +14 -0
- package/dist/indexer/adapter/go.d.ts.map +1 -0
- package/dist/indexer/adapter/go.js +400 -0
- package/dist/indexer/adapter/go.js.map +1 -0
- package/dist/indexer/adapter/index.d.ts +14 -0
- package/dist/indexer/adapter/index.d.ts.map +1 -0
- package/dist/indexer/adapter/index.js +13 -0
- package/dist/indexer/adapter/index.js.map +1 -0
- package/dist/indexer/adapter/java.d.ts +14 -0
- package/dist/indexer/adapter/java.d.ts.map +1 -0
- package/dist/indexer/adapter/java.js +391 -0
- package/dist/indexer/adapter/java.js.map +1 -0
- package/dist/indexer/adapter/kotlin.d.ts +18 -0
- package/dist/indexer/adapter/kotlin.d.ts.map +1 -0
- package/dist/indexer/adapter/kotlin.js +599 -0
- package/dist/indexer/adapter/kotlin.js.map +1 -0
- package/dist/indexer/adapter/php.d.ts +18 -0
- package/dist/indexer/adapter/php.d.ts.map +1 -0
- package/dist/indexer/adapter/php.js +574 -0
- package/dist/indexer/adapter/php.js.map +1 -0
- package/dist/indexer/adapter/plugin/index.d.ts +3 -0
- package/dist/indexer/adapter/plugin/index.d.ts.map +1 -0
- package/dist/indexer/adapter/plugin/index.js +3 -0
- package/dist/indexer/adapter/plugin/index.js.map +1 -0
- package/dist/indexer/adapter/plugin/loader.d.ts +13 -0
- package/dist/indexer/adapter/plugin/loader.d.ts.map +1 -0
- package/dist/indexer/adapter/plugin/loader.js +154 -0
- package/dist/indexer/adapter/plugin/loader.js.map +1 -0
- package/dist/indexer/adapter/plugin/types.d.ts +76 -0
- package/dist/indexer/adapter/plugin/types.d.ts.map +1 -0
- package/dist/indexer/adapter/plugin/types.js +47 -0
- package/dist/indexer/adapter/plugin/types.js.map +1 -0
- package/dist/indexer/adapter/python.d.ts +14 -0
- package/dist/indexer/adapter/python.d.ts.map +1 -0
- package/dist/indexer/adapter/python.js +511 -0
- package/dist/indexer/adapter/python.js.map +1 -0
- package/dist/indexer/adapter/registry.d.ts +17 -0
- package/dist/indexer/adapter/registry.d.ts.map +1 -0
- package/dist/indexer/adapter/registry.js +134 -0
- package/dist/indexer/adapter/registry.js.map +1 -0
- package/dist/indexer/adapter/rust.d.ts +18 -0
- package/dist/indexer/adapter/rust.d.ts.map +1 -0
- package/dist/indexer/adapter/rust.js +709 -0
- package/dist/indexer/adapter/rust.js.map +1 -0
- package/dist/indexer/adapter/shell.d.ts +18 -0
- package/dist/indexer/adapter/shell.d.ts.map +1 -0
- package/dist/indexer/adapter/shell.js +345 -0
- package/dist/indexer/adapter/shell.js.map +1 -0
- package/dist/indexer/adapter/typescript.d.ts +14 -0
- package/dist/indexer/adapter/typescript.d.ts.map +1 -0
- package/dist/indexer/adapter/typescript.js +31 -0
- package/dist/indexer/adapter/typescript.js.map +1 -0
- package/dist/indexer/configEdges.d.ts +30 -0
- package/dist/indexer/configEdges.d.ts.map +1 -0
- package/dist/indexer/configEdges.js +260 -0
- package/dist/indexer/configEdges.js.map +1 -0
- package/dist/indexer/fileScanner.d.ts +16 -0
- package/dist/indexer/fileScanner.d.ts.map +1 -0
- package/dist/indexer/fileScanner.js +90 -0
- package/dist/indexer/fileScanner.js.map +1 -0
- package/dist/indexer/fingerprints.d.ts +23 -0
- package/dist/indexer/fingerprints.d.ts.map +1 -0
- package/dist/indexer/fingerprints.js +97 -0
- package/dist/indexer/fingerprints.js.map +1 -0
- package/dist/indexer/indexer.d.ts +58 -0
- package/dist/indexer/indexer.d.ts.map +1 -0
- package/dist/indexer/indexer.js +1229 -0
- package/dist/indexer/indexer.js.map +1 -0
- package/dist/indexer/summaries.d.ts +5 -0
- package/dist/indexer/summaries.d.ts.map +1 -0
- package/dist/indexer/summaries.js +331 -0
- package/dist/indexer/summaries.js.map +1 -0
- package/dist/indexer/treesitter/extractCalls.d.ts +40 -0
- package/dist/indexer/treesitter/extractCalls.d.ts.map +1 -0
- package/dist/indexer/treesitter/extractCalls.js +561 -0
- package/dist/indexer/treesitter/extractCalls.js.map +1 -0
- package/dist/indexer/treesitter/extractImports.d.ts +12 -0
- package/dist/indexer/treesitter/extractImports.d.ts.map +1 -0
- package/dist/indexer/treesitter/extractImports.js +184 -0
- package/dist/indexer/treesitter/extractImports.js.map +1 -0
- package/dist/indexer/treesitter/extractSymbols.d.ts +24 -0
- package/dist/indexer/treesitter/extractSymbols.d.ts.map +1 -0
- package/dist/indexer/treesitter/extractSymbols.js +389 -0
- package/dist/indexer/treesitter/extractSymbols.js.map +1 -0
- package/dist/indexer/treesitter/grammarLoader.d.ts +6 -0
- package/dist/indexer/treesitter/grammarLoader.d.ts.map +1 -0
- package/dist/indexer/treesitter/grammarLoader.js +125 -0
- package/dist/indexer/treesitter/grammarLoader.js.map +1 -0
- package/dist/indexer/treesitter/symbolUtils.d.ts +4 -0
- package/dist/indexer/treesitter/symbolUtils.d.ts.map +1 -0
- package/dist/indexer/treesitter/symbolUtils.js +26 -0
- package/dist/indexer/treesitter/symbolUtils.js.map +1 -0
- package/dist/indexer/treesitter/tsTreesitter.d.ts +9 -0
- package/dist/indexer/treesitter/tsTreesitter.d.ts.map +1 -0
- package/dist/indexer/treesitter/tsTreesitter.js +54 -0
- package/dist/indexer/treesitter/tsTreesitter.js.map +1 -0
- package/dist/indexer/treesitter/types.d.ts +19 -0
- package/dist/indexer/treesitter/types.d.ts.map +1 -0
- package/dist/indexer/treesitter/types.js +7 -0
- package/dist/indexer/treesitter/types.js.map +1 -0
- package/dist/indexer/ts/tsParser.d.ts +20 -0
- package/dist/indexer/ts/tsParser.d.ts.map +1 -0
- package/dist/indexer/ts/tsParser.js +114 -0
- package/dist/indexer/ts/tsParser.js.map +1 -0
- package/dist/indexer/worker.d.ts +2 -0
- package/dist/indexer/worker.d.ts.map +1 -0
- package/dist/indexer/worker.js +59 -0
- package/dist/indexer/worker.js.map +1 -0
- package/dist/indexer/workerPool.d.ts +20 -0
- package/dist/indexer/workerPool.d.ts.map +1 -0
- package/dist/indexer/workerPool.js +93 -0
- package/dist/indexer/workerPool.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +111 -0
- package/dist/main.js.map +1 -0
- package/dist/mcp/errors.d.ts +40 -0
- package/dist/mcp/errors.d.ts.map +1 -0
- package/dist/mcp/errors.js +66 -0
- package/dist/mcp/errors.js.map +1 -0
- package/dist/mcp/resources.d.ts +24 -0
- package/dist/mcp/resources.d.ts.map +1 -0
- package/dist/mcp/resources.js +140 -0
- package/dist/mcp/resources.js.map +1 -0
- package/dist/mcp/telemetry.d.ts +67 -0
- package/dist/mcp/telemetry.d.ts.map +1 -0
- package/dist/mcp/telemetry.js +128 -0
- package/dist/mcp/telemetry.js.map +1 -0
- package/dist/mcp/tools/agent.d.ts +241 -0
- package/dist/mcp/tools/agent.d.ts.map +1 -0
- package/dist/mcp/tools/agent.js +113 -0
- package/dist/mcp/tools/agent.js.map +1 -0
- package/dist/mcp/tools/code.d.ts +32 -0
- package/dist/mcp/tools/code.d.ts.map +1 -0
- package/dist/mcp/tools/code.js +388 -0
- package/dist/mcp/tools/code.js.map +1 -0
- package/dist/mcp/tools/delta.d.ts +12 -0
- package/dist/mcp/tools/delta.d.ts.map +1 -0
- package/dist/mcp/tools/delta.js +82 -0
- package/dist/mcp/tools/delta.js.map +1 -0
- package/dist/mcp/tools/index.d.ts +3 -0
- package/dist/mcp/tools/index.d.ts.map +1 -0
- package/dist/mcp/tools/index.js +35 -0
- package/dist/mcp/tools/index.js.map +1 -0
- package/dist/mcp/tools/policy.d.ts +20 -0
- package/dist/mcp/tools/policy.d.ts.map +1 -0
- package/dist/mcp/tools/policy.js +67 -0
- package/dist/mcp/tools/policy.js.map +1 -0
- package/dist/mcp/tools/prRisk.d.ts +34 -0
- package/dist/mcp/tools/prRisk.d.ts.map +1 -0
- package/dist/mcp/tools/prRisk.js +304 -0
- package/dist/mcp/tools/prRisk.js.map +1 -0
- package/dist/mcp/tools/repo.d.ts +46 -0
- package/dist/mcp/tools/repo.d.ts.map +1 -0
- package/dist/mcp/tools/repo.js +224 -0
- package/dist/mcp/tools/repo.js.map +1 -0
- package/dist/mcp/tools/slice.d.ts +44 -0
- package/dist/mcp/tools/slice.d.ts.map +1 -0
- package/dist/mcp/tools/slice.js +688 -0
- package/dist/mcp/tools/slice.js.map +1 -0
- package/dist/mcp/tools/symbol.d.ts +21 -0
- package/dist/mcp/tools/symbol.d.ts.map +1 -0
- package/dist/mcp/tools/symbol.js +416 -0
- package/dist/mcp/tools/symbol.js.map +1 -0
- package/dist/mcp/tools.d.ts +6003 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +932 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/mcp/types.d.ts +500 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +2 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/policy/engine.d.ts +21 -0
- package/dist/policy/engine.d.ts.map +1 -0
- package/dist/policy/engine.js +477 -0
- package/dist/policy/engine.js.map +1 -0
- package/dist/policy/types.d.ts +73 -0
- package/dist/policy/types.d.ts.map +1 -0
- package/dist/policy/types.js +12 -0
- package/dist/policy/types.js.map +1 -0
- package/dist/server.d.ts +17 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +136 -0
- package/dist/server.js.map +1 -0
- package/dist/sync/pull.d.ts +4 -0
- package/dist/sync/pull.d.ts.map +1 -0
- package/dist/sync/pull.js +113 -0
- package/dist/sync/pull.js.map +1 -0
- package/dist/sync/sync.d.ts +6 -0
- package/dist/sync/sync.d.ts.map +1 -0
- package/dist/sync/sync.js +244 -0
- package/dist/sync/sync.js.map +1 -0
- package/dist/sync/types.d.ts +136 -0
- package/dist/sync/types.d.ts.map +1 -0
- package/dist/sync/types.js +2 -0
- package/dist/sync/types.js.map +1 -0
- package/dist/ts/diagnostics.d.ts +61 -0
- package/dist/ts/diagnostics.d.ts.map +1 -0
- package/dist/ts/diagnostics.js +259 -0
- package/dist/ts/diagnostics.js.map +1 -0
- package/dist/ts/mapping.d.ts +27 -0
- package/dist/ts/mapping.d.ts.map +1 -0
- package/dist/ts/mapping.js +68 -0
- package/dist/ts/mapping.js.map +1 -0
- package/dist/util/asyncFs.d.ts +103 -0
- package/dist/util/asyncFs.d.ts.map +1 -0
- package/dist/util/asyncFs.js +133 -0
- package/dist/util/asyncFs.js.map +1 -0
- package/dist/util/concurrency.d.ts +77 -0
- package/dist/util/concurrency.d.ts.map +1 -0
- package/dist/util/concurrency.js +146 -0
- package/dist/util/concurrency.js.map +1 -0
- package/dist/util/depLabels.d.ts +3 -0
- package/dist/util/depLabels.d.ts.map +1 -0
- package/dist/util/depLabels.js +19 -0
- package/dist/util/depLabels.js.map +1 -0
- package/dist/util/findPackageRoot.d.ts +7 -0
- package/dist/util/findPackageRoot.d.ts.map +1 -0
- package/dist/util/findPackageRoot.js +21 -0
- package/dist/util/findPackageRoot.js.map +1 -0
- package/dist/util/hashing.d.ts +9 -0
- package/dist/util/hashing.d.ts.map +1 -0
- package/dist/util/hashing.js +37 -0
- package/dist/util/hashing.js.map +1 -0
- package/dist/util/logger.d.ts +14 -0
- package/dist/util/logger.d.ts.map +1 -0
- package/dist/util/logger.js +51 -0
- package/dist/util/logger.js.map +1 -0
- package/dist/util/paths.d.ts +6 -0
- package/dist/util/paths.d.ts.map +1 -0
- package/dist/util/paths.js +79 -0
- package/dist/util/paths.js.map +1 -0
- package/dist/util/time.d.ts +4 -0
- package/dist/util/time.d.ts.map +1 -0
- package/dist/util/time.js +20 -0
- package/dist/util/time.js.map +1 -0
- package/dist/util/tokenize.d.ts +5 -0
- package/dist/util/tokenize.d.ts.map +1 -0
- package/dist/util/tokenize.js +30 -0
- package/dist/util/tokenize.js.map +1 -0
- package/dist/util/truncation.d.ts +38 -0
- package/dist/util/truncation.d.ts.map +1 -0
- package/dist/util/truncation.js +259 -0
- package/dist/util/truncation.js.map +1 -0
- package/migrations/.gitkeep +1 -0
- package/migrations/0001_init.sql +61 -0
- package/migrations/0002_edges_indexes.sql +2 -0
- package/migrations/0003_versions.sql +22 -0
- package/migrations/0004_metrics_audit.sql +23 -0
- package/migrations/0005_slice_handles.sql +15 -0
- package/migrations/0006_content_addressed.sql +29 -0
- package/migrations/0007_add_language_to_symbols.sql +28 -0
- package/migrations/0008_performance_indexes.sql +21 -0
- package/migrations/0009_fix_edge_fks.sql +37 -0
- package/migrations/0010_standardize_fks.sql +35 -0
- package/migrations/0011_add_directory_column.sql +20 -0
- package/migrations/0012_symbol_references.sql +16 -0
- package/migrations/0013_sync_artifacts.sql +17 -0
- package/package.json +107 -0
- package/templates/CLAUDE.md.template +179 -0
- package/templates/README.md +228 -0
- package/templates/claude-code.json +54 -0
- package/templates/codex.json +55 -0
- package/templates/gemini.json +66 -0
- package/templates/opencode.json +90 -0
- package/templates/plugin-template/LICENSE +21 -0
- package/templates/plugin-template/README.md +309 -0
- package/templates/plugin-template/index.ts +160 -0
- package/templates/plugin-template/package.json +31 -0
- package/templates/plugin-template/test/plugin.test.ts +186 -0
- package/templates/plugin-template/tsconfig.json +21 -0
|
@@ -0,0 +1,1229 @@
|
|
|
1
|
+
import { watch } from "fs";
|
|
2
|
+
import { createRequire } from "module";
|
|
3
|
+
import { dirname, join, relative, resolve } from "path";
|
|
4
|
+
import { platform } from "process";
|
|
5
|
+
import os from "os";
|
|
6
|
+
import { getRepo, upsertFile, deleteSymbolsByFileWithEdges, deleteFileTransaction, upsertSymbolTransaction, createEdgeTransaction, createSnapshotTransaction, getFilesByRepo, getFileByRepoPath, getSymbolsByFile, getSymbolsByFileLite, getSymbolsByRepoForSnapshot, getEdgesByRepo, getSymbolsByRepo, getSymbol, getFile, deleteSymbolReferencesByFileId, insertSymbolReference, } from "../db/queries.js";
|
|
7
|
+
import { getDb } from "../db/db.js";
|
|
8
|
+
import { scanRepository } from "./fileScanner.js";
|
|
9
|
+
import { generateAstFingerprint, generateSymbolId } from "./fingerprints.js";
|
|
10
|
+
import { WATCH_DEBOUNCE_MS, WATCH_STABILITY_THRESHOLD_MS, WATCH_POLL_INTERVAL_MS, WATCHER_ERROR_MAX_COUNT, } from "../config/constants.js";
|
|
11
|
+
import { hashContent } from "../util/hashing.js";
|
|
12
|
+
import { normalizePath } from "../util/paths.js";
|
|
13
|
+
import { generateSummary, extractInvariants, extractSideEffects, } from "./summaries.js";
|
|
14
|
+
import { updateMetricsForRepo } from "../graph/metrics.js";
|
|
15
|
+
import { extractConfigEdgesFromTree } from "./configEdges.js";
|
|
16
|
+
import { loadConfig } from "../config/loadConfig.js";
|
|
17
|
+
import { createTsCallResolver } from "./ts/tsParser.js";
|
|
18
|
+
import { getAdapterForExtension } from "./adapter/registry.js";
|
|
19
|
+
import { ParserWorkerPool } from "./workerPool.js";
|
|
20
|
+
import { logger } from "../util/logger.js";
|
|
21
|
+
import { readFileAsync, existsAsync } from "../util/asyncFs.js";
|
|
22
|
+
const require = createRequire(import.meta.url);
|
|
23
|
+
async function processFile(params) {
|
|
24
|
+
const { repoId, repoRoot, fileMeta, languages, mode, existingFile, symbolIndex, pendingCallEdges, createdCallEdges, tsResolver, config, allSymbolsByName, onProgress: _onProgress, workerPool, } = params;
|
|
25
|
+
try {
|
|
26
|
+
const filePath = join(repoRoot, fileMeta.path);
|
|
27
|
+
const content = await readFileAsync(filePath, "utf-8");
|
|
28
|
+
const contentHash = hashContent(content);
|
|
29
|
+
const ext = fileMeta.path.split(".").pop() || "";
|
|
30
|
+
const extWithDot = `.${ext}`;
|
|
31
|
+
if (mode === "incremental" &&
|
|
32
|
+
existingFile &&
|
|
33
|
+
existingFile.content_hash === contentHash) {
|
|
34
|
+
return {
|
|
35
|
+
symbolsIndexed: 0,
|
|
36
|
+
edgesCreated: 0,
|
|
37
|
+
changed: false,
|
|
38
|
+
configEdges: [],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (!languages.includes(ext)) {
|
|
42
|
+
logger.debug(`Language ${ext} not in enabled languages, skipping ${fileMeta.path}`);
|
|
43
|
+
if (existingFile) {
|
|
44
|
+
deleteSymbolsByFileWithEdges(existingFile.file_id);
|
|
45
|
+
}
|
|
46
|
+
upsertFile({
|
|
47
|
+
repo_id: repoId,
|
|
48
|
+
rel_path: fileMeta.path,
|
|
49
|
+
content_hash: contentHash,
|
|
50
|
+
language: ext,
|
|
51
|
+
byte_size: fileMeta.size,
|
|
52
|
+
last_indexed_at: new Date().toISOString(),
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
symbolsIndexed: 0,
|
|
56
|
+
edgesCreated: 0,
|
|
57
|
+
changed: true,
|
|
58
|
+
configEdges: [],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const adapter = getAdapterForExtension(extWithDot);
|
|
62
|
+
if (!adapter) {
|
|
63
|
+
logger.debug(`No adapter found for ${extWithDot}, skipping ${fileMeta.path}`);
|
|
64
|
+
if (existingFile) {
|
|
65
|
+
deleteSymbolsByFileWithEdges(existingFile.file_id);
|
|
66
|
+
}
|
|
67
|
+
upsertFile({
|
|
68
|
+
repo_id: repoId,
|
|
69
|
+
rel_path: fileMeta.path,
|
|
70
|
+
content_hash: contentHash,
|
|
71
|
+
language: ext,
|
|
72
|
+
byte_size: fileMeta.size,
|
|
73
|
+
last_indexed_at: new Date().toISOString(),
|
|
74
|
+
});
|
|
75
|
+
return {
|
|
76
|
+
symbolsIndexed: 0,
|
|
77
|
+
edgesCreated: 0,
|
|
78
|
+
changed: true,
|
|
79
|
+
configEdges: [],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
let symbolsWithNodeIds = [];
|
|
83
|
+
let imports = [];
|
|
84
|
+
let calls = [];
|
|
85
|
+
let parseError = null;
|
|
86
|
+
let tree = null;
|
|
87
|
+
try {
|
|
88
|
+
if (workerPool) {
|
|
89
|
+
try {
|
|
90
|
+
const result = await workerPool.parse(filePath, content, extWithDot);
|
|
91
|
+
symbolsWithNodeIds = result.symbols;
|
|
92
|
+
imports = result.imports;
|
|
93
|
+
calls = result.calls;
|
|
94
|
+
// tree remains null when using worker pool - fingerprinting will use empty string
|
|
95
|
+
}
|
|
96
|
+
catch (workerError) {
|
|
97
|
+
parseError =
|
|
98
|
+
workerError instanceof Error
|
|
99
|
+
? workerError
|
|
100
|
+
: new Error(String(workerError));
|
|
101
|
+
logger.warn(`Worker pool parse failed for ${fileMeta.path}, falling back to sync: ${parseError.message}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (parseError || !workerPool) {
|
|
105
|
+
tree = adapter.parse(content, filePath);
|
|
106
|
+
if (!tree) {
|
|
107
|
+
if (existingFile) {
|
|
108
|
+
deleteSymbolsByFileWithEdges(existingFile.file_id);
|
|
109
|
+
}
|
|
110
|
+
upsertFile({
|
|
111
|
+
repo_id: repoId,
|
|
112
|
+
rel_path: fileMeta.path,
|
|
113
|
+
content_hash: contentHash,
|
|
114
|
+
language: adapter.languageId,
|
|
115
|
+
byte_size: fileMeta.size,
|
|
116
|
+
last_indexed_at: new Date().toISOString(),
|
|
117
|
+
});
|
|
118
|
+
return {
|
|
119
|
+
symbolsIndexed: 0,
|
|
120
|
+
edgesCreated: 0,
|
|
121
|
+
changed: true,
|
|
122
|
+
configEdges: [],
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
let extractedSymbols;
|
|
126
|
+
try {
|
|
127
|
+
extractedSymbols = adapter.extractSymbols(tree, content, filePath);
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
logger.warn(`Partial parse error for ${fileMeta.path}: ${error}, extracting available symbols`);
|
|
131
|
+
extractedSymbols = [];
|
|
132
|
+
}
|
|
133
|
+
imports = adapter.extractImports(tree, content, filePath);
|
|
134
|
+
symbolsWithNodeIds = extractedSymbols.map((symbol) => ({
|
|
135
|
+
nodeId: symbol.nodeId,
|
|
136
|
+
kind: symbol.kind,
|
|
137
|
+
name: symbol.name,
|
|
138
|
+
exported: symbol.exported,
|
|
139
|
+
range: symbol.range,
|
|
140
|
+
signature: symbol.signature,
|
|
141
|
+
visibility: symbol.visibility,
|
|
142
|
+
}));
|
|
143
|
+
calls = adapter.extractCalls(tree, content, filePath, symbolsWithNodeIds);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
logger.error(`Fatal parse error for ${fileMeta.path}: ${error}`);
|
|
148
|
+
return {
|
|
149
|
+
symbolsIndexed: 0,
|
|
150
|
+
edgesCreated: 0,
|
|
151
|
+
changed: false,
|
|
152
|
+
configEdges: [],
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
const symbolsIndexed = symbolsWithNodeIds.length;
|
|
156
|
+
let edgesCreated = 0;
|
|
157
|
+
const existingSymbolsById = new Map();
|
|
158
|
+
if (existingFile) {
|
|
159
|
+
const existingSymbols = getSymbolsByFile(existingFile.file_id);
|
|
160
|
+
for (const symbol of existingSymbols) {
|
|
161
|
+
existingSymbolsById.set(symbol.symbol_id, symbol);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const fileRecord = {
|
|
165
|
+
repo_id: repoId,
|
|
166
|
+
rel_path: fileMeta.path,
|
|
167
|
+
content_hash: contentHash,
|
|
168
|
+
language: ext,
|
|
169
|
+
byte_size: fileMeta.size,
|
|
170
|
+
last_indexed_at: new Date().toISOString(),
|
|
171
|
+
};
|
|
172
|
+
upsertFile(fileRecord);
|
|
173
|
+
const file = getFileByRepoPath(repoId, fileMeta.path);
|
|
174
|
+
if (!file) {
|
|
175
|
+
return { symbolsIndexed, edgesCreated, changed: true, configEdges: [] };
|
|
176
|
+
}
|
|
177
|
+
if (existingFile) {
|
|
178
|
+
deleteSymbolsByFileWithEdges(existingFile.file_id);
|
|
179
|
+
deleteSymbolReferencesByFileId(existingFile.file_id);
|
|
180
|
+
}
|
|
181
|
+
if (isTestFile(fileMeta.path, languages)) {
|
|
182
|
+
extractSymbolReferences(content, repoId, file.file_id);
|
|
183
|
+
}
|
|
184
|
+
const exportSymbols = symbolsWithNodeIds.filter((symbol) => symbol.exported);
|
|
185
|
+
const edgeSourceSymbols = exportSymbols.length > 0 ? exportSymbols : symbolsWithNodeIds;
|
|
186
|
+
const extensions = languages.map((lang) => `.${lang}`);
|
|
187
|
+
const importResolution = await resolveImportTargets(repoId, repoRoot, fileMeta.path, imports, extensions, adapter.languageId);
|
|
188
|
+
const importTargets = importResolution.targets;
|
|
189
|
+
const symbolDetails = symbolsWithNodeIds.map((extractedSymbol) => {
|
|
190
|
+
// When using worker pool, tree is null - use empty fingerprint
|
|
191
|
+
// The fingerprint is still useful for change detection but not critical
|
|
192
|
+
let astFingerprint = "";
|
|
193
|
+
if (tree) {
|
|
194
|
+
const astNode = tree.rootNode
|
|
195
|
+
.descendantsOfType(extractedSymbol.kind === "function"
|
|
196
|
+
? "function_declaration"
|
|
197
|
+
: extractedSymbol.kind === "class"
|
|
198
|
+
? "class_declaration"
|
|
199
|
+
: extractedSymbol.kind === "interface"
|
|
200
|
+
? "interface_declaration"
|
|
201
|
+
: extractedSymbol.kind === "type"
|
|
202
|
+
? "type_alias_declaration"
|
|
203
|
+
: extractedSymbol.kind === "method"
|
|
204
|
+
? "method_definition"
|
|
205
|
+
: extractedSymbol.kind === "variable"
|
|
206
|
+
? "variable_declaration"
|
|
207
|
+
: "ambient_statement")
|
|
208
|
+
.find((node) => {
|
|
209
|
+
const nameNode = node.childForFieldName("name");
|
|
210
|
+
return nameNode?.text === extractedSymbol.name;
|
|
211
|
+
});
|
|
212
|
+
astFingerprint = astNode ? generateAstFingerprint(astNode) : "";
|
|
213
|
+
}
|
|
214
|
+
const symbolId = generateSymbolId(repoId, fileMeta.path, extractedSymbol.kind, extractedSymbol.name, astFingerprint);
|
|
215
|
+
return {
|
|
216
|
+
extractedSymbol,
|
|
217
|
+
astFingerprint,
|
|
218
|
+
symbolId,
|
|
219
|
+
};
|
|
220
|
+
});
|
|
221
|
+
const nodeIdToSymbolId = new Map();
|
|
222
|
+
const nameToSymbolIds = new Map();
|
|
223
|
+
for (const detail of symbolDetails) {
|
|
224
|
+
nodeIdToSymbolId.set(detail.extractedSymbol.nodeId, detail.symbolId);
|
|
225
|
+
const existing = nameToSymbolIds.get(detail.extractedSymbol.name) ?? [];
|
|
226
|
+
existing.push(detail.symbolId);
|
|
227
|
+
nameToSymbolIds.set(detail.extractedSymbol.name, existing);
|
|
228
|
+
}
|
|
229
|
+
for (const detail of symbolDetails) {
|
|
230
|
+
const extractedSymbol = detail.extractedSymbol;
|
|
231
|
+
const symbolId = detail.symbolId;
|
|
232
|
+
const existingSymbol = existingSymbolsById.get(symbolId);
|
|
233
|
+
let summary = existingSymbol?.summary ?? null;
|
|
234
|
+
if (summary === null) {
|
|
235
|
+
summary = generateSummary(extractedSymbol, content);
|
|
236
|
+
}
|
|
237
|
+
let invariantsJson = existingSymbol?.invariants_json ?? null;
|
|
238
|
+
if (invariantsJson === null) {
|
|
239
|
+
const invariants = extractInvariants(extractedSymbol, content);
|
|
240
|
+
invariantsJson =
|
|
241
|
+
invariants.length > 0 ? JSON.stringify(invariants) : null;
|
|
242
|
+
}
|
|
243
|
+
let sideEffectsJson = existingSymbol?.side_effects_json ?? null;
|
|
244
|
+
if (sideEffectsJson === null) {
|
|
245
|
+
const sideEffects = extractSideEffects(extractedSymbol, content);
|
|
246
|
+
sideEffectsJson =
|
|
247
|
+
sideEffects.length > 0 ? JSON.stringify(sideEffects) : null;
|
|
248
|
+
}
|
|
249
|
+
const symbol = {
|
|
250
|
+
symbol_id: symbolId,
|
|
251
|
+
repo_id: repoId,
|
|
252
|
+
file_id: file.file_id,
|
|
253
|
+
kind: extractedSymbol.kind,
|
|
254
|
+
name: extractedSymbol.name,
|
|
255
|
+
exported: extractedSymbol.exported ? 1 : 0,
|
|
256
|
+
visibility: extractedSymbol.visibility || null,
|
|
257
|
+
language: adapter.languageId,
|
|
258
|
+
range_start_line: extractedSymbol.range.startLine,
|
|
259
|
+
range_start_col: extractedSymbol.range.startCol,
|
|
260
|
+
range_end_line: extractedSymbol.range.endLine,
|
|
261
|
+
range_end_col: extractedSymbol.range.endCol,
|
|
262
|
+
ast_fingerprint: detail.astFingerprint,
|
|
263
|
+
signature_json: extractedSymbol.signature
|
|
264
|
+
? JSON.stringify(extractedSymbol.signature)
|
|
265
|
+
: null,
|
|
266
|
+
summary,
|
|
267
|
+
invariants_json: invariantsJson,
|
|
268
|
+
side_effects_json: sideEffectsJson,
|
|
269
|
+
updated_at: new Date().toISOString(),
|
|
270
|
+
};
|
|
271
|
+
upsertSymbolTransaction(symbol);
|
|
272
|
+
if (symbolIndex) {
|
|
273
|
+
addToSymbolIndex(symbolIndex, fileMeta.path, symbol.symbol_id, symbol.name, symbol.kind);
|
|
274
|
+
}
|
|
275
|
+
if (edgeSourceSymbols.some((s) => s.nodeId === extractedSymbol.nodeId)) {
|
|
276
|
+
for (const target of importTargets) {
|
|
277
|
+
const edge = {
|
|
278
|
+
repo_id: repoId,
|
|
279
|
+
from_symbol_id: symbolId,
|
|
280
|
+
to_symbol_id: target.symbolId,
|
|
281
|
+
type: "import",
|
|
282
|
+
weight: 0.6,
|
|
283
|
+
provenance: `import:${target.provenance}`,
|
|
284
|
+
created_at: new Date().toISOString(),
|
|
285
|
+
};
|
|
286
|
+
createEdgeTransaction(edge);
|
|
287
|
+
edgesCreated++;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
for (const call of calls) {
|
|
291
|
+
if (call.callerNodeId !== extractedSymbol.nodeId) {
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
const resolved = resolveCallTarget(call, nodeIdToSymbolId, nameToSymbolIds, importResolution.importedNameToSymbolIds, importResolution.namespaceImports);
|
|
295
|
+
if (!resolved) {
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
// 36-1.3: Handle both resolved and unresolved edges
|
|
299
|
+
if (resolved.isResolved && resolved.symbolId) {
|
|
300
|
+
// Fully resolved edge
|
|
301
|
+
const edgeKey = `${symbolId}->${resolved.symbolId}`;
|
|
302
|
+
if (createdCallEdges && createdCallEdges.has(edgeKey)) {
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
const edge = {
|
|
306
|
+
repo_id: repoId,
|
|
307
|
+
from_symbol_id: symbolId,
|
|
308
|
+
to_symbol_id: resolved.symbolId,
|
|
309
|
+
type: "call",
|
|
310
|
+
weight: 1.0,
|
|
311
|
+
provenance: `call:${call.calleeIdentifier}`,
|
|
312
|
+
created_at: new Date().toISOString(),
|
|
313
|
+
};
|
|
314
|
+
createEdgeTransaction(edge);
|
|
315
|
+
createdCallEdges?.add(edgeKey);
|
|
316
|
+
edgesCreated++;
|
|
317
|
+
}
|
|
318
|
+
else if (resolved.targetName) {
|
|
319
|
+
// 36-1.3: Unresolved edge - still useful for graph traversal
|
|
320
|
+
// Use a placeholder symbol ID that encodes the unresolved target
|
|
321
|
+
const unresolvedTargetId = `unresolved:call:${resolved.targetName}`;
|
|
322
|
+
const edgeKey = `${symbolId}->${unresolvedTargetId}`;
|
|
323
|
+
if (createdCallEdges && createdCallEdges.has(edgeKey)) {
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
const edge = {
|
|
327
|
+
repo_id: repoId,
|
|
328
|
+
from_symbol_id: symbolId,
|
|
329
|
+
to_symbol_id: unresolvedTargetId,
|
|
330
|
+
type: "call",
|
|
331
|
+
weight: 0.5, // Lower weight for unresolved edges
|
|
332
|
+
provenance: `unresolved-call:${call.calleeIdentifier}${resolved.candidateCount ? `:candidates=${resolved.candidateCount}` : ""}`,
|
|
333
|
+
created_at: new Date().toISOString(),
|
|
334
|
+
};
|
|
335
|
+
createEdgeTransaction(edge);
|
|
336
|
+
createdCallEdges?.add(edgeKey);
|
|
337
|
+
edgesCreated++;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
if (tsResolver && symbolIndex && pendingCallEdges && createdCallEdges) {
|
|
342
|
+
const tsCalls = tsResolver.getResolvedCalls(fileMeta.path);
|
|
343
|
+
for (const tsCall of tsCalls) {
|
|
344
|
+
const callerNodeId = findEnclosingSymbolByRange(tsCall.caller, symbolDetails);
|
|
345
|
+
if (!callerNodeId)
|
|
346
|
+
continue;
|
|
347
|
+
const fromSymbolId = nodeIdToSymbolId.get(callerNodeId);
|
|
348
|
+
if (!fromSymbolId)
|
|
349
|
+
continue;
|
|
350
|
+
const toSymbolId = resolveSymbolIdFromIndex(symbolIndex, repoId, tsCall.callee.filePath, tsCall.callee.name, tsCall.callee.kind, adapter.languageId);
|
|
351
|
+
if (toSymbolId) {
|
|
352
|
+
const edgeKey = `${fromSymbolId}->${toSymbolId}`;
|
|
353
|
+
if (createdCallEdges.has(edgeKey))
|
|
354
|
+
continue;
|
|
355
|
+
createEdgeTransaction({
|
|
356
|
+
repo_id: repoId,
|
|
357
|
+
from_symbol_id: fromSymbolId,
|
|
358
|
+
to_symbol_id: toSymbolId,
|
|
359
|
+
type: "call",
|
|
360
|
+
weight: 1.0,
|
|
361
|
+
provenance: `ts-call:${tsCall.callee.name}`,
|
|
362
|
+
created_at: new Date().toISOString(),
|
|
363
|
+
});
|
|
364
|
+
createdCallEdges.add(edgeKey);
|
|
365
|
+
edgesCreated++;
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
pendingCallEdges.push({
|
|
369
|
+
fromSymbolId,
|
|
370
|
+
toFile: tsCall.callee.filePath,
|
|
371
|
+
toName: tsCall.callee.name,
|
|
372
|
+
toKind: tsCall.callee.kind,
|
|
373
|
+
provenance: `ts-call:${tsCall.callee.name}`,
|
|
374
|
+
callerLanguage: adapter.languageId,
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
let configEdges = [];
|
|
380
|
+
// Config edges require the AST tree - skip when using worker pool (tree is null)
|
|
381
|
+
if (config && allSymbolsByName && tree) {
|
|
382
|
+
const fileSymbols = getSymbolsByFile(file.file_id);
|
|
383
|
+
configEdges = extractConfigEdgesFromTree({
|
|
384
|
+
repoId,
|
|
385
|
+
repoRoot,
|
|
386
|
+
config,
|
|
387
|
+
tree,
|
|
388
|
+
fileSymbols,
|
|
389
|
+
allSymbolsByName,
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
return { symbolsIndexed, edgesCreated, changed: true, configEdges };
|
|
393
|
+
}
|
|
394
|
+
catch (error) {
|
|
395
|
+
console.error(`Error processing file ${fileMeta.path}:`, error);
|
|
396
|
+
return {
|
|
397
|
+
symbolsIndexed: 0,
|
|
398
|
+
edgesCreated: 0,
|
|
399
|
+
changed: false,
|
|
400
|
+
configEdges: [],
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
function isTestFile(relPath, languages) {
|
|
405
|
+
const ext = relPath.split(".").pop() || "";
|
|
406
|
+
if (!languages.includes(ext))
|
|
407
|
+
return false;
|
|
408
|
+
const fileName = relPath.split("/").pop() || relPath.split("\\").pop() || "";
|
|
409
|
+
const hasTestSuffix = fileName.includes(".test.") || fileName.includes(".spec.");
|
|
410
|
+
const isInTestDir = relPath.includes("/tests/") ||
|
|
411
|
+
relPath.includes("\\tests\\") ||
|
|
412
|
+
relPath.includes("/__tests__/") ||
|
|
413
|
+
relPath.includes("\\__tests__\\");
|
|
414
|
+
return hasTestSuffix || isInTestDir;
|
|
415
|
+
}
|
|
416
|
+
function extractSymbolReferences(content, repoId, fileId) {
|
|
417
|
+
const tokens = content.match(/[A-Za-z_][A-Za-z0-9_]*/g);
|
|
418
|
+
if (!tokens)
|
|
419
|
+
return;
|
|
420
|
+
const uniqueTokens = new Set(tokens);
|
|
421
|
+
const createdAt = new Date().toISOString();
|
|
422
|
+
for (const token of uniqueTokens) {
|
|
423
|
+
insertSymbolReference({
|
|
424
|
+
repo_id: repoId,
|
|
425
|
+
symbol_name: token,
|
|
426
|
+
file_id: fileId,
|
|
427
|
+
line_number: null,
|
|
428
|
+
created_at: createdAt,
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
async function resolveImportTargets(repoId, repoRoot, importerRelPath, imports, extensions, importerLanguage) {
|
|
433
|
+
const targets = [];
|
|
434
|
+
const importedNameToSymbolIds = new Map();
|
|
435
|
+
const namespaceImports = new Map();
|
|
436
|
+
for (const imp of imports) {
|
|
437
|
+
const resolvedPath = await resolveImportToPath(repoRoot, importerRelPath, imp.specifier, extensions);
|
|
438
|
+
const importedNames = new Set();
|
|
439
|
+
if (imp.defaultImport)
|
|
440
|
+
importedNames.add(imp.defaultImport);
|
|
441
|
+
for (const name of imp.imports)
|
|
442
|
+
importedNames.add(name);
|
|
443
|
+
if (importedNames.size === 0) {
|
|
444
|
+
importedNames.add("*");
|
|
445
|
+
}
|
|
446
|
+
if (!resolvedPath) {
|
|
447
|
+
for (const name of importedNames) {
|
|
448
|
+
targets.push({
|
|
449
|
+
symbolId: `unresolved:${imp.specifier}:${name}`,
|
|
450
|
+
provenance: `${imp.specifier}:${name}`,
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
if (imp.namespaceImport) {
|
|
454
|
+
targets.push({
|
|
455
|
+
symbolId: `unresolved:${imp.specifier}:* as ${imp.namespaceImport}`,
|
|
456
|
+
provenance: `${imp.specifier}:* as ${imp.namespaceImport}`,
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
const targetFile = getFileByRepoPath(repoId, resolvedPath);
|
|
462
|
+
if (!targetFile) {
|
|
463
|
+
for (const name of importedNames) {
|
|
464
|
+
targets.push({
|
|
465
|
+
symbolId: `unresolved:${resolvedPath}:${name}`,
|
|
466
|
+
provenance: `${resolvedPath}:${name}`,
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
if (imp.namespaceImport) {
|
|
470
|
+
targets.push({
|
|
471
|
+
symbolId: `unresolved:${resolvedPath}:* as ${imp.namespaceImport}`,
|
|
472
|
+
provenance: `${resolvedPath}:* as ${imp.namespaceImport}`,
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
// ML-D.1: Language-aware import resolution
|
|
478
|
+
// Cross-language imports are resolved when possible
|
|
479
|
+
if (targetFile.language !== importerLanguage) {
|
|
480
|
+
for (const name of importedNames) {
|
|
481
|
+
targets.push({
|
|
482
|
+
symbolId: `unresolved:${resolvedPath}:${name}`,
|
|
483
|
+
provenance: `cross-language:${targetFile.language}->${importerLanguage}:${name}`,
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
if (imp.namespaceImport) {
|
|
487
|
+
targets.push({
|
|
488
|
+
symbolId: `unresolved:${resolvedPath}:* as ${imp.namespaceImport}`,
|
|
489
|
+
provenance: `cross-language:${targetFile.language}->${importerLanguage}:* as ${imp.namespaceImport}`,
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
const targetSymbols = getSymbolsByFileLite(targetFile.file_id).filter((symbol) => symbol.exported === 1);
|
|
494
|
+
for (const name of importedNames) {
|
|
495
|
+
if (name.startsWith("*")) {
|
|
496
|
+
targets.push({
|
|
497
|
+
symbolId: `unresolved:${resolvedPath}:${name}`,
|
|
498
|
+
provenance: `${resolvedPath}:${name}`,
|
|
499
|
+
});
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
502
|
+
let match = targetSymbols.find((symbol) => symbol.name === name);
|
|
503
|
+
if (!match && imp.defaultImport === name && targetSymbols.length === 1) {
|
|
504
|
+
match = targetSymbols[0];
|
|
505
|
+
}
|
|
506
|
+
if (match) {
|
|
507
|
+
targets.push({
|
|
508
|
+
symbolId: match.symbol_id,
|
|
509
|
+
provenance: `${resolvedPath}:${name}`,
|
|
510
|
+
});
|
|
511
|
+
const existing = importedNameToSymbolIds.get(name) ?? [];
|
|
512
|
+
existing.push(match.symbol_id);
|
|
513
|
+
importedNameToSymbolIds.set(name, existing);
|
|
514
|
+
}
|
|
515
|
+
else {
|
|
516
|
+
targets.push({
|
|
517
|
+
symbolId: `unresolved:${resolvedPath}:${name}`,
|
|
518
|
+
provenance: `${resolvedPath}:${name}`,
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
if (imp.namespaceImport) {
|
|
523
|
+
const namespaceMap = new Map();
|
|
524
|
+
for (const symbol of targetSymbols) {
|
|
525
|
+
namespaceMap.set(symbol.name, symbol.symbol_id);
|
|
526
|
+
targets.push({
|
|
527
|
+
symbolId: symbol.symbol_id,
|
|
528
|
+
provenance: `${resolvedPath}:*`,
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
if (namespaceMap.size > 0) {
|
|
532
|
+
namespaceImports.set(imp.namespaceImport, namespaceMap);
|
|
533
|
+
}
|
|
534
|
+
else {
|
|
535
|
+
targets.push({
|
|
536
|
+
symbolId: `unresolved:${resolvedPath}:* as ${imp.namespaceImport}`,
|
|
537
|
+
provenance: `${resolvedPath}:* as ${imp.namespaceImport}`,
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
return { targets, importedNameToSymbolIds, namespaceImports };
|
|
543
|
+
}
|
|
544
|
+
async function resolveImportToPath(repoRoot, importerRelPath, specifier, extensions) {
|
|
545
|
+
if (!specifier.startsWith("./") && !specifier.startsWith("../")) {
|
|
546
|
+
return null;
|
|
547
|
+
}
|
|
548
|
+
const importerDir = dirname(importerRelPath);
|
|
549
|
+
const baseRelPath = normalizePath(join(importerDir, specifier));
|
|
550
|
+
const baseAbsPath = resolve(repoRoot, baseRelPath);
|
|
551
|
+
const hasExtension = extensions.some((ext) => baseRelPath.endsWith(ext));
|
|
552
|
+
const candidates = [];
|
|
553
|
+
if (hasExtension) {
|
|
554
|
+
candidates.push(baseRelPath);
|
|
555
|
+
}
|
|
556
|
+
else {
|
|
557
|
+
for (const ext of extensions) {
|
|
558
|
+
candidates.push(`${baseRelPath}${ext}`);
|
|
559
|
+
}
|
|
560
|
+
for (const ext of extensions) {
|
|
561
|
+
candidates.push(normalizePath(join(baseRelPath, `index${ext}`)));
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
for (const relPath of candidates) {
|
|
565
|
+
const absPath = resolve(repoRoot, relPath);
|
|
566
|
+
if (await existsAsync(absPath)) {
|
|
567
|
+
return normalizePath(relPath);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
if (hasExtension && (await existsAsync(baseAbsPath))) {
|
|
571
|
+
return normalizePath(baseRelPath);
|
|
572
|
+
}
|
|
573
|
+
return null;
|
|
574
|
+
}
|
|
575
|
+
function resolveCallTarget(call, nodeIdToSymbolId, nameToSymbolIds, importedNameToSymbolIds, namespaceImports) {
|
|
576
|
+
// Already resolved to a specific symbol
|
|
577
|
+
if (call.calleeSymbolId && nodeIdToSymbolId.has(call.calleeSymbolId)) {
|
|
578
|
+
return {
|
|
579
|
+
symbolId: nodeIdToSymbolId.get(call.calleeSymbolId) ?? null,
|
|
580
|
+
isResolved: true,
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
const candidateId = call.calleeSymbolId ?? call.calleeIdentifier;
|
|
584
|
+
if (!candidateId) {
|
|
585
|
+
return null;
|
|
586
|
+
}
|
|
587
|
+
const cleaned = candidateId.replace(/^new\s+/, "");
|
|
588
|
+
if (cleaned.includes(".")) {
|
|
589
|
+
const parts = cleaned.split(".");
|
|
590
|
+
const prefix = parts[0];
|
|
591
|
+
const member = parts[parts.length - 1];
|
|
592
|
+
const namespace = namespaceImports.get(prefix);
|
|
593
|
+
if (namespace && namespace.has(member)) {
|
|
594
|
+
return {
|
|
595
|
+
symbolId: namespace.get(member) ?? null,
|
|
596
|
+
isResolved: true,
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
const identifier = extractLastIdentifier(candidateId);
|
|
601
|
+
if (!identifier) {
|
|
602
|
+
return null;
|
|
603
|
+
}
|
|
604
|
+
// Check imported names first
|
|
605
|
+
const importedCandidates = importedNameToSymbolIds.get(identifier);
|
|
606
|
+
if (importedCandidates && importedCandidates.length === 1) {
|
|
607
|
+
return {
|
|
608
|
+
symbolId: importedCandidates[0],
|
|
609
|
+
isResolved: true,
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
// 36-1.3: Handle ambiguous imported names - create unresolved edge
|
|
613
|
+
if (importedCandidates && importedCandidates.length > 1) {
|
|
614
|
+
return {
|
|
615
|
+
symbolId: null,
|
|
616
|
+
isResolved: false,
|
|
617
|
+
candidateCount: importedCandidates.length,
|
|
618
|
+
targetName: identifier,
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
// Check local symbols
|
|
622
|
+
const candidates = nameToSymbolIds.get(identifier);
|
|
623
|
+
if (candidates && candidates.length === 1) {
|
|
624
|
+
return {
|
|
625
|
+
symbolId: candidates[0],
|
|
626
|
+
isResolved: true,
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
// 36-1.3: Handle ambiguous local names - create unresolved edge
|
|
630
|
+
if (candidates && candidates.length > 1) {
|
|
631
|
+
return {
|
|
632
|
+
symbolId: null,
|
|
633
|
+
isResolved: false,
|
|
634
|
+
candidateCount: candidates.length,
|
|
635
|
+
targetName: identifier,
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
// No candidates at all - still create an unresolved edge if we have a name
|
|
639
|
+
// This helps with external calls that might be resolved later
|
|
640
|
+
if (identifier && call.callType !== "dynamic") {
|
|
641
|
+
return {
|
|
642
|
+
symbolId: null,
|
|
643
|
+
isResolved: false,
|
|
644
|
+
candidateCount: 0,
|
|
645
|
+
targetName: identifier,
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
return null;
|
|
649
|
+
}
|
|
650
|
+
function extractLastIdentifier(text) {
|
|
651
|
+
const cleaned = text.replace(/^new\s+/, "");
|
|
652
|
+
const parts = cleaned.split(".");
|
|
653
|
+
const last = parts[parts.length - 1]?.trim();
|
|
654
|
+
return last || null;
|
|
655
|
+
}
|
|
656
|
+
function addToSymbolIndex(index, filePath, symbolId, name, kind) {
|
|
657
|
+
const fileKey = normalizePath(filePath);
|
|
658
|
+
let fileEntry = index.get(fileKey);
|
|
659
|
+
if (!fileEntry) {
|
|
660
|
+
fileEntry = new Map();
|
|
661
|
+
index.set(fileKey, fileEntry);
|
|
662
|
+
}
|
|
663
|
+
let nameEntry = fileEntry.get(name);
|
|
664
|
+
if (!nameEntry) {
|
|
665
|
+
nameEntry = new Map();
|
|
666
|
+
fileEntry.set(name, nameEntry);
|
|
667
|
+
}
|
|
668
|
+
const kindEntry = nameEntry.get(kind) ?? [];
|
|
669
|
+
kindEntry.push(symbolId);
|
|
670
|
+
nameEntry.set(kind, kindEntry);
|
|
671
|
+
}
|
|
672
|
+
function resolveSymbolIdFromIndex(index, repoId, filePath, name, kind, callerLanguage) {
|
|
673
|
+
const fileEntry = index.get(normalizePath(filePath));
|
|
674
|
+
if (!fileEntry)
|
|
675
|
+
return null;
|
|
676
|
+
const nameEntry = fileEntry.get(name);
|
|
677
|
+
if (!nameEntry)
|
|
678
|
+
return null;
|
|
679
|
+
const candidates = nameEntry.get(kind);
|
|
680
|
+
if (!candidates || candidates.length !== 1)
|
|
681
|
+
return null;
|
|
682
|
+
// ML-D.1: Language-aware symbol resolution
|
|
683
|
+
// If callerLanguage is provided, check if the target file is the same language
|
|
684
|
+
if (callerLanguage) {
|
|
685
|
+
const targetFile = getFileByRepoPath(repoId, filePath);
|
|
686
|
+
if (targetFile && targetFile.language !== callerLanguage) {
|
|
687
|
+
// Cross-language call - return null to mark as unresolved
|
|
688
|
+
return null;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
return candidates[0];
|
|
692
|
+
}
|
|
693
|
+
function resolvePendingCallEdges(pending, index, created, repoId) {
|
|
694
|
+
for (const edge of pending) {
|
|
695
|
+
const toSymbolId = resolveSymbolIdFromIndex(index, repoId, edge.toFile, edge.toName, edge.toKind, edge.callerLanguage);
|
|
696
|
+
if (!toSymbolId) {
|
|
697
|
+
continue;
|
|
698
|
+
}
|
|
699
|
+
const edgeKey = `${edge.fromSymbolId}->${toSymbolId}`;
|
|
700
|
+
if (created.has(edgeKey)) {
|
|
701
|
+
continue;
|
|
702
|
+
}
|
|
703
|
+
createEdgeTransaction({
|
|
704
|
+
repo_id: repoId,
|
|
705
|
+
from_symbol_id: edge.fromSymbolId,
|
|
706
|
+
to_symbol_id: toSymbolId,
|
|
707
|
+
type: "call",
|
|
708
|
+
weight: 1.0,
|
|
709
|
+
provenance: edge.provenance,
|
|
710
|
+
created_at: new Date().toISOString(),
|
|
711
|
+
});
|
|
712
|
+
created.add(edgeKey);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
function cleanupUnresolvedEdges(repoId) {
|
|
716
|
+
const allEdges = getEdgesByRepo(repoId);
|
|
717
|
+
const unresolvedEdges = allEdges.filter((edge) => edge.to_symbol_id.startsWith("unresolved:"));
|
|
718
|
+
const database = getDb();
|
|
719
|
+
const deleteEdgeStmt = database.prepare("DELETE FROM edges WHERE from_symbol_id = ? AND to_symbol_id = ?");
|
|
720
|
+
// IE-K.3: Node.js built-ins to skip
|
|
721
|
+
const nodeBuiltins = new Set([
|
|
722
|
+
"assert",
|
|
723
|
+
"async_hooks",
|
|
724
|
+
"buffer",
|
|
725
|
+
"child_process",
|
|
726
|
+
"cluster",
|
|
727
|
+
"console",
|
|
728
|
+
"crypto",
|
|
729
|
+
"dgram",
|
|
730
|
+
"dns",
|
|
731
|
+
"domain",
|
|
732
|
+
"events",
|
|
733
|
+
"fs",
|
|
734
|
+
"http",
|
|
735
|
+
"http2",
|
|
736
|
+
"https",
|
|
737
|
+
"inspector",
|
|
738
|
+
"module",
|
|
739
|
+
"net",
|
|
740
|
+
"os",
|
|
741
|
+
"path",
|
|
742
|
+
"perf_hooks",
|
|
743
|
+
"process",
|
|
744
|
+
"punycode",
|
|
745
|
+
"querystring",
|
|
746
|
+
"readline",
|
|
747
|
+
"repl",
|
|
748
|
+
"stream",
|
|
749
|
+
"string_decoder",
|
|
750
|
+
"sys",
|
|
751
|
+
"timers",
|
|
752
|
+
"tls",
|
|
753
|
+
"trace_events",
|
|
754
|
+
"tty",
|
|
755
|
+
"url",
|
|
756
|
+
"util",
|
|
757
|
+
"v8",
|
|
758
|
+
"vm",
|
|
759
|
+
"worker_threads",
|
|
760
|
+
"zlib",
|
|
761
|
+
]);
|
|
762
|
+
// IE-K.3: Check if unresolved edge points to external package
|
|
763
|
+
const isExternalPackage = (target, edgeType) => {
|
|
764
|
+
// Import edges: unresolved:package:name (e.g., unresolved:tree-sitter:Parser)
|
|
765
|
+
if (edgeType === "import") {
|
|
766
|
+
const parts = target.split(":");
|
|
767
|
+
if (parts.length >= 3) {
|
|
768
|
+
const packagePath = parts[1];
|
|
769
|
+
// Skip if not relative path (i.e., external package)
|
|
770
|
+
if (!packagePath.startsWith("./") &&
|
|
771
|
+
!packagePath.startsWith("../") &&
|
|
772
|
+
!packagePath.startsWith("/")) {
|
|
773
|
+
return true;
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
// Call edges: unresolved:call:name or unresolved:call:package:name
|
|
778
|
+
// Check if name matches known patterns (Node.js built-ins or external packages)
|
|
779
|
+
if (target.startsWith("unresolved:call:")) {
|
|
780
|
+
const namePart = target.slice("unresolved:call:".length);
|
|
781
|
+
// Skip if name is a Node.js builtin
|
|
782
|
+
if (nodeBuiltins.has(namePart)) {
|
|
783
|
+
return true;
|
|
784
|
+
}
|
|
785
|
+
// Skip if name contains package-like pattern (e.g., "tree-sitter:Parser")
|
|
786
|
+
if (namePart.includes(":") &&
|
|
787
|
+
!namePart.startsWith("./") &&
|
|
788
|
+
!namePart.startsWith("../")) {
|
|
789
|
+
return true;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
return false;
|
|
793
|
+
};
|
|
794
|
+
// Cache repo symbols for call edge resolution
|
|
795
|
+
let repoSymbols = null;
|
|
796
|
+
const getRepoSymbolsCached = () => {
|
|
797
|
+
if (!repoSymbols) {
|
|
798
|
+
repoSymbols = getSymbolsByRepo(repoId);
|
|
799
|
+
}
|
|
800
|
+
return repoSymbols;
|
|
801
|
+
};
|
|
802
|
+
// Cache symbol-to-file mapping
|
|
803
|
+
const symbolToFile = new Map();
|
|
804
|
+
const getSymbolFile = (symbolId) => {
|
|
805
|
+
if (symbolToFile.has(symbolId)) {
|
|
806
|
+
return symbolToFile.get(symbolId) ?? null;
|
|
807
|
+
}
|
|
808
|
+
const symbol = getSymbol(symbolId);
|
|
809
|
+
if (!symbol) {
|
|
810
|
+
symbolToFile.set(symbolId, null);
|
|
811
|
+
return null;
|
|
812
|
+
}
|
|
813
|
+
const file = getFile(symbol.file_id);
|
|
814
|
+
symbolToFile.set(symbolId, file ?? null);
|
|
815
|
+
return file ?? null;
|
|
816
|
+
};
|
|
817
|
+
for (const edge of unresolvedEdges) {
|
|
818
|
+
const target = edge.to_symbol_id;
|
|
819
|
+
// IE-K.3: Skip external package edges (don't try to resolve, don't warn)
|
|
820
|
+
if (isExternalPackage(target, edge.type)) {
|
|
821
|
+
continue;
|
|
822
|
+
}
|
|
823
|
+
let matchingSymbolId;
|
|
824
|
+
// Format 1: unresolved:call:functionName - simple call edge
|
|
825
|
+
const callMatch = target.match(/^unresolved:call:(.+)$/);
|
|
826
|
+
if (callMatch) {
|
|
827
|
+
const targetName = callMatch[1];
|
|
828
|
+
const match = getRepoSymbolsCached().find((sym) => {
|
|
829
|
+
if (sym.name === targetName)
|
|
830
|
+
return true;
|
|
831
|
+
if (targetName.includes(":")) {
|
|
832
|
+
const parts = targetName.split(":");
|
|
833
|
+
return parts.some((part) => sym.name === part);
|
|
834
|
+
}
|
|
835
|
+
return false;
|
|
836
|
+
});
|
|
837
|
+
matchingSymbolId = match?.symbol_id;
|
|
838
|
+
}
|
|
839
|
+
// Format 2: unresolved:path/to/file.js:symbolName - import edge with file path
|
|
840
|
+
// Skip namespace imports (* as X) and star imports (*)
|
|
841
|
+
if (!callMatch && !target.includes(":*")) {
|
|
842
|
+
// Parse: unresolved:path:symbolName (last colon separates path from symbol)
|
|
843
|
+
const lastColon = target.lastIndexOf(":");
|
|
844
|
+
if (lastColon > 11) {
|
|
845
|
+
// "unresolved:".length = 11
|
|
846
|
+
const pathPart = target.slice(11, lastColon);
|
|
847
|
+
const symbolName = target.slice(lastColon + 1);
|
|
848
|
+
// Get the source file to resolve relative paths
|
|
849
|
+
const sourceFile = getSymbolFile(edge.from_symbol_id);
|
|
850
|
+
if (sourceFile &&
|
|
851
|
+
(pathPart.startsWith("./") || pathPart.startsWith("../"))) {
|
|
852
|
+
// Resolve relative path from source file's directory
|
|
853
|
+
const sourceDir = dirname(sourceFile.rel_path);
|
|
854
|
+
const joinedPath = join(sourceDir, pathPart);
|
|
855
|
+
const normalizedJoined = normalizePath(joinedPath);
|
|
856
|
+
// Try multiple path variants for better matching
|
|
857
|
+
const pathVariants = [
|
|
858
|
+
// Normalized path with original extension
|
|
859
|
+
normalizedJoined,
|
|
860
|
+
// .js -> .ts conversion
|
|
861
|
+
normalizedJoined.replace(/\.js$/, ".ts"),
|
|
862
|
+
// .jsx -> .tsx conversion
|
|
863
|
+
normalizedJoined.replace(/\.jsx$/, ".tsx"),
|
|
864
|
+
// Try with .ts extension if no extension
|
|
865
|
+
!normalizedJoined.match(/\.(js|ts|jsx|tsx)$/)
|
|
866
|
+
? `${normalizedJoined}.ts`
|
|
867
|
+
: normalizedJoined,
|
|
868
|
+
// Try with .js extension if no extension
|
|
869
|
+
!normalizedJoined.match(/\.(js|ts|jsx|tsx)$/)
|
|
870
|
+
? `${normalizedJoined}.js`
|
|
871
|
+
: normalizedJoined,
|
|
872
|
+
// Try index.ts (with and without trailing slash)
|
|
873
|
+
normalizedJoined.replace(/\.(js|ts|jsx|tsx)$/, "") + "/index.ts",
|
|
874
|
+
// Try index.js
|
|
875
|
+
normalizedJoined.replace(/\.(js|ts|jsx|tsx)$/, "") + "/index.js",
|
|
876
|
+
// Try removing any extension and keeping as directory
|
|
877
|
+
normalizedJoined.replace(/\.(js|ts|jsx|tsx)$/, ""),
|
|
878
|
+
];
|
|
879
|
+
// Remove duplicates from variants
|
|
880
|
+
const uniqueVariants = [...new Set(pathVariants)];
|
|
881
|
+
for (const variant of uniqueVariants) {
|
|
882
|
+
const targetFile = getFileByRepoPath(repoId, variant);
|
|
883
|
+
if (targetFile) {
|
|
884
|
+
// Find exported symbol by name in that file
|
|
885
|
+
const fileSymbols = getSymbolsByFileLite(targetFile.file_id).filter((s) => s.exported === 1);
|
|
886
|
+
const match = fileSymbols.find((s) => s.name === symbolName);
|
|
887
|
+
if (match) {
|
|
888
|
+
matchingSymbolId = match.symbol_id;
|
|
889
|
+
break;
|
|
890
|
+
}
|
|
891
|
+
// Fallback: if single export and looking for default
|
|
892
|
+
if (!matchingSymbolId && fileSymbols.length === 1) {
|
|
893
|
+
matchingSymbolId = fileSymbols[0].symbol_id;
|
|
894
|
+
break;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
// IE-K.2: Try case-insensitive matching on Windows
|
|
898
|
+
if (!matchingSymbolId && platform === "win32") {
|
|
899
|
+
const allFiles = getFilesByRepo(repoId);
|
|
900
|
+
const caseInsensitiveMatch = allFiles.find((f) => f.rel_path.toLowerCase() === variant.toLowerCase());
|
|
901
|
+
if (caseInsensitiveMatch) {
|
|
902
|
+
const fileSymbols = getSymbolsByFileLite(caseInsensitiveMatch.file_id).filter((s) => s.exported === 1);
|
|
903
|
+
const match = fileSymbols.find((s) => s.name === symbolName);
|
|
904
|
+
if (match) {
|
|
905
|
+
matchingSymbolId = match.symbol_id;
|
|
906
|
+
break;
|
|
907
|
+
}
|
|
908
|
+
// Fallback: if single export and looking for default
|
|
909
|
+
if (!matchingSymbolId && fileSymbols.length === 1) {
|
|
910
|
+
matchingSymbolId = fileSymbols[0].symbol_id;
|
|
911
|
+
break;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
else if (!pathPart.startsWith("./") && !pathPart.startsWith("../")) {
|
|
918
|
+
// Non-relative import (node_modules, etc.) - skip
|
|
919
|
+
continue;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
if (matchingSymbolId) {
|
|
924
|
+
deleteEdgeStmt.run(edge.from_symbol_id, edge.to_symbol_id);
|
|
925
|
+
createEdgeTransaction({
|
|
926
|
+
repo_id: edge.repo_id,
|
|
927
|
+
from_symbol_id: edge.from_symbol_id,
|
|
928
|
+
to_symbol_id: matchingSymbolId,
|
|
929
|
+
type: edge.type,
|
|
930
|
+
weight: edge.type === "import" ? 0.6 : 1.0,
|
|
931
|
+
provenance: edge.provenance,
|
|
932
|
+
created_at: new Date().toISOString(),
|
|
933
|
+
});
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
function findEnclosingSymbolByRange(range, symbols) {
|
|
938
|
+
let bestMatch = null;
|
|
939
|
+
for (const detail of symbols) {
|
|
940
|
+
const symRange = detail.extractedSymbol.range;
|
|
941
|
+
const nodeLine = range.startLine;
|
|
942
|
+
const nodeCol = range.startCol;
|
|
943
|
+
if (nodeLine < symRange.startLine || nodeLine > symRange.endLine) {
|
|
944
|
+
continue;
|
|
945
|
+
}
|
|
946
|
+
if (nodeLine === symRange.startLine && nodeCol < symRange.startCol) {
|
|
947
|
+
continue;
|
|
948
|
+
}
|
|
949
|
+
if (nodeLine === symRange.endLine && nodeCol > symRange.endCol) {
|
|
950
|
+
continue;
|
|
951
|
+
}
|
|
952
|
+
const size = symRange.endLine -
|
|
953
|
+
symRange.startLine +
|
|
954
|
+
(symRange.endCol - symRange.startCol);
|
|
955
|
+
if (!bestMatch || size < bestMatch.size) {
|
|
956
|
+
bestMatch = { nodeId: detail.extractedSymbol.nodeId, size };
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
return bestMatch?.nodeId ?? null;
|
|
960
|
+
}
|
|
961
|
+
export async function indexRepo(repoId, mode, onProgress) {
|
|
962
|
+
const startTime = Date.now();
|
|
963
|
+
const repoRow = getRepo(repoId);
|
|
964
|
+
if (!repoRow) {
|
|
965
|
+
throw new Error(`Repository ${repoId} not found`);
|
|
966
|
+
}
|
|
967
|
+
const config = JSON.parse(repoRow.config_json);
|
|
968
|
+
onProgress?.({ stage: "scanning", current: 0, total: 0 });
|
|
969
|
+
const files = await scanRepository(repoRow.root_path, config);
|
|
970
|
+
onProgress?.({ stage: "parsing", current: 0, total: files.length });
|
|
971
|
+
const appConfig = loadConfig();
|
|
972
|
+
const concurrency = Math.max(1, Math.min(appConfig.indexing?.concurrency ?? 4, files.length || 1));
|
|
973
|
+
const workerPool = new ParserWorkerPool(appConfig.indexing?.workerPoolSize ?? os.cpus().length - 1);
|
|
974
|
+
const existingFiles = getFilesByRepo(repoId);
|
|
975
|
+
const existingByPath = new Map(existingFiles.map((file) => [file.rel_path, file]));
|
|
976
|
+
const scannedPaths = new Set(files.map((file) => file.path));
|
|
977
|
+
let removedFiles = 0;
|
|
978
|
+
for (const file of existingFiles) {
|
|
979
|
+
if (!scannedPaths.has(file.rel_path)) {
|
|
980
|
+
deleteFileTransaction(file.file_id);
|
|
981
|
+
removedFiles++;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
const symbolIndex = new Map();
|
|
985
|
+
const pendingCallEdges = [];
|
|
986
|
+
const createdCallEdges = new Set();
|
|
987
|
+
const tsResolver = createTsCallResolver(repoRow.root_path, files);
|
|
988
|
+
const allSymbolsByName = new Map();
|
|
989
|
+
const repoSymbols = getSymbolsByRepo(repoId);
|
|
990
|
+
for (const symbol of repoSymbols) {
|
|
991
|
+
const byName = allSymbolsByName.get(symbol.name) ?? [];
|
|
992
|
+
byName.push(symbol);
|
|
993
|
+
allSymbolsByName.set(symbol.name, byName);
|
|
994
|
+
}
|
|
995
|
+
let filesProcessed = 0;
|
|
996
|
+
let changedFiles = 0;
|
|
997
|
+
let totalSymbolsIndexed = 0;
|
|
998
|
+
let totalEdgesCreated = 0;
|
|
999
|
+
let configEdgesCreated = 0;
|
|
1000
|
+
const allConfigEdges = [];
|
|
1001
|
+
const changedFileIds = new Set();
|
|
1002
|
+
let nextIndex = 0;
|
|
1003
|
+
const updateProgress = (currentFile) => {
|
|
1004
|
+
onProgress?.({
|
|
1005
|
+
stage: "indexing",
|
|
1006
|
+
current: Math.min(filesProcessed, files.length),
|
|
1007
|
+
total: files.length,
|
|
1008
|
+
currentFile,
|
|
1009
|
+
});
|
|
1010
|
+
};
|
|
1011
|
+
const runWorker = async () => {
|
|
1012
|
+
// eslint-disable-next-line no-constant-condition
|
|
1013
|
+
while (true) {
|
|
1014
|
+
const index = nextIndex++;
|
|
1015
|
+
if (index >= files.length) {
|
|
1016
|
+
return;
|
|
1017
|
+
}
|
|
1018
|
+
const file = files[index];
|
|
1019
|
+
updateProgress(file.path);
|
|
1020
|
+
try {
|
|
1021
|
+
const result = await processFile({
|
|
1022
|
+
repoId,
|
|
1023
|
+
repoRoot: repoRow.root_path,
|
|
1024
|
+
fileMeta: file,
|
|
1025
|
+
languages: config.languages,
|
|
1026
|
+
mode,
|
|
1027
|
+
existingFile: existingByPath.get(file.path),
|
|
1028
|
+
symbolIndex,
|
|
1029
|
+
pendingCallEdges,
|
|
1030
|
+
createdCallEdges,
|
|
1031
|
+
tsResolver,
|
|
1032
|
+
config,
|
|
1033
|
+
allSymbolsByName,
|
|
1034
|
+
onProgress,
|
|
1035
|
+
workerPool,
|
|
1036
|
+
});
|
|
1037
|
+
filesProcessed++;
|
|
1038
|
+
if (result.changed) {
|
|
1039
|
+
changedFiles++;
|
|
1040
|
+
const fileRecord = getFileByRepoPath(repoId, file.path);
|
|
1041
|
+
if (fileRecord) {
|
|
1042
|
+
changedFileIds.add(fileRecord.file_id);
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
totalSymbolsIndexed += result.symbolsIndexed;
|
|
1046
|
+
totalEdgesCreated += result.edgesCreated;
|
|
1047
|
+
allConfigEdges.push(...result.configEdges);
|
|
1048
|
+
}
|
|
1049
|
+
catch (error) {
|
|
1050
|
+
filesProcessed++;
|
|
1051
|
+
console.error(`Error processing file ${file.path}:`, error);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
};
|
|
1055
|
+
const workers = Array.from({ length: Math.min(concurrency, files.length || 1) }, () => runWorker());
|
|
1056
|
+
await Promise.all(workers);
|
|
1057
|
+
onProgress?.({
|
|
1058
|
+
stage: "finalizing",
|
|
1059
|
+
current: files.length,
|
|
1060
|
+
total: files.length,
|
|
1061
|
+
});
|
|
1062
|
+
changedFiles += removedFiles;
|
|
1063
|
+
resolvePendingCallEdges(pendingCallEdges, symbolIndex, createdCallEdges, repoId);
|
|
1064
|
+
cleanupUnresolvedEdges(repoId);
|
|
1065
|
+
const configWeight = appConfig.slice?.edgeWeights?.config !== undefined
|
|
1066
|
+
? appConfig.slice.edgeWeights.config
|
|
1067
|
+
: 0.8;
|
|
1068
|
+
for (const edge of allConfigEdges) {
|
|
1069
|
+
createEdgeTransaction({
|
|
1070
|
+
repo_id: repoId,
|
|
1071
|
+
from_symbol_id: edge.fromSymbolId,
|
|
1072
|
+
to_symbol_id: edge.toSymbolId,
|
|
1073
|
+
type: "config",
|
|
1074
|
+
weight: edge.weight ?? configWeight,
|
|
1075
|
+
provenance: edge.provenance ?? "config",
|
|
1076
|
+
created_at: new Date().toISOString(),
|
|
1077
|
+
});
|
|
1078
|
+
configEdgesCreated++;
|
|
1079
|
+
}
|
|
1080
|
+
const versionId = `v${Date.now()}`;
|
|
1081
|
+
const version = {
|
|
1082
|
+
version_id: versionId,
|
|
1083
|
+
repo_id: repoId,
|
|
1084
|
+
created_at: new Date().toISOString(),
|
|
1085
|
+
reason: mode === "full" ? "Full index" : "Incremental index",
|
|
1086
|
+
prev_version_hash: null,
|
|
1087
|
+
version_hash: null,
|
|
1088
|
+
};
|
|
1089
|
+
const symbols = getSymbolsByRepoForSnapshot(repoId);
|
|
1090
|
+
const snapshots = symbols.map((symbol) => ({
|
|
1091
|
+
version_id: versionId,
|
|
1092
|
+
symbol_id: symbol.symbol_id,
|
|
1093
|
+
ast_fingerprint: symbol.ast_fingerprint,
|
|
1094
|
+
signature_json: symbol.signature_json,
|
|
1095
|
+
summary: symbol.summary,
|
|
1096
|
+
invariants_json: symbol.invariants_json,
|
|
1097
|
+
side_effects_json: symbol.side_effects_json,
|
|
1098
|
+
}));
|
|
1099
|
+
createSnapshotTransaction(version, snapshots);
|
|
1100
|
+
const durationMs = Date.now() - startTime;
|
|
1101
|
+
const changedFileIdsParam = mode === "incremental" && changedFileIds.size > 0
|
|
1102
|
+
? changedFileIds
|
|
1103
|
+
: undefined;
|
|
1104
|
+
await updateMetricsForRepo(repoId, changedFileIdsParam);
|
|
1105
|
+
// Shutdown worker pool to release resources
|
|
1106
|
+
await workerPool.shutdown();
|
|
1107
|
+
return {
|
|
1108
|
+
versionId,
|
|
1109
|
+
filesProcessed,
|
|
1110
|
+
changedFiles,
|
|
1111
|
+
removedFiles,
|
|
1112
|
+
symbolsIndexed: totalSymbolsIndexed,
|
|
1113
|
+
edgesCreated: totalEdgesCreated + configEdgesCreated,
|
|
1114
|
+
durationMs,
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
function loadChokidar() {
|
|
1118
|
+
try {
|
|
1119
|
+
return require("chokidar");
|
|
1120
|
+
}
|
|
1121
|
+
catch {
|
|
1122
|
+
return null;
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
const watcherErrors = [];
|
|
1126
|
+
export function watchRepository(repoId) {
|
|
1127
|
+
const repoRow = getRepo(repoId);
|
|
1128
|
+
if (!repoRow) {
|
|
1129
|
+
throw new Error(`Repository ${repoId} not found`);
|
|
1130
|
+
}
|
|
1131
|
+
const config = JSON.parse(repoRow.config_json);
|
|
1132
|
+
const extensions = config.languages.map((lang) => `.${lang}`);
|
|
1133
|
+
const reindex = async (filePath) => {
|
|
1134
|
+
try {
|
|
1135
|
+
process.stderr.write(`[sdl-mcp] File change detected: ${filePath}\n`);
|
|
1136
|
+
await indexRepo(repoId, "incremental");
|
|
1137
|
+
}
|
|
1138
|
+
catch (error) {
|
|
1139
|
+
process.stderr.write(`[sdl-mcp] Failed incremental index for ${filePath}: ${error}\n`);
|
|
1140
|
+
}
|
|
1141
|
+
};
|
|
1142
|
+
const pending = new Map();
|
|
1143
|
+
const schedule = (filePath) => {
|
|
1144
|
+
const existing = pending.get(filePath);
|
|
1145
|
+
if (existing) {
|
|
1146
|
+
clearTimeout(existing);
|
|
1147
|
+
}
|
|
1148
|
+
pending.set(filePath, setTimeout(() => {
|
|
1149
|
+
pending.delete(filePath);
|
|
1150
|
+
void reindex(filePath);
|
|
1151
|
+
}, WATCH_DEBOUNCE_MS));
|
|
1152
|
+
};
|
|
1153
|
+
const chokidar = loadChokidar();
|
|
1154
|
+
if (chokidar) {
|
|
1155
|
+
const watcher = chokidar.watch(repoRow.root_path, {
|
|
1156
|
+
ignored: config.ignore,
|
|
1157
|
+
ignoreInitial: true,
|
|
1158
|
+
awaitWriteFinish: {
|
|
1159
|
+
stabilityThreshold: WATCH_STABILITY_THRESHOLD_MS,
|
|
1160
|
+
pollInterval: WATCH_POLL_INTERVAL_MS,
|
|
1161
|
+
},
|
|
1162
|
+
});
|
|
1163
|
+
watcher.on("error", (error) => {
|
|
1164
|
+
const errorMsg = `[sdl-mcp] File watcher error: ${error}`;
|
|
1165
|
+
process.stderr.write(`${errorMsg}
|
|
1166
|
+
`);
|
|
1167
|
+
watcherErrors.push(`${new Date().toISOString()} - ${errorMsg}`);
|
|
1168
|
+
if (watcherErrors.length > WATCHER_ERROR_MAX_COUNT) {
|
|
1169
|
+
watcherErrors.shift();
|
|
1170
|
+
}
|
|
1171
|
+
});
|
|
1172
|
+
const handler = (filePath) => {
|
|
1173
|
+
const relPath = normalizePath(relative(repoRow.root_path, filePath));
|
|
1174
|
+
if (shouldIgnorePath(relPath, config.ignore)) {
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
if (!matchesExtensions(relPath, extensions)) {
|
|
1178
|
+
return;
|
|
1179
|
+
}
|
|
1180
|
+
schedule(relPath);
|
|
1181
|
+
};
|
|
1182
|
+
watcher.on("add", handler);
|
|
1183
|
+
watcher.on("change", handler);
|
|
1184
|
+
watcher.on("unlink", handler);
|
|
1185
|
+
return {
|
|
1186
|
+
close: async () => {
|
|
1187
|
+
await watcher.close();
|
|
1188
|
+
},
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
const watcher = watch(repoRow.root_path, { recursive: true }, (_eventType, filename) => {
|
|
1192
|
+
if (!filename)
|
|
1193
|
+
return;
|
|
1194
|
+
const relPath = normalizePath(filename.toString());
|
|
1195
|
+
if (shouldIgnorePath(relPath, config.ignore)) {
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
if (!matchesExtensions(relPath, extensions)) {
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
schedule(relPath);
|
|
1202
|
+
});
|
|
1203
|
+
return {
|
|
1204
|
+
close: async () => {
|
|
1205
|
+
watcher.close();
|
|
1206
|
+
},
|
|
1207
|
+
};
|
|
1208
|
+
}
|
|
1209
|
+
function matchesExtensions(path, extensions) {
|
|
1210
|
+
return extensions.some((ext) => path.endsWith(ext));
|
|
1211
|
+
}
|
|
1212
|
+
function shouldIgnorePath(path, ignorePatterns) {
|
|
1213
|
+
const normalized = normalizePath(path);
|
|
1214
|
+
for (const pattern of ignorePatterns) {
|
|
1215
|
+
const token = pattern
|
|
1216
|
+
.replace(/\*\*\//g, "")
|
|
1217
|
+
.replace(/\/\*\*/g, "")
|
|
1218
|
+
.replace(/\*/g, "")
|
|
1219
|
+
.replace(/\/+/g, "/")
|
|
1220
|
+
.trim();
|
|
1221
|
+
if (!token)
|
|
1222
|
+
continue;
|
|
1223
|
+
if (normalized.includes(token)) {
|
|
1224
|
+
return true;
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
return false;
|
|
1228
|
+
}
|
|
1229
|
+
//# sourceMappingURL=indexer.js.map
|