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,1054 @@
|
|
|
1
|
+
import { getDb } from "./db.js";
|
|
2
|
+
import { hashContent } from "../util/hashing.js";
|
|
3
|
+
import { MAX_STATEMENT_CACHE_SIZE, DB_CHUNK_SIZE, DB_QUERY_LIMIT_DEFAULT, DB_QUERY_LIMIT_MAX, } from "../config/constants.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
const stmtCache = new Map();
|
|
6
|
+
const stmtCacheOrder = [];
|
|
7
|
+
/**
|
|
8
|
+
* Escapes SQL LIKE wildcard characters (%, _, \) in user input.
|
|
9
|
+
* Prevents unintended pattern matching when user input contains these chars.
|
|
10
|
+
*/
|
|
11
|
+
function escapeSearchPattern(query) {
|
|
12
|
+
return query.replace(/[%_\\]/g, "\\$&");
|
|
13
|
+
}
|
|
14
|
+
function stmt(sql) {
|
|
15
|
+
let s = stmtCache.get(sql);
|
|
16
|
+
if (s) {
|
|
17
|
+
const idx = stmtCacheOrder.indexOf(sql);
|
|
18
|
+
if (idx !== -1) {
|
|
19
|
+
stmtCacheOrder.splice(idx, 1);
|
|
20
|
+
stmtCacheOrder.push(sql);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
s = getDb().prepare(sql);
|
|
25
|
+
stmtCache.set(sql, s);
|
|
26
|
+
stmtCacheOrder.push(sql);
|
|
27
|
+
if (stmtCache.size > MAX_STATEMENT_CACHE_SIZE) {
|
|
28
|
+
const oldest = stmtCacheOrder.shift();
|
|
29
|
+
if (oldest) {
|
|
30
|
+
stmtCache.delete(oldest);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return s;
|
|
35
|
+
}
|
|
36
|
+
export function resetQueryCache() {
|
|
37
|
+
stmtCache.clear();
|
|
38
|
+
stmtCacheOrder.length = 0;
|
|
39
|
+
}
|
|
40
|
+
// Repo operations
|
|
41
|
+
/**
|
|
42
|
+
* Creates a new repository record in the database.
|
|
43
|
+
*
|
|
44
|
+
* @param repo - Repository record with repo_id, root_path, config_json, and created_at
|
|
45
|
+
*/
|
|
46
|
+
export function createRepo(repo) {
|
|
47
|
+
stmt("INSERT INTO repos (repo_id, root_path, config_json, created_at) VALUES (?, ?, ?, ?)").run(repo.repo_id, repo.root_path, repo.config_json, repo.created_at);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Retrieves a repository by ID.
|
|
51
|
+
*
|
|
52
|
+
* @param repoId - Repository identifier
|
|
53
|
+
* @returns Repository record or null if not found
|
|
54
|
+
*/
|
|
55
|
+
export function getRepo(repoId) {
|
|
56
|
+
return stmt("SELECT * FROM repos WHERE repo_id = ?").get(repoId);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Lists all repositories in the database.
|
|
60
|
+
*
|
|
61
|
+
* @returns Array of all repository records
|
|
62
|
+
*/
|
|
63
|
+
export function listRepos() {
|
|
64
|
+
return stmt("SELECT * FROM repos").all();
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Updates repository root_path and config_json by ID.
|
|
68
|
+
*
|
|
69
|
+
* @param repoId - Repository identifier
|
|
70
|
+
* @param updates - Partial repository record with fields to update (only root_path and config_json are supported)
|
|
71
|
+
*/
|
|
72
|
+
export function updateRepo(repoId, updates) {
|
|
73
|
+
stmt("UPDATE repos SET root_path = coalesce(?, root_path), config_json = coalesce(?, config_json) WHERE repo_id = ?").run(updates.root_path ?? null, updates.config_json ?? null, repoId);
|
|
74
|
+
}
|
|
75
|
+
// File operations
|
|
76
|
+
/**
|
|
77
|
+
* Inserts or updates a file record.
|
|
78
|
+
* Uses upsert semantics to handle both new and existing files.
|
|
79
|
+
*
|
|
80
|
+
* @param file - File record without file_id (auto-generated) and directory (computed)
|
|
81
|
+
*/
|
|
82
|
+
export function upsertFile(file) {
|
|
83
|
+
const directory = file.rel_path.includes("/")
|
|
84
|
+
? file.rel_path.substring(0, file.rel_path.lastIndexOf("/"))
|
|
85
|
+
: "";
|
|
86
|
+
stmt(`INSERT INTO files (repo_id, rel_path, content_hash, language, byte_size, last_indexed_at, directory)
|
|
87
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
88
|
+
ON CONFLICT(repo_id, rel_path) DO UPDATE SET
|
|
89
|
+
content_hash = excluded.content_hash,
|
|
90
|
+
language = excluded.language,
|
|
91
|
+
byte_size = excluded.byte_size,
|
|
92
|
+
last_indexed_at = excluded.last_indexed_at,
|
|
93
|
+
directory = excluded.directory`).run(file.repo_id, file.rel_path, file.content_hash, file.language, file.byte_size, file.last_indexed_at, directory);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Retrieves a file by ID.
|
|
97
|
+
*
|
|
98
|
+
* @param fileId - File identifier
|
|
99
|
+
* @returns File record or null if not found
|
|
100
|
+
*/
|
|
101
|
+
export function getFile(fileId) {
|
|
102
|
+
return stmt("SELECT * FROM files WHERE file_id = ?").get(fileId);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Lists all files for a repository.
|
|
106
|
+
*
|
|
107
|
+
* @param repoId - Repository identifier
|
|
108
|
+
* @returns Array of file records for the repository
|
|
109
|
+
*/
|
|
110
|
+
export function getFilesByRepo(repoId) {
|
|
111
|
+
return stmt("SELECT * FROM files WHERE repo_id = ?").all(repoId);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Lists all files for a repository with minimal projection.
|
|
115
|
+
* Returns only file_id and rel_path for lightweight lookups.
|
|
116
|
+
*
|
|
117
|
+
* @param repoId - Repository identifier
|
|
118
|
+
* @returns Array of file records with minimal fields
|
|
119
|
+
*/
|
|
120
|
+
export function getFilesByRepoLite(repoId) {
|
|
121
|
+
return stmt("SELECT file_id, rel_path FROM files WHERE repo_id = ?").all(repoId);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Retrieves a file by repository ID and relative path.
|
|
125
|
+
*
|
|
126
|
+
* @param repoId - Repository identifier
|
|
127
|
+
* @param relPath - Relative path within repository
|
|
128
|
+
* @returns File record or null if not found
|
|
129
|
+
*/
|
|
130
|
+
export function getFileByRepoPath(repoId, relPath) {
|
|
131
|
+
return stmt("SELECT * FROM files WHERE repo_id = ? AND rel_path = ?").get(repoId, relPath);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Deletes a file record by ID.
|
|
135
|
+
*
|
|
136
|
+
* @param fileId - File identifier
|
|
137
|
+
*/
|
|
138
|
+
export function deleteFile(fileId) {
|
|
139
|
+
stmt("DELETE FROM files WHERE file_id = ?").run(fileId);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Batch fetch files by IDs. Uses chunked queries to avoid SQLite parameter limits.
|
|
143
|
+
* Returns a Map for O(1) lookup by file_id.
|
|
144
|
+
*/
|
|
145
|
+
export function getFilesByIds(fileIds) {
|
|
146
|
+
if (fileIds.length === 0)
|
|
147
|
+
return new Map();
|
|
148
|
+
const result = new Map();
|
|
149
|
+
const uniqueIds = [...new Set(fileIds)]; // Deduplicate
|
|
150
|
+
for (let i = 0; i < uniqueIds.length; i += DB_CHUNK_SIZE) {
|
|
151
|
+
const chunk = uniqueIds.slice(i, i + DB_CHUNK_SIZE);
|
|
152
|
+
const placeholders = chunk.map(() => "?").join(",");
|
|
153
|
+
const rows = getDb()
|
|
154
|
+
.prepare(`SELECT * FROM files WHERE file_id IN (${placeholders})`)
|
|
155
|
+
.all(...chunk);
|
|
156
|
+
for (const row of rows) {
|
|
157
|
+
result.set(row.file_id, row);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Batch fetch files by IDs with minimal projection.
|
|
164
|
+
* Returns only file_id and rel_path for lightweight lookups.
|
|
165
|
+
* Uses chunked queries to avoid SQLite parameter limits.
|
|
166
|
+
*
|
|
167
|
+
* @param fileIds - Array of file identifiers
|
|
168
|
+
* @returns Map of file_id to minimal file record
|
|
169
|
+
*/
|
|
170
|
+
export function getFilesByIdsLite(fileIds) {
|
|
171
|
+
if (fileIds.length === 0)
|
|
172
|
+
return new Map();
|
|
173
|
+
const result = new Map();
|
|
174
|
+
const uniqueIds = [...new Set(fileIds)]; // Deduplicate
|
|
175
|
+
for (let i = 0; i < uniqueIds.length; i += DB_CHUNK_SIZE) {
|
|
176
|
+
const chunk = uniqueIds.slice(i, i + DB_CHUNK_SIZE);
|
|
177
|
+
const placeholders = chunk.map(() => "?").join(",");
|
|
178
|
+
const rows = getDb()
|
|
179
|
+
.prepare(`SELECT file_id, rel_path FROM files WHERE file_id IN (${placeholders})`)
|
|
180
|
+
.all(...chunk);
|
|
181
|
+
for (const row of rows) {
|
|
182
|
+
result.set(row.file_id, row);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return result;
|
|
186
|
+
}
|
|
187
|
+
// Symbol operations
|
|
188
|
+
/**
|
|
189
|
+
* Inserts or updates a symbol record.
|
|
190
|
+
* Uses upsert semantics to handle both new and existing symbols.
|
|
191
|
+
*
|
|
192
|
+
* @param symbol - Complete symbol record with all fields
|
|
193
|
+
*/
|
|
194
|
+
export function upsertSymbol(symbol) {
|
|
195
|
+
stmt(`INSERT INTO symbols (
|
|
196
|
+
symbol_id, repo_id, file_id, kind, name, exported, visibility, language,
|
|
197
|
+
range_start_line, range_start_col, range_end_line, range_end_col,
|
|
198
|
+
ast_fingerprint, signature_json, summary, invariants_json, side_effects_json, updated_at
|
|
199
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
200
|
+
ON CONFLICT(symbol_id) DO UPDATE SET
|
|
201
|
+
repo_id = excluded.repo_id,
|
|
202
|
+
file_id = excluded.file_id,
|
|
203
|
+
kind = excluded.kind,
|
|
204
|
+
name = excluded.name,
|
|
205
|
+
exported = excluded.exported,
|
|
206
|
+
visibility = excluded.visibility,
|
|
207
|
+
language = excluded.language,
|
|
208
|
+
range_start_line = excluded.range_start_line,
|
|
209
|
+
range_start_col = excluded.range_start_col,
|
|
210
|
+
range_end_line = excluded.range_end_line,
|
|
211
|
+
range_end_col = excluded.range_end_col,
|
|
212
|
+
ast_fingerprint = excluded.ast_fingerprint,
|
|
213
|
+
signature_json = excluded.signature_json,
|
|
214
|
+
summary = excluded.summary,
|
|
215
|
+
invariants_json = excluded.invariants_json,
|
|
216
|
+
side_effects_json = excluded.side_effects_json,
|
|
217
|
+
updated_at = excluded.updated_at`).run(symbol.symbol_id, symbol.repo_id, symbol.file_id, symbol.kind, symbol.name, symbol.exported, symbol.visibility, symbol.language, symbol.range_start_line, symbol.range_start_col, symbol.range_end_line, symbol.range_end_col, symbol.ast_fingerprint, symbol.signature_json, symbol.summary, symbol.invariants_json, symbol.side_effects_json, symbol.updated_at);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Retrieves a symbol by ID.
|
|
221
|
+
*
|
|
222
|
+
* @param symbolId - Symbol identifier
|
|
223
|
+
* @returns Symbol record or null if not found
|
|
224
|
+
*/
|
|
225
|
+
export function getSymbol(symbolId) {
|
|
226
|
+
return stmt("SELECT * FROM symbols WHERE symbol_id = ?").get(symbolId);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Lists all symbols for a file.
|
|
230
|
+
*
|
|
231
|
+
* @param fileId - File identifier
|
|
232
|
+
* @returns Array of symbol records for the file
|
|
233
|
+
*/
|
|
234
|
+
export function getSymbolsByFile(fileId) {
|
|
235
|
+
return stmt("SELECT * FROM symbols WHERE file_id = ?").all(fileId);
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Lists all symbol IDs for a file (minimal projection).
|
|
239
|
+
* Use when only symbol IDs are needed, not full records.
|
|
240
|
+
*
|
|
241
|
+
* @param fileId - File identifier
|
|
242
|
+
* @returns Array of symbol identifiers
|
|
243
|
+
*/
|
|
244
|
+
export function getSymbolIdsByFile(fileId) {
|
|
245
|
+
return stmt("SELECT symbol_id FROM symbols WHERE file_id = ?")
|
|
246
|
+
.all(fileId)
|
|
247
|
+
.map((row) => row.symbol_id);
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Lists all symbols for a file with minimal projection.
|
|
251
|
+
* Returns symbol_id, name, exported for import resolution.
|
|
252
|
+
*
|
|
253
|
+
* @param fileId - File identifier
|
|
254
|
+
* @returns Array of symbol records with minimal fields
|
|
255
|
+
*/
|
|
256
|
+
export function getSymbolsByFileLite(fileId) {
|
|
257
|
+
return stmt("SELECT symbol_id, name, exported FROM symbols WHERE file_id = ?").all(fileId);
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Lists all symbols for a repository.
|
|
261
|
+
*
|
|
262
|
+
* @param repoId - Repository identifier
|
|
263
|
+
* @returns Array of all symbol records for repository
|
|
264
|
+
*/
|
|
265
|
+
export function getSymbolsByRepo(repoId) {
|
|
266
|
+
return stmt("SELECT * FROM symbols WHERE repo_id = ?").all(repoId);
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Lists all symbols for a repository with version snapshot projection.
|
|
270
|
+
* Returns only fields needed for versioning: symbol_id, ast_fingerprint, signature_json,
|
|
271
|
+
* summary, invariants_json, side_effects_json.
|
|
272
|
+
*
|
|
273
|
+
* @param repoId - Repository identifier
|
|
274
|
+
* @returns Array of symbol records for snapshot
|
|
275
|
+
*/
|
|
276
|
+
export function getSymbolsByRepoForSnapshot(repoId) {
|
|
277
|
+
return stmt(`SELECT symbol_id, ast_fingerprint, signature_json, summary, invariants_json, side_effects_json
|
|
278
|
+
FROM symbols WHERE repo_id = ?`).all(repoId);
|
|
279
|
+
}
|
|
280
|
+
export function countSymbolsByRepo(repoId) {
|
|
281
|
+
const result = stmt("SELECT COUNT(*) as count FROM symbols WHERE repo_id = ?").get(repoId);
|
|
282
|
+
return result.count;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Batch fetch symbols by IDs. Uses chunked queries to avoid SQLite parameter limits.
|
|
286
|
+
* Returns a Map for O(1) lookup by symbol_id.
|
|
287
|
+
*
|
|
288
|
+
* @param symbolIds - Array of symbol identifiers
|
|
289
|
+
* @returns Map of symbol_id to SymbolRow
|
|
290
|
+
*/
|
|
291
|
+
export function getSymbolsByIds(symbolIds) {
|
|
292
|
+
if (symbolIds.length === 0)
|
|
293
|
+
return new Map();
|
|
294
|
+
const result = new Map();
|
|
295
|
+
for (let i = 0; i < symbolIds.length; i += DB_CHUNK_SIZE) {
|
|
296
|
+
const chunk = symbolIds.slice(i, i + DB_CHUNK_SIZE);
|
|
297
|
+
const placeholders = chunk.map(() => "?").join(",");
|
|
298
|
+
const rows = getDb()
|
|
299
|
+
.prepare(`SELECT * FROM symbols WHERE symbol_id IN (${placeholders})`)
|
|
300
|
+
.all(...chunk);
|
|
301
|
+
for (const row of rows) {
|
|
302
|
+
result.set(row.symbol_id, row);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return result;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Batch fetch symbols by IDs with minimal projection.
|
|
309
|
+
* Returns only symbol_id, name, file_id for lightweight lookups.
|
|
310
|
+
* Uses chunked queries to avoid SQLite parameter limits.
|
|
311
|
+
*
|
|
312
|
+
* @param symbolIds - Array of symbol identifiers
|
|
313
|
+
* @returns Map of symbol_id to minimal symbol record
|
|
314
|
+
*/
|
|
315
|
+
export function getSymbolsByIdsLite(symbolIds) {
|
|
316
|
+
if (symbolIds.length === 0)
|
|
317
|
+
return new Map();
|
|
318
|
+
const result = new Map();
|
|
319
|
+
for (let i = 0; i < symbolIds.length; i += DB_CHUNK_SIZE) {
|
|
320
|
+
const chunk = symbolIds.slice(i, i + DB_CHUNK_SIZE);
|
|
321
|
+
const placeholders = chunk.map(() => "?").join(",");
|
|
322
|
+
const rows = getDb()
|
|
323
|
+
.prepare(`SELECT symbol_id, name, file_id FROM symbols WHERE symbol_id IN (${placeholders})`)
|
|
324
|
+
.all(...chunk);
|
|
325
|
+
for (const row of rows) {
|
|
326
|
+
result.set(row.symbol_id, row);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return result;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Searches symbols by name or summary with LIKE pattern matching.
|
|
333
|
+
* Returns full symbol records with all fields.
|
|
334
|
+
*
|
|
335
|
+
* @param repoId - Repository identifier
|
|
336
|
+
* @param query - Search query string
|
|
337
|
+
* @param limit - Maximum number of results to return
|
|
338
|
+
* @returns Array of matching symbol records
|
|
339
|
+
*/
|
|
340
|
+
export function searchSymbols(repoId, query, limit) {
|
|
341
|
+
const searchPattern = `%${escapeSearchPattern(query)}%`;
|
|
342
|
+
// Order results by relevance:
|
|
343
|
+
// 1. Exact name match (case-sensitive) first
|
|
344
|
+
// 2. Exact name match (case-insensitive) second
|
|
345
|
+
// 3. Prefer core files over adapter/test files (deprioritize adapter/, tests/, scripts/)
|
|
346
|
+
// 4. Important symbol kinds (class, function, interface, type, method) before variables
|
|
347
|
+
// 5. Name matches before summary-only matches
|
|
348
|
+
return stmt(`SELECT s.* FROM symbols s
|
|
349
|
+
JOIN files f ON s.file_id = f.file_id
|
|
350
|
+
WHERE s.repo_id = ? AND (s.name LIKE ? ESCAPE '\\' OR s.summary LIKE ? ESCAPE '\\')
|
|
351
|
+
ORDER BY
|
|
352
|
+
CASE WHEN s.name = ? THEN 0 ELSE 1 END,
|
|
353
|
+
CASE WHEN LOWER(s.name) = LOWER(?) THEN 0 ELSE 1 END,
|
|
354
|
+
CASE
|
|
355
|
+
WHEN f.rel_path LIKE '%/adapter/%' THEN 2
|
|
356
|
+
WHEN f.rel_path LIKE '%/tests/%' OR f.rel_path LIKE 'tests/%' THEN 2
|
|
357
|
+
WHEN f.rel_path LIKE 'scripts/%' THEN 2
|
|
358
|
+
WHEN f.rel_path LIKE '%.test.%' OR f.rel_path LIKE '%.spec.%' THEN 2
|
|
359
|
+
ELSE 0
|
|
360
|
+
END,
|
|
361
|
+
CASE s.kind
|
|
362
|
+
WHEN 'class' THEN 0
|
|
363
|
+
WHEN 'function' THEN 1
|
|
364
|
+
WHEN 'interface' THEN 2
|
|
365
|
+
WHEN 'type' THEN 3
|
|
366
|
+
WHEN 'method' THEN 4
|
|
367
|
+
WHEN 'constructor' THEN 5
|
|
368
|
+
WHEN 'module' THEN 6
|
|
369
|
+
ELSE 7
|
|
370
|
+
END,
|
|
371
|
+
CASE WHEN s.name LIKE ? ESCAPE '\\' THEN 0 ELSE 1 END
|
|
372
|
+
LIMIT ?`).all(repoId, searchPattern, searchPattern, query, query, searchPattern, limit);
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Searches symbols by name or summary with LIKE pattern matching.
|
|
376
|
+
* Returns minimal projection: only symbol_id, name, file_id, kind.
|
|
377
|
+
* Use for search result listings where full symbol data is not needed.
|
|
378
|
+
*
|
|
379
|
+
* @param repoId - Repository identifier
|
|
380
|
+
* @param query - Search query string
|
|
381
|
+
* @param limit - Maximum number of results to return
|
|
382
|
+
* @returns Array of symbol records with minimal fields
|
|
383
|
+
*/
|
|
384
|
+
export function searchSymbolsLite(repoId, query, limit) {
|
|
385
|
+
const searchPattern = `%${escapeSearchPattern(query)}%`;
|
|
386
|
+
// Order results by relevance (same logic as searchSymbols)
|
|
387
|
+
return stmt(`SELECT s.symbol_id, s.name, s.file_id, s.kind FROM symbols s
|
|
388
|
+
JOIN files f ON s.file_id = f.file_id
|
|
389
|
+
WHERE s.repo_id = ? AND (s.name LIKE ? ESCAPE '\\' OR s.summary LIKE ? ESCAPE '\\')
|
|
390
|
+
ORDER BY
|
|
391
|
+
CASE WHEN s.name = ? THEN 0 ELSE 1 END,
|
|
392
|
+
CASE WHEN LOWER(s.name) = LOWER(?) THEN 0 ELSE 1 END,
|
|
393
|
+
CASE
|
|
394
|
+
WHEN f.rel_path LIKE '%/adapter/%' THEN 2
|
|
395
|
+
WHEN f.rel_path LIKE '%/tests/%' OR f.rel_path LIKE 'tests/%' THEN 2
|
|
396
|
+
WHEN f.rel_path LIKE 'scripts/%' THEN 2
|
|
397
|
+
WHEN f.rel_path LIKE '%.test.%' OR f.rel_path LIKE '%.spec.%' THEN 2
|
|
398
|
+
ELSE 0
|
|
399
|
+
END,
|
|
400
|
+
CASE s.kind
|
|
401
|
+
WHEN 'class' THEN 0
|
|
402
|
+
WHEN 'function' THEN 1
|
|
403
|
+
WHEN 'interface' THEN 2
|
|
404
|
+
WHEN 'type' THEN 3
|
|
405
|
+
WHEN 'method' THEN 4
|
|
406
|
+
WHEN 'constructor' THEN 5
|
|
407
|
+
WHEN 'module' THEN 6
|
|
408
|
+
ELSE 7
|
|
409
|
+
END,
|
|
410
|
+
CASE WHEN s.name LIKE ? ESCAPE '\\' THEN 0 ELSE 1 END
|
|
411
|
+
LIMIT ?`).all(repoId, searchPattern, searchPattern, query, query, searchPattern, limit);
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Finds symbols within a line range, sorted by containment.
|
|
415
|
+
* Returns fully contained symbols first, then overlapping.
|
|
416
|
+
*
|
|
417
|
+
* @param repoId - Repository identifier
|
|
418
|
+
* @param fileId - File identifier
|
|
419
|
+
* @param startLine - Start line of range (1-indexed)
|
|
420
|
+
* @param endLine - End line of range (1-indexed)
|
|
421
|
+
* @returns Array of symbol records sorted by containment
|
|
422
|
+
*/
|
|
423
|
+
export function findSymbolsInRange(repoId, fileId, startLine, endLine) {
|
|
424
|
+
return stmt(`SELECT * FROM symbols
|
|
425
|
+
WHERE repo_id = ? AND file_id = ?
|
|
426
|
+
AND range_start_line <= ? AND range_end_line >= ?
|
|
427
|
+
ORDER BY
|
|
428
|
+
CASE
|
|
429
|
+
WHEN range_start_line >= ? AND range_end_line <= ? THEN 0
|
|
430
|
+
WHEN range_start_line <= ? AND range_end_line >= ? THEN 1
|
|
431
|
+
WHEN range_start_line >= ? AND range_start_line <= ? THEN 2
|
|
432
|
+
WHEN range_end_line >= ? AND range_end_line <= ? THEN 3
|
|
433
|
+
ELSE 4
|
|
434
|
+
END,
|
|
435
|
+
ABS(range_start_line - ?)`).all(repoId, fileId, endLine, startLine, startLine, endLine, startLine, endLine, startLine, endLine, startLine, endLine, startLine, startLine);
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Finds symbols within a line range with minimal projection.
|
|
439
|
+
* Returns only symbol_id for diagnostic mapping.
|
|
440
|
+
*
|
|
441
|
+
* @param repoId - Repository identifier
|
|
442
|
+
* @param fileId - File identifier
|
|
443
|
+
* @param startLine - Start line of range (1-indexed)
|
|
444
|
+
* @param endLine - End line of range (1-indexed)
|
|
445
|
+
* @returns Array of symbol IDs sorted by containment
|
|
446
|
+
*/
|
|
447
|
+
export function findSymbolsInRangeLite(repoId, fileId, startLine, endLine) {
|
|
448
|
+
return stmt(`SELECT symbol_id FROM symbols
|
|
449
|
+
WHERE repo_id = ? AND file_id = ?
|
|
450
|
+
AND range_start_line <= ? AND range_end_line >= ?
|
|
451
|
+
ORDER BY
|
|
452
|
+
CASE
|
|
453
|
+
WHEN range_start_line >= ? AND range_end_line <= ? THEN 0
|
|
454
|
+
WHEN range_start_line <= ? AND range_end_line >= ? THEN 1
|
|
455
|
+
WHEN range_start_line >= ? AND range_start_line <= ? THEN 2
|
|
456
|
+
WHEN range_end_line >= ? AND range_end_line <= ? THEN 3
|
|
457
|
+
ELSE 4
|
|
458
|
+
END,
|
|
459
|
+
ABS(range_start_line - ?)`).all(repoId, fileId, endLine, startLine, startLine, endLine, startLine, endLine, startLine, endLine, startLine, endLine, startLine, startLine);
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Deletes all symbols for a file.
|
|
463
|
+
*
|
|
464
|
+
* @param fileId - File identifier
|
|
465
|
+
*/
|
|
466
|
+
export function deleteSymbolsByFile(fileId) {
|
|
467
|
+
stmt("DELETE FROM symbols WHERE file_id = ?").run(fileId);
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Deletes all symbols for a file along with their edges, metrics, and versions.
|
|
471
|
+
* Runs within a transaction for atomicity.
|
|
472
|
+
*
|
|
473
|
+
* @param fileId - File identifier
|
|
474
|
+
*/
|
|
475
|
+
export function deleteSymbolsByFileWithEdges(fileId) {
|
|
476
|
+
// Cascading foreign keys on symbols remove dependent edges/metrics/versions.
|
|
477
|
+
deleteSymbolsByFile(fileId);
|
|
478
|
+
}
|
|
479
|
+
// Edge operations
|
|
480
|
+
/**
|
|
481
|
+
* Creates a new edge record.
|
|
482
|
+
*
|
|
483
|
+
* @param edge - Edge record with all required fields
|
|
484
|
+
*/
|
|
485
|
+
export function createEdge(edge) {
|
|
486
|
+
stmt("INSERT INTO edges (repo_id, from_symbol_id, to_symbol_id, type, weight, provenance, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)").run(edge.repo_id, edge.from_symbol_id, edge.to_symbol_id, edge.type, edge.weight, edge.provenance, edge.created_at);
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Retrieves outgoing edges for a symbol.
|
|
490
|
+
*
|
|
491
|
+
* @param symbolId - Symbol identifier
|
|
492
|
+
* @returns Array of outgoing edge records
|
|
493
|
+
*/
|
|
494
|
+
export function getEdgesFrom(symbolId) {
|
|
495
|
+
return stmt("SELECT * FROM edges WHERE from_symbol_id = ?").all(symbolId);
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Retrieves incoming edges for a symbol.
|
|
499
|
+
* Used by scripts/dump-symbol.ts for symbol analysis.
|
|
500
|
+
*
|
|
501
|
+
* @param symbolId - Symbol identifier
|
|
502
|
+
* @returns Array of incoming edge records
|
|
503
|
+
*/
|
|
504
|
+
export function getEdgesTo(symbolId) {
|
|
505
|
+
return stmt("SELECT * FROM edges WHERE to_symbol_id = ?").all(symbolId);
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Lists all edges for a repository.
|
|
509
|
+
*
|
|
510
|
+
* @param repoId - Repository identifier
|
|
511
|
+
* @returns Array of all edge records for repository
|
|
512
|
+
*/
|
|
513
|
+
export function getEdgesByRepo(repoId) {
|
|
514
|
+
return stmt("SELECT * FROM edges WHERE repo_id = ?").all(repoId);
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Batch fetch outgoing edges for multiple symbols. Uses chunked queries.
|
|
518
|
+
* Returns a Map where key is from_symbol_id and value is array of edges.
|
|
519
|
+
*
|
|
520
|
+
* @param symbolIds - Array of symbol identifiers
|
|
521
|
+
* @returns Map of symbol_id to array of outgoing edges
|
|
522
|
+
*/
|
|
523
|
+
export function getEdgesFromSymbols(symbolIds) {
|
|
524
|
+
if (symbolIds.length === 0)
|
|
525
|
+
return new Map();
|
|
526
|
+
const result = new Map();
|
|
527
|
+
// Initialize empty arrays for all requested symbols
|
|
528
|
+
for (const id of symbolIds) {
|
|
529
|
+
result.set(id, []);
|
|
530
|
+
}
|
|
531
|
+
for (let i = 0; i < symbolIds.length; i += DB_CHUNK_SIZE) {
|
|
532
|
+
const chunk = symbolIds.slice(i, i + DB_CHUNK_SIZE);
|
|
533
|
+
const placeholders = chunk.map(() => "?").join(",");
|
|
534
|
+
const rows = getDb()
|
|
535
|
+
.prepare(`SELECT * FROM edges WHERE from_symbol_id IN (${placeholders})`)
|
|
536
|
+
.all(...chunk);
|
|
537
|
+
for (const row of rows) {
|
|
538
|
+
const edges = result.get(row.from_symbol_id);
|
|
539
|
+
if (edges) {
|
|
540
|
+
edges.push(row);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return result;
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Batch fetch outgoing edges for multiple symbols with minimal projection.
|
|
548
|
+
* Returns only from_symbol_id, to_symbol_id, type for dependency tracking.
|
|
549
|
+
* Uses chunked queries to avoid SQLite parameter limits.
|
|
550
|
+
*
|
|
551
|
+
* @param symbolIds - Array of symbol identifiers
|
|
552
|
+
* @returns Map of symbol_id to array of minimal edge records
|
|
553
|
+
*/
|
|
554
|
+
export function getEdgesFromSymbolsLite(symbolIds) {
|
|
555
|
+
if (symbolIds.length === 0)
|
|
556
|
+
return new Map();
|
|
557
|
+
const result = new Map();
|
|
558
|
+
// Initialize empty arrays for all requested symbols
|
|
559
|
+
for (const id of symbolIds) {
|
|
560
|
+
result.set(id, []);
|
|
561
|
+
}
|
|
562
|
+
for (let i = 0; i < symbolIds.length; i += DB_CHUNK_SIZE) {
|
|
563
|
+
const chunk = symbolIds.slice(i, i + DB_CHUNK_SIZE);
|
|
564
|
+
const placeholders = chunk.map(() => "?").join(",");
|
|
565
|
+
const rows = getDb()
|
|
566
|
+
.prepare(`SELECT from_symbol_id, to_symbol_id, type FROM edges WHERE from_symbol_id IN (${placeholders})`)
|
|
567
|
+
.all(...chunk);
|
|
568
|
+
for (const row of rows) {
|
|
569
|
+
const edges = result.get(row.from_symbol_id);
|
|
570
|
+
if (edges) {
|
|
571
|
+
edges.push(row);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
return result;
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* Deletes all edges (both incoming and outgoing) for a symbol.
|
|
579
|
+
*
|
|
580
|
+
* @param symbolId - Symbol identifier
|
|
581
|
+
*/
|
|
582
|
+
export function deleteEdgesBySymbol(symbolId) {
|
|
583
|
+
stmt("DELETE FROM edges WHERE from_symbol_id = ? OR to_symbol_id = ?").run(symbolId, symbolId);
|
|
584
|
+
}
|
|
585
|
+
// Version operations
|
|
586
|
+
export function createVersion(version) {
|
|
587
|
+
stmt("INSERT INTO versions (version_id, repo_id, created_at, reason) VALUES (?, ?, ?, ?)").run(version.version_id, version.repo_id, version.created_at, version.reason);
|
|
588
|
+
}
|
|
589
|
+
export function getVersion(versionId) {
|
|
590
|
+
return stmt("SELECT * FROM versions WHERE version_id = ?").get(versionId);
|
|
591
|
+
}
|
|
592
|
+
export function getLatestVersion(repoId) {
|
|
593
|
+
return stmt("SELECT * FROM versions WHERE repo_id = ? ORDER BY created_at DESC LIMIT 1").get(repoId);
|
|
594
|
+
}
|
|
595
|
+
export function listVersions(repoId, limit = DB_QUERY_LIMIT_DEFAULT) {
|
|
596
|
+
return stmt("SELECT * FROM versions WHERE repo_id = ? ORDER BY created_at DESC LIMIT ?").all(repoId, limit);
|
|
597
|
+
}
|
|
598
|
+
// Symbol version operations
|
|
599
|
+
export function snapshotSymbolVersion(versionId, symbolId, snapshot) {
|
|
600
|
+
stmt(`INSERT INTO symbol_versions (version_id, symbol_id, ast_fingerprint, signature_json, summary, invariants_json, side_effects_json)
|
|
601
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
602
|
+
ON CONFLICT(version_id, symbol_id) DO UPDATE SET
|
|
603
|
+
ast_fingerprint = excluded.ast_fingerprint,
|
|
604
|
+
signature_json = excluded.signature_json,
|
|
605
|
+
summary = excluded.summary,
|
|
606
|
+
invariants_json = excluded.invariants_json,
|
|
607
|
+
side_effects_json = excluded.side_effects_json`).run(versionId, symbolId, snapshot.ast_fingerprint, snapshot.signature_json, snapshot.summary, snapshot.invariants_json, snapshot.side_effects_json);
|
|
608
|
+
}
|
|
609
|
+
export function getSymbolVersion(versionId, symbolId) {
|
|
610
|
+
return stmt("SELECT * FROM symbol_versions WHERE version_id = ? AND symbol_id = ?").get(versionId, symbolId);
|
|
611
|
+
}
|
|
612
|
+
// Metrics operations
|
|
613
|
+
export function upsertMetrics(metrics) {
|
|
614
|
+
stmt(`INSERT INTO metrics (symbol_id, fan_in, fan_out, churn_30d, test_refs_json, updated_at)
|
|
615
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
616
|
+
ON CONFLICT(symbol_id) DO UPDATE SET
|
|
617
|
+
fan_in = excluded.fan_in,
|
|
618
|
+
fan_out = excluded.fan_out,
|
|
619
|
+
churn_30d = excluded.churn_30d,
|
|
620
|
+
test_refs_json = excluded.test_refs_json,
|
|
621
|
+
updated_at = excluded.updated_at`).run(metrics.symbolId, metrics.fanIn, metrics.fanOut, metrics.churn30d, metrics.testRefsJson, metrics.updatedAt);
|
|
622
|
+
}
|
|
623
|
+
export function getMetrics(symbolId) {
|
|
624
|
+
return stmt("SELECT * FROM metrics WHERE symbol_id = ?").get(symbolId);
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Batch fetch metrics by symbol IDs. Uses chunked queries to avoid SQLite parameter limits.
|
|
628
|
+
* Returns a Map for O(1) lookup by symbol_id.
|
|
629
|
+
*/
|
|
630
|
+
export function getMetricsBySymbolIds(symbolIds) {
|
|
631
|
+
if (symbolIds.length === 0)
|
|
632
|
+
return new Map();
|
|
633
|
+
const result = new Map();
|
|
634
|
+
for (let i = 0; i < symbolIds.length; i += DB_CHUNK_SIZE) {
|
|
635
|
+
const chunk = symbolIds.slice(i, i + DB_CHUNK_SIZE);
|
|
636
|
+
const placeholders = chunk.map(() => "?").join(",");
|
|
637
|
+
const rows = getDb()
|
|
638
|
+
.prepare(`SELECT * FROM metrics WHERE symbol_id IN (${placeholders})`)
|
|
639
|
+
.all(...chunk);
|
|
640
|
+
for (const row of rows) {
|
|
641
|
+
result.set(row.symbol_id, row);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
return result;
|
|
645
|
+
}
|
|
646
|
+
const AuditEventSchema = z.object({
|
|
647
|
+
timestamp: z.string(),
|
|
648
|
+
tool: z.string(),
|
|
649
|
+
decision: z.string(),
|
|
650
|
+
repoId: z.string().optional(),
|
|
651
|
+
symbolId: z.string().optional(),
|
|
652
|
+
detailsJson: z.string(),
|
|
653
|
+
});
|
|
654
|
+
export function logAuditEvent(event) {
|
|
655
|
+
const validated = AuditEventSchema.parse(event);
|
|
656
|
+
stmt("INSERT INTO audit (timestamp, tool, decision, repo_id, symbol_id, details_json) VALUES (?, ?, ?, ?, ?, ?)").run(validated.timestamp, validated.tool, validated.decision, validated.repoId ?? null, validated.symbolId ?? null, validated.detailsJson);
|
|
657
|
+
}
|
|
658
|
+
export function getAuditEvents(repoId, limit) {
|
|
659
|
+
return stmt(`SELECT * FROM audit
|
|
660
|
+
WHERE (? IS NULL OR repo_id = ?)
|
|
661
|
+
ORDER BY timestamp DESC
|
|
662
|
+
LIMIT ?`).all(repoId ?? null, repoId ?? null, limit ?? DB_QUERY_LIMIT_MAX);
|
|
663
|
+
}
|
|
664
|
+
// Transaction helpers
|
|
665
|
+
export function createRepoTransaction(repo) {
|
|
666
|
+
const db = getDb();
|
|
667
|
+
const createTx = db.transaction(() => {
|
|
668
|
+
createRepo(repo);
|
|
669
|
+
});
|
|
670
|
+
createTx();
|
|
671
|
+
}
|
|
672
|
+
export function upsertFileTransaction(file) {
|
|
673
|
+
const db = getDb();
|
|
674
|
+
const upsertTx = db.transaction(() => {
|
|
675
|
+
upsertFile(file);
|
|
676
|
+
});
|
|
677
|
+
upsertTx();
|
|
678
|
+
}
|
|
679
|
+
export function upsertSymbolTransaction(symbol) {
|
|
680
|
+
const db = getDb();
|
|
681
|
+
const upsertTx = db.transaction(() => {
|
|
682
|
+
upsertSymbol(symbol);
|
|
683
|
+
});
|
|
684
|
+
upsertTx();
|
|
685
|
+
}
|
|
686
|
+
export function createEdgeTransaction(edge) {
|
|
687
|
+
const db = getDb();
|
|
688
|
+
const createTx = db.transaction(() => {
|
|
689
|
+
createEdge(edge);
|
|
690
|
+
});
|
|
691
|
+
createTx();
|
|
692
|
+
}
|
|
693
|
+
export function createVersionTransaction(version) {
|
|
694
|
+
const db = getDb();
|
|
695
|
+
const createTx = db.transaction(() => {
|
|
696
|
+
createVersion(version);
|
|
697
|
+
});
|
|
698
|
+
createTx();
|
|
699
|
+
}
|
|
700
|
+
export function deleteFileTransaction(fileId) {
|
|
701
|
+
const db = getDb();
|
|
702
|
+
const deleteTx = db.transaction(() => {
|
|
703
|
+
deleteSymbolsByFileWithEdges(fileId);
|
|
704
|
+
deleteSymbolReferencesByFileId(fileId);
|
|
705
|
+
deleteFile(fileId);
|
|
706
|
+
});
|
|
707
|
+
deleteTx();
|
|
708
|
+
}
|
|
709
|
+
export function deleteSymbolTransaction(symbolId) {
|
|
710
|
+
const db = getDb();
|
|
711
|
+
const deleteTx = db.transaction(() => {
|
|
712
|
+
deleteEdgesBySymbol(symbolId);
|
|
713
|
+
stmt("DELETE FROM metrics WHERE symbol_id = ?").run(symbolId);
|
|
714
|
+
stmt("DELETE FROM symbol_versions WHERE symbol_id = ?").run(symbolId);
|
|
715
|
+
stmt("DELETE FROM symbols WHERE symbol_id = ?").run(symbolId);
|
|
716
|
+
});
|
|
717
|
+
deleteTx();
|
|
718
|
+
}
|
|
719
|
+
export function createSnapshotTransaction(version, snapshots) {
|
|
720
|
+
const db = getDb();
|
|
721
|
+
const snapshotTx = db.transaction(() => {
|
|
722
|
+
createVersion(version);
|
|
723
|
+
for (const snapshot of snapshots) {
|
|
724
|
+
snapshotSymbolVersion(version.version_id, snapshot.symbol_id, snapshot);
|
|
725
|
+
}
|
|
726
|
+
const sortedVersions = [...snapshots].sort((a, b) => a.symbol_id.localeCompare(b.symbol_id));
|
|
727
|
+
const fingerprints = sortedVersions
|
|
728
|
+
.map((sv) => sv.ast_fingerprint)
|
|
729
|
+
.join("|");
|
|
730
|
+
const combined = `${version.prev_version_hash || "none"}:${fingerprints}`;
|
|
731
|
+
const versionHash = hashContent(combined);
|
|
732
|
+
updateVersionHashes(version.version_id, version.prev_version_hash, versionHash);
|
|
733
|
+
});
|
|
734
|
+
snapshotTx();
|
|
735
|
+
}
|
|
736
|
+
// Slice handle operations
|
|
737
|
+
export function createSliceHandle(handle) {
|
|
738
|
+
stmt(`INSERT INTO slice_handles (handle, repo_id, created_at, expires_at, min_version, max_version, slice_hash, spillover_ref)
|
|
739
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(handle.handle, handle.repo_id, handle.created_at, handle.expires_at, handle.min_version ?? null, handle.max_version ?? null, handle.slice_hash, handle.spillover_ref ?? null);
|
|
740
|
+
}
|
|
741
|
+
export function getSliceHandle(handle) {
|
|
742
|
+
return stmt("SELECT * FROM slice_handles WHERE handle = ?").get(handle);
|
|
743
|
+
}
|
|
744
|
+
export function deleteSliceHandle(handle) {
|
|
745
|
+
stmt("DELETE FROM slice_handles WHERE handle = ?").run(handle);
|
|
746
|
+
}
|
|
747
|
+
export function deleteExpiredSliceHandles(beforeTimestamp) {
|
|
748
|
+
const result = stmt("DELETE FROM slice_handles WHERE expires_at < ?").run(beforeTimestamp);
|
|
749
|
+
return result.changes;
|
|
750
|
+
}
|
|
751
|
+
export function updateSliceHandleSpillover(handle, spilloverRef) {
|
|
752
|
+
stmt("UPDATE slice_handles SET spillover_ref = ? WHERE handle = ?").run(spilloverRef, handle);
|
|
753
|
+
}
|
|
754
|
+
// Content-addressed storage operations
|
|
755
|
+
export function upsertCardHash(cardHash, cardBlob, createdAt) {
|
|
756
|
+
stmt(`INSERT INTO card_hashes (card_hash, card_blob, created_at)
|
|
757
|
+
VALUES (?, ?, ?)
|
|
758
|
+
ON CONFLICT(card_hash) DO NOTHING`).run(cardHash, cardBlob, createdAt);
|
|
759
|
+
}
|
|
760
|
+
export function getCardHash(cardHash) {
|
|
761
|
+
return stmt("SELECT * FROM card_hashes WHERE card_hash = ?").get(cardHash);
|
|
762
|
+
}
|
|
763
|
+
export function upsertToolPolicyHash(policyHash, policyBlob, createdAt) {
|
|
764
|
+
stmt(`INSERT INTO tool_policy_hashes (policy_hash, policy_blob, created_at)
|
|
765
|
+
VALUES (?, ?, ?)
|
|
766
|
+
ON CONFLICT(policy_hash) DO NOTHING`).run(policyHash, policyBlob, createdAt);
|
|
767
|
+
}
|
|
768
|
+
export function getToolPolicyHash(policyHash) {
|
|
769
|
+
return stmt("SELECT * FROM tool_policy_hashes WHERE policy_hash = ?").get(policyHash);
|
|
770
|
+
}
|
|
771
|
+
export function upsertTsconfigHash(tsconfigHash, tsconfigBlob, createdAt) {
|
|
772
|
+
stmt(`INSERT INTO tsconfig_hashes (tsconfig_hash, tsconfig_blob, created_at)
|
|
773
|
+
VALUES (?, ?, ?)
|
|
774
|
+
ON CONFLICT(tsconfig_hash) DO NOTHING`).run(tsconfigHash, tsconfigBlob, createdAt);
|
|
775
|
+
}
|
|
776
|
+
export function getTsconfigHash(tsconfigHash) {
|
|
777
|
+
return stmt("SELECT * FROM tsconfig_hashes WHERE tsconfig_hash = ?").get(tsconfigHash);
|
|
778
|
+
}
|
|
779
|
+
// Version hash operations
|
|
780
|
+
export function updateVersionHashes(versionId, prevVersionHash, versionHash) {
|
|
781
|
+
stmt("UPDATE versions SET prev_version_hash = ?, version_hash = ? WHERE version_id = ?").run(prevVersionHash, versionHash, versionId);
|
|
782
|
+
}
|
|
783
|
+
export function getVersionByHash(versionHash) {
|
|
784
|
+
return stmt("SELECT * FROM versions WHERE version_hash = ?").get(versionHash);
|
|
785
|
+
}
|
|
786
|
+
export function listVersionsByPrevHash(prevVersionHash) {
|
|
787
|
+
return stmt("SELECT * FROM versions WHERE prev_version_hash = ? ORDER BY created_at DESC").all(prevVersionHash);
|
|
788
|
+
}
|
|
789
|
+
// Symbol reference operations (inverted index for test references)
|
|
790
|
+
export function insertSymbolReference(ref) {
|
|
791
|
+
stmt(`INSERT INTO symbol_references (repo_id, symbol_name, file_id, line_number, created_at)
|
|
792
|
+
VALUES (?, ?, ?, ?, ?)`).run(ref.repo_id, ref.symbol_name, ref.file_id, ref.line_number, ref.created_at);
|
|
793
|
+
}
|
|
794
|
+
export function getTestRefsForSymbol(repoId, symbolName) {
|
|
795
|
+
return stmt(`SELECT f.rel_path FROM symbol_references sr
|
|
796
|
+
JOIN files f ON sr.file_id = f.file_id
|
|
797
|
+
WHERE sr.repo_id = ? AND sr.symbol_name = ?`)
|
|
798
|
+
.all(repoId, symbolName)
|
|
799
|
+
.map((r) => r.rel_path);
|
|
800
|
+
}
|
|
801
|
+
export function deleteSymbolReferencesByFileId(fileId) {
|
|
802
|
+
stmt("DELETE FROM symbol_references WHERE file_id = ?").run(fileId);
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Aggregates symbol counts by directory for a repository.
|
|
806
|
+
* Groups files by their parent directory and counts symbols by kind.
|
|
807
|
+
*
|
|
808
|
+
* @param repoId - Repository identifier
|
|
809
|
+
* @returns Array of directory aggregations
|
|
810
|
+
*/
|
|
811
|
+
export function getDirectoryAggregates(repoId) {
|
|
812
|
+
// Use pre-computed directory column for better performance
|
|
813
|
+
return stmt(`
|
|
814
|
+
SELECT
|
|
815
|
+
f.directory,
|
|
816
|
+
COUNT(DISTINCT s.file_id) as file_count,
|
|
817
|
+
COUNT(*) as symbol_count,
|
|
818
|
+
SUM(CASE WHEN s.exported = 1 THEN 1 ELSE 0 END) as exported_count,
|
|
819
|
+
SUM(CASE WHEN s.kind = 'function' THEN 1 ELSE 0 END) as function_count,
|
|
820
|
+
SUM(CASE WHEN s.kind = 'class' THEN 1 ELSE 0 END) as class_count,
|
|
821
|
+
SUM(CASE WHEN s.kind = 'interface' THEN 1 ELSE 0 END) as interface_count,
|
|
822
|
+
SUM(CASE WHEN s.kind = 'type' THEN 1 ELSE 0 END) as type_count,
|
|
823
|
+
SUM(CASE WHEN s.kind = 'method' THEN 1 ELSE 0 END) as method_count,
|
|
824
|
+
SUM(CASE WHEN s.kind = 'variable' THEN 1 ELSE 0 END) as variable_count,
|
|
825
|
+
SUM(CASE WHEN s.kind = 'module' THEN 1 ELSE 0 END) as module_count,
|
|
826
|
+
SUM(CASE WHEN s.kind = 'constructor' THEN 1 ELSE 0 END) as constructor_count
|
|
827
|
+
FROM symbols s
|
|
828
|
+
JOIN files f ON s.file_id = f.file_id
|
|
829
|
+
WHERE s.repo_id = ?
|
|
830
|
+
GROUP BY f.directory
|
|
831
|
+
ORDER BY symbol_count DESC
|
|
832
|
+
`).all(repoId);
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* Gets exported symbols grouped by directory.
|
|
836
|
+
*
|
|
837
|
+
* @param repoId - Repository identifier
|
|
838
|
+
* @param limit - Maximum symbols per directory
|
|
839
|
+
* @returns Array of exported symbol records with directory
|
|
840
|
+
*/
|
|
841
|
+
export function getExportedSymbolsByDirectory(repoId, limit = 20) {
|
|
842
|
+
return stmt(`
|
|
843
|
+
WITH file_dirs AS (
|
|
844
|
+
SELECT
|
|
845
|
+
file_id,
|
|
846
|
+
CASE
|
|
847
|
+
WHEN instr(rel_path, '/') > 0
|
|
848
|
+
THEN substr(rel_path, 1, length(rel_path) - length(replace(rel_path, rtrim(rel_path, replace(rel_path, '/', '')), '')))
|
|
849
|
+
ELSE ''
|
|
850
|
+
END as directory
|
|
851
|
+
FROM files
|
|
852
|
+
WHERE repo_id = ?
|
|
853
|
+
),
|
|
854
|
+
ranked_exports AS (
|
|
855
|
+
SELECT
|
|
856
|
+
s.symbol_id,
|
|
857
|
+
s.name,
|
|
858
|
+
s.kind,
|
|
859
|
+
s.exported,
|
|
860
|
+
s.signature_json,
|
|
861
|
+
fd.directory,
|
|
862
|
+
ROW_NUMBER() OVER (PARTITION BY fd.directory ORDER BY s.name) as rn
|
|
863
|
+
FROM symbols s
|
|
864
|
+
JOIN file_dirs fd ON s.file_id = fd.file_id
|
|
865
|
+
WHERE s.repo_id = ? AND s.exported = 1
|
|
866
|
+
)
|
|
867
|
+
SELECT symbol_id, name, kind, exported, directory, signature_json
|
|
868
|
+
FROM ranked_exports
|
|
869
|
+
WHERE rn <= ?
|
|
870
|
+
ORDER BY directory, name
|
|
871
|
+
`).all(repoId, repoId, limit);
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Gets top symbols by fan-in (most depended upon).
|
|
875
|
+
*
|
|
876
|
+
* @param repoId - Repository identifier
|
|
877
|
+
* @param limit - Maximum number of symbols to return
|
|
878
|
+
* @returns Array of symbols ordered by fan-in descending
|
|
879
|
+
*/
|
|
880
|
+
export function getTopSymbolsByFanIn(repoId, limit = 10) {
|
|
881
|
+
return stmt(`
|
|
882
|
+
WITH file_dirs AS (
|
|
883
|
+
SELECT
|
|
884
|
+
file_id,
|
|
885
|
+
CASE
|
|
886
|
+
WHEN instr(rel_path, '/') > 0
|
|
887
|
+
THEN substr(rel_path, 1, length(rel_path) - length(replace(rel_path, rtrim(rel_path, replace(rel_path, '/', '')), '')))
|
|
888
|
+
ELSE ''
|
|
889
|
+
END as directory
|
|
890
|
+
FROM files
|
|
891
|
+
WHERE repo_id = ?
|
|
892
|
+
)
|
|
893
|
+
SELECT
|
|
894
|
+
s.symbol_id,
|
|
895
|
+
s.name,
|
|
896
|
+
s.kind,
|
|
897
|
+
s.exported,
|
|
898
|
+
s.signature_json,
|
|
899
|
+
COALESCE(m.fan_in, 0) as fan_in,
|
|
900
|
+
COALESCE(m.fan_out, 0) as fan_out,
|
|
901
|
+
COALESCE(m.churn_30d, 0) as churn_30d,
|
|
902
|
+
COALESCE(fd.directory, '') as directory
|
|
903
|
+
FROM symbols s
|
|
904
|
+
LEFT JOIN metrics m ON s.symbol_id = m.symbol_id
|
|
905
|
+
LEFT JOIN file_dirs fd ON s.file_id = fd.file_id
|
|
906
|
+
WHERE s.repo_id = ?
|
|
907
|
+
ORDER BY COALESCE(m.fan_in, 0) DESC
|
|
908
|
+
LIMIT ?
|
|
909
|
+
`).all(repoId, repoId, limit);
|
|
910
|
+
}
|
|
911
|
+
/**
|
|
912
|
+
* Gets top symbols by churn (most frequently changed).
|
|
913
|
+
*
|
|
914
|
+
* @param repoId - Repository identifier
|
|
915
|
+
* @param limit - Maximum number of symbols to return
|
|
916
|
+
* @returns Array of symbols ordered by churn descending
|
|
917
|
+
*/
|
|
918
|
+
export function getTopSymbolsByChurn(repoId, limit = 10) {
|
|
919
|
+
return stmt(`
|
|
920
|
+
WITH file_dirs AS (
|
|
921
|
+
SELECT
|
|
922
|
+
file_id,
|
|
923
|
+
CASE
|
|
924
|
+
WHEN instr(rel_path, '/') > 0
|
|
925
|
+
THEN substr(rel_path, 1, length(rel_path) - length(replace(rel_path, rtrim(rel_path, replace(rel_path, '/', '')), '')))
|
|
926
|
+
ELSE ''
|
|
927
|
+
END as directory
|
|
928
|
+
FROM files
|
|
929
|
+
WHERE repo_id = ?
|
|
930
|
+
)
|
|
931
|
+
SELECT
|
|
932
|
+
s.symbol_id,
|
|
933
|
+
s.name,
|
|
934
|
+
s.kind,
|
|
935
|
+
s.exported,
|
|
936
|
+
s.signature_json,
|
|
937
|
+
COALESCE(m.fan_in, 0) as fan_in,
|
|
938
|
+
COALESCE(m.fan_out, 0) as fan_out,
|
|
939
|
+
COALESCE(m.churn_30d, 0) as churn_30d,
|
|
940
|
+
COALESCE(fd.directory, '') as directory
|
|
941
|
+
FROM symbols s
|
|
942
|
+
LEFT JOIN metrics m ON s.symbol_id = m.symbol_id
|
|
943
|
+
LEFT JOIN file_dirs fd ON s.file_id = fd.file_id
|
|
944
|
+
WHERE s.repo_id = ? AND COALESCE(m.churn_30d, 0) > 0
|
|
945
|
+
ORDER BY COALESCE(m.churn_30d, 0) DESC
|
|
946
|
+
LIMIT ?
|
|
947
|
+
`).all(repoId, repoId, limit);
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Gets files with most symbols.
|
|
951
|
+
*
|
|
952
|
+
* @param repoId - Repository identifier
|
|
953
|
+
* @param limit - Maximum number of files to return
|
|
954
|
+
* @returns Array of files ordered by symbol count descending
|
|
955
|
+
*/
|
|
956
|
+
export function getFilesBySymbolCount(repoId, limit = 10) {
|
|
957
|
+
return stmt(`
|
|
958
|
+
SELECT
|
|
959
|
+
f.rel_path,
|
|
960
|
+
CASE
|
|
961
|
+
WHEN instr(f.rel_path, '/') > 0
|
|
962
|
+
THEN substr(f.rel_path, 1, length(f.rel_path) - length(replace(f.rel_path, rtrim(f.rel_path, replace(f.rel_path, '/', '')), '')))
|
|
963
|
+
ELSE ''
|
|
964
|
+
END as directory,
|
|
965
|
+
COUNT(s.symbol_id) as symbol_count,
|
|
966
|
+
0 as edge_count
|
|
967
|
+
FROM files f
|
|
968
|
+
LEFT JOIN symbols s ON f.file_id = s.file_id
|
|
969
|
+
WHERE f.repo_id = ?
|
|
970
|
+
GROUP BY f.file_id
|
|
971
|
+
ORDER BY symbol_count DESC
|
|
972
|
+
LIMIT ?
|
|
973
|
+
`).all(repoId, limit);
|
|
974
|
+
}
|
|
975
|
+
/**
|
|
976
|
+
* Gets files with most edges (highest connectivity).
|
|
977
|
+
*
|
|
978
|
+
* @param repoId - Repository identifier
|
|
979
|
+
* @param limit - Maximum number of files to return
|
|
980
|
+
* @returns Array of files ordered by edge count descending
|
|
981
|
+
*/
|
|
982
|
+
export function getFilesByEdgeCount(repoId, limit = 10) {
|
|
983
|
+
return stmt(`
|
|
984
|
+
WITH file_edges AS (
|
|
985
|
+
SELECT
|
|
986
|
+
s.file_id,
|
|
987
|
+
COUNT(e.edge_id) as edge_count
|
|
988
|
+
FROM symbols s
|
|
989
|
+
LEFT JOIN edges e ON s.symbol_id = e.from_symbol_id OR s.symbol_id = e.to_symbol_id
|
|
990
|
+
WHERE s.repo_id = ?
|
|
991
|
+
GROUP BY s.file_id
|
|
992
|
+
)
|
|
993
|
+
SELECT
|
|
994
|
+
f.rel_path,
|
|
995
|
+
CASE
|
|
996
|
+
WHEN instr(f.rel_path, '/') > 0
|
|
997
|
+
THEN substr(f.rel_path, 1, length(f.rel_path) - length(replace(f.rel_path, rtrim(f.rel_path, replace(f.rel_path, '/', '')), '')))
|
|
998
|
+
ELSE ''
|
|
999
|
+
END as directory,
|
|
1000
|
+
0 as symbol_count,
|
|
1001
|
+
COALESCE(fe.edge_count, 0) as edge_count
|
|
1002
|
+
FROM files f
|
|
1003
|
+
LEFT JOIN file_edges fe ON f.file_id = fe.file_id
|
|
1004
|
+
WHERE f.repo_id = ?
|
|
1005
|
+
ORDER BY edge_count DESC
|
|
1006
|
+
LIMIT ?
|
|
1007
|
+
`).all(repoId, repoId, limit);
|
|
1008
|
+
}
|
|
1009
|
+
/**
|
|
1010
|
+
* Gets aggregate edge counts by type for a repository.
|
|
1011
|
+
*
|
|
1012
|
+
* @param repoId - Repository identifier
|
|
1013
|
+
* @returns Object with counts per edge type
|
|
1014
|
+
*/
|
|
1015
|
+
export function getEdgeCountsByType(repoId) {
|
|
1016
|
+
const rows = stmt(`
|
|
1017
|
+
SELECT type, COUNT(*) as count
|
|
1018
|
+
FROM edges
|
|
1019
|
+
WHERE repo_id = ?
|
|
1020
|
+
GROUP BY type
|
|
1021
|
+
`).all(repoId);
|
|
1022
|
+
const result = { call: 0, import: 0, config: 0 };
|
|
1023
|
+
for (const row of rows) {
|
|
1024
|
+
if (row.type === "call")
|
|
1025
|
+
result.call = row.count;
|
|
1026
|
+
else if (row.type === "import")
|
|
1027
|
+
result.import = row.count;
|
|
1028
|
+
else if (row.type === "config")
|
|
1029
|
+
result.config = row.count;
|
|
1030
|
+
}
|
|
1031
|
+
return result;
|
|
1032
|
+
}
|
|
1033
|
+
/**
|
|
1034
|
+
* Gets total counts for files, symbols, and edges in a repository.
|
|
1035
|
+
*
|
|
1036
|
+
* @param repoId - Repository identifier
|
|
1037
|
+
* @returns Object with total counts
|
|
1038
|
+
*/
|
|
1039
|
+
export function getRepoTotals(repoId) {
|
|
1040
|
+
const row = stmt(`
|
|
1041
|
+
SELECT
|
|
1042
|
+
(SELECT COUNT(*) FROM files WHERE repo_id = ?) as file_count,
|
|
1043
|
+
(SELECT COUNT(*) FROM symbols WHERE repo_id = ?) as symbol_count,
|
|
1044
|
+
(SELECT COUNT(*) FROM edges WHERE repo_id = ?) as edge_count,
|
|
1045
|
+
(SELECT COUNT(*) FROM symbols WHERE repo_id = ? AND exported = 1) as exported_count
|
|
1046
|
+
`).get(repoId, repoId, repoId, repoId);
|
|
1047
|
+
return {
|
|
1048
|
+
fileCount: row.file_count,
|
|
1049
|
+
symbolCount: row.symbol_count,
|
|
1050
|
+
edgeCount: row.edge_count,
|
|
1051
|
+
exportedCount: row.exported_count,
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
//# sourceMappingURL=queries.js.map
|