@vohongtho.infotech/code-intel 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/main.js +3401 -237
- package/dist/cli/main.js.map +1 -1
- package/dist/index.d.ts +386 -31
- package/dist/index.js +3940 -17
- package/dist/index.js.map +1 -1
- package/package.json +15 -12
- package/dist/call-graph/call-builder.d.ts +0 -6
- package/dist/call-graph/call-builder.d.ts.map +0 -1
- package/dist/call-graph/call-builder.js +0 -69
- package/dist/call-graph/call-builder.js.map +0 -1
- package/dist/call-graph/call-classifier.d.ts +0 -12
- package/dist/call-graph/call-classifier.d.ts.map +0 -1
- package/dist/call-graph/call-classifier.js +0 -11
- package/dist/call-graph/call-classifier.js.map +0 -1
- package/dist/call-graph/index.d.ts +0 -4
- package/dist/call-graph/index.d.ts.map +0 -1
- package/dist/call-graph/index.js +0 -3
- package/dist/call-graph/index.js.map +0 -1
- package/dist/cli/context-writer.d.ts +0 -18
- package/dist/cli/context-writer.d.ts.map +0 -1
- package/dist/cli/context-writer.js +0 -104
- package/dist/cli/context-writer.js.map +0 -1
- package/dist/cli/main.d.ts +0 -3
- package/dist/cli/main.d.ts.map +0 -1
- package/dist/cli/skill-writer.d.ts +0 -17
- package/dist/cli/skill-writer.d.ts.map +0 -1
- package/dist/cli/skill-writer.js +0 -249
- package/dist/cli/skill-writer.js.map +0 -1
- package/dist/clustering/community-detector.d.ts +0 -9
- package/dist/clustering/community-detector.d.ts.map +0 -1
- package/dist/clustering/community-detector.js +0 -67
- package/dist/clustering/community-detector.js.map +0 -1
- package/dist/clustering/index.d.ts +0 -3
- package/dist/clustering/index.d.ts.map +0 -1
- package/dist/clustering/index.js +0 -2
- package/dist/clustering/index.js.map +0 -1
- package/dist/flow-detection/entry-point-finder.d.ts +0 -14
- package/dist/flow-detection/entry-point-finder.d.ts.map +0 -1
- package/dist/flow-detection/entry-point-finder.js +0 -86
- package/dist/flow-detection/entry-point-finder.js.map +0 -1
- package/dist/flow-detection/index.d.ts +0 -3
- package/dist/flow-detection/index.d.ts.map +0 -1
- package/dist/flow-detection/index.js +0 -2
- package/dist/flow-detection/index.js.map +0 -1
- package/dist/graph/id-generator.d.ts +0 -4
- package/dist/graph/id-generator.d.ts.map +0 -1
- package/dist/graph/id-generator.js +0 -7
- package/dist/graph/id-generator.js.map +0 -1
- package/dist/graph/index.d.ts +0 -4
- package/dist/graph/index.d.ts.map +0 -1
- package/dist/graph/index.js +0 -3
- package/dist/graph/index.js.map +0 -1
- package/dist/graph/knowledge-graph.d.ts +0 -21
- package/dist/graph/knowledge-graph.d.ts.map +0 -1
- package/dist/graph/knowledge-graph.js +0 -126
- package/dist/graph/knowledge-graph.js.map +0 -1
- package/dist/http/app.d.ts +0 -5
- package/dist/http/app.d.ts.map +0 -1
- package/dist/http/app.js +0 -359
- package/dist/http/app.js.map +0 -1
- package/dist/http/index.d.ts +0 -2
- package/dist/http/index.d.ts.map +0 -1
- package/dist/http/index.js +0 -2
- package/dist/http/index.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/inheritance/heritage-builder.d.ts +0 -9
- package/dist/inheritance/heritage-builder.d.ts.map +0 -1
- package/dist/inheritance/heritage-builder.js +0 -40
- package/dist/inheritance/heritage-builder.js.map +0 -1
- package/dist/inheritance/index.d.ts +0 -6
- package/dist/inheritance/index.d.ts.map +0 -1
- package/dist/inheritance/index.js +0 -4
- package/dist/inheritance/index.js.map +0 -1
- package/dist/inheritance/mro-walker.d.ts +0 -3
- package/dist/inheritance/mro-walker.d.ts.map +0 -1
- package/dist/inheritance/mro-walker.js +0 -80
- package/dist/inheritance/mro-walker.js.map +0 -1
- package/dist/inheritance/override-detector.d.ts +0 -4
- package/dist/inheritance/override-detector.d.ts.map +0 -1
- package/dist/inheritance/override-detector.js +0 -39
- package/dist/inheritance/override-detector.js.map +0 -1
- package/dist/languages/index.d.ts +0 -3
- package/dist/languages/index.d.ts.map +0 -1
- package/dist/languages/index.js +0 -2
- package/dist/languages/index.js.map +0 -1
- package/dist/languages/modules/c.d.ts +0 -3
- package/dist/languages/modules/c.d.ts.map +0 -1
- package/dist/languages/modules/c.js +0 -23
- package/dist/languages/modules/c.js.map +0 -1
- package/dist/languages/modules/cpp.d.ts +0 -3
- package/dist/languages/modules/cpp.d.ts.map +0 -1
- package/dist/languages/modules/cpp.js +0 -23
- package/dist/languages/modules/cpp.js.map +0 -1
- package/dist/languages/modules/csharp.d.ts +0 -3
- package/dist/languages/modules/csharp.d.ts.map +0 -1
- package/dist/languages/modules/csharp.js +0 -21
- package/dist/languages/modules/csharp.js.map +0 -1
- package/dist/languages/modules/dart.d.ts +0 -3
- package/dist/languages/modules/dart.d.ts.map +0 -1
- package/dist/languages/modules/dart.js +0 -30
- package/dist/languages/modules/dart.js.map +0 -1
- package/dist/languages/modules/go.d.ts +0 -3
- package/dist/languages/modules/go.d.ts.map +0 -1
- package/dist/languages/modules/go.js +0 -25
- package/dist/languages/modules/go.js.map +0 -1
- package/dist/languages/modules/java.d.ts +0 -3
- package/dist/languages/modules/java.d.ts.map +0 -1
- package/dist/languages/modules/java.js +0 -23
- package/dist/languages/modules/java.js.map +0 -1
- package/dist/languages/modules/kotlin.d.ts +0 -3
- package/dist/languages/modules/kotlin.d.ts.map +0 -1
- package/dist/languages/modules/kotlin.js +0 -22
- package/dist/languages/modules/kotlin.js.map +0 -1
- package/dist/languages/modules/php.d.ts +0 -3
- package/dist/languages/modules/php.d.ts.map +0 -1
- package/dist/languages/modules/php.js +0 -21
- package/dist/languages/modules/php.js.map +0 -1
- package/dist/languages/modules/python.d.ts +0 -3
- package/dist/languages/modules/python.d.ts.map +0 -1
- package/dist/languages/modules/python.js +0 -36
- package/dist/languages/modules/python.js.map +0 -1
- package/dist/languages/modules/ruby.d.ts +0 -3
- package/dist/languages/modules/ruby.d.ts.map +0 -1
- package/dist/languages/modules/ruby.js +0 -20
- package/dist/languages/modules/ruby.js.map +0 -1
- package/dist/languages/modules/rust.d.ts +0 -3
- package/dist/languages/modules/rust.d.ts.map +0 -1
- package/dist/languages/modules/rust.js +0 -23
- package/dist/languages/modules/rust.js.map +0 -1
- package/dist/languages/modules/swift.d.ts +0 -3
- package/dist/languages/modules/swift.d.ts.map +0 -1
- package/dist/languages/modules/swift.js +0 -21
- package/dist/languages/modules/swift.js.map +0 -1
- package/dist/languages/modules/typescript.d.ts +0 -4
- package/dist/languages/modules/typescript.d.ts.map +0 -1
- package/dist/languages/modules/typescript.js +0 -47
- package/dist/languages/modules/typescript.js.map +0 -1
- package/dist/languages/registry.d.ts +0 -5
- package/dist/languages/registry.d.ts.map +0 -1
- package/dist/languages/registry.js +0 -37
- package/dist/languages/registry.js.map +0 -1
- package/dist/languages/types.d.ts +0 -18
- package/dist/languages/types.d.ts.map +0 -1
- package/dist/languages/types.js +0 -2
- package/dist/languages/types.js.map +0 -1
- package/dist/mcp-server/index.d.ts +0 -2
- package/dist/mcp-server/index.d.ts.map +0 -1
- package/dist/mcp-server/index.js +0 -2
- package/dist/mcp-server/index.js.map +0 -1
- package/dist/mcp-server/server.d.ts +0 -5
- package/dist/mcp-server/server.d.ts.map +0 -1
- package/dist/mcp-server/server.js +0 -224
- package/dist/mcp-server/server.js.map +0 -1
- package/dist/multi-repo/cross-repo-search.d.ts +0 -3
- package/dist/multi-repo/cross-repo-search.d.ts.map +0 -1
- package/dist/multi-repo/cross-repo-search.js +0 -5
- package/dist/multi-repo/cross-repo-search.js.map +0 -1
- package/dist/multi-repo/group-config.d.ts +0 -10
- package/dist/multi-repo/group-config.d.ts.map +0 -1
- package/dist/multi-repo/group-config.js +0 -54
- package/dist/multi-repo/group-config.js.map +0 -1
- package/dist/multi-repo/group-manager.d.ts +0 -6
- package/dist/multi-repo/group-manager.d.ts.map +0 -1
- package/dist/multi-repo/group-manager.js +0 -42
- package/dist/multi-repo/group-manager.js.map +0 -1
- package/dist/multi-repo/index.d.ts +0 -5
- package/dist/multi-repo/index.d.ts.map +0 -1
- package/dist/multi-repo/index.js +0 -4
- package/dist/multi-repo/index.js.map +0 -1
- package/dist/parsing/ast-cache.d.ts +0 -13
- package/dist/parsing/ast-cache.d.ts.map +0 -1
- package/dist/parsing/ast-cache.js +0 -45
- package/dist/parsing/ast-cache.js.map +0 -1
- package/dist/parsing/index.d.ts +0 -5
- package/dist/parsing/index.d.ts.map +0 -1
- package/dist/parsing/index.js +0 -4
- package/dist/parsing/index.js.map +0 -1
- package/dist/parsing/parser-manager.d.ts +0 -7
- package/dist/parsing/parser-manager.d.ts.map +0 -1
- package/dist/parsing/parser-manager.js +0 -48
- package/dist/parsing/parser-manager.js.map +0 -1
- package/dist/parsing/queries/c.d.ts +0 -2
- package/dist/parsing/queries/c.d.ts.map +0 -1
- package/dist/parsing/queries/c.js +0 -32
- package/dist/parsing/queries/c.js.map +0 -1
- package/dist/parsing/queries/cpp.d.ts +0 -2
- package/dist/parsing/queries/cpp.d.ts.map +0 -1
- package/dist/parsing/queries/cpp.js +0 -45
- package/dist/parsing/queries/cpp.js.map +0 -1
- package/dist/parsing/queries/csharp.d.ts +0 -2
- package/dist/parsing/queries/csharp.d.ts.map +0 -1
- package/dist/parsing/queries/csharp.js +0 -55
- package/dist/parsing/queries/csharp.js.map +0 -1
- package/dist/parsing/queries/go.d.ts +0 -2
- package/dist/parsing/queries/go.d.ts.map +0 -1
- package/dist/parsing/queries/go.js +0 -46
- package/dist/parsing/queries/go.js.map +0 -1
- package/dist/parsing/queries/index.d.ts +0 -13
- package/dist/parsing/queries/index.d.ts.map +0 -1
- package/dist/parsing/queries/index.js +0 -13
- package/dist/parsing/queries/index.js.map +0 -1
- package/dist/parsing/queries/java.d.ts +0 -2
- package/dist/parsing/queries/java.d.ts.map +0 -1
- package/dist/parsing/queries/java.js +0 -46
- package/dist/parsing/queries/java.js.map +0 -1
- package/dist/parsing/queries/kotlin.d.ts +0 -2
- package/dist/parsing/queries/kotlin.d.ts.map +0 -1
- package/dist/parsing/queries/kotlin.js +0 -41
- package/dist/parsing/queries/kotlin.js.map +0 -1
- package/dist/parsing/queries/php.d.ts +0 -2
- package/dist/parsing/queries/php.d.ts.map +0 -1
- package/dist/parsing/queries/php.js +0 -60
- package/dist/parsing/queries/php.js.map +0 -1
- package/dist/parsing/queries/python.d.ts +0 -2
- package/dist/parsing/queries/python.d.ts.map +0 -1
- package/dist/parsing/queries/python.js +0 -47
- package/dist/parsing/queries/python.js.map +0 -1
- package/dist/parsing/queries/ruby.d.ts +0 -2
- package/dist/parsing/queries/ruby.d.ts.map +0 -1
- package/dist/parsing/queries/ruby.js +0 -36
- package/dist/parsing/queries/ruby.js.map +0 -1
- package/dist/parsing/queries/rust.d.ts +0 -2
- package/dist/parsing/queries/rust.d.ts.map +0 -1
- package/dist/parsing/queries/rust.js +0 -47
- package/dist/parsing/queries/rust.js.map +0 -1
- package/dist/parsing/queries/swift.d.ts +0 -2
- package/dist/parsing/queries/swift.d.ts.map +0 -1
- package/dist/parsing/queries/swift.js +0 -39
- package/dist/parsing/queries/swift.js.map +0 -1
- package/dist/parsing/queries/typescript.d.ts +0 -2
- package/dist/parsing/queries/typescript.d.ts.map +0 -1
- package/dist/parsing/queries/typescript.js +0 -84
- package/dist/parsing/queries/typescript.js.map +0 -1
- package/dist/parsing/query-runner.d.ts +0 -8
- package/dist/parsing/query-runner.d.ts.map +0 -1
- package/dist/parsing/query-runner.js +0 -16
- package/dist/parsing/query-runner.js.map +0 -1
- package/dist/pipeline/dag-validator.d.ts +0 -8
- package/dist/pipeline/dag-validator.d.ts.map +0 -1
- package/dist/pipeline/dag-validator.js +0 -88
- package/dist/pipeline/dag-validator.js.map +0 -1
- package/dist/pipeline/index.d.ts +0 -6
- package/dist/pipeline/index.d.ts.map +0 -1
- package/dist/pipeline/index.js +0 -4
- package/dist/pipeline/index.js.map +0 -1
- package/dist/pipeline/orchestrator.d.ts +0 -8
- package/dist/pipeline/orchestrator.d.ts.map +0 -1
- package/dist/pipeline/orchestrator.js +0 -47
- package/dist/pipeline/orchestrator.js.map +0 -1
- package/dist/pipeline/phases/cluster-phase.d.ts +0 -3
- package/dist/pipeline/phases/cluster-phase.d.ts.map +0 -1
- package/dist/pipeline/phases/cluster-phase.js +0 -52
- package/dist/pipeline/phases/cluster-phase.js.map +0 -1
- package/dist/pipeline/phases/flow-phase.d.ts +0 -3
- package/dist/pipeline/phases/flow-phase.d.ts.map +0 -1
- package/dist/pipeline/phases/flow-phase.js +0 -92
- package/dist/pipeline/phases/flow-phase.js.map +0 -1
- package/dist/pipeline/phases/index.d.ts +0 -6
- package/dist/pipeline/phases/index.d.ts.map +0 -1
- package/dist/pipeline/phases/index.js +0 -6
- package/dist/pipeline/phases/index.js.map +0 -1
- package/dist/pipeline/phases/parse-phase.d.ts +0 -3
- package/dist/pipeline/phases/parse-phase.d.ts.map +0 -1
- package/dist/pipeline/phases/parse-phase.js +0 -288
- package/dist/pipeline/phases/parse-phase.js.map +0 -1
- package/dist/pipeline/phases/resolve-phase.d.ts +0 -3
- package/dist/pipeline/phases/resolve-phase.d.ts.map +0 -1
- package/dist/pipeline/phases/resolve-phase.js +0 -388
- package/dist/pipeline/phases/resolve-phase.js.map +0 -1
- package/dist/pipeline/phases/scan-phase.d.ts +0 -4
- package/dist/pipeline/phases/scan-phase.d.ts.map +0 -1
- package/dist/pipeline/phases/scan-phase.js +0 -119
- package/dist/pipeline/phases/scan-phase.js.map +0 -1
- package/dist/pipeline/types.d.ts +0 -19
- package/dist/pipeline/types.d.ts.map +0 -1
- package/dist/pipeline/types.js +0 -2
- package/dist/pipeline/types.js.map +0 -1
- package/dist/resolver/binding-tracker.d.ts +0 -15
- package/dist/resolver/binding-tracker.d.ts.map +0 -1
- package/dist/resolver/binding-tracker.js +0 -22
- package/dist/resolver/binding-tracker.js.map +0 -1
- package/dist/resolver/import-resolver.d.ts +0 -16
- package/dist/resolver/import-resolver.d.ts.map +0 -1
- package/dist/resolver/import-resolver.js +0 -43
- package/dist/resolver/import-resolver.js.map +0 -1
- package/dist/resolver/index.d.ts +0 -5
- package/dist/resolver/index.d.ts.map +0 -1
- package/dist/resolver/index.js +0 -3
- package/dist/resolver/index.js.map +0 -1
- package/dist/resolver/strategies/namespace-alias.d.ts +0 -3
- package/dist/resolver/strategies/namespace-alias.d.ts.map +0 -1
- package/dist/resolver/strategies/namespace-alias.js +0 -15
- package/dist/resolver/strategies/namespace-alias.js.map +0 -1
- package/dist/resolver/strategies/package-lookup.d.ts +0 -3
- package/dist/resolver/strategies/package-lookup.d.ts.map +0 -1
- package/dist/resolver/strategies/package-lookup.js +0 -10
- package/dist/resolver/strategies/package-lookup.js.map +0 -1
- package/dist/resolver/strategies/relative-path.d.ts +0 -3
- package/dist/resolver/strategies/relative-path.d.ts.map +0 -1
- package/dist/resolver/strategies/relative-path.js +0 -12
- package/dist/resolver/strategies/relative-path.js.map +0 -1
- package/dist/resolver/strategies/types.d.ts +0 -11
- package/dist/resolver/strategies/types.d.ts.map +0 -1
- package/dist/resolver/strategies/types.js +0 -2
- package/dist/resolver/strategies/types.js.map +0 -1
- package/dist/resolver/strategies/wildcard-expand.d.ts +0 -3
- package/dist/resolver/strategies/wildcard-expand.d.ts.map +0 -1
- package/dist/resolver/strategies/wildcard-expand.js +0 -8
- package/dist/resolver/strategies/wildcard-expand.js.map +0 -1
- package/dist/scope-analysis/index.d.ts +0 -3
- package/dist/scope-analysis/index.d.ts.map +0 -1
- package/dist/scope-analysis/index.js +0 -2
- package/dist/scope-analysis/index.js.map +0 -1
- package/dist/scope-analysis/scope-builder.d.ts +0 -16
- package/dist/scope-analysis/scope-builder.d.ts.map +0 -1
- package/dist/scope-analysis/scope-builder.js +0 -19
- package/dist/scope-analysis/scope-builder.js.map +0 -1
- package/dist/search/embedder.d.ts +0 -14
- package/dist/search/embedder.d.ts.map +0 -1
- package/dist/search/embedder.js +0 -45
- package/dist/search/embedder.js.map +0 -1
- package/dist/search/index.d.ts +0 -7
- package/dist/search/index.d.ts.map +0 -1
- package/dist/search/index.js +0 -4
- package/dist/search/index.js.map +0 -1
- package/dist/search/text-search.d.ts +0 -12
- package/dist/search/text-search.d.ts.map +0 -1
- package/dist/search/text-search.js +0 -72
- package/dist/search/text-search.js.map +0 -1
- package/dist/search/vector-index.d.ts +0 -18
- package/dist/search/vector-index.d.ts.map +0 -1
- package/dist/search/vector-index.js +0 -70
- package/dist/search/vector-index.js.map +0 -1
- package/dist/shared/detection.d.ts +0 -4
- package/dist/shared/detection.d.ts.map +0 -1
- package/dist/shared/detection.js +0 -38
- package/dist/shared/detection.js.map +0 -1
- package/dist/shared/graph-types.d.ts +0 -22
- package/dist/shared/graph-types.d.ts.map +0 -1
- package/dist/shared/graph-types.js +0 -2
- package/dist/shared/graph-types.js.map +0 -1
- package/dist/shared/index.d.ts +0 -5
- package/dist/shared/index.d.ts.map +0 -1
- package/dist/shared/index.js +0 -3
- package/dist/shared/index.js.map +0 -1
- package/dist/shared/languages.d.ts +0 -17
- package/dist/shared/languages.d.ts.map +0 -1
- package/dist/shared/languages.js +0 -18
- package/dist/shared/languages.js.map +0 -1
- package/dist/shared/pipeline-types.d.ts +0 -21
- package/dist/shared/pipeline-types.d.ts.map +0 -1
- package/dist/shared/pipeline-types.js +0 -2
- package/dist/shared/pipeline-types.js.map +0 -1
- package/dist/storage/csv-writer.d.ts +0 -9
- package/dist/storage/csv-writer.d.ts.map +0 -1
- package/dist/storage/csv-writer.js +0 -77
- package/dist/storage/csv-writer.js.map +0 -1
- package/dist/storage/db-manager.d.ts +0 -12
- package/dist/storage/db-manager.d.ts.map +0 -1
- package/dist/storage/db-manager.js +0 -50
- package/dist/storage/db-manager.js.map +0 -1
- package/dist/storage/graph-loader.d.ts +0 -7
- package/dist/storage/graph-loader.d.ts.map +0 -1
- package/dist/storage/graph-loader.js +0 -71
- package/dist/storage/graph-loader.js.map +0 -1
- package/dist/storage/index.d.ts +0 -10
- package/dist/storage/index.d.ts.map +0 -1
- package/dist/storage/index.js +0 -7
- package/dist/storage/index.js.map +0 -1
- package/dist/storage/metadata.d.ts +0 -15
- package/dist/storage/metadata.d.ts.map +0 -1
- package/dist/storage/metadata.js +0 -23
- package/dist/storage/metadata.js.map +0 -1
- package/dist/storage/repo-registry.d.ts +0 -15
- package/dist/storage/repo-registry.d.ts.map +0 -1
- package/dist/storage/repo-registry.js +0 -34
- package/dist/storage/repo-registry.js.map +0 -1
- package/dist/storage/schema.d.ts +0 -6
- package/dist/storage/schema.d.ts.map +0 -1
- package/dist/storage/schema.js +0 -54
- package/dist/storage/schema.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,18 +1,3941 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
1
|
+
import fs8 from 'fs';
|
|
2
|
+
import path6 from 'path';
|
|
3
|
+
import os2 from 'os';
|
|
4
|
+
import { Parser, Language, Query } from 'web-tree-sitter';
|
|
5
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
6
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
7
|
+
import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
8
|
+
import express from 'express';
|
|
9
|
+
import cors from 'cors';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
11
|
+
import { Database, Connection } from '@ladybugdb/core';
|
|
12
|
+
|
|
13
|
+
var __defProp = Object.defineProperty;
|
|
14
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
15
|
+
var __esm = (fn, res) => function __init() {
|
|
16
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
17
|
+
};
|
|
18
|
+
var __export = (target, all) => {
|
|
19
|
+
for (var name in all)
|
|
20
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// src/search/embedder.ts
|
|
24
|
+
var embedder_exports = {};
|
|
25
|
+
__export(embedder_exports, {
|
|
26
|
+
embedNodes: () => embedNodes
|
|
27
|
+
});
|
|
28
|
+
async function getEmbedder() {
|
|
29
|
+
if (!pipelineInstance) {
|
|
30
|
+
const { pipeline } = await import('@huggingface/transformers');
|
|
31
|
+
pipelineInstance = await pipeline("feature-extraction", "Xenova/all-MiniLM-L6-v2");
|
|
32
|
+
}
|
|
33
|
+
return pipelineInstance;
|
|
34
|
+
}
|
|
35
|
+
async function embedNodes(graph, opts = {}) {
|
|
36
|
+
const { batchSize = 32, onProgress } = opts;
|
|
37
|
+
const candidates = [];
|
|
38
|
+
for (const node of graph.allNodes()) {
|
|
39
|
+
if (["cluster", "directory", "flow"].includes(node.kind)) continue;
|
|
40
|
+
const text = buildText(node);
|
|
41
|
+
candidates.push({ id: node.id, name: node.name, kind: node.kind, filePath: node.filePath, text });
|
|
42
|
+
}
|
|
43
|
+
const embedder = await getEmbedder();
|
|
44
|
+
const results = [];
|
|
45
|
+
for (let i = 0; i < candidates.length; i += batchSize) {
|
|
46
|
+
const batch = candidates.slice(i, i + batchSize);
|
|
47
|
+
const texts = batch.map((c) => c.text);
|
|
48
|
+
for (let j = 0; j < texts.length; j++) {
|
|
49
|
+
const out = await embedder(texts[j], { pooling: "mean", normalize: true });
|
|
50
|
+
results.push({ ...batch[j], embedding: Array.from(out.data) });
|
|
51
|
+
}
|
|
52
|
+
onProgress?.(Math.min(i + batchSize, candidates.length), candidates.length);
|
|
53
|
+
}
|
|
54
|
+
return results;
|
|
55
|
+
}
|
|
56
|
+
function buildText(node) {
|
|
57
|
+
const parts = [`${node.kind} ${node.name}`];
|
|
58
|
+
const sig = node.metadata?.signature;
|
|
59
|
+
if (sig) parts.push(sig);
|
|
60
|
+
if (node.content) parts.push(node.content.slice(0, 256));
|
|
61
|
+
parts.push(node.filePath);
|
|
62
|
+
return parts.join(" ").slice(0, 512);
|
|
63
|
+
}
|
|
64
|
+
var pipelineInstance;
|
|
65
|
+
var init_embedder = __esm({
|
|
66
|
+
"src/search/embedder.ts"() {
|
|
67
|
+
pipelineInstance = null;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// src/multi-repo/group-registry.ts
|
|
72
|
+
var group_registry_exports = {};
|
|
73
|
+
__export(group_registry_exports, {
|
|
74
|
+
addMember: () => addMember,
|
|
75
|
+
deleteGroup: () => deleteGroup,
|
|
76
|
+
groupExists: () => groupExists,
|
|
77
|
+
listGroups: () => listGroups,
|
|
78
|
+
loadGroup: () => loadGroup,
|
|
79
|
+
loadSyncResult: () => loadSyncResult,
|
|
80
|
+
removeMember: () => removeMember,
|
|
81
|
+
saveGroup: () => saveGroup,
|
|
82
|
+
saveSyncResult: () => saveSyncResult
|
|
83
|
+
});
|
|
84
|
+
function groupFile(name) {
|
|
85
|
+
return path6.join(GROUPS_DIR, `${name}.json`);
|
|
86
|
+
}
|
|
87
|
+
function loadGroup(name) {
|
|
88
|
+
try {
|
|
89
|
+
return JSON.parse(fs8.readFileSync(groupFile(name), "utf-8"));
|
|
90
|
+
} catch {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function saveGroup(group) {
|
|
95
|
+
fs8.mkdirSync(GROUPS_DIR, { recursive: true });
|
|
96
|
+
fs8.writeFileSync(groupFile(group.name), JSON.stringify(group, null, 2) + "\n");
|
|
97
|
+
}
|
|
98
|
+
function listGroups() {
|
|
99
|
+
const groups = [];
|
|
100
|
+
try {
|
|
101
|
+
for (const file of fs8.readdirSync(GROUPS_DIR)) {
|
|
102
|
+
if (!file.endsWith(".json") || file.endsWith(".sync.json")) continue;
|
|
103
|
+
try {
|
|
104
|
+
const g = JSON.parse(
|
|
105
|
+
fs8.readFileSync(path6.join(GROUPS_DIR, file), "utf-8")
|
|
106
|
+
);
|
|
107
|
+
groups.push(g);
|
|
108
|
+
} catch {
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} catch {
|
|
112
|
+
}
|
|
113
|
+
return groups;
|
|
114
|
+
}
|
|
115
|
+
function deleteGroup(name) {
|
|
116
|
+
try {
|
|
117
|
+
fs8.unlinkSync(groupFile(name));
|
|
118
|
+
} catch {
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
fs8.unlinkSync(path6.join(GROUPS_DIR, `${name}.sync.json`));
|
|
122
|
+
} catch {
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function groupExists(name) {
|
|
126
|
+
return fs8.existsSync(groupFile(name));
|
|
127
|
+
}
|
|
128
|
+
function addMember(groupName, member) {
|
|
129
|
+
const group = loadGroup(groupName);
|
|
130
|
+
if (!group) throw new Error(`Group "${groupName}" not found.`);
|
|
131
|
+
const idx = group.members.findIndex((m) => m.groupPath === member.groupPath);
|
|
132
|
+
if (idx >= 0) {
|
|
133
|
+
group.members[idx] = member;
|
|
134
|
+
} else {
|
|
135
|
+
group.members.push(member);
|
|
136
|
+
}
|
|
137
|
+
saveGroup(group);
|
|
138
|
+
return group;
|
|
139
|
+
}
|
|
140
|
+
function removeMember(groupName, groupPath) {
|
|
141
|
+
const group = loadGroup(groupName);
|
|
142
|
+
if (!group) throw new Error(`Group "${groupName}" not found.`);
|
|
143
|
+
const before = group.members.length;
|
|
144
|
+
group.members = group.members.filter((m) => m.groupPath !== groupPath);
|
|
145
|
+
if (group.members.length === before) {
|
|
146
|
+
throw new Error(`No member at path "${groupPath}" in group "${groupName}".`);
|
|
147
|
+
}
|
|
148
|
+
saveGroup(group);
|
|
149
|
+
return group;
|
|
150
|
+
}
|
|
151
|
+
function saveSyncResult(result) {
|
|
152
|
+
fs8.mkdirSync(GROUPS_DIR, { recursive: true });
|
|
153
|
+
fs8.writeFileSync(
|
|
154
|
+
path6.join(GROUPS_DIR, `${result.groupName}.sync.json`),
|
|
155
|
+
JSON.stringify(result, null, 2) + "\n"
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
function loadSyncResult(groupName) {
|
|
159
|
+
try {
|
|
160
|
+
return JSON.parse(
|
|
161
|
+
fs8.readFileSync(path6.join(GROUPS_DIR, `${groupName}.sync.json`), "utf-8")
|
|
162
|
+
);
|
|
163
|
+
} catch {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
var GROUPS_DIR;
|
|
168
|
+
var init_group_registry = __esm({
|
|
169
|
+
"src/multi-repo/group-registry.ts"() {
|
|
170
|
+
GROUPS_DIR = path6.join(os2.homedir(), ".code-intel", "groups");
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// src/graph/knowledge-graph.ts
|
|
175
|
+
function createKnowledgeGraph() {
|
|
176
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
177
|
+
const edges = /* @__PURE__ */ new Map();
|
|
178
|
+
const edgesByKind = /* @__PURE__ */ new Map();
|
|
179
|
+
const edgesFromNode = /* @__PURE__ */ new Map();
|
|
180
|
+
const edgesToNode = /* @__PURE__ */ new Map();
|
|
181
|
+
function indexEdge(edge) {
|
|
182
|
+
let kindSet = edgesByKind.get(edge.kind);
|
|
183
|
+
if (!kindSet) {
|
|
184
|
+
kindSet = /* @__PURE__ */ new Set();
|
|
185
|
+
edgesByKind.set(edge.kind, kindSet);
|
|
186
|
+
}
|
|
187
|
+
kindSet.add(edge.id);
|
|
188
|
+
let fromSet = edgesFromNode.get(edge.source);
|
|
189
|
+
if (!fromSet) {
|
|
190
|
+
fromSet = /* @__PURE__ */ new Set();
|
|
191
|
+
edgesFromNode.set(edge.source, fromSet);
|
|
192
|
+
}
|
|
193
|
+
fromSet.add(edge.id);
|
|
194
|
+
let toSet = edgesToNode.get(edge.target);
|
|
195
|
+
if (!toSet) {
|
|
196
|
+
toSet = /* @__PURE__ */ new Set();
|
|
197
|
+
edgesToNode.set(edge.target, toSet);
|
|
198
|
+
}
|
|
199
|
+
toSet.add(edge.id);
|
|
200
|
+
}
|
|
201
|
+
function unindexEdge(edge) {
|
|
202
|
+
edgesByKind.get(edge.kind)?.delete(edge.id);
|
|
203
|
+
edgesFromNode.get(edge.source)?.delete(edge.id);
|
|
204
|
+
edgesToNode.get(edge.target)?.delete(edge.id);
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
addNode(node) {
|
|
208
|
+
nodes.set(node.id, node);
|
|
209
|
+
},
|
|
210
|
+
addEdge(edge) {
|
|
211
|
+
edges.set(edge.id, edge);
|
|
212
|
+
indexEdge(edge);
|
|
213
|
+
},
|
|
214
|
+
getNode(id) {
|
|
215
|
+
return nodes.get(id);
|
|
216
|
+
},
|
|
217
|
+
getEdge(id) {
|
|
218
|
+
return edges.get(id);
|
|
219
|
+
},
|
|
220
|
+
*findEdgesByKind(kind) {
|
|
221
|
+
const ids = edgesByKind.get(kind);
|
|
222
|
+
if (!ids) return;
|
|
223
|
+
for (const id of ids) {
|
|
224
|
+
const edge = edges.get(id);
|
|
225
|
+
if (edge) yield edge;
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
*findEdgesFrom(sourceId) {
|
|
229
|
+
const ids = edgesFromNode.get(sourceId);
|
|
230
|
+
if (!ids) return;
|
|
231
|
+
for (const id of ids) {
|
|
232
|
+
const edge = edges.get(id);
|
|
233
|
+
if (edge) yield edge;
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
*findEdgesTo(targetId) {
|
|
237
|
+
const ids = edgesToNode.get(targetId);
|
|
238
|
+
if (!ids) return;
|
|
239
|
+
for (const id of ids) {
|
|
240
|
+
const edge = edges.get(id);
|
|
241
|
+
if (edge) yield edge;
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
removeNodeCascade(id) {
|
|
245
|
+
const fromEdges = edgesFromNode.get(id);
|
|
246
|
+
if (fromEdges) {
|
|
247
|
+
for (const edgeId of [...fromEdges]) {
|
|
248
|
+
const edge = edges.get(edgeId);
|
|
249
|
+
if (edge) {
|
|
250
|
+
unindexEdge(edge);
|
|
251
|
+
edges.delete(edgeId);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
const toEdges = edgesToNode.get(id);
|
|
256
|
+
if (toEdges) {
|
|
257
|
+
for (const edgeId of [...toEdges]) {
|
|
258
|
+
const edge = edges.get(edgeId);
|
|
259
|
+
if (edge) {
|
|
260
|
+
unindexEdge(edge);
|
|
261
|
+
edges.delete(edgeId);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
edgesFromNode.delete(id);
|
|
266
|
+
edgesToNode.delete(id);
|
|
267
|
+
nodes.delete(id);
|
|
268
|
+
},
|
|
269
|
+
removeEdge(id) {
|
|
270
|
+
const edge = edges.get(id);
|
|
271
|
+
if (edge) {
|
|
272
|
+
unindexEdge(edge);
|
|
273
|
+
edges.delete(id);
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
*allNodes() {
|
|
277
|
+
yield* nodes.values();
|
|
278
|
+
},
|
|
279
|
+
*allEdges() {
|
|
280
|
+
yield* edges.values();
|
|
281
|
+
},
|
|
282
|
+
get size() {
|
|
283
|
+
return { nodes: nodes.size, edges: edges.size };
|
|
284
|
+
},
|
|
285
|
+
clear() {
|
|
286
|
+
nodes.clear();
|
|
287
|
+
edges.clear();
|
|
288
|
+
edgesByKind.clear();
|
|
289
|
+
edgesFromNode.clear();
|
|
290
|
+
edgesToNode.clear();
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/graph/id-generator.ts
|
|
296
|
+
function generateNodeId(kind, filePath, qualifiedName) {
|
|
297
|
+
return `${kind}:${filePath}:${qualifiedName}`;
|
|
298
|
+
}
|
|
299
|
+
function generateEdgeId(source, target, kind) {
|
|
300
|
+
return `${kind}:${source}->${target}`;
|
|
301
|
+
}
|
|
302
|
+
var initialized = false;
|
|
303
|
+
var parserCache = /* @__PURE__ */ new Map();
|
|
304
|
+
var languageCache = /* @__PURE__ */ new Map();
|
|
305
|
+
var GRAMMAR_WASM_MAP = {
|
|
306
|
+
// WASM grammar files to be downloaded/provided per language
|
|
307
|
+
// For now, the parser manager provides a placeholder
|
|
308
|
+
};
|
|
309
|
+
async function initParser() {
|
|
310
|
+
if (initialized) return;
|
|
311
|
+
await Parser.init();
|
|
312
|
+
initialized = true;
|
|
313
|
+
}
|
|
314
|
+
async function getParser(lang) {
|
|
315
|
+
await initParser();
|
|
316
|
+
let parser = parserCache.get(lang);
|
|
317
|
+
if (parser) return parser;
|
|
318
|
+
parser = new Parser();
|
|
319
|
+
parserCache.set(lang, parser);
|
|
320
|
+
return parser;
|
|
321
|
+
}
|
|
322
|
+
async function getLanguage(lang) {
|
|
323
|
+
const cached = languageCache.get(lang);
|
|
324
|
+
if (cached) return cached;
|
|
325
|
+
const wasmPath = GRAMMAR_WASM_MAP[lang];
|
|
326
|
+
if (!wasmPath) return null;
|
|
327
|
+
try {
|
|
328
|
+
const language = await Language.load(wasmPath);
|
|
329
|
+
languageCache.set(lang, language);
|
|
330
|
+
return language;
|
|
331
|
+
} catch {
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
async function parseSource(lang, source) {
|
|
336
|
+
const parser = await getParser(lang);
|
|
337
|
+
const language = await getLanguage(lang);
|
|
338
|
+
if (!language) return null;
|
|
339
|
+
parser.setLanguage(language);
|
|
340
|
+
return parser.parse(source);
|
|
341
|
+
}
|
|
342
|
+
function runQuery(tree, language, querySource) {
|
|
343
|
+
const query = new Query(language, querySource);
|
|
344
|
+
const matches = query.matches(tree.rootNode);
|
|
345
|
+
const captures = [];
|
|
346
|
+
for (const match of matches) {
|
|
347
|
+
for (const capture of match.captures) {
|
|
348
|
+
captures.push({
|
|
349
|
+
name: capture.name,
|
|
350
|
+
node: capture.node,
|
|
351
|
+
text: capture.node.text
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return captures;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// src/parsing/ast-cache.ts
|
|
359
|
+
var DEFAULT_MAX = 500;
|
|
360
|
+
var AstCache = class {
|
|
361
|
+
cache = /* @__PURE__ */ new Map();
|
|
362
|
+
maxEntries;
|
|
363
|
+
constructor(maxEntries = DEFAULT_MAX) {
|
|
364
|
+
this.maxEntries = maxEntries;
|
|
365
|
+
}
|
|
366
|
+
get(filePath) {
|
|
367
|
+
const entry = this.cache.get(filePath);
|
|
368
|
+
if (entry) {
|
|
369
|
+
entry.accessedAt = Date.now();
|
|
370
|
+
return entry.tree;
|
|
371
|
+
}
|
|
372
|
+
return void 0;
|
|
373
|
+
}
|
|
374
|
+
set(filePath, tree) {
|
|
375
|
+
if (this.cache.size >= this.maxEntries) {
|
|
376
|
+
this.evictLRU();
|
|
377
|
+
}
|
|
378
|
+
this.cache.set(filePath, { tree, accessedAt: Date.now() });
|
|
379
|
+
}
|
|
380
|
+
has(filePath) {
|
|
381
|
+
return this.cache.has(filePath);
|
|
382
|
+
}
|
|
383
|
+
clear() {
|
|
384
|
+
this.cache.clear();
|
|
385
|
+
}
|
|
386
|
+
get size() {
|
|
387
|
+
return this.cache.size;
|
|
388
|
+
}
|
|
389
|
+
evictLRU() {
|
|
390
|
+
let oldest = null;
|
|
391
|
+
let oldestTime = Infinity;
|
|
392
|
+
for (const [key, entry] of this.cache) {
|
|
393
|
+
if (entry.accessedAt < oldestTime) {
|
|
394
|
+
oldest = key;
|
|
395
|
+
oldestTime = entry.accessedAt;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
if (oldest) {
|
|
399
|
+
this.cache.delete(oldest);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
// src/shared/detection.ts
|
|
405
|
+
var EXTENSION_MAP = {
|
|
406
|
+
".ts": "typescript" /* TypeScript */,
|
|
407
|
+
".tsx": "typescript" /* TypeScript */,
|
|
408
|
+
".mts": "typescript" /* TypeScript */,
|
|
409
|
+
".cts": "typescript" /* TypeScript */,
|
|
410
|
+
".js": "javascript" /* JavaScript */,
|
|
411
|
+
".jsx": "javascript" /* JavaScript */,
|
|
412
|
+
".mjs": "javascript" /* JavaScript */,
|
|
413
|
+
".cjs": "javascript" /* JavaScript */,
|
|
414
|
+
".py": "python" /* Python */,
|
|
415
|
+
".pyi": "python" /* Python */,
|
|
416
|
+
".java": "java" /* Java */,
|
|
417
|
+
".go": "go" /* Go */,
|
|
418
|
+
".c": "c" /* C */,
|
|
419
|
+
".h": "c" /* C */,
|
|
420
|
+
".cpp": "cpp" /* Cpp */,
|
|
421
|
+
".cxx": "cpp" /* Cpp */,
|
|
422
|
+
".cc": "cpp" /* Cpp */,
|
|
423
|
+
".hpp": "cpp" /* Cpp */,
|
|
424
|
+
".hxx": "cpp" /* Cpp */,
|
|
425
|
+
".cs": "csharp" /* CSharp */,
|
|
426
|
+
".rs": "rust" /* Rust */,
|
|
427
|
+
".php": "php" /* PHP */,
|
|
428
|
+
".kt": "kotlin" /* Kotlin */,
|
|
429
|
+
".kts": "kotlin" /* Kotlin */,
|
|
430
|
+
".rb": "ruby" /* Ruby */,
|
|
431
|
+
".swift": "swift" /* Swift */,
|
|
432
|
+
".dart": "dart" /* Dart */
|
|
433
|
+
};
|
|
434
|
+
function detectLanguage(filePath) {
|
|
435
|
+
const ext = filePath.slice(filePath.lastIndexOf("."));
|
|
436
|
+
return EXTENSION_MAP[ext] ?? null;
|
|
437
|
+
}
|
|
438
|
+
function getSupportedExtensions() {
|
|
439
|
+
return Object.keys(EXTENSION_MAP);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// src/parsing/queries/typescript.ts
|
|
443
|
+
var typescriptQueries = `
|
|
444
|
+
;; Class declaration
|
|
445
|
+
(class_declaration
|
|
446
|
+
name: (type_identifier) @def.class.name) @def.class
|
|
447
|
+
|
|
448
|
+
;; Abstract class
|
|
449
|
+
(abstract_class_declaration
|
|
450
|
+
name: (type_identifier) @def.class.name) @def.class
|
|
451
|
+
|
|
452
|
+
;; Interface declaration
|
|
453
|
+
(interface_declaration
|
|
454
|
+
name: (type_identifier) @def.interface.name) @def.interface
|
|
455
|
+
|
|
456
|
+
;; Type alias
|
|
457
|
+
(type_alias_declaration
|
|
458
|
+
name: (type_identifier) @def.type_alias.name) @def.type_alias
|
|
459
|
+
|
|
460
|
+
;; Enum
|
|
461
|
+
(enum_declaration
|
|
462
|
+
name: (identifier) @def.enum.name) @def.enum
|
|
463
|
+
|
|
464
|
+
;; Function declaration
|
|
465
|
+
(function_declaration
|
|
466
|
+
name: (identifier) @def.func.name) @def.func
|
|
467
|
+
|
|
468
|
+
;; Arrow function in variable
|
|
469
|
+
(lexical_declaration
|
|
470
|
+
(variable_declarator
|
|
471
|
+
name: (identifier) @def.func.name
|
|
472
|
+
value: (arrow_function))) @def.func
|
|
473
|
+
|
|
474
|
+
;; Const/let/var variable (non-function)
|
|
475
|
+
(lexical_declaration
|
|
476
|
+
(variable_declarator
|
|
477
|
+
name: (identifier) @def.var.name
|
|
478
|
+
value: (_) @def.var.value)) @def.var
|
|
479
|
+
|
|
480
|
+
;; Method definition
|
|
481
|
+
(method_definition
|
|
482
|
+
name: (property_identifier) @def.method.name) @def.method
|
|
483
|
+
|
|
484
|
+
;; Public field definition
|
|
485
|
+
(public_field_definition
|
|
486
|
+
name: (property_identifier) @def.property.name) @def.property
|
|
487
|
+
|
|
488
|
+
;; Import statement
|
|
489
|
+
(import_statement
|
|
490
|
+
source: (string) @imp.source) @imp
|
|
491
|
+
|
|
492
|
+
;; Import specifier
|
|
493
|
+
(import_specifier
|
|
494
|
+
name: (identifier) @imp.name)
|
|
495
|
+
|
|
496
|
+
;; Namespace import
|
|
497
|
+
(namespace_import (identifier) @imp.namespace)
|
|
498
|
+
|
|
499
|
+
;; Export statement
|
|
500
|
+
(export_statement) @export
|
|
501
|
+
|
|
502
|
+
;; Call expression \u2014 function call
|
|
503
|
+
(call_expression
|
|
504
|
+
function: (identifier) @call.name) @call
|
|
505
|
+
|
|
506
|
+
;; Call expression \u2014 member call
|
|
507
|
+
(call_expression
|
|
508
|
+
function: (member_expression
|
|
509
|
+
object: (_) @call.receiver
|
|
510
|
+
property: (property_identifier) @call.method)) @call.member
|
|
511
|
+
|
|
512
|
+
;; New expression
|
|
513
|
+
(new_expression
|
|
514
|
+
constructor: (identifier) @call.constructor) @call.new
|
|
515
|
+
|
|
516
|
+
;; Class heritage \u2014 extends
|
|
517
|
+
(class_heritage
|
|
518
|
+
(extends_clause
|
|
519
|
+
value: (identifier) @inherit.extends))
|
|
520
|
+
|
|
521
|
+
;; Class heritage \u2014 implements
|
|
522
|
+
(class_heritage
|
|
523
|
+
(implements_clause
|
|
524
|
+
(type_reference (type_identifier) @inherit.implements)))
|
|
525
|
+
`;
|
|
526
|
+
function resolveRelative(rawPath, fromFile, workspace) {
|
|
527
|
+
const fromDir = path6.dirname(fromFile);
|
|
528
|
+
const cleaned = rawPath.replace(/['"]/g, "");
|
|
529
|
+
const extensions = [".ts", ".tsx", ".js", ".jsx", "/index.ts", "/index.js"];
|
|
530
|
+
const resolved = workspace.resolve(fromDir, cleaned);
|
|
531
|
+
if (resolved) return resolved;
|
|
532
|
+
for (const ext of extensions) {
|
|
533
|
+
const r = workspace.resolve(fromDir, cleaned + ext);
|
|
534
|
+
if (r) return r;
|
|
535
|
+
}
|
|
536
|
+
return null;
|
|
537
|
+
}
|
|
538
|
+
var typescriptModule = {
|
|
539
|
+
lang: "typescript" /* TypeScript */,
|
|
540
|
+
fileExtensions: [".ts", ".tsx", ".mts", ".cts"],
|
|
541
|
+
queries: typescriptQueries,
|
|
542
|
+
importStyle: "explicit",
|
|
543
|
+
inheritanceStrategy: "depth-first",
|
|
544
|
+
resolveImport(rawPath, fromFile, workspace) {
|
|
545
|
+
const cleaned = rawPath.replace(/['"]/g, "");
|
|
546
|
+
if (cleaned.startsWith(".")) {
|
|
547
|
+
return resolveRelative(rawPath, fromFile, workspace);
|
|
548
|
+
}
|
|
549
|
+
return workspace.findByPackage(cleaned);
|
|
550
|
+
},
|
|
551
|
+
isExported(node) {
|
|
552
|
+
const parent = node.parent;
|
|
553
|
+
if (!parent) return false;
|
|
554
|
+
return parent.type === "export_statement" || node.type === "export_statement";
|
|
555
|
+
},
|
|
556
|
+
extractType(node) {
|
|
557
|
+
const typeAnnotation = node.childForFieldName("type");
|
|
558
|
+
return typeAnnotation?.text ?? null;
|
|
559
|
+
}
|
|
560
|
+
};
|
|
561
|
+
var javascriptModule = {
|
|
562
|
+
...typescriptModule,
|
|
563
|
+
lang: "javascript" /* JavaScript */,
|
|
564
|
+
fileExtensions: [".js", ".jsx", ".mjs", ".cjs"]
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
// src/parsing/queries/python.ts
|
|
568
|
+
var pythonQueries = `
|
|
569
|
+
;; Class definition
|
|
570
|
+
(class_definition
|
|
571
|
+
name: (identifier) @def.class.name) @def.class
|
|
572
|
+
|
|
573
|
+
;; Function definition
|
|
574
|
+
(function_definition
|
|
575
|
+
name: (identifier) @def.func.name) @def.func
|
|
576
|
+
|
|
577
|
+
;; Decorated definition
|
|
578
|
+
(decorated_definition
|
|
579
|
+
(function_definition
|
|
580
|
+
name: (identifier) @def.func.name)) @def.func.decorated
|
|
581
|
+
|
|
582
|
+
;; Import from
|
|
583
|
+
(import_from_statement
|
|
584
|
+
module_name: (dotted_name) @imp.source) @imp
|
|
585
|
+
|
|
586
|
+
;; Import
|
|
587
|
+
(import_statement
|
|
588
|
+
name: (dotted_name) @imp.module) @imp.direct
|
|
589
|
+
|
|
590
|
+
;; Import alias
|
|
591
|
+
(aliased_import
|
|
592
|
+
name: (dotted_name) @imp.alias.original
|
|
593
|
+
alias: (identifier) @imp.alias.name)
|
|
594
|
+
|
|
595
|
+
;; Call expression
|
|
596
|
+
(call
|
|
597
|
+
function: (identifier) @call.name) @call
|
|
598
|
+
|
|
599
|
+
;; Attribute call
|
|
600
|
+
(call
|
|
601
|
+
function: (attribute
|
|
602
|
+
object: (_) @call.receiver
|
|
603
|
+
attribute: (identifier) @call.method)) @call.member
|
|
604
|
+
|
|
605
|
+
;; Assignment
|
|
606
|
+
(assignment
|
|
607
|
+
left: (identifier) @def.var.name) @def.var
|
|
608
|
+
|
|
609
|
+
;; Class base classes
|
|
610
|
+
(class_definition
|
|
611
|
+
superclasses: (argument_list
|
|
612
|
+
(identifier) @inherit.extends))
|
|
613
|
+
`;
|
|
614
|
+
var pythonModule = {
|
|
615
|
+
lang: "python" /* Python */,
|
|
616
|
+
fileExtensions: [".py", ".pyi"],
|
|
617
|
+
queries: pythonQueries,
|
|
618
|
+
importStyle: "namespace",
|
|
619
|
+
inheritanceStrategy: "c3",
|
|
620
|
+
resolveImport(rawPath, fromFile, workspace) {
|
|
621
|
+
const cleaned = rawPath.replace(/['"]/g, "");
|
|
622
|
+
const parts = cleaned.split(".");
|
|
623
|
+
const fromDir = path6.dirname(fromFile);
|
|
624
|
+
const relPath = parts.join("/");
|
|
625
|
+
for (const suffix of ["/__init__.py", ".py"]) {
|
|
626
|
+
const r = workspace.resolve(fromDir, relPath + suffix);
|
|
627
|
+
if (r) return r;
|
|
628
|
+
}
|
|
629
|
+
return workspace.findByPackage(cleaned);
|
|
630
|
+
},
|
|
631
|
+
isExported(node) {
|
|
632
|
+
const name = node.childForFieldName("name");
|
|
633
|
+
if (!name) return true;
|
|
634
|
+
return !name.text.startsWith("_");
|
|
635
|
+
},
|
|
636
|
+
extractType(node) {
|
|
637
|
+
const returnType = node.childForFieldName("return_type");
|
|
638
|
+
return returnType?.text ?? null;
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
// src/parsing/queries/java.ts
|
|
643
|
+
var javaQueries = `
|
|
644
|
+
;; Class declaration
|
|
645
|
+
(class_declaration
|
|
646
|
+
name: (identifier) @def.class.name) @def.class
|
|
647
|
+
|
|
648
|
+
;; Interface declaration
|
|
649
|
+
(interface_declaration
|
|
650
|
+
name: (identifier) @def.interface.name) @def.interface
|
|
651
|
+
|
|
652
|
+
;; Enum declaration
|
|
653
|
+
(enum_declaration
|
|
654
|
+
name: (identifier) @def.enum.name) @def.enum
|
|
655
|
+
|
|
656
|
+
;; Method declaration
|
|
657
|
+
(method_declaration
|
|
658
|
+
name: (identifier) @def.method.name) @def.method
|
|
659
|
+
|
|
660
|
+
;; Constructor declaration
|
|
661
|
+
(constructor_declaration
|
|
662
|
+
name: (identifier) @def.constructor.name) @def.constructor
|
|
663
|
+
|
|
664
|
+
;; Field declaration
|
|
665
|
+
(field_declaration
|
|
666
|
+
declarator: (variable_declarator
|
|
667
|
+
name: (identifier) @def.property.name)) @def.property
|
|
668
|
+
|
|
669
|
+
;; Import
|
|
670
|
+
(import_declaration
|
|
671
|
+
(scoped_identifier) @imp.source) @imp
|
|
672
|
+
|
|
673
|
+
;; Call
|
|
674
|
+
(method_invocation
|
|
675
|
+
name: (identifier) @call.name) @call
|
|
676
|
+
|
|
677
|
+
;; Object creation
|
|
678
|
+
(object_creation_expression
|
|
679
|
+
type: (type_identifier) @call.constructor) @call.new
|
|
680
|
+
|
|
681
|
+
;; Extends
|
|
682
|
+
(superclass (type_identifier) @inherit.extends)
|
|
683
|
+
|
|
684
|
+
;; Implements
|
|
685
|
+
(super_interfaces
|
|
686
|
+
(type_list (type_identifier) @inherit.implements))
|
|
687
|
+
`;
|
|
688
|
+
|
|
689
|
+
// src/languages/modules/java.ts
|
|
690
|
+
var javaModule = {
|
|
691
|
+
lang: "java" /* Java */,
|
|
692
|
+
fileExtensions: [".java"],
|
|
693
|
+
queries: javaQueries,
|
|
694
|
+
importStyle: "explicit",
|
|
695
|
+
inheritanceStrategy: "depth-first",
|
|
696
|
+
resolveImport(rawPath, _fromFile, workspace) {
|
|
697
|
+
const cleaned = rawPath.replace(/['"]/g, "");
|
|
698
|
+
const filePath = cleaned.replace(/\./g, "/") + ".java";
|
|
699
|
+
return workspace.findByPackage(filePath);
|
|
700
|
+
},
|
|
701
|
+
isExported(node) {
|
|
702
|
+
const text = node.text;
|
|
703
|
+
return text.includes("public");
|
|
704
|
+
},
|
|
705
|
+
extractType(node) {
|
|
706
|
+
const typeNode = node.childForFieldName("type");
|
|
707
|
+
return typeNode?.text ?? null;
|
|
708
|
+
}
|
|
709
|
+
};
|
|
710
|
+
|
|
711
|
+
// src/parsing/queries/go.ts
|
|
712
|
+
var goQueries = `
|
|
713
|
+
;; Function declaration
|
|
714
|
+
(function_declaration
|
|
715
|
+
name: (identifier) @def.func.name) @def.func
|
|
716
|
+
|
|
717
|
+
;; Method declaration
|
|
718
|
+
(method_declaration
|
|
719
|
+
name: (field_identifier) @def.method.name) @def.method
|
|
720
|
+
|
|
721
|
+
;; Type declaration \u2014 struct
|
|
722
|
+
(type_declaration
|
|
723
|
+
(type_spec
|
|
724
|
+
name: (type_identifier) @def.struct.name
|
|
725
|
+
type: (struct_type))) @def.struct
|
|
726
|
+
|
|
727
|
+
;; Type declaration \u2014 interface
|
|
728
|
+
(type_declaration
|
|
729
|
+
(type_spec
|
|
730
|
+
name: (type_identifier) @def.interface.name
|
|
731
|
+
type: (interface_type))) @def.interface
|
|
732
|
+
|
|
733
|
+
;; Import spec
|
|
734
|
+
(import_spec
|
|
735
|
+
path: (interpreted_string_literal) @imp.source) @imp
|
|
736
|
+
|
|
737
|
+
;; Call expression
|
|
738
|
+
(call_expression
|
|
739
|
+
function: (identifier) @call.name) @call
|
|
740
|
+
|
|
741
|
+
;; Selector call
|
|
742
|
+
(call_expression
|
|
743
|
+
function: (selector_expression
|
|
744
|
+
operand: (_) @call.receiver
|
|
745
|
+
field: (field_identifier) @call.method)) @call.member
|
|
746
|
+
|
|
747
|
+
;; Const declaration
|
|
748
|
+
(const_declaration
|
|
749
|
+
(const_spec
|
|
750
|
+
name: (identifier) @def.constant.name)) @def.constant
|
|
751
|
+
|
|
752
|
+
;; Var declaration
|
|
753
|
+
(var_declaration
|
|
754
|
+
(var_spec
|
|
755
|
+
name: (identifier) @def.var.name)) @def.var
|
|
756
|
+
`;
|
|
757
|
+
|
|
758
|
+
// src/languages/modules/go.ts
|
|
759
|
+
var goModule = {
|
|
760
|
+
lang: "go" /* Go */,
|
|
761
|
+
fileExtensions: [".go"],
|
|
762
|
+
queries: goQueries,
|
|
763
|
+
importStyle: "wildcard",
|
|
764
|
+
inheritanceStrategy: "depth-first",
|
|
765
|
+
resolveImport(rawPath, _fromFile, workspace) {
|
|
766
|
+
const cleaned = rawPath.replace(/['"]/g, "");
|
|
767
|
+
return workspace.findByPackage(cleaned);
|
|
768
|
+
},
|
|
769
|
+
isExported(node) {
|
|
770
|
+
const name = node.childForFieldName("name");
|
|
771
|
+
if (!name) return false;
|
|
772
|
+
const first = name.text[0];
|
|
773
|
+
return first === first.toUpperCase() && first !== first.toLowerCase();
|
|
774
|
+
},
|
|
775
|
+
extractType(node) {
|
|
776
|
+
const typeNode = node.childForFieldName("type");
|
|
777
|
+
return typeNode?.text ?? null;
|
|
778
|
+
}
|
|
779
|
+
};
|
|
780
|
+
|
|
781
|
+
// src/parsing/queries/c.ts
|
|
782
|
+
var cQueries = `
|
|
783
|
+
;; Function definition
|
|
784
|
+
(function_definition
|
|
785
|
+
declarator: (function_declarator
|
|
786
|
+
declarator: (identifier) @def.func.name)) @def.func
|
|
787
|
+
|
|
788
|
+
;; Struct specifier
|
|
789
|
+
(struct_specifier
|
|
790
|
+
name: (type_identifier) @def.struct.name) @def.struct
|
|
791
|
+
|
|
792
|
+
;; Enum specifier
|
|
793
|
+
(enum_specifier
|
|
794
|
+
name: (type_identifier) @def.enum.name) @def.enum
|
|
795
|
+
|
|
796
|
+
;; Typedef
|
|
797
|
+
(type_definition
|
|
798
|
+
declarator: (type_identifier) @def.type_alias.name) @def.type_alias
|
|
799
|
+
|
|
800
|
+
;; Include
|
|
801
|
+
(preproc_include
|
|
802
|
+
path: (_) @imp.source) @imp
|
|
803
|
+
|
|
804
|
+
;; Call
|
|
805
|
+
(call_expression
|
|
806
|
+
function: (identifier) @call.name) @call
|
|
807
|
+
|
|
808
|
+
;; Global variable
|
|
809
|
+
(declaration
|
|
810
|
+
declarator: (init_declarator
|
|
811
|
+
declarator: (identifier) @def.var.name)) @def.var
|
|
812
|
+
`;
|
|
813
|
+
var cModule = {
|
|
814
|
+
lang: "c" /* C */,
|
|
815
|
+
fileExtensions: [".c", ".h"],
|
|
816
|
+
queries: cQueries,
|
|
817
|
+
importStyle: "include",
|
|
818
|
+
inheritanceStrategy: "none",
|
|
819
|
+
resolveImport(rawPath, fromFile, workspace) {
|
|
820
|
+
const cleaned = rawPath.replace(/[<>"']/g, "");
|
|
821
|
+
const fromDir = path6.dirname(fromFile);
|
|
822
|
+
return workspace.resolve(fromDir, cleaned);
|
|
823
|
+
},
|
|
824
|
+
isExported(_node) {
|
|
825
|
+
return true;
|
|
826
|
+
},
|
|
827
|
+
extractType(node) {
|
|
828
|
+
const typeNode = node.childForFieldName("type");
|
|
829
|
+
return typeNode?.text ?? null;
|
|
830
|
+
}
|
|
831
|
+
};
|
|
832
|
+
|
|
833
|
+
// src/parsing/queries/cpp.ts
|
|
834
|
+
var cppQueries = `
|
|
835
|
+
;; Class specifier
|
|
836
|
+
(class_specifier
|
|
837
|
+
name: (type_identifier) @def.class.name) @def.class
|
|
838
|
+
|
|
839
|
+
;; Struct specifier
|
|
840
|
+
(struct_specifier
|
|
841
|
+
name: (type_identifier) @def.struct.name) @def.struct
|
|
842
|
+
|
|
843
|
+
;; Function definition
|
|
844
|
+
(function_definition
|
|
845
|
+
declarator: (function_declarator
|
|
846
|
+
declarator: (identifier) @def.func.name)) @def.func
|
|
847
|
+
|
|
848
|
+
;; Namespace definition
|
|
849
|
+
(namespace_definition
|
|
850
|
+
name: (identifier) @def.namespace.name) @def.namespace
|
|
851
|
+
|
|
852
|
+
;; Template declaration
|
|
853
|
+
(template_declaration
|
|
854
|
+
(class_specifier
|
|
855
|
+
name: (type_identifier) @def.class.name)) @def.class.template
|
|
856
|
+
|
|
857
|
+
;; Include
|
|
858
|
+
(preproc_include
|
|
859
|
+
path: (_) @imp.source) @imp
|
|
860
|
+
|
|
861
|
+
;; Call
|
|
862
|
+
(call_expression
|
|
863
|
+
function: (identifier) @call.name) @call
|
|
864
|
+
|
|
865
|
+
;; Member call
|
|
866
|
+
(call_expression
|
|
867
|
+
function: (field_expression
|
|
868
|
+
field: (field_identifier) @call.method)) @call.member
|
|
869
|
+
|
|
870
|
+
;; Base class clause
|
|
871
|
+
(base_class_clause
|
|
872
|
+
(type_identifier) @inherit.extends)
|
|
873
|
+
|
|
874
|
+
;; Enum
|
|
875
|
+
(enum_specifier
|
|
876
|
+
name: (type_identifier) @def.enum.name) @def.enum
|
|
877
|
+
`;
|
|
878
|
+
var cppModule = {
|
|
879
|
+
lang: "cpp" /* Cpp */,
|
|
880
|
+
fileExtensions: [".cpp", ".cxx", ".cc", ".hpp", ".hxx"],
|
|
881
|
+
queries: cppQueries,
|
|
882
|
+
importStyle: "include",
|
|
883
|
+
inheritanceStrategy: "depth-first",
|
|
884
|
+
resolveImport(rawPath, fromFile, workspace) {
|
|
885
|
+
const cleaned = rawPath.replace(/[<>"']/g, "");
|
|
886
|
+
const fromDir = path6.dirname(fromFile);
|
|
887
|
+
return workspace.resolve(fromDir, cleaned);
|
|
888
|
+
},
|
|
889
|
+
isExported(_node) {
|
|
890
|
+
return true;
|
|
891
|
+
},
|
|
892
|
+
extractType(node) {
|
|
893
|
+
const typeNode = node.childForFieldName("type");
|
|
894
|
+
return typeNode?.text ?? null;
|
|
895
|
+
}
|
|
896
|
+
};
|
|
897
|
+
|
|
898
|
+
// src/parsing/queries/csharp.ts
|
|
899
|
+
var csharpQueries = `
|
|
900
|
+
;; Class declaration
|
|
901
|
+
(class_declaration
|
|
902
|
+
name: (identifier) @def.class.name) @def.class
|
|
903
|
+
|
|
904
|
+
;; Interface declaration
|
|
905
|
+
(interface_declaration
|
|
906
|
+
name: (identifier) @def.interface.name) @def.interface
|
|
907
|
+
|
|
908
|
+
;; Struct declaration
|
|
909
|
+
(struct_declaration
|
|
910
|
+
name: (identifier) @def.struct.name) @def.struct
|
|
911
|
+
|
|
912
|
+
;; Enum declaration
|
|
913
|
+
(enum_declaration
|
|
914
|
+
name: (identifier) @def.enum.name) @def.enum
|
|
915
|
+
|
|
916
|
+
;; Method declaration
|
|
917
|
+
(method_declaration
|
|
918
|
+
name: (identifier) @def.method.name) @def.method
|
|
919
|
+
|
|
920
|
+
;; Constructor declaration
|
|
921
|
+
(constructor_declaration
|
|
922
|
+
name: (identifier) @def.constructor.name) @def.constructor
|
|
923
|
+
|
|
924
|
+
;; Property declaration
|
|
925
|
+
(property_declaration
|
|
926
|
+
name: (identifier) @def.property.name) @def.property
|
|
927
|
+
|
|
928
|
+
;; Namespace declaration
|
|
929
|
+
(namespace_declaration
|
|
930
|
+
name: (_) @def.namespace.name) @def.namespace
|
|
931
|
+
|
|
932
|
+
;; Using directive
|
|
933
|
+
(using_directive
|
|
934
|
+
(qualified_name) @imp.source) @imp
|
|
935
|
+
|
|
936
|
+
;; Invocation
|
|
937
|
+
(invocation_expression
|
|
938
|
+
function: (identifier) @call.name) @call
|
|
939
|
+
|
|
940
|
+
;; Member invocation
|
|
941
|
+
(invocation_expression
|
|
942
|
+
function: (member_access_expression
|
|
943
|
+
name: (identifier) @call.method)) @call.member
|
|
944
|
+
|
|
945
|
+
;; Object creation
|
|
946
|
+
(object_creation_expression
|
|
947
|
+
type: (identifier) @call.constructor) @call.new
|
|
948
|
+
|
|
949
|
+
;; Base list (extends/implements)
|
|
950
|
+
(base_list
|
|
951
|
+
(identifier) @inherit.extends)
|
|
952
|
+
`;
|
|
953
|
+
|
|
954
|
+
// src/languages/modules/csharp.ts
|
|
955
|
+
var csharpModule = {
|
|
956
|
+
lang: "csharp" /* CSharp */,
|
|
957
|
+
fileExtensions: [".cs"],
|
|
958
|
+
queries: csharpQueries,
|
|
959
|
+
importStyle: "explicit",
|
|
960
|
+
inheritanceStrategy: "depth-first",
|
|
961
|
+
resolveImport(rawPath, _fromFile, workspace) {
|
|
962
|
+
const cleaned = rawPath.replace(/['"]/g, "");
|
|
963
|
+
return workspace.findByPackage(cleaned);
|
|
964
|
+
},
|
|
965
|
+
isExported(node) {
|
|
966
|
+
return node.text.includes("public") || node.text.includes("internal");
|
|
967
|
+
},
|
|
968
|
+
extractType(node) {
|
|
969
|
+
const typeNode = node.childForFieldName("type");
|
|
970
|
+
return typeNode?.text ?? null;
|
|
971
|
+
}
|
|
972
|
+
};
|
|
973
|
+
|
|
974
|
+
// src/parsing/queries/rust.ts
|
|
975
|
+
var rustQueries = `
|
|
976
|
+
;; Function item
|
|
977
|
+
(function_item
|
|
978
|
+
name: (identifier) @def.func.name) @def.func
|
|
979
|
+
|
|
980
|
+
;; Struct item
|
|
981
|
+
(struct_item
|
|
982
|
+
name: (type_identifier) @def.struct.name) @def.struct
|
|
983
|
+
|
|
984
|
+
;; Enum item
|
|
985
|
+
(enum_item
|
|
986
|
+
name: (type_identifier) @def.enum.name) @def.enum
|
|
987
|
+
|
|
988
|
+
;; Trait item
|
|
989
|
+
(trait_item
|
|
990
|
+
name: (type_identifier) @def.trait.name) @def.trait
|
|
991
|
+
|
|
992
|
+
;; Impl item
|
|
993
|
+
(impl_item
|
|
994
|
+
type: (type_identifier) @def.class.name) @def.impl
|
|
995
|
+
|
|
996
|
+
;; Type alias
|
|
997
|
+
(type_item
|
|
998
|
+
name: (type_identifier) @def.type_alias.name) @def.type_alias
|
|
999
|
+
|
|
1000
|
+
;; Use declaration
|
|
1001
|
+
(use_declaration
|
|
1002
|
+
argument: (_) @imp.source) @imp
|
|
1003
|
+
|
|
1004
|
+
;; Call
|
|
1005
|
+
(call_expression
|
|
1006
|
+
function: (identifier) @call.name) @call
|
|
1007
|
+
|
|
1008
|
+
;; Method call
|
|
1009
|
+
(call_expression
|
|
1010
|
+
function: (field_expression
|
|
1011
|
+
field: (field_identifier) @call.method)) @call.member
|
|
1012
|
+
|
|
1013
|
+
;; Const item
|
|
1014
|
+
(const_item
|
|
1015
|
+
name: (identifier) @def.constant.name) @def.constant
|
|
1016
|
+
|
|
1017
|
+
;; Static item
|
|
1018
|
+
(static_item
|
|
1019
|
+
name: (identifier) @def.var.name) @def.var
|
|
1020
|
+
`;
|
|
1021
|
+
|
|
1022
|
+
// src/languages/modules/rust.ts
|
|
1023
|
+
var rustModule = {
|
|
1024
|
+
lang: "rust" /* Rust */,
|
|
1025
|
+
fileExtensions: [".rs"],
|
|
1026
|
+
queries: rustQueries,
|
|
1027
|
+
importStyle: "explicit",
|
|
1028
|
+
inheritanceStrategy: "none",
|
|
1029
|
+
resolveImport(rawPath, _fromFile, workspace) {
|
|
1030
|
+
const cleaned = rawPath.replace(/['"]/g, "");
|
|
1031
|
+
const parts = cleaned.split("::");
|
|
1032
|
+
const filePath = parts.join("/") + ".rs";
|
|
1033
|
+
return workspace.findByPackage(filePath);
|
|
1034
|
+
},
|
|
1035
|
+
isExported(node) {
|
|
1036
|
+
return node.text.startsWith("pub ") || node.text.startsWith("pub(");
|
|
1037
|
+
},
|
|
1038
|
+
extractType(node) {
|
|
1039
|
+
const returnType = node.childForFieldName("return_type");
|
|
1040
|
+
return returnType?.text ?? null;
|
|
1041
|
+
}
|
|
1042
|
+
};
|
|
1043
|
+
|
|
1044
|
+
// src/parsing/queries/php.ts
|
|
1045
|
+
var phpQueries = `
|
|
1046
|
+
;; Class declaration
|
|
1047
|
+
(class_declaration
|
|
1048
|
+
name: (name) @def.class.name) @def.class
|
|
1049
|
+
|
|
1050
|
+
;; Interface declaration
|
|
1051
|
+
(interface_declaration
|
|
1052
|
+
name: (name) @def.interface.name) @def.interface
|
|
1053
|
+
|
|
1054
|
+
;; Trait declaration
|
|
1055
|
+
(trait_declaration
|
|
1056
|
+
name: (name) @def.trait.name) @def.trait
|
|
1057
|
+
|
|
1058
|
+
;; Function definition
|
|
1059
|
+
(function_definition
|
|
1060
|
+
name: (name) @def.func.name) @def.func
|
|
1061
|
+
|
|
1062
|
+
;; Method declaration
|
|
1063
|
+
(method_declaration
|
|
1064
|
+
name: (name) @def.method.name) @def.method
|
|
1065
|
+
|
|
1066
|
+
;; Property declaration
|
|
1067
|
+
(property_declaration
|
|
1068
|
+
(property_element
|
|
1069
|
+
(variable_name) @def.property.name)) @def.property
|
|
1070
|
+
|
|
1071
|
+
;; Namespace definition
|
|
1072
|
+
(namespace_definition
|
|
1073
|
+
name: (namespace_name) @def.namespace.name) @def.namespace
|
|
1074
|
+
|
|
1075
|
+
;; Use declaration (import)
|
|
1076
|
+
(namespace_use_declaration
|
|
1077
|
+
(namespace_use_clause
|
|
1078
|
+
(qualified_name) @imp.source)) @imp
|
|
1079
|
+
|
|
1080
|
+
;; Include/require
|
|
1081
|
+
(include_expression
|
|
1082
|
+
(_) @imp.source) @imp.include
|
|
1083
|
+
|
|
1084
|
+
;; Function call
|
|
1085
|
+
(function_call_expression
|
|
1086
|
+
function: (name) @call.name) @call
|
|
1087
|
+
|
|
1088
|
+
;; Method call
|
|
1089
|
+
(member_call_expression
|
|
1090
|
+
name: (name) @call.method) @call.member
|
|
1091
|
+
|
|
1092
|
+
;; Object creation
|
|
1093
|
+
(object_creation_expression
|
|
1094
|
+
(name) @call.constructor) @call.new
|
|
1095
|
+
|
|
1096
|
+
;; Class base clause
|
|
1097
|
+
(base_clause
|
|
1098
|
+
(name) @inherit.extends)
|
|
1099
|
+
|
|
1100
|
+
;; Class interface clause
|
|
1101
|
+
(class_interface_clause
|
|
1102
|
+
(name) @inherit.implements)
|
|
1103
|
+
`;
|
|
1104
|
+
|
|
1105
|
+
// src/languages/modules/php.ts
|
|
1106
|
+
var phpModule = {
|
|
1107
|
+
lang: "php" /* PHP */,
|
|
1108
|
+
fileExtensions: [".php"],
|
|
1109
|
+
queries: phpQueries,
|
|
1110
|
+
importStyle: "explicit",
|
|
1111
|
+
inheritanceStrategy: "depth-first",
|
|
1112
|
+
resolveImport(rawPath, _fromFile, workspace) {
|
|
1113
|
+
const cleaned = rawPath.replace(/['"\\]/g, "/").replace(/^\//, "");
|
|
1114
|
+
return workspace.findByPackage(cleaned + ".php");
|
|
1115
|
+
},
|
|
1116
|
+
isExported(node) {
|
|
1117
|
+
return node.text.includes("public") || !node.text.includes("private");
|
|
1118
|
+
},
|
|
1119
|
+
extractType(node) {
|
|
1120
|
+
const typeNode = node.childForFieldName("type");
|
|
1121
|
+
return typeNode?.text ?? null;
|
|
1122
|
+
}
|
|
1123
|
+
};
|
|
1124
|
+
|
|
1125
|
+
// src/parsing/queries/kotlin.ts
|
|
1126
|
+
var kotlinQueries = `
|
|
1127
|
+
;; Class declaration
|
|
1128
|
+
(class_declaration
|
|
1129
|
+
(type_identifier) @def.class.name) @def.class
|
|
1130
|
+
|
|
1131
|
+
;; Object declaration
|
|
1132
|
+
(object_declaration
|
|
1133
|
+
(type_identifier) @def.class.name) @def.class.object
|
|
1134
|
+
|
|
1135
|
+
;; Interface declaration
|
|
1136
|
+
(class_declaration
|
|
1137
|
+
(type_identifier) @def.interface.name) @def.interface
|
|
1138
|
+
|
|
1139
|
+
;; Function declaration
|
|
1140
|
+
(function_declaration
|
|
1141
|
+
(simple_identifier) @def.func.name) @def.func
|
|
1142
|
+
|
|
1143
|
+
;; Property declaration
|
|
1144
|
+
(property_declaration
|
|
1145
|
+
(variable_declaration
|
|
1146
|
+
(simple_identifier) @def.property.name)) @def.property
|
|
1147
|
+
|
|
1148
|
+
;; Import
|
|
1149
|
+
(import_header
|
|
1150
|
+
(identifier) @imp.source) @imp
|
|
1151
|
+
|
|
1152
|
+
;; Call
|
|
1153
|
+
(call_expression
|
|
1154
|
+
(simple_identifier) @call.name) @call
|
|
1155
|
+
|
|
1156
|
+
;; Navigation call
|
|
1157
|
+
(call_expression
|
|
1158
|
+
(navigation_expression
|
|
1159
|
+
(simple_identifier) @call.method)) @call.member
|
|
1160
|
+
|
|
1161
|
+
;; Delegation specifier (extends/implements)
|
|
1162
|
+
(delegation_specifier
|
|
1163
|
+
(user_type
|
|
1164
|
+
(type_identifier) @inherit.extends))
|
|
1165
|
+
`;
|
|
1166
|
+
|
|
1167
|
+
// src/languages/modules/kotlin.ts
|
|
1168
|
+
var kotlinModule = {
|
|
1169
|
+
lang: "kotlin" /* Kotlin */,
|
|
1170
|
+
fileExtensions: [".kt", ".kts"],
|
|
1171
|
+
queries: kotlinQueries,
|
|
1172
|
+
importStyle: "explicit",
|
|
1173
|
+
inheritanceStrategy: "depth-first",
|
|
1174
|
+
resolveImport(rawPath, _fromFile, workspace) {
|
|
1175
|
+
const cleaned = rawPath.replace(/['"]/g, "");
|
|
1176
|
+
const filePath = cleaned.replace(/\./g, "/") + ".kt";
|
|
1177
|
+
return workspace.findByPackage(filePath);
|
|
1178
|
+
},
|
|
1179
|
+
isExported(node) {
|
|
1180
|
+
return !node.text.includes("private") && !node.text.includes("internal");
|
|
1181
|
+
},
|
|
1182
|
+
extractType(node) {
|
|
1183
|
+
const typeNode = node.childForFieldName("type");
|
|
1184
|
+
return typeNode?.text ?? null;
|
|
1185
|
+
}
|
|
1186
|
+
};
|
|
1187
|
+
|
|
1188
|
+
// src/parsing/queries/ruby.ts
|
|
1189
|
+
var rubyQueries = `
|
|
1190
|
+
;; Class
|
|
1191
|
+
(class
|
|
1192
|
+
name: (constant) @def.class.name) @def.class
|
|
1193
|
+
|
|
1194
|
+
;; Module
|
|
1195
|
+
(module
|
|
1196
|
+
name: (constant) @def.module.name) @def.module
|
|
1197
|
+
|
|
1198
|
+
;; Method
|
|
1199
|
+
(method
|
|
1200
|
+
name: (identifier) @def.method.name) @def.method
|
|
1201
|
+
|
|
1202
|
+
;; Singleton method
|
|
1203
|
+
(singleton_method
|
|
1204
|
+
name: (identifier) @def.method.name) @def.method.static
|
|
1205
|
+
|
|
1206
|
+
;; Assignment
|
|
1207
|
+
(assignment
|
|
1208
|
+
left: (identifier) @def.var.name) @def.var
|
|
1209
|
+
|
|
1210
|
+
;; Require
|
|
1211
|
+
(call
|
|
1212
|
+
method: (identifier) @_method
|
|
1213
|
+
arguments: (argument_list (string) @imp.source)
|
|
1214
|
+
(#match? @_method "^require"))
|
|
1215
|
+
|
|
1216
|
+
;; Call
|
|
1217
|
+
(call
|
|
1218
|
+
method: (identifier) @call.name) @call
|
|
1219
|
+
|
|
1220
|
+
;; Superclass
|
|
1221
|
+
(superclass
|
|
1222
|
+
(constant) @inherit.extends)
|
|
1223
|
+
`;
|
|
1224
|
+
|
|
1225
|
+
// src/languages/modules/ruby.ts
|
|
1226
|
+
var rubyModule = {
|
|
1227
|
+
lang: "ruby" /* Ruby */,
|
|
1228
|
+
fileExtensions: [".rb"],
|
|
1229
|
+
queries: rubyQueries,
|
|
1230
|
+
importStyle: "wildcard",
|
|
1231
|
+
inheritanceStrategy: "mixin-aware",
|
|
1232
|
+
resolveImport(rawPath, _fromFile, workspace) {
|
|
1233
|
+
const cleaned = rawPath.replace(/['"]/g, "");
|
|
1234
|
+
return workspace.findByPackage(cleaned + ".rb") ?? workspace.findByPackage(cleaned);
|
|
1235
|
+
},
|
|
1236
|
+
isExported(_node) {
|
|
1237
|
+
return true;
|
|
1238
|
+
},
|
|
1239
|
+
extractType(_node) {
|
|
1240
|
+
return null;
|
|
1241
|
+
}
|
|
1242
|
+
};
|
|
1243
|
+
|
|
1244
|
+
// src/parsing/queries/swift.ts
|
|
1245
|
+
var swiftQueries = `
|
|
1246
|
+
;; Class declaration
|
|
1247
|
+
(class_declaration
|
|
1248
|
+
name: (type_identifier) @def.class.name) @def.class
|
|
1249
|
+
|
|
1250
|
+
;; Struct declaration
|
|
1251
|
+
(struct_declaration
|
|
1252
|
+
name: (type_identifier) @def.struct.name) @def.struct
|
|
1253
|
+
|
|
1254
|
+
;; Protocol declaration
|
|
1255
|
+
(protocol_declaration
|
|
1256
|
+
name: (type_identifier) @def.interface.name) @def.interface
|
|
1257
|
+
|
|
1258
|
+
;; Enum declaration
|
|
1259
|
+
(enum_declaration
|
|
1260
|
+
name: (type_identifier) @def.enum.name) @def.enum
|
|
1261
|
+
|
|
1262
|
+
;; Function declaration
|
|
1263
|
+
(function_declaration
|
|
1264
|
+
name: (simple_identifier) @def.func.name) @def.func
|
|
1265
|
+
|
|
1266
|
+
;; Property declaration
|
|
1267
|
+
(property_declaration
|
|
1268
|
+
(pattern
|
|
1269
|
+
(simple_identifier) @def.property.name)) @def.property
|
|
1270
|
+
|
|
1271
|
+
;; Import
|
|
1272
|
+
(import_declaration
|
|
1273
|
+
(identifier) @imp.source) @imp
|
|
1274
|
+
|
|
1275
|
+
;; Call
|
|
1276
|
+
(call_expression
|
|
1277
|
+
(simple_identifier) @call.name) @call
|
|
1278
|
+
|
|
1279
|
+
;; Inheritance
|
|
1280
|
+
(inheritance_specifier
|
|
1281
|
+
(type_identifier) @inherit.extends)
|
|
1282
|
+
`;
|
|
1283
|
+
|
|
1284
|
+
// src/languages/modules/swift.ts
|
|
1285
|
+
var swiftModule = {
|
|
1286
|
+
lang: "swift" /* Swift */,
|
|
1287
|
+
fileExtensions: [".swift"],
|
|
1288
|
+
queries: swiftQueries,
|
|
1289
|
+
importStyle: "wildcard",
|
|
1290
|
+
inheritanceStrategy: "depth-first",
|
|
1291
|
+
resolveImport(rawPath, _fromFile, workspace) {
|
|
1292
|
+
const cleaned = rawPath.replace(/['"]/g, "");
|
|
1293
|
+
return workspace.findByPackage(cleaned);
|
|
1294
|
+
},
|
|
1295
|
+
isExported(node) {
|
|
1296
|
+
return !node.text.includes("private") && !node.text.includes("fileprivate");
|
|
1297
|
+
},
|
|
1298
|
+
extractType(node) {
|
|
1299
|
+
const typeAnnotation = node.childForFieldName("type");
|
|
1300
|
+
return typeAnnotation?.text ?? null;
|
|
1301
|
+
}
|
|
1302
|
+
};
|
|
1303
|
+
var dartModule = {
|
|
1304
|
+
lang: "dart" /* Dart */,
|
|
1305
|
+
fileExtensions: [".dart"],
|
|
1306
|
+
queries: typescriptQueries,
|
|
1307
|
+
// Dart grammar fallback
|
|
1308
|
+
importStyle: "wildcard",
|
|
1309
|
+
inheritanceStrategy: "depth-first",
|
|
1310
|
+
resolveImport(rawPath, fromFile, workspace) {
|
|
1311
|
+
const cleaned = rawPath.replace(/['"]/g, "");
|
|
1312
|
+
if (cleaned.startsWith("package:")) {
|
|
1313
|
+
const pkg = cleaned.replace("package:", "");
|
|
1314
|
+
return workspace.findByPackage(pkg);
|
|
1315
|
+
}
|
|
1316
|
+
const fromDir = path6.dirname(fromFile);
|
|
1317
|
+
return workspace.resolve(fromDir, cleaned);
|
|
1318
|
+
},
|
|
1319
|
+
isExported(node) {
|
|
1320
|
+
const name = node.childForFieldName("name");
|
|
1321
|
+
if (!name) return true;
|
|
1322
|
+
return !name.text.startsWith("_");
|
|
1323
|
+
},
|
|
1324
|
+
extractType(node) {
|
|
1325
|
+
const typeNode = node.childForFieldName("type");
|
|
1326
|
+
return typeNode?.text ?? null;
|
|
1327
|
+
}
|
|
1328
|
+
};
|
|
1329
|
+
|
|
1330
|
+
// src/languages/registry.ts
|
|
1331
|
+
var MODULES = {
|
|
1332
|
+
["typescript" /* TypeScript */]: typescriptModule,
|
|
1333
|
+
["javascript" /* JavaScript */]: javascriptModule,
|
|
1334
|
+
["python" /* Python */]: pythonModule,
|
|
1335
|
+
["java" /* Java */]: javaModule,
|
|
1336
|
+
["go" /* Go */]: goModule,
|
|
1337
|
+
["c" /* C */]: cModule,
|
|
1338
|
+
["cpp" /* Cpp */]: cppModule,
|
|
1339
|
+
["csharp" /* CSharp */]: csharpModule,
|
|
1340
|
+
["rust" /* Rust */]: rustModule,
|
|
1341
|
+
["php" /* PHP */]: phpModule,
|
|
1342
|
+
["kotlin" /* Kotlin */]: kotlinModule,
|
|
1343
|
+
["ruby" /* Ruby */]: rubyModule,
|
|
1344
|
+
["swift" /* Swift */]: swiftModule,
|
|
1345
|
+
["dart" /* Dart */]: dartModule
|
|
1346
|
+
};
|
|
1347
|
+
function getLanguageModule(lang) {
|
|
1348
|
+
return MODULES[lang];
|
|
1349
|
+
}
|
|
1350
|
+
function getAllLanguageModules() {
|
|
1351
|
+
return Object.values(MODULES);
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
// src/resolver/binding-tracker.ts
|
|
1355
|
+
var BindingTracker = class {
|
|
1356
|
+
bindings = /* @__PURE__ */ new Map();
|
|
1357
|
+
addBinding(filePath, binding) {
|
|
1358
|
+
let fileBindings = this.bindings.get(filePath);
|
|
1359
|
+
if (!fileBindings) {
|
|
1360
|
+
fileBindings = /* @__PURE__ */ new Map();
|
|
1361
|
+
this.bindings.set(filePath, fileBindings);
|
|
1362
|
+
}
|
|
1363
|
+
fileBindings.set(binding.localName, binding);
|
|
1364
|
+
}
|
|
1365
|
+
getBinding(filePath, localName) {
|
|
1366
|
+
return this.bindings.get(filePath)?.get(localName);
|
|
1367
|
+
}
|
|
1368
|
+
getFileBindings(filePath) {
|
|
1369
|
+
const fileBindings = this.bindings.get(filePath);
|
|
1370
|
+
return fileBindings ? [...fileBindings.values()] : [];
|
|
1371
|
+
}
|
|
1372
|
+
clear() {
|
|
1373
|
+
this.bindings.clear();
|
|
1374
|
+
}
|
|
1375
|
+
};
|
|
1376
|
+
|
|
1377
|
+
// src/resolver/import-resolver.ts
|
|
1378
|
+
function resolveImports(filePath, fileNodeId, imports, langModule, workspace) {
|
|
1379
|
+
const bindings = new BindingTracker();
|
|
1380
|
+
const edges = [];
|
|
1381
|
+
const maxReExportHops = 5;
|
|
1382
|
+
for (const imp of imports) {
|
|
1383
|
+
let resolvedPath = langModule.resolveImport(imp.rawPath, filePath, workspace);
|
|
1384
|
+
let hops = 0;
|
|
1385
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1386
|
+
while (resolvedPath && hops < maxReExportHops && !visited.has(resolvedPath)) {
|
|
1387
|
+
visited.add(resolvedPath);
|
|
1388
|
+
hops++;
|
|
1389
|
+
break;
|
|
1390
|
+
}
|
|
1391
|
+
if (!resolvedPath) continue;
|
|
1392
|
+
const targetNodeId = `file:${resolvedPath}:${resolvedPath}`;
|
|
1393
|
+
const edge = {
|
|
1394
|
+
id: generateEdgeId(fileNodeId, targetNodeId, "imports"),
|
|
1395
|
+
source: fileNodeId,
|
|
1396
|
+
target: targetNodeId,
|
|
1397
|
+
kind: "imports",
|
|
1398
|
+
weight: 0.95,
|
|
1399
|
+
label: imp.rawPath
|
|
1400
|
+
};
|
|
1401
|
+
edges.push(edge);
|
|
1402
|
+
for (const localName of imp.localNames) {
|
|
1403
|
+
const binding = {
|
|
1404
|
+
localName,
|
|
1405
|
+
sourcePath: resolvedPath,
|
|
1406
|
+
exportedName: localName,
|
|
1407
|
+
isDefault: imp.isDefault,
|
|
1408
|
+
isNamespace: imp.isNamespace
|
|
1409
|
+
};
|
|
1410
|
+
bindings.addBinding(filePath, binding);
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
return { edges, bindings };
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
// src/call-graph/call-builder.ts
|
|
1417
|
+
function buildCallEdges(callSites, graph, bindings) {
|
|
1418
|
+
const edges = [];
|
|
1419
|
+
const symbolIndex = buildSymbolIndex(graph);
|
|
1420
|
+
const tiers = [
|
|
1421
|
+
{
|
|
1422
|
+
name: "same-file",
|
|
1423
|
+
confidence: 0.95,
|
|
1424
|
+
resolve(cs) {
|
|
1425
|
+
const key = `${cs.callerFilePath}:${cs.name}`;
|
|
1426
|
+
return symbolIndex.get(key) ?? null;
|
|
1427
|
+
}
|
|
1428
|
+
},
|
|
1429
|
+
{
|
|
1430
|
+
name: "imported",
|
|
1431
|
+
confidence: 0.9,
|
|
1432
|
+
resolve(cs) {
|
|
1433
|
+
const binding = bindings.getBinding(cs.callerFilePath, cs.name);
|
|
1434
|
+
if (!binding) return null;
|
|
1435
|
+
const key = `${binding.sourcePath}:${binding.exportedName}`;
|
|
1436
|
+
return symbolIndex.get(key) ?? null;
|
|
1437
|
+
}
|
|
1438
|
+
},
|
|
1439
|
+
{
|
|
1440
|
+
name: "global",
|
|
1441
|
+
confidence: 0.5,
|
|
1442
|
+
resolve(cs) {
|
|
1443
|
+
return globalSymbolIndex.get(cs.name) ?? null;
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
];
|
|
1447
|
+
const globalSymbolIndex = /* @__PURE__ */ new Map();
|
|
1448
|
+
for (const node of graph.allNodes()) {
|
|
1449
|
+
if (["function", "method", "class", "constructor"].includes(node.kind)) {
|
|
1450
|
+
if (!globalSymbolIndex.has(node.name)) {
|
|
1451
|
+
globalSymbolIndex.set(node.name, node.id);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
for (const cs of callSites) {
|
|
1456
|
+
for (const tier of tiers) {
|
|
1457
|
+
const targetId = tier.resolve(cs);
|
|
1458
|
+
if (targetId && targetId !== cs.callerNodeId) {
|
|
1459
|
+
edges.push({
|
|
1460
|
+
id: generateEdgeId(cs.callerNodeId, targetId, "calls"),
|
|
1461
|
+
source: cs.callerNodeId,
|
|
1462
|
+
target: targetId,
|
|
1463
|
+
kind: "calls",
|
|
1464
|
+
weight: tier.confidence,
|
|
1465
|
+
label: cs.name
|
|
1466
|
+
});
|
|
1467
|
+
break;
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
return edges;
|
|
1472
|
+
}
|
|
1473
|
+
function buildSymbolIndex(graph) {
|
|
1474
|
+
const index = /* @__PURE__ */ new Map();
|
|
1475
|
+
for (const node of graph.allNodes()) {
|
|
1476
|
+
if (["function", "method", "class", "constructor", "variable"].includes(node.kind)) {
|
|
1477
|
+
const key = `${node.filePath}:${node.name}`;
|
|
1478
|
+
index.set(key, node.id);
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
return index;
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
// src/call-graph/call-classifier.ts
|
|
1485
|
+
function classifyCall(name, hasReceiver, isNew) {
|
|
1486
|
+
if (isNew) return "constructor";
|
|
1487
|
+
if (hasReceiver) return "member";
|
|
1488
|
+
if (name[0] === name[0].toUpperCase() && name[0] !== name[0].toLowerCase()) {
|
|
1489
|
+
return "constructor";
|
|
1490
|
+
}
|
|
1491
|
+
return "free";
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
// src/inheritance/heritage-builder.ts
|
|
1495
|
+
function buildHeritageEdges(heritages, graph) {
|
|
1496
|
+
const edges = [];
|
|
1497
|
+
const classIndex = /* @__PURE__ */ new Map();
|
|
1498
|
+
for (const node of graph.allNodes()) {
|
|
1499
|
+
if (["class", "interface", "struct", "trait"].includes(node.kind)) {
|
|
1500
|
+
classIndex.set(node.name, node.id);
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
for (const h of heritages) {
|
|
1504
|
+
for (const name of h.extendsNames) {
|
|
1505
|
+
const targetId = classIndex.get(name);
|
|
1506
|
+
if (targetId) {
|
|
1507
|
+
edges.push({
|
|
1508
|
+
id: generateEdgeId(h.classNodeId, targetId, "extends"),
|
|
1509
|
+
source: h.classNodeId,
|
|
1510
|
+
target: targetId,
|
|
1511
|
+
kind: "extends",
|
|
1512
|
+
weight: 1,
|
|
1513
|
+
label: `extends ${name}`
|
|
1514
|
+
});
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
for (const name of h.implementsNames) {
|
|
1518
|
+
const targetId = classIndex.get(name);
|
|
1519
|
+
if (targetId) {
|
|
1520
|
+
edges.push({
|
|
1521
|
+
id: generateEdgeId(h.classNodeId, targetId, "implements"),
|
|
1522
|
+
source: h.classNodeId,
|
|
1523
|
+
target: targetId,
|
|
1524
|
+
kind: "implements",
|
|
1525
|
+
weight: 1,
|
|
1526
|
+
label: `implements ${name}`
|
|
1527
|
+
});
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
return edges;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
// src/inheritance/mro-walker.ts
|
|
1535
|
+
function computeMRO(classId, parentMap, strategy) {
|
|
1536
|
+
switch (strategy) {
|
|
1537
|
+
case "depth-first":
|
|
1538
|
+
return depthFirstMRO(classId, parentMap);
|
|
1539
|
+
case "c3":
|
|
1540
|
+
return c3Linearize(classId, parentMap);
|
|
1541
|
+
case "mixin-aware":
|
|
1542
|
+
return mixinAwareMRO(classId, parentMap);
|
|
1543
|
+
case "none":
|
|
1544
|
+
return [classId];
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
function depthFirstMRO(classId, parentMap) {
|
|
1548
|
+
const result = [];
|
|
1549
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1550
|
+
const stack = [classId];
|
|
1551
|
+
while (stack.length > 0) {
|
|
1552
|
+
const current = stack.pop();
|
|
1553
|
+
if (visited.has(current)) continue;
|
|
1554
|
+
visited.add(current);
|
|
1555
|
+
result.push(current);
|
|
1556
|
+
const parents = parentMap.get(current) ?? [];
|
|
1557
|
+
for (let i = parents.length - 1; i >= 0; i--) {
|
|
1558
|
+
stack.push(parents[i]);
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
return result;
|
|
1562
|
+
}
|
|
1563
|
+
function c3Linearize(classId, parentMap) {
|
|
1564
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1565
|
+
const inProgress = /* @__PURE__ */ new Set();
|
|
1566
|
+
function linearize(cls) {
|
|
1567
|
+
if (cache.has(cls)) return cache.get(cls);
|
|
1568
|
+
if (inProgress.has(cls)) return [cls];
|
|
1569
|
+
inProgress.add(cls);
|
|
1570
|
+
const parents = parentMap.get(cls) ?? [];
|
|
1571
|
+
if (parents.length === 0) {
|
|
1572
|
+
const result2 = [cls];
|
|
1573
|
+
cache.set(cls, result2);
|
|
1574
|
+
inProgress.delete(cls);
|
|
1575
|
+
return result2;
|
|
1576
|
+
}
|
|
1577
|
+
const parentLinearizations = parents.map((p) => linearize(p));
|
|
1578
|
+
const sequences = [...parentLinearizations, parents];
|
|
1579
|
+
const result = [cls];
|
|
1580
|
+
while (sequences.some((s) => s.length > 0)) {
|
|
1581
|
+
let found = false;
|
|
1582
|
+
for (const seq of sequences) {
|
|
1583
|
+
if (seq.length === 0) continue;
|
|
1584
|
+
const head = seq[0];
|
|
1585
|
+
const inTail = sequences.some((s) => s.indexOf(head) > 0);
|
|
1586
|
+
if (!inTail) {
|
|
1587
|
+
result.push(head);
|
|
1588
|
+
for (const s of sequences) {
|
|
1589
|
+
const idx = s.indexOf(head);
|
|
1590
|
+
if (idx >= 0) s.splice(idx, 1);
|
|
1591
|
+
}
|
|
1592
|
+
found = true;
|
|
1593
|
+
break;
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
if (!found) break;
|
|
1597
|
+
}
|
|
1598
|
+
cache.set(cls, result);
|
|
1599
|
+
inProgress.delete(cls);
|
|
1600
|
+
return result;
|
|
1601
|
+
}
|
|
1602
|
+
return linearize(classId);
|
|
1603
|
+
}
|
|
1604
|
+
function mixinAwareMRO(classId, parentMap) {
|
|
1605
|
+
return depthFirstMRO(classId, parentMap);
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
// src/inheritance/override-detector.ts
|
|
1609
|
+
function detectOverrides(graph) {
|
|
1610
|
+
const edges = [];
|
|
1611
|
+
const methodsByOwner = /* @__PURE__ */ new Map();
|
|
1612
|
+
for (const edge of graph.findEdgesByKind("has_member")) {
|
|
1613
|
+
const member = graph.getNode(edge.target);
|
|
1614
|
+
if (member && member.kind === "method") {
|
|
1615
|
+
let methods = methodsByOwner.get(edge.source);
|
|
1616
|
+
if (!methods) {
|
|
1617
|
+
methods = /* @__PURE__ */ new Map();
|
|
1618
|
+
methodsByOwner.set(edge.source, methods);
|
|
1619
|
+
}
|
|
1620
|
+
methods.set(member.name, member.id);
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
for (const extendsEdge of graph.findEdgesByKind("extends")) {
|
|
1624
|
+
const childMethods = methodsByOwner.get(extendsEdge.source);
|
|
1625
|
+
const parentMethods = methodsByOwner.get(extendsEdge.target);
|
|
1626
|
+
if (!childMethods || !parentMethods) continue;
|
|
1627
|
+
for (const [methodName, childMethodId] of childMethods) {
|
|
1628
|
+
const parentMethodId = parentMethods.get(methodName);
|
|
1629
|
+
if (parentMethodId) {
|
|
1630
|
+
edges.push({
|
|
1631
|
+
id: generateEdgeId(childMethodId, parentMethodId, "overrides"),
|
|
1632
|
+
source: childMethodId,
|
|
1633
|
+
target: parentMethodId,
|
|
1634
|
+
kind: "overrides",
|
|
1635
|
+
weight: 1,
|
|
1636
|
+
label: `overrides ${methodName}`
|
|
1637
|
+
});
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
return edges;
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
// src/pipeline/dag-validator.ts
|
|
1645
|
+
function validateDAG(phases) {
|
|
1646
|
+
const errors = [];
|
|
1647
|
+
const names = /* @__PURE__ */ new Set();
|
|
1648
|
+
for (const phase of phases) {
|
|
1649
|
+
if (names.has(phase.name)) {
|
|
1650
|
+
errors.push({ type: "duplicate", message: `Duplicate phase name: ${phase.name}` });
|
|
1651
|
+
}
|
|
1652
|
+
names.add(phase.name);
|
|
1653
|
+
}
|
|
1654
|
+
for (const phase of phases) {
|
|
1655
|
+
for (const dep of phase.dependencies) {
|
|
1656
|
+
if (!names.has(dep)) {
|
|
1657
|
+
errors.push({
|
|
1658
|
+
type: "missing-dep",
|
|
1659
|
+
message: `Phase "${phase.name}" depends on missing phase "${dep}"`
|
|
1660
|
+
});
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
1665
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1666
|
+
const phaseMap = new Map(phases.map((p) => [p.name, p]));
|
|
1667
|
+
function dfs(name, path17) {
|
|
1668
|
+
if (visiting.has(name)) {
|
|
1669
|
+
const cycleStart = path17.indexOf(name);
|
|
1670
|
+
const cycle = path17.slice(cycleStart).concat(name);
|
|
1671
|
+
errors.push({ type: "cycle", message: `Cycle detected: ${cycle.join(" \u2192 ")}` });
|
|
1672
|
+
return true;
|
|
1673
|
+
}
|
|
1674
|
+
if (visited.has(name)) return false;
|
|
1675
|
+
visiting.add(name);
|
|
1676
|
+
path17.push(name);
|
|
1677
|
+
const phase = phaseMap.get(name);
|
|
1678
|
+
if (phase) {
|
|
1679
|
+
for (const dep of phase.dependencies) {
|
|
1680
|
+
if (dfs(dep, path17)) return true;
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
visiting.delete(name);
|
|
1684
|
+
visited.add(name);
|
|
1685
|
+
path17.pop();
|
|
1686
|
+
return false;
|
|
1687
|
+
}
|
|
1688
|
+
for (const phase of phases) {
|
|
1689
|
+
if (!visited.has(phase.name)) {
|
|
1690
|
+
dfs(phase.name, []);
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
return errors;
|
|
1694
|
+
}
|
|
1695
|
+
function topologicalSort(phases) {
|
|
1696
|
+
const phaseMap = new Map(phases.map((p) => [p.name, p]));
|
|
1697
|
+
const inDegree = /* @__PURE__ */ new Map();
|
|
1698
|
+
const adjList = /* @__PURE__ */ new Map();
|
|
1699
|
+
for (const phase of phases) {
|
|
1700
|
+
inDegree.set(phase.name, 0);
|
|
1701
|
+
adjList.set(phase.name, []);
|
|
1702
|
+
}
|
|
1703
|
+
for (const phase of phases) {
|
|
1704
|
+
for (const dep of phase.dependencies) {
|
|
1705
|
+
adjList.get(dep)?.push(phase.name);
|
|
1706
|
+
inDegree.set(phase.name, (inDegree.get(phase.name) ?? 0) + 1);
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
const queue = [];
|
|
1710
|
+
for (const [name, degree] of inDegree) {
|
|
1711
|
+
if (degree === 0) queue.push(name);
|
|
1712
|
+
}
|
|
1713
|
+
const sorted = [];
|
|
1714
|
+
while (queue.length > 0) {
|
|
1715
|
+
const current = queue.shift();
|
|
1716
|
+
sorted.push(phaseMap.get(current));
|
|
1717
|
+
for (const neighbor of adjList.get(current) ?? []) {
|
|
1718
|
+
const newDegree = (inDegree.get(neighbor) ?? 1) - 1;
|
|
1719
|
+
inDegree.set(neighbor, newDegree);
|
|
1720
|
+
if (newDegree === 0) queue.push(neighbor);
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
return sorted;
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
// src/pipeline/orchestrator.ts
|
|
1727
|
+
async function runPipeline(phases, context) {
|
|
1728
|
+
const errors = validateDAG(phases);
|
|
1729
|
+
if (errors.length > 0) {
|
|
1730
|
+
throw new Error(`Pipeline validation failed:
|
|
1731
|
+
${errors.map((e) => e.message).join("\n")}`);
|
|
1732
|
+
}
|
|
1733
|
+
const sorted = topologicalSort(phases);
|
|
1734
|
+
const results = /* @__PURE__ */ new Map();
|
|
1735
|
+
const startTime = Date.now();
|
|
1736
|
+
let success = true;
|
|
1737
|
+
for (const phase of sorted) {
|
|
1738
|
+
context.onProgress?.(phase.name, "running");
|
|
1739
|
+
const phaseStart = Date.now();
|
|
1740
|
+
try {
|
|
1741
|
+
const depResults = /* @__PURE__ */ new Map();
|
|
1742
|
+
for (const dep of phase.dependencies) {
|
|
1743
|
+
const depResult = results.get(dep);
|
|
1744
|
+
if (depResult) depResults.set(dep, depResult);
|
|
1745
|
+
}
|
|
1746
|
+
const result = await phase.execute(context, depResults);
|
|
1747
|
+
results.set(phase.name, result);
|
|
1748
|
+
context.onProgress?.(phase.name, result.status);
|
|
1749
|
+
if (result.status === "failed") {
|
|
1750
|
+
success = false;
|
|
1751
|
+
break;
|
|
1752
|
+
}
|
|
1753
|
+
} catch (err) {
|
|
1754
|
+
const result = {
|
|
1755
|
+
status: "failed",
|
|
1756
|
+
duration: Date.now() - phaseStart,
|
|
1757
|
+
message: err instanceof Error ? err.message : String(err)
|
|
1758
|
+
};
|
|
1759
|
+
results.set(phase.name, result);
|
|
1760
|
+
context.onProgress?.(phase.name, "failed");
|
|
1761
|
+
success = false;
|
|
1762
|
+
break;
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
return {
|
|
1766
|
+
success,
|
|
1767
|
+
results,
|
|
1768
|
+
totalDuration: Date.now() - startTime
|
|
1769
|
+
};
|
|
1770
|
+
}
|
|
1771
|
+
var IGNORED_DIRS = /* @__PURE__ */ new Set([
|
|
1772
|
+
"node_modules",
|
|
1773
|
+
".git",
|
|
1774
|
+
".svn",
|
|
1775
|
+
".hg",
|
|
1776
|
+
"dist",
|
|
1777
|
+
"dist-tests",
|
|
1778
|
+
"build",
|
|
1779
|
+
"out",
|
|
1780
|
+
"__pycache__",
|
|
1781
|
+
".tox",
|
|
1782
|
+
".pytest_cache",
|
|
1783
|
+
".mypy_cache",
|
|
1784
|
+
"vendor",
|
|
1785
|
+
"target",
|
|
1786
|
+
".code-intel",
|
|
1787
|
+
"coverage",
|
|
1788
|
+
".next",
|
|
1789
|
+
".turbo",
|
|
1790
|
+
".cache",
|
|
1791
|
+
"tmp",
|
|
1792
|
+
"temp",
|
|
1793
|
+
".parcel-cache"
|
|
1794
|
+
]);
|
|
1795
|
+
function loadIgnorePatterns(workspaceRoot) {
|
|
1796
|
+
try {
|
|
1797
|
+
const raw = fs8.readFileSync(path6.join(workspaceRoot, ".codeintelignore"), "utf-8");
|
|
1798
|
+
const extras = /* @__PURE__ */ new Set();
|
|
1799
|
+
for (const line of raw.split("\n")) {
|
|
1800
|
+
const trimmed = line.trim();
|
|
1801
|
+
if (trimmed && !trimmed.startsWith("#")) extras.add(trimmed);
|
|
1802
|
+
}
|
|
1803
|
+
return extras;
|
|
1804
|
+
} catch {
|
|
1805
|
+
return /* @__PURE__ */ new Set();
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
var scanPhase = {
|
|
1809
|
+
name: "scan",
|
|
1810
|
+
dependencies: [],
|
|
1811
|
+
async execute(context) {
|
|
1812
|
+
const start = Date.now();
|
|
1813
|
+
const extensions = new Set(getSupportedExtensions());
|
|
1814
|
+
const filePaths = [];
|
|
1815
|
+
const extraIgnore = loadIgnorePatterns(context.workspaceRoot);
|
|
1816
|
+
function walk(dir) {
|
|
1817
|
+
let entries;
|
|
1818
|
+
try {
|
|
1819
|
+
entries = fs8.readdirSync(dir, { withFileTypes: true });
|
|
1820
|
+
} catch {
|
|
1821
|
+
return;
|
|
1822
|
+
}
|
|
1823
|
+
for (const entry of entries) {
|
|
1824
|
+
if (entry.name.startsWith(".") && entry.isDirectory()) continue;
|
|
1825
|
+
if (IGNORED_DIRS.has(entry.name) && entry.isDirectory()) continue;
|
|
1826
|
+
if (extraIgnore.has(entry.name) && entry.isDirectory()) continue;
|
|
1827
|
+
const fullPath = path6.join(dir, entry.name);
|
|
1828
|
+
if (entry.isDirectory()) {
|
|
1829
|
+
walk(fullPath);
|
|
1830
|
+
} else if (entry.isFile()) {
|
|
1831
|
+
const ext = path6.extname(entry.name);
|
|
1832
|
+
const fullName = entry.name;
|
|
1833
|
+
if (fullName.endsWith(".d.ts") || fullName.endsWith(".js.map") || fullName.endsWith(".d.ts.map")) continue;
|
|
1834
|
+
if (extensions.has(ext)) {
|
|
1835
|
+
filePaths.push(fullPath);
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
walk(context.workspaceRoot);
|
|
1841
|
+
context.filePaths.push(...filePaths);
|
|
1842
|
+
return {
|
|
1843
|
+
status: "completed",
|
|
1844
|
+
duration: Date.now() - start,
|
|
1845
|
+
message: `Found ${filePaths.length} source files`
|
|
1846
|
+
};
|
|
1847
|
+
}
|
|
1848
|
+
};
|
|
1849
|
+
var structurePhase = {
|
|
1850
|
+
name: "structure",
|
|
1851
|
+
dependencies: ["scan"],
|
|
1852
|
+
async execute(context) {
|
|
1853
|
+
const start = Date.now();
|
|
1854
|
+
const dirs = /* @__PURE__ */ new Set();
|
|
1855
|
+
for (const filePath of context.filePaths) {
|
|
1856
|
+
const relativePath = path6.relative(context.workspaceRoot, filePath);
|
|
1857
|
+
const lang = detectLanguage(filePath);
|
|
1858
|
+
context.graph.addNode({
|
|
1859
|
+
id: generateNodeId("file", relativePath, relativePath),
|
|
1860
|
+
kind: "file",
|
|
1861
|
+
name: path6.basename(filePath),
|
|
1862
|
+
filePath: relativePath,
|
|
1863
|
+
metadata: lang ? { language: lang } : void 0
|
|
1864
|
+
});
|
|
1865
|
+
let dir = path6.dirname(relativePath);
|
|
1866
|
+
while (dir && dir !== "." && dir !== "") {
|
|
1867
|
+
if (dirs.has(dir)) break;
|
|
1868
|
+
dirs.add(dir);
|
|
1869
|
+
dir = path6.dirname(dir);
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
for (const dir of dirs) {
|
|
1873
|
+
context.graph.addNode({
|
|
1874
|
+
id: generateNodeId("directory", dir, dir),
|
|
1875
|
+
kind: "directory",
|
|
1876
|
+
name: path6.basename(dir),
|
|
1877
|
+
filePath: dir
|
|
1878
|
+
});
|
|
1879
|
+
}
|
|
1880
|
+
return {
|
|
1881
|
+
status: "completed",
|
|
1882
|
+
duration: Date.now() - start,
|
|
1883
|
+
message: `Created ${context.filePaths.length} file nodes, ${dirs.size} directory nodes`
|
|
1884
|
+
};
|
|
1885
|
+
}
|
|
1886
|
+
};
|
|
1887
|
+
var parsePhase = {
|
|
1888
|
+
name: "parse",
|
|
1889
|
+
dependencies: ["structure"],
|
|
1890
|
+
async execute(context) {
|
|
1891
|
+
const start = Date.now();
|
|
1892
|
+
let symbolCount = 0;
|
|
1893
|
+
for (const filePath of context.filePaths) {
|
|
1894
|
+
const lang = detectLanguage(filePath);
|
|
1895
|
+
if (!lang) {
|
|
1896
|
+
if (context.verbose) {
|
|
1897
|
+
const relativePath2 = path6.relative(context.workspaceRoot, filePath);
|
|
1898
|
+
console.log(` [parse] skipped (no parser): ${relativePath2}`);
|
|
1899
|
+
}
|
|
1900
|
+
continue;
|
|
1901
|
+
}
|
|
1902
|
+
const relativePath = path6.relative(context.workspaceRoot, filePath);
|
|
1903
|
+
const fileNodeId = generateNodeId("file", relativePath, relativePath);
|
|
1904
|
+
let source;
|
|
1905
|
+
try {
|
|
1906
|
+
source = fs8.readFileSync(filePath, "utf-8");
|
|
1907
|
+
} catch {
|
|
1908
|
+
continue;
|
|
1909
|
+
}
|
|
1910
|
+
const fileNode = context.graph.getNode(fileNodeId);
|
|
1911
|
+
if (fileNode) {
|
|
1912
|
+
fileNode.content = source.slice(0, 2e3);
|
|
1913
|
+
}
|
|
1914
|
+
const nodes = [];
|
|
1915
|
+
const edges = [];
|
|
1916
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1917
|
+
const lines = source.split("\n");
|
|
1918
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1919
|
+
const line = lines[i];
|
|
1920
|
+
const trimmed = line.trim();
|
|
1921
|
+
if (trimmed.startsWith("//") || trimmed.startsWith("#") || trimmed.startsWith("*") || trimmed.startsWith("/*")) continue;
|
|
1922
|
+
const extracted = extractSymbol(trimmed, lang);
|
|
1923
|
+
if (!extracted) continue;
|
|
1924
|
+
if (seen.has(extracted.name + ":" + extracted.kind)) continue;
|
|
1925
|
+
seen.add(extracted.name + ":" + extracted.kind);
|
|
1926
|
+
const nodeId = generateNodeId(extracted.kind, relativePath, extracted.name);
|
|
1927
|
+
nodes.push({
|
|
1928
|
+
id: nodeId,
|
|
1929
|
+
kind: extracted.kind,
|
|
1930
|
+
name: extracted.name,
|
|
1931
|
+
filePath: relativePath,
|
|
1932
|
+
startLine: i + 1,
|
|
1933
|
+
exported: extracted.exported,
|
|
1934
|
+
content: extractBlock(lines, i, 20)
|
|
1935
|
+
});
|
|
1936
|
+
edges.push({
|
|
1937
|
+
id: generateEdgeId(fileNodeId, nodeId, "contains"),
|
|
1938
|
+
source: fileNodeId,
|
|
1939
|
+
target: nodeId,
|
|
1940
|
+
kind: "contains",
|
|
1941
|
+
weight: 1
|
|
1942
|
+
});
|
|
1943
|
+
if (extracted.ownerName) {
|
|
1944
|
+
const ownerId = generateNodeId("class", relativePath, extracted.ownerName);
|
|
1945
|
+
if (context.graph.getNode(ownerId) || nodes.some((n) => n.id === ownerId)) {
|
|
1946
|
+
edges.push({
|
|
1947
|
+
id: generateEdgeId(ownerId, nodeId, "has_member"),
|
|
1948
|
+
source: ownerId,
|
|
1949
|
+
target: nodeId,
|
|
1950
|
+
kind: "has_member",
|
|
1951
|
+
weight: 1
|
|
1952
|
+
});
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
symbolCount++;
|
|
1956
|
+
}
|
|
1957
|
+
for (const n of nodes) context.graph.addNode(n);
|
|
1958
|
+
for (const e of edges) context.graph.addEdge(e);
|
|
1959
|
+
}
|
|
1960
|
+
return {
|
|
1961
|
+
status: "completed",
|
|
1962
|
+
duration: Date.now() - start,
|
|
1963
|
+
message: `Extracted ${symbolCount} symbols`
|
|
1964
|
+
};
|
|
1965
|
+
}
|
|
1966
|
+
};
|
|
1967
|
+
function extractSymbol(line, lang, _lineNum, _filePath) {
|
|
1968
|
+
if (lang === "typescript" /* TypeScript */ || lang === "javascript" /* JavaScript */) {
|
|
1969
|
+
const func = line.match(/^(?:export\s+)?(?:default\s+)?(?:async\s+)?function\s+(\w+)/);
|
|
1970
|
+
if (func) return { kind: "function", name: func[1], exported: line.includes("export") };
|
|
1971
|
+
const arrowFunc = line.match(/^(?:export\s+)?(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?\(/);
|
|
1972
|
+
if (arrowFunc) return { kind: "function", name: arrowFunc[1], exported: line.includes("export") };
|
|
1973
|
+
const arrowFunc2 = line.match(/^(?:export\s+)?(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?(?:\([^)]*\)|[a-zA-Z_]\w*)\s*=>/);
|
|
1974
|
+
if (arrowFunc2) return { kind: "function", name: arrowFunc2[1], exported: line.includes("export") };
|
|
1975
|
+
const cls = line.match(/^(?:export\s+)?(?:default\s+)?(?:abstract\s+)?class\s+(\w+)/);
|
|
1976
|
+
if (cls) return { kind: "class", name: cls[1], exported: line.includes("export") };
|
|
1977
|
+
const iface = line.match(/^(?:export\s+)?interface\s+(\w+)/);
|
|
1978
|
+
if (iface) return { kind: "interface", name: iface[1], exported: line.includes("export") };
|
|
1979
|
+
const enumM = line.match(/^(?:export\s+)?enum\s+(\w+)/);
|
|
1980
|
+
if (enumM) return { kind: "enum", name: enumM[1], exported: line.includes("export") };
|
|
1981
|
+
const typeAlias = line.match(/^(?:export\s+)?type\s+(\w+)\s*[=<]/);
|
|
1982
|
+
if (typeAlias) return { kind: "type_alias", name: typeAlias[1], exported: line.includes("export") };
|
|
1983
|
+
const constVar = line.match(/^(?:export\s+)?const\s+(\w+)\s*(?::\s*\w[^=]*)?\s*=/);
|
|
1984
|
+
if (constVar && /^[A-Z_]+$/.test(constVar[1])) {
|
|
1985
|
+
return { kind: "constant", name: constVar[1], exported: line.includes("export") };
|
|
1986
|
+
}
|
|
1987
|
+
const method = line.match(/^(?:(?:public|private|protected|static|async|readonly)\s+)*(\w+)\s*\(/);
|
|
1988
|
+
if (method && !["if", "for", "while", "switch", "catch", "return", "constructor"].includes(method[1])) {
|
|
1989
|
+
if (method[1] === "constructor") {
|
|
1990
|
+
return { kind: "constructor", name: "constructor", exported: false };
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
if (lang === "python" /* Python */) {
|
|
1995
|
+
const func = line.match(/^(?:async\s+)?def\s+(\w+)/);
|
|
1996
|
+
if (func) return { kind: func[1].startsWith("__") ? "method" : "function", name: func[1], exported: !func[1].startsWith("_") };
|
|
1997
|
+
const cls = line.match(/^class\s+(\w+)/);
|
|
1998
|
+
if (cls) return { kind: "class", name: cls[1], exported: !cls[1].startsWith("_") };
|
|
1999
|
+
}
|
|
2000
|
+
if (lang === "java" /* Java */) {
|
|
2001
|
+
const cls = line.match(/(?:public|private|protected)?\s*(?:static\s+)?(?:abstract\s+)?(?:final\s+)?class\s+(\w+)/);
|
|
2002
|
+
if (cls) return { kind: "class", name: cls[1], exported: line.includes("public") };
|
|
2003
|
+
const iface = line.match(/(?:public\s+)?interface\s+(\w+)/);
|
|
2004
|
+
if (iface) return { kind: "interface", name: iface[1], exported: line.includes("public") };
|
|
2005
|
+
const enumM = line.match(/(?:public\s+)?enum\s+(\w+)/);
|
|
2006
|
+
if (enumM) return { kind: "enum", name: enumM[1], exported: line.includes("public") };
|
|
2007
|
+
const method = line.match(/(?:public|private|protected)\s+(?:static\s+)?(?:[\w<>\[\]]+)\s+(\w+)\s*\(/);
|
|
2008
|
+
if (method) return { kind: "method", name: method[1], exported: line.includes("public") };
|
|
2009
|
+
}
|
|
2010
|
+
if (lang === "go" /* Go */) {
|
|
2011
|
+
const func = line.match(/^func\s+(\w+)\s*\(/);
|
|
2012
|
+
if (func) return { kind: "function", name: func[1], exported: func[1][0] === func[1][0].toUpperCase() };
|
|
2013
|
+
const method = line.match(/^func\s+\([^)]+\)\s+(\w+)\s*\(/);
|
|
2014
|
+
if (method) return { kind: "method", name: method[1], exported: method[1][0] === method[1][0].toUpperCase() };
|
|
2015
|
+
const structM = line.match(/^type\s+(\w+)\s+struct\b/);
|
|
2016
|
+
if (structM) return { kind: "struct", name: structM[1], exported: structM[1][0] === structM[1][0].toUpperCase() };
|
|
2017
|
+
const ifaceM = line.match(/^type\s+(\w+)\s+interface\b/);
|
|
2018
|
+
if (ifaceM) return { kind: "interface", name: ifaceM[1], exported: ifaceM[1][0] === ifaceM[1][0].toUpperCase() };
|
|
2019
|
+
}
|
|
2020
|
+
if (lang === "rust" /* Rust */) {
|
|
2021
|
+
const func = line.match(/^(?:pub\s+)?(?:async\s+)?fn\s+(\w+)/);
|
|
2022
|
+
if (func) return { kind: "function", name: func[1], exported: line.startsWith("pub") };
|
|
2023
|
+
const structM = line.match(/^(?:pub\s+)?struct\s+(\w+)/);
|
|
2024
|
+
if (structM) return { kind: "struct", name: structM[1], exported: line.startsWith("pub") };
|
|
2025
|
+
const enumM = line.match(/^(?:pub\s+)?enum\s+(\w+)/);
|
|
2026
|
+
if (enumM) return { kind: "enum", name: enumM[1], exported: line.startsWith("pub") };
|
|
2027
|
+
const traitM = line.match(/^(?:pub\s+)?trait\s+(\w+)/);
|
|
2028
|
+
if (traitM) return { kind: "trait", name: traitM[1], exported: line.startsWith("pub") };
|
|
2029
|
+
const implM = line.match(/^impl(?:<[^>]*>)?\s+(\w+)/);
|
|
2030
|
+
if (implM) return { kind: "class", name: implM[1], exported: false };
|
|
2031
|
+
}
|
|
2032
|
+
if (lang === "c" /* C */ || lang === "cpp" /* Cpp */) {
|
|
2033
|
+
const cls = line.match(/^(?:class|struct)\s+(\w+)/);
|
|
2034
|
+
if (cls) return { kind: lang === "cpp" /* Cpp */ ? "class" : "struct", name: cls[1], exported: true };
|
|
2035
|
+
const nsM = line.match(/^namespace\s+(\w+)/);
|
|
2036
|
+
if (nsM) return { kind: "namespace", name: nsM[1], exported: true };
|
|
2037
|
+
const func = line.match(/^(?:[\w:*&<>\[\]]+\s+)+(\w+)\s*\([^;]*$/);
|
|
2038
|
+
if (func && !["if", "for", "while", "switch", "return"].includes(func[1])) {
|
|
2039
|
+
return { kind: "function", name: func[1], exported: true };
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
if (lang === "csharp" /* CSharp */) {
|
|
2043
|
+
const cls = line.match(/(?:public|internal|private)?\s*(?:static\s+)?(?:abstract\s+)?(?:partial\s+)?class\s+(\w+)/);
|
|
2044
|
+
if (cls) return { kind: "class", name: cls[1], exported: line.includes("public") };
|
|
2045
|
+
const iface = line.match(/(?:public\s+)?interface\s+(\w+)/);
|
|
2046
|
+
if (iface) return { kind: "interface", name: iface[1], exported: line.includes("public") };
|
|
2047
|
+
const structM = line.match(/(?:public\s+)?struct\s+(\w+)/);
|
|
2048
|
+
if (structM) return { kind: "struct", name: structM[1], exported: line.includes("public") };
|
|
2049
|
+
const method = line.match(/(?:public|private|protected|internal)\s+(?:static\s+)?(?:async\s+)?(?:[\w<>\[\]?]+)\s+(\w+)\s*\(/);
|
|
2050
|
+
if (method) return { kind: "method", name: method[1], exported: line.includes("public") };
|
|
2051
|
+
const nsM = line.match(/namespace\s+([\w.]+)/);
|
|
2052
|
+
if (nsM) return { kind: "namespace", name: nsM[1], exported: true };
|
|
2053
|
+
}
|
|
2054
|
+
if (lang === "php" /* PHP */) {
|
|
2055
|
+
const cls = line.match(/(?:abstract\s+)?class\s+(\w+)/);
|
|
2056
|
+
if (cls) return { kind: "class", name: cls[1], exported: true };
|
|
2057
|
+
const func = line.match(/(?:public|private|protected|static\s+)*function\s+(\w+)/);
|
|
2058
|
+
if (func) return { kind: "function", name: func[1], exported: line.includes("public") || !line.includes("private") };
|
|
2059
|
+
const iface = line.match(/interface\s+(\w+)/);
|
|
2060
|
+
if (iface) return { kind: "interface", name: iface[1], exported: true };
|
|
2061
|
+
const traitM = line.match(/trait\s+(\w+)/);
|
|
2062
|
+
if (traitM) return { kind: "trait", name: traitM[1], exported: true };
|
|
2063
|
+
}
|
|
2064
|
+
if (lang === "kotlin" /* Kotlin */) {
|
|
2065
|
+
const cls = line.match(/(?:data\s+|sealed\s+|abstract\s+|open\s+)?class\s+(\w+)/);
|
|
2066
|
+
if (cls) return { kind: "class", name: cls[1], exported: !line.includes("private") };
|
|
2067
|
+
const iface = line.match(/interface\s+(\w+)/);
|
|
2068
|
+
if (iface) return { kind: "interface", name: iface[1], exported: !line.includes("private") };
|
|
2069
|
+
const func = line.match(/(?:suspend\s+)?fun\s+(\w+)/);
|
|
2070
|
+
if (func) return { kind: "function", name: func[1], exported: !line.includes("private") };
|
|
2071
|
+
const obj = line.match(/object\s+(\w+)/);
|
|
2072
|
+
if (obj) return { kind: "class", name: obj[1], exported: !line.includes("private") };
|
|
2073
|
+
}
|
|
2074
|
+
if (lang === "ruby" /* Ruby */) {
|
|
2075
|
+
const cls = line.match(/^class\s+(\w+)/);
|
|
2076
|
+
if (cls) return { kind: "class", name: cls[1], exported: true };
|
|
2077
|
+
const modM = line.match(/^module\s+(\w+)/);
|
|
2078
|
+
if (modM) return { kind: "module", name: modM[1], exported: true };
|
|
2079
|
+
const method = line.match(/^(?:def\s+(?:self\.)?(\w+))/);
|
|
2080
|
+
if (method) return { kind: "method", name: method[1], exported: true };
|
|
2081
|
+
}
|
|
2082
|
+
if (lang === "swift" /* Swift */) {
|
|
2083
|
+
const cls = line.match(/(?:public\s+|open\s+)?(?:final\s+)?class\s+(\w+)/);
|
|
2084
|
+
if (cls) return { kind: "class", name: cls[1], exported: !line.includes("private") };
|
|
2085
|
+
const structM = line.match(/(?:public\s+)?struct\s+(\w+)/);
|
|
2086
|
+
if (structM) return { kind: "struct", name: structM[1], exported: !line.includes("private") };
|
|
2087
|
+
const proto = line.match(/(?:public\s+)?protocol\s+(\w+)/);
|
|
2088
|
+
if (proto) return { kind: "interface", name: proto[1], exported: !line.includes("private") };
|
|
2089
|
+
const enumM = line.match(/(?:public\s+)?enum\s+(\w+)/);
|
|
2090
|
+
if (enumM) return { kind: "enum", name: enumM[1], exported: !line.includes("private") };
|
|
2091
|
+
const func = line.match(/(?:public\s+|private\s+|internal\s+)?(?:static\s+)?func\s+(\w+)/);
|
|
2092
|
+
if (func) return { kind: "function", name: func[1], exported: !line.includes("private") };
|
|
2093
|
+
}
|
|
2094
|
+
if (lang === "dart" /* Dart */) {
|
|
2095
|
+
const cls = line.match(/(?:abstract\s+)?class\s+(\w+)/);
|
|
2096
|
+
if (cls) return { kind: "class", name: cls[1], exported: !cls[1].startsWith("_") };
|
|
2097
|
+
const func = line.match(/^(?:\w+\s+)?(\w+)\s*\(/);
|
|
2098
|
+
if (func && !["if", "for", "while", "switch", "catch", "return"].includes(func[1])) {
|
|
2099
|
+
return { kind: "function", name: func[1], exported: !func[1].startsWith("_") };
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
return null;
|
|
2103
|
+
}
|
|
2104
|
+
function extractBlock(lines, startIdx, maxLines) {
|
|
2105
|
+
const end = Math.min(startIdx + maxLines, lines.length);
|
|
2106
|
+
return lines.slice(startIdx, end).join("\n");
|
|
2107
|
+
}
|
|
2108
|
+
var resolvePhase = {
|
|
2109
|
+
name: "resolve",
|
|
2110
|
+
dependencies: ["parse"],
|
|
2111
|
+
async execute(context) {
|
|
2112
|
+
const start = Date.now();
|
|
2113
|
+
const { graph, workspaceRoot, filePaths } = context;
|
|
2114
|
+
let importEdges = 0;
|
|
2115
|
+
let callEdges = 0;
|
|
2116
|
+
let heritageEdges = 0;
|
|
2117
|
+
const fileIndex = /* @__PURE__ */ new Map();
|
|
2118
|
+
for (const fp of filePaths) {
|
|
2119
|
+
const rel = path6.relative(workspaceRoot, fp);
|
|
2120
|
+
fileIndex.set(rel, fp);
|
|
2121
|
+
const noExt = rel.replace(/\.\w+$/, "");
|
|
2122
|
+
if (!fileIndex.has(noExt)) fileIndex.set(noExt, fp);
|
|
2123
|
+
const base = path6.basename(rel, path6.extname(rel));
|
|
2124
|
+
if (!fileIndex.has(base)) fileIndex.set(base, fp);
|
|
2125
|
+
}
|
|
2126
|
+
const symbolIndex = /* @__PURE__ */ new Map();
|
|
2127
|
+
const fileSymbolIndex = /* @__PURE__ */ new Map();
|
|
2128
|
+
for (const node of graph.allNodes()) {
|
|
2129
|
+
if (["function", "class", "interface", "method", "enum", "type_alias", "variable", "constant", "struct", "trait"].includes(node.kind)) {
|
|
2130
|
+
symbolIndex.set(node.name, node.id);
|
|
2131
|
+
let fileMap = fileSymbolIndex.get(node.filePath);
|
|
2132
|
+
if (!fileMap) {
|
|
2133
|
+
fileMap = /* @__PURE__ */ new Map();
|
|
2134
|
+
fileSymbolIndex.set(node.filePath, fileMap);
|
|
2135
|
+
}
|
|
2136
|
+
fileMap.set(node.name, node.id);
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
for (const filePath of filePaths) {
|
|
2140
|
+
const lang = detectLanguage(filePath);
|
|
2141
|
+
if (!lang) continue;
|
|
2142
|
+
const relativePath = path6.relative(workspaceRoot, filePath);
|
|
2143
|
+
const fileNodeId = generateNodeId("file", relativePath, relativePath);
|
|
2144
|
+
let source;
|
|
2145
|
+
try {
|
|
2146
|
+
source = fs8.readFileSync(filePath, "utf-8");
|
|
2147
|
+
} catch {
|
|
2148
|
+
continue;
|
|
2149
|
+
}
|
|
2150
|
+
const lines = source.split("\n");
|
|
2151
|
+
const imports = extractImports(lines, lang === "python");
|
|
2152
|
+
const calls = extractCalls(lines);
|
|
2153
|
+
const heritages = extractHeritage(lines);
|
|
2154
|
+
for (const imp of imports) {
|
|
2155
|
+
const cleaned = imp.rawPath.replace(/['"]/g, "");
|
|
2156
|
+
let resolvedRelPath = null;
|
|
2157
|
+
if (cleaned.startsWith(".")) {
|
|
2158
|
+
const cleanedNoJs = cleaned.replace(/\.(js|jsx)$/, "");
|
|
2159
|
+
const fromDir = path6.dirname(relativePath);
|
|
2160
|
+
for (const ext of ["", ".ts", ".tsx", ".js", ".jsx", ".py", ".java", ".go", "/index.ts", "/index.js"]) {
|
|
2161
|
+
const candidate = path6.join(fromDir, cleanedNoJs + ext);
|
|
2162
|
+
const normalized = path6.normalize(candidate);
|
|
2163
|
+
if (fileIndex.has(normalized)) {
|
|
2164
|
+
const absPath = fileIndex.get(normalized);
|
|
2165
|
+
resolvedRelPath = path6.relative(workspaceRoot, absPath);
|
|
2166
|
+
break;
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
} else {
|
|
2170
|
+
for (const ext of ["", ".ts", ".js", ".py", ".java", ".go"]) {
|
|
2171
|
+
if (fileIndex.has(cleaned + ext)) {
|
|
2172
|
+
resolvedRelPath = cleaned + ext;
|
|
2173
|
+
break;
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2176
|
+
const asPath = cleaned.replace(/\./g, "/");
|
|
2177
|
+
for (const ext of ["", ".ts", ".js", ".py", ".java", ".go", "/index.ts", "/__init__.py"]) {
|
|
2178
|
+
if (fileIndex.has(asPath + ext)) {
|
|
2179
|
+
resolvedRelPath = asPath + ext;
|
|
2180
|
+
break;
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
if (resolvedRelPath) {
|
|
2185
|
+
const targetFileId = generateNodeId("file", resolvedRelPath, resolvedRelPath);
|
|
2186
|
+
if (graph.getNode(targetFileId)) {
|
|
2187
|
+
const edgeId = generateEdgeId(fileNodeId, targetFileId, "imports");
|
|
2188
|
+
if (!graph.getEdge(edgeId)) {
|
|
2189
|
+
graph.addEdge({
|
|
2190
|
+
id: edgeId,
|
|
2191
|
+
source: fileNodeId,
|
|
2192
|
+
target: targetFileId,
|
|
2193
|
+
kind: "imports",
|
|
2194
|
+
weight: 0.95,
|
|
2195
|
+
label: cleaned
|
|
2196
|
+
});
|
|
2197
|
+
importEdges++;
|
|
2198
|
+
}
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2202
|
+
const localSymbols = fileSymbolIndex.get(relativePath);
|
|
2203
|
+
for (const call of calls) {
|
|
2204
|
+
let targetId = localSymbols?.get(call.name);
|
|
2205
|
+
let confidence = 0.95;
|
|
2206
|
+
if (!targetId) {
|
|
2207
|
+
targetId = symbolIndex.get(call.name);
|
|
2208
|
+
confidence = 0.5;
|
|
2209
|
+
}
|
|
2210
|
+
if (targetId) {
|
|
2211
|
+
const callerNodeId = findEnclosingFunction(graph, relativePath, call.line);
|
|
2212
|
+
const sourceId = callerNodeId ?? fileNodeId;
|
|
2213
|
+
if (sourceId !== targetId) {
|
|
2214
|
+
const edgeId = generateEdgeId(sourceId, targetId, "calls");
|
|
2215
|
+
if (!graph.getEdge(edgeId)) {
|
|
2216
|
+
graph.addEdge({
|
|
2217
|
+
id: edgeId,
|
|
2218
|
+
source: sourceId,
|
|
2219
|
+
target: targetId,
|
|
2220
|
+
kind: "calls",
|
|
2221
|
+
weight: confidence,
|
|
2222
|
+
label: call.name
|
|
2223
|
+
});
|
|
2224
|
+
callEdges++;
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
for (const h of heritages) {
|
|
2230
|
+
const classNodeId = localSymbols?.get(h.className) ?? symbolIndex.get(h.className);
|
|
2231
|
+
if (!classNodeId) continue;
|
|
2232
|
+
for (const ext of h.extendsNames) {
|
|
2233
|
+
const targetId = symbolIndex.get(ext);
|
|
2234
|
+
if (targetId) {
|
|
2235
|
+
const edgeId = generateEdgeId(classNodeId, targetId, "extends");
|
|
2236
|
+
if (!graph.getEdge(edgeId)) {
|
|
2237
|
+
graph.addEdge({
|
|
2238
|
+
id: edgeId,
|
|
2239
|
+
source: classNodeId,
|
|
2240
|
+
target: targetId,
|
|
2241
|
+
kind: "extends",
|
|
2242
|
+
weight: 1,
|
|
2243
|
+
label: `extends ${ext}`
|
|
2244
|
+
});
|
|
2245
|
+
heritageEdges++;
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2249
|
+
for (const impl of h.implementsNames) {
|
|
2250
|
+
const targetId = symbolIndex.get(impl);
|
|
2251
|
+
if (targetId) {
|
|
2252
|
+
const edgeId = generateEdgeId(classNodeId, targetId, "implements");
|
|
2253
|
+
if (!graph.getEdge(edgeId)) {
|
|
2254
|
+
graph.addEdge({
|
|
2255
|
+
id: edgeId,
|
|
2256
|
+
source: classNodeId,
|
|
2257
|
+
target: targetId,
|
|
2258
|
+
kind: "implements",
|
|
2259
|
+
weight: 1,
|
|
2260
|
+
label: `implements ${impl}`
|
|
2261
|
+
});
|
|
2262
|
+
heritageEdges++;
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
return {
|
|
2269
|
+
status: "completed",
|
|
2270
|
+
duration: Date.now() - start,
|
|
2271
|
+
message: `Resolved ${importEdges} imports, ${callEdges} calls, ${heritageEdges} heritage edges. Graph: ${graph.size.nodes} nodes, ${graph.size.edges} edges`
|
|
2272
|
+
};
|
|
2273
|
+
}
|
|
2274
|
+
};
|
|
2275
|
+
function extractImports(lines, isPython) {
|
|
2276
|
+
const imports = [];
|
|
2277
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2278
|
+
const line = lines[i].trim();
|
|
2279
|
+
const tsImport = line.match(/import\s+.*?from\s+['"]([^'"]+)['"]/);
|
|
2280
|
+
if (tsImport) {
|
|
2281
|
+
const names = [];
|
|
2282
|
+
const namedMatch = line.match(/\{([^}]+)\}/);
|
|
2283
|
+
if (namedMatch) {
|
|
2284
|
+
names.push(...namedMatch[1].split(",").map((n) => n.trim().split(/\s+as\s+/).pop().trim()).filter(Boolean));
|
|
2285
|
+
}
|
|
2286
|
+
const defaultMatch = line.match(/import\s+(\w+)/);
|
|
2287
|
+
if (defaultMatch && defaultMatch[1] !== "type") {
|
|
2288
|
+
names.push(defaultMatch[1]);
|
|
2289
|
+
}
|
|
2290
|
+
imports.push({
|
|
2291
|
+
rawPath: tsImport[1],
|
|
2292
|
+
localNames: names,
|
|
2293
|
+
isDefault: !namedMatch,
|
|
2294
|
+
line: i + 1
|
|
2295
|
+
});
|
|
2296
|
+
continue;
|
|
2297
|
+
}
|
|
2298
|
+
if (isPython) {
|
|
2299
|
+
const fromImport = line.match(/from\s+([\w.]+)\s+import\s+(.+)/);
|
|
2300
|
+
if (fromImport) {
|
|
2301
|
+
const names = fromImport[2].split(",").map((n) => n.trim().split(/\s+as\s+/).pop().trim()).filter(Boolean);
|
|
2302
|
+
imports.push({ rawPath: fromImport[1], localNames: names, isDefault: false, line: i + 1 });
|
|
2303
|
+
continue;
|
|
2304
|
+
}
|
|
2305
|
+
const directImport = line.match(/^import\s+([\w.]+)(?:\s+as\s+(\w+))?/);
|
|
2306
|
+
if (directImport) {
|
|
2307
|
+
imports.push({
|
|
2308
|
+
rawPath: directImport[1],
|
|
2309
|
+
localNames: [directImport[2] ?? directImport[1].split(".").pop()],
|
|
2310
|
+
isDefault: false,
|
|
2311
|
+
line: i + 1
|
|
2312
|
+
});
|
|
2313
|
+
continue;
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
const javaImport = line.match(/^import\s+(?:static\s+)?([\w.]+)/);
|
|
2317
|
+
if (javaImport && !line.includes("from")) {
|
|
2318
|
+
const parts = javaImport[1].split(".");
|
|
2319
|
+
imports.push({
|
|
2320
|
+
rawPath: javaImport[1],
|
|
2321
|
+
localNames: [parts[parts.length - 1]],
|
|
2322
|
+
isDefault: false,
|
|
2323
|
+
line: i + 1
|
|
2324
|
+
});
|
|
2325
|
+
continue;
|
|
2326
|
+
}
|
|
2327
|
+
const goImport = line.match(/^\s*"([^"]+)"/);
|
|
2328
|
+
if (goImport && (i > 0 && lines[i - 1]?.includes("import") || line.match(/^import\s+"/))) {
|
|
2329
|
+
const parts = goImport[1].split("/");
|
|
2330
|
+
imports.push({
|
|
2331
|
+
rawPath: goImport[1],
|
|
2332
|
+
localNames: [parts[parts.length - 1]],
|
|
2333
|
+
isDefault: false,
|
|
2334
|
+
line: i + 1
|
|
2335
|
+
});
|
|
2336
|
+
continue;
|
|
2337
|
+
}
|
|
2338
|
+
const includeMatch = line.match(/#include\s+[<"]([^>"]+)[>"]/);
|
|
2339
|
+
if (includeMatch) {
|
|
2340
|
+
imports.push({
|
|
2341
|
+
rawPath: includeMatch[1],
|
|
2342
|
+
localNames: [],
|
|
2343
|
+
isDefault: false,
|
|
2344
|
+
line: i + 1
|
|
2345
|
+
});
|
|
2346
|
+
continue;
|
|
2347
|
+
}
|
|
2348
|
+
const rustUse = line.match(/^use\s+([\w:]+)/);
|
|
2349
|
+
if (rustUse) {
|
|
2350
|
+
const parts = rustUse[1].split("::");
|
|
2351
|
+
imports.push({
|
|
2352
|
+
rawPath: rustUse[1],
|
|
2353
|
+
localNames: [parts[parts.length - 1]],
|
|
2354
|
+
isDefault: false,
|
|
2355
|
+
line: i + 1
|
|
2356
|
+
});
|
|
2357
|
+
continue;
|
|
2358
|
+
}
|
|
2359
|
+
const usingMatch = line.match(/^using\s+([\w.]+)/);
|
|
2360
|
+
if (usingMatch) {
|
|
2361
|
+
const parts = usingMatch[1].split(".");
|
|
2362
|
+
imports.push({
|
|
2363
|
+
rawPath: usingMatch[1],
|
|
2364
|
+
localNames: [parts[parts.length - 1]],
|
|
2365
|
+
isDefault: false,
|
|
2366
|
+
line: i + 1
|
|
2367
|
+
});
|
|
2368
|
+
}
|
|
2369
|
+
const requireMatch = line.match(/require\s+['"]([^'"]+)['"]/);
|
|
2370
|
+
if (requireMatch) {
|
|
2371
|
+
imports.push({
|
|
2372
|
+
rawPath: requireMatch[1],
|
|
2373
|
+
localNames: [],
|
|
2374
|
+
isDefault: false,
|
|
2375
|
+
line: i + 1
|
|
2376
|
+
});
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
return imports;
|
|
2380
|
+
}
|
|
2381
|
+
function extractCalls(lines) {
|
|
2382
|
+
const calls = [];
|
|
2383
|
+
const callRegex = /(?:new\s+)?(\w+)\s*\(/g;
|
|
2384
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2385
|
+
const line = lines[i];
|
|
2386
|
+
if (/^\s*(export\s+)?(async\s+)?function\s/.test(line)) continue;
|
|
2387
|
+
if (/^\s*(export\s+)?(abstract\s+)?class\s/.test(line)) continue;
|
|
2388
|
+
if (/^\s*(export\s+)?interface\s/.test(line)) continue;
|
|
2389
|
+
if (/^\s*(export\s+)?enum\s/.test(line)) continue;
|
|
2390
|
+
if (/^\s*(export\s+)?type\s+\w+\s*=/.test(line)) continue;
|
|
2391
|
+
if (/^\s*import\s/.test(line)) continue;
|
|
2392
|
+
if (/^\s*\/\//.test(line)) continue;
|
|
2393
|
+
let match;
|
|
2394
|
+
callRegex.lastIndex = 0;
|
|
2395
|
+
while ((match = callRegex.exec(line)) !== null) {
|
|
2396
|
+
const name = match[1];
|
|
2397
|
+
if (["if", "for", "while", "switch", "catch", "return", "throw", "typeof", "instanceof", "delete", "void", "new", "import", "export", "from", "const", "let", "var", "function", "class", "interface", "type", "enum", "extends", "implements"].includes(name)) continue;
|
|
2398
|
+
const isNew = line.substring(Math.max(0, match.index - 4), match.index).includes("new");
|
|
2399
|
+
calls.push({ name, isNew, line: i + 1 });
|
|
2400
|
+
}
|
|
2401
|
+
const memberCallRegex = /(\w+)\.(\w+)\s*\(/g;
|
|
2402
|
+
memberCallRegex.lastIndex = 0;
|
|
2403
|
+
while ((match = memberCallRegex.exec(line)) !== null) {
|
|
2404
|
+
calls.push({
|
|
2405
|
+
name: match[2],
|
|
2406
|
+
receiverText: match[1],
|
|
2407
|
+
isNew: false,
|
|
2408
|
+
line: i + 1
|
|
2409
|
+
});
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
2412
|
+
return calls;
|
|
2413
|
+
}
|
|
2414
|
+
function extractHeritage(lines) {
|
|
2415
|
+
const heritages = [];
|
|
2416
|
+
for (const line of lines) {
|
|
2417
|
+
const classMatch = line.match(/class\s+(\w+)(?:\s+extends\s+(\w+))?(?:\s+implements\s+([\w,\s]+))?/);
|
|
2418
|
+
if (classMatch) {
|
|
2419
|
+
const extendsNames = classMatch[2] ? [classMatch[2]] : [];
|
|
2420
|
+
const implementsNames = classMatch[3] ? classMatch[3].split(",").map((n) => n.trim()).filter(Boolean) : [];
|
|
2421
|
+
heritages.push({ className: classMatch[1], extendsNames, implementsNames });
|
|
2422
|
+
continue;
|
|
2423
|
+
}
|
|
2424
|
+
const pyClassMatch = line.match(/class\s+(\w+)\(([^)]+)\)/);
|
|
2425
|
+
if (pyClassMatch) {
|
|
2426
|
+
const bases = pyClassMatch[2].split(",").map((n) => n.trim()).filter(Boolean);
|
|
2427
|
+
heritages.push({ className: pyClassMatch[1], extendsNames: bases, implementsNames: [] });
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2430
|
+
return heritages;
|
|
2431
|
+
}
|
|
2432
|
+
function findEnclosingFunction(graph, filePath, line) {
|
|
2433
|
+
let best = null;
|
|
2434
|
+
for (const node of graph.allNodes()) {
|
|
2435
|
+
if (node.filePath !== filePath) continue;
|
|
2436
|
+
if (!["function", "method"].includes(node.kind)) continue;
|
|
2437
|
+
if (!node.startLine) continue;
|
|
2438
|
+
if (node.startLine <= line) {
|
|
2439
|
+
if (!best || node.startLine > best.startLine) {
|
|
2440
|
+
best = { id: node.id, startLine: node.startLine };
|
|
2441
|
+
}
|
|
2442
|
+
}
|
|
2443
|
+
}
|
|
2444
|
+
return best?.id ?? null;
|
|
2445
|
+
}
|
|
2446
|
+
|
|
2447
|
+
// src/pipeline/phases/cluster-phase.ts
|
|
2448
|
+
var clusterPhase = {
|
|
2449
|
+
name: "cluster",
|
|
2450
|
+
dependencies: ["resolve"],
|
|
2451
|
+
async execute(context) {
|
|
2452
|
+
const start = Date.now();
|
|
2453
|
+
const { graph } = context;
|
|
2454
|
+
const relevantKinds = /* @__PURE__ */ new Set(["function", "class", "method", "interface", "struct", "trait", "enum"]);
|
|
2455
|
+
const nodesByDir = /* @__PURE__ */ new Map();
|
|
2456
|
+
for (const node of graph.allNodes()) {
|
|
2457
|
+
if (!relevantKinds.has(node.kind)) continue;
|
|
2458
|
+
const dir = node.filePath.split("/").slice(0, -1).join("/") || ".";
|
|
2459
|
+
let group = nodesByDir.get(dir);
|
|
2460
|
+
if (!group) {
|
|
2461
|
+
group = [];
|
|
2462
|
+
nodesByDir.set(dir, group);
|
|
2463
|
+
}
|
|
2464
|
+
group.push({ id: node.id, name: node.name });
|
|
2465
|
+
}
|
|
2466
|
+
let clusterCount = 0;
|
|
2467
|
+
for (const [dir, members] of nodesByDir) {
|
|
2468
|
+
if (members.length < 2) continue;
|
|
2469
|
+
const clusterId = generateNodeId("cluster", dir, `cluster-${clusterCount}`);
|
|
2470
|
+
const label = dir.split("/").filter(Boolean).pop() ?? `cluster-${clusterCount}`;
|
|
2471
|
+
graph.addNode({
|
|
2472
|
+
id: clusterId,
|
|
2473
|
+
kind: "cluster",
|
|
2474
|
+
name: label,
|
|
2475
|
+
filePath: dir,
|
|
2476
|
+
metadata: { memberCount: members.length }
|
|
2477
|
+
});
|
|
2478
|
+
for (const member of members) {
|
|
2479
|
+
graph.addEdge({
|
|
2480
|
+
id: generateEdgeId(member.id, clusterId, "belongs_to"),
|
|
2481
|
+
source: member.id,
|
|
2482
|
+
target: clusterId,
|
|
2483
|
+
kind: "belongs_to",
|
|
2484
|
+
weight: 1
|
|
2485
|
+
});
|
|
2486
|
+
}
|
|
2487
|
+
clusterCount++;
|
|
2488
|
+
}
|
|
2489
|
+
return {
|
|
2490
|
+
status: "completed",
|
|
2491
|
+
duration: Date.now() - start,
|
|
2492
|
+
message: `Created ${clusterCount} clusters`
|
|
2493
|
+
};
|
|
2494
|
+
}
|
|
2495
|
+
};
|
|
2496
|
+
|
|
2497
|
+
// src/pipeline/phases/flow-phase.ts
|
|
2498
|
+
var flowPhase = {
|
|
2499
|
+
name: "flow",
|
|
2500
|
+
dependencies: ["resolve"],
|
|
2501
|
+
async execute(context) {
|
|
2502
|
+
const start = Date.now();
|
|
2503
|
+
const { graph } = context;
|
|
2504
|
+
const calledNodes = /* @__PURE__ */ new Set();
|
|
2505
|
+
for (const edge of graph.findEdgesByKind("calls")) {
|
|
2506
|
+
calledNodes.add(edge.target);
|
|
2507
|
+
}
|
|
2508
|
+
const entryPoints = [];
|
|
2509
|
+
for (const node of graph.allNodes()) {
|
|
2510
|
+
if (!["function", "method"].includes(node.kind)) continue;
|
|
2511
|
+
let score = 0;
|
|
2512
|
+
const hasCallers = calledNodes.has(node.id);
|
|
2513
|
+
const outCalls = [...graph.findEdgesFrom(node.id)].filter((e) => e.kind === "calls");
|
|
2514
|
+
if (!hasCallers && outCalls.length > 0) score += 10;
|
|
2515
|
+
if (node.exported) score += 5;
|
|
2516
|
+
if (/^(main|handle|init|start|run|execute|process|serve|listen|bootstrap)/.test(node.name)) score += 3;
|
|
2517
|
+
if (node.filePath.includes("test") || node.filePath.includes("spec") || node.filePath.includes("__test")) score -= 20;
|
|
2518
|
+
if (node.filePath.includes("route") || node.filePath.includes("controller") || node.filePath.includes("handler")) score += 8;
|
|
2519
|
+
if (score >= 5) {
|
|
2520
|
+
entryPoints.push({ id: node.id, name: node.name, score, filePath: node.filePath });
|
|
2521
|
+
}
|
|
2522
|
+
}
|
|
2523
|
+
entryPoints.sort((a, b) => b.score - a.score);
|
|
2524
|
+
const maxFlows = 75;
|
|
2525
|
+
const maxDepth = 10;
|
|
2526
|
+
const maxBranching = 4;
|
|
2527
|
+
let flowCount = 0;
|
|
2528
|
+
for (const ep of entryPoints.slice(0, 20)) {
|
|
2529
|
+
if (flowCount >= maxFlows) break;
|
|
2530
|
+
const queue = [{ nodeId: ep.id, path: [ep.id] }];
|
|
2531
|
+
const visited = /* @__PURE__ */ new Set();
|
|
2532
|
+
while (queue.length > 0 && flowCount < maxFlows) {
|
|
2533
|
+
const { nodeId, path: path17 } = queue.shift();
|
|
2534
|
+
if (path17.length > maxDepth) continue;
|
|
2535
|
+
const callEdges = [...graph.findEdgesFrom(nodeId)].filter((e) => e.kind === "calls").slice(0, maxBranching);
|
|
2536
|
+
if (callEdges.length === 0 && path17.length >= 3) {
|
|
2537
|
+
const flowId = generateNodeId("flow", ep.filePath, `flow-${flowCount}`);
|
|
2538
|
+
graph.addNode({
|
|
2539
|
+
id: flowId,
|
|
2540
|
+
kind: "flow",
|
|
2541
|
+
name: `${ep.name} flow ${flowCount}`,
|
|
2542
|
+
filePath: ep.filePath,
|
|
2543
|
+
metadata: { steps: path17, entryPoint: ep.name }
|
|
2544
|
+
});
|
|
2545
|
+
for (let i = 0; i < path17.length; i++) {
|
|
2546
|
+
graph.addEdge({
|
|
2547
|
+
id: generateEdgeId(path17[i], flowId, `step_of_${i}`),
|
|
2548
|
+
source: path17[i],
|
|
2549
|
+
target: flowId,
|
|
2550
|
+
kind: "step_of",
|
|
2551
|
+
weight: 1,
|
|
2552
|
+
label: `step ${i + 1}`
|
|
2553
|
+
});
|
|
2554
|
+
}
|
|
2555
|
+
flowCount++;
|
|
2556
|
+
continue;
|
|
2557
|
+
}
|
|
2558
|
+
for (const edge of callEdges) {
|
|
2559
|
+
if (visited.has(edge.target)) continue;
|
|
2560
|
+
visited.add(edge.target);
|
|
2561
|
+
queue.push({ nodeId: edge.target, path: [...path17, edge.target] });
|
|
2562
|
+
}
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2565
|
+
return {
|
|
2566
|
+
status: "completed",
|
|
2567
|
+
duration: Date.now() - start,
|
|
2568
|
+
message: `Found ${entryPoints.length} entry points, traced ${flowCount} flows`
|
|
2569
|
+
};
|
|
2570
|
+
}
|
|
2571
|
+
};
|
|
2572
|
+
|
|
2573
|
+
// src/scope-analysis/scope-builder.ts
|
|
2574
|
+
function createScope(name, kind, parent = null) {
|
|
2575
|
+
const scope = { name, kind, parent, bindings: /* @__PURE__ */ new Map(), children: [] };
|
|
2576
|
+
parent?.children.push(scope);
|
|
2577
|
+
return scope;
|
|
2578
|
+
}
|
|
2579
|
+
function resolveBinding(name, scope) {
|
|
2580
|
+
let current = scope;
|
|
2581
|
+
while (current !== null) {
|
|
2582
|
+
const binding = current.bindings.get(name);
|
|
2583
|
+
if (binding) return binding;
|
|
2584
|
+
current = current.parent;
|
|
2585
|
+
}
|
|
2586
|
+
return null;
|
|
2587
|
+
}
|
|
2588
|
+
function addBinding(scope, binding) {
|
|
2589
|
+
scope.bindings.set(binding.name, binding);
|
|
2590
|
+
}
|
|
2591
|
+
|
|
2592
|
+
// src/clustering/community-detector.ts
|
|
2593
|
+
function detectCommunities(graph) {
|
|
2594
|
+
const relevantKinds = /* @__PURE__ */ new Set(["function", "class", "method", "interface", "struct"]);
|
|
2595
|
+
const nodes = [];
|
|
2596
|
+
for (const node of graph.allNodes()) {
|
|
2597
|
+
if (relevantKinds.has(node.kind)) {
|
|
2598
|
+
nodes.push(node);
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
if (nodes.length < 10) return [];
|
|
2602
|
+
const dirGroups = /* @__PURE__ */ new Map();
|
|
2603
|
+
for (const node of nodes) {
|
|
2604
|
+
const dir = node.filePath.split("/").slice(0, -1).join("/") || ".";
|
|
2605
|
+
let group = dirGroups.get(dir);
|
|
2606
|
+
if (!group) {
|
|
2607
|
+
group = [];
|
|
2608
|
+
dirGroups.set(dir, group);
|
|
2609
|
+
}
|
|
2610
|
+
group.push(node);
|
|
2611
|
+
}
|
|
2612
|
+
const clusters = [];
|
|
2613
|
+
let idx = 0;
|
|
2614
|
+
for (const [dir, members] of dirGroups) {
|
|
2615
|
+
if (members.length < 2) continue;
|
|
2616
|
+
const clusterId = generateNodeId("cluster", dir, `cluster-${idx}`);
|
|
2617
|
+
const label = generateLabel(dir, members);
|
|
2618
|
+
clusters.push({
|
|
2619
|
+
clusterId,
|
|
2620
|
+
label,
|
|
2621
|
+
memberIds: members.map((m) => m.id)
|
|
2622
|
+
});
|
|
2623
|
+
idx++;
|
|
2624
|
+
}
|
|
2625
|
+
return clusters;
|
|
2626
|
+
}
|
|
2627
|
+
function generateLabel(dir, members) {
|
|
2628
|
+
const parts = dir.split("/").filter(Boolean);
|
|
2629
|
+
if (parts.length > 0) {
|
|
2630
|
+
return parts[parts.length - 1];
|
|
2631
|
+
}
|
|
2632
|
+
return `cluster-${members[0]?.name ?? "unknown"}`;
|
|
2633
|
+
}
|
|
2634
|
+
function addClustersToGraph(graph, clusters) {
|
|
2635
|
+
for (const cluster of clusters) {
|
|
2636
|
+
graph.addNode({
|
|
2637
|
+
id: cluster.clusterId,
|
|
2638
|
+
kind: "cluster",
|
|
2639
|
+
name: cluster.label,
|
|
2640
|
+
filePath: "",
|
|
2641
|
+
metadata: { memberCount: cluster.memberIds.length }
|
|
2642
|
+
});
|
|
2643
|
+
for (const memberId of cluster.memberIds) {
|
|
2644
|
+
graph.addEdge({
|
|
2645
|
+
id: generateEdgeId(memberId, cluster.clusterId, "belongs_to"),
|
|
2646
|
+
source: memberId,
|
|
2647
|
+
target: cluster.clusterId,
|
|
2648
|
+
kind: "belongs_to",
|
|
2649
|
+
weight: 1
|
|
2650
|
+
});
|
|
2651
|
+
}
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2654
|
+
|
|
2655
|
+
// src/flow-detection/entry-point-finder.ts
|
|
2656
|
+
function findEntryPoints(graph) {
|
|
2657
|
+
const calledNodes = /* @__PURE__ */ new Set();
|
|
2658
|
+
for (const edge of graph.findEdgesByKind("calls")) {
|
|
2659
|
+
calledNodes.add(edge.target);
|
|
2660
|
+
}
|
|
2661
|
+
const entryPoints = [];
|
|
2662
|
+
for (const node of graph.allNodes()) {
|
|
2663
|
+
if (!["function", "method"].includes(node.kind)) continue;
|
|
2664
|
+
const outEdges = [...graph.findEdgesFrom(node.id)].filter((e) => e.kind === "calls");
|
|
2665
|
+
const inDegree = calledNodes.has(node.id) ? 1 : 0;
|
|
2666
|
+
let score = 0;
|
|
2667
|
+
if (outEdges.length > 0 && inDegree === 0) score += 10;
|
|
2668
|
+
if (node.exported) score += 5;
|
|
2669
|
+
if (/^(main|handle|init|start|run|execute|process|serve|listen)/.test(node.name)) score += 3;
|
|
2670
|
+
if (node.filePath.includes("test") || node.filePath.includes("spec")) score -= 20;
|
|
2671
|
+
if (node.filePath.includes("route") || node.filePath.includes("controller")) score += 8;
|
|
2672
|
+
if (score >= 5) {
|
|
2673
|
+
entryPoints.push({
|
|
2674
|
+
nodeId: node.id,
|
|
2675
|
+
name: node.name,
|
|
2676
|
+
score,
|
|
2677
|
+
filePath: node.filePath
|
|
2678
|
+
});
|
|
2679
|
+
}
|
|
2680
|
+
}
|
|
2681
|
+
return entryPoints.sort((a, b) => b.score - a.score);
|
|
2682
|
+
}
|
|
2683
|
+
function traceFlow(entryId, graph, maxDepth = 10, maxBranching = 4) {
|
|
2684
|
+
const flows = [];
|
|
2685
|
+
const maxFlows = 75;
|
|
2686
|
+
function bfs() {
|
|
2687
|
+
const queue = [{ nodeId: entryId, path: [entryId] }];
|
|
2688
|
+
const visited = /* @__PURE__ */ new Set();
|
|
2689
|
+
while (queue.length > 0 && flows.length < maxFlows) {
|
|
2690
|
+
const { nodeId, path: path17 } = queue.shift();
|
|
2691
|
+
if (path17.length > maxDepth) continue;
|
|
2692
|
+
const callEdges = [...graph.findEdgesFrom(nodeId)].filter((e) => e.kind === "calls").slice(0, maxBranching);
|
|
2693
|
+
if (callEdges.length === 0 && path17.length >= 3) {
|
|
2694
|
+
flows.push({ entryPointId: entryId, steps: [...path17] });
|
|
2695
|
+
continue;
|
|
2696
|
+
}
|
|
2697
|
+
for (const edge of callEdges) {
|
|
2698
|
+
if (visited.has(edge.target)) continue;
|
|
2699
|
+
visited.add(edge.target);
|
|
2700
|
+
queue.push({ nodeId: edge.target, path: [...path17, edge.target] });
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
}
|
|
2704
|
+
bfs();
|
|
2705
|
+
return deduplicateFlows(flows);
|
|
2706
|
+
}
|
|
2707
|
+
function deduplicateFlows(flows) {
|
|
2708
|
+
const result = [];
|
|
2709
|
+
for (const flow of flows) {
|
|
2710
|
+
const edges = /* @__PURE__ */ new Set();
|
|
2711
|
+
for (let i = 0; i < flow.steps.length - 1; i++) {
|
|
2712
|
+
edges.add(`${flow.steps[i]}->${flow.steps[i + 1]}`);
|
|
2713
|
+
}
|
|
2714
|
+
const isDuplicate = result.some((existing) => {
|
|
2715
|
+
const existingEdges = /* @__PURE__ */ new Set();
|
|
2716
|
+
for (let i = 0; i < existing.steps.length - 1; i++) {
|
|
2717
|
+
existingEdges.add(`${existing.steps[i]}->${existing.steps[i + 1]}`);
|
|
2718
|
+
}
|
|
2719
|
+
let overlap = 0;
|
|
2720
|
+
for (const e of edges) {
|
|
2721
|
+
if (existingEdges.has(e)) overlap++;
|
|
2722
|
+
}
|
|
2723
|
+
return overlap / Math.max(edges.size, 1) > 0.7;
|
|
2724
|
+
});
|
|
2725
|
+
if (!isDuplicate) result.push(flow);
|
|
2726
|
+
}
|
|
2727
|
+
return result;
|
|
2728
|
+
}
|
|
2729
|
+
|
|
2730
|
+
// src/search/text-search.ts
|
|
2731
|
+
function textSearch(graph, query, limit = 20) {
|
|
2732
|
+
const terms = query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
2733
|
+
const results = [];
|
|
2734
|
+
const isTestPath = (fp) => fp.includes("test") || fp.includes("spec") || fp.includes("__test");
|
|
2735
|
+
const isDistPath = (fp) => fp.includes("/dist") || fp.includes("\\dist") || fp.includes(".d.ts");
|
|
2736
|
+
for (const node of graph.allNodes()) {
|
|
2737
|
+
if (["directory", "cluster", "flow"].includes(node.kind)) continue;
|
|
2738
|
+
let score = 0;
|
|
2739
|
+
const nameLC = node.name.toLowerCase();
|
|
2740
|
+
const pathLC = node.filePath.toLowerCase();
|
|
2741
|
+
for (const term of terms) {
|
|
2742
|
+
if (nameLC === term) score += 10;
|
|
2743
|
+
else if (nameLC.startsWith(term)) score += 7;
|
|
2744
|
+
else if (nameLC.includes(term)) score += 5;
|
|
2745
|
+
if (pathLC.includes(term)) score += 2;
|
|
2746
|
+
if (node.content?.toLowerCase().includes(term)) score += 3;
|
|
2747
|
+
}
|
|
2748
|
+
if (score > 0) {
|
|
2749
|
+
if (isDistPath(node.filePath)) score -= 8;
|
|
2750
|
+
if (isTestPath(node.filePath)) score -= 4;
|
|
2751
|
+
if (["function", "class", "interface", "method"].includes(node.kind)) score += 1;
|
|
2752
|
+
}
|
|
2753
|
+
if (score > 0) {
|
|
2754
|
+
results.push({
|
|
2755
|
+
nodeId: node.id,
|
|
2756
|
+
name: node.name,
|
|
2757
|
+
kind: node.kind,
|
|
2758
|
+
filePath: node.filePath,
|
|
2759
|
+
score,
|
|
2760
|
+
snippet: node.content?.slice(0, 200)
|
|
2761
|
+
});
|
|
2762
|
+
}
|
|
2763
|
+
}
|
|
2764
|
+
results.sort((a, b) => b.score - a.score);
|
|
2765
|
+
return results.slice(0, limit);
|
|
2766
|
+
}
|
|
2767
|
+
function reciprocalRankFusion(...rankings) {
|
|
2768
|
+
const K = 60;
|
|
2769
|
+
const scoreMap = /* @__PURE__ */ new Map();
|
|
2770
|
+
for (const ranking of rankings) {
|
|
2771
|
+
for (let rank = 0; rank < ranking.length; rank++) {
|
|
2772
|
+
const result = ranking[rank];
|
|
2773
|
+
const existing = scoreMap.get(result.nodeId);
|
|
2774
|
+
const rrfContribution = 1 / (K + rank + 1);
|
|
2775
|
+
if (existing) {
|
|
2776
|
+
existing.rrfScore += rrfContribution;
|
|
2777
|
+
} else {
|
|
2778
|
+
scoreMap.set(result.nodeId, {
|
|
2779
|
+
result,
|
|
2780
|
+
rrfScore: rrfContribution
|
|
2781
|
+
});
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
return [...scoreMap.values()].sort((a, b) => b.rrfScore - a.rrfScore).map((entry) => ({ ...entry.result, score: entry.rrfScore }));
|
|
2786
|
+
}
|
|
2787
|
+
|
|
2788
|
+
// src/search/index.ts
|
|
2789
|
+
init_embedder();
|
|
2790
|
+
|
|
2791
|
+
// src/search/vector-index.ts
|
|
2792
|
+
var EMBED_TABLE = "embed_nodes";
|
|
2793
|
+
var EMBED_DIM = 384;
|
|
2794
|
+
var INDEX_NAME = "embed_vec_idx";
|
|
2795
|
+
var VectorIndex = class {
|
|
2796
|
+
db;
|
|
2797
|
+
constructor(db) {
|
|
2798
|
+
this.db = db;
|
|
2799
|
+
}
|
|
2800
|
+
async init() {
|
|
2801
|
+
await this.db.execute("INSTALL VECTOR");
|
|
2802
|
+
await this.db.execute("LOAD EXTENSION VECTOR");
|
|
2803
|
+
await this.db.execute(`
|
|
2804
|
+
CREATE NODE TABLE IF NOT EXISTS ${EMBED_TABLE} (
|
|
2805
|
+
id STRING,
|
|
2806
|
+
name STRING,
|
|
2807
|
+
kind STRING,
|
|
2808
|
+
file_path STRING,
|
|
2809
|
+
text STRING,
|
|
2810
|
+
embedding FLOAT[${EMBED_DIM}],
|
|
2811
|
+
PRIMARY KEY (id)
|
|
2812
|
+
)
|
|
2813
|
+
`);
|
|
2814
|
+
}
|
|
2815
|
+
async buildIndex(nodes) {
|
|
2816
|
+
await this.db.execute(`MATCH (n:${EMBED_TABLE}) DETACH DELETE n`).catch(() => {
|
|
2817
|
+
});
|
|
2818
|
+
for (const node of nodes) {
|
|
2819
|
+
const vecLiteral = `[${node.embedding.join(",")}]`;
|
|
2820
|
+
await this.db.execute(
|
|
2821
|
+
`CREATE (:${EMBED_TABLE} {
|
|
2822
|
+
id: '${esc(node.id)}',
|
|
2823
|
+
name: '${esc(node.name)}',
|
|
2824
|
+
kind: '${esc(node.kind)}',
|
|
2825
|
+
file_path: '${esc(node.filePath)}',
|
|
2826
|
+
text: '${esc(node.text)}',
|
|
2827
|
+
embedding: ${vecLiteral}
|
|
2828
|
+
})`
|
|
2829
|
+
);
|
|
2830
|
+
}
|
|
2831
|
+
await this.db.execute(`CALL DROP_VECTOR_INDEX('${EMBED_TABLE}', '${INDEX_NAME}')`).catch(() => {
|
|
2832
|
+
});
|
|
2833
|
+
await this.db.execute(`CALL CREATE_VECTOR_INDEX('${EMBED_TABLE}', '${INDEX_NAME}', 'embedding')`);
|
|
2834
|
+
}
|
|
2835
|
+
async search(queryEmbedding, topK = 10) {
|
|
2836
|
+
const vecLiteral = `[${queryEmbedding.join(",")}]`;
|
|
2837
|
+
const rows = await this.db.query(
|
|
2838
|
+
`CALL QUERY_VECTOR_INDEX('${EMBED_TABLE}', '${INDEX_NAME}', ${vecLiteral}, ${topK}) RETURN node.id, node.name, node.kind, node.file_path, distance`
|
|
2839
|
+
);
|
|
2840
|
+
return rows.map((r) => ({
|
|
2841
|
+
nodeId: String(r["node.id"]),
|
|
2842
|
+
name: String(r["node.name"]),
|
|
2843
|
+
kind: String(r["node.kind"]),
|
|
2844
|
+
filePath: String(r["node.file_path"]),
|
|
2845
|
+
score: 1 - Number(r["distance"])
|
|
2846
|
+
// cosine distance → similarity
|
|
2847
|
+
}));
|
|
2848
|
+
}
|
|
2849
|
+
async isBuilt() {
|
|
2850
|
+
try {
|
|
2851
|
+
const rows = await this.db.query(`MATCH (n:${EMBED_TABLE}) RETURN count(n) AS cnt`);
|
|
2852
|
+
return Number(rows[0]?.cnt ?? 0) > 0;
|
|
2853
|
+
} catch {
|
|
2854
|
+
return false;
|
|
2855
|
+
}
|
|
2856
|
+
}
|
|
2857
|
+
};
|
|
2858
|
+
function esc(s) {
|
|
2859
|
+
return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "");
|
|
2860
|
+
}
|
|
2861
|
+
function createMcpServer(graph, repoName) {
|
|
2862
|
+
const server = new Server(
|
|
2863
|
+
{ name: "code-intel", version: "0.1.0" },
|
|
2864
|
+
{ capabilities: { tools: {}, resources: {} } }
|
|
2865
|
+
);
|
|
2866
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
2867
|
+
tools: [
|
|
2868
|
+
{
|
|
2869
|
+
name: "repos",
|
|
2870
|
+
description: "List indexed repositories",
|
|
2871
|
+
inputSchema: { type: "object", properties: {} }
|
|
2872
|
+
},
|
|
2873
|
+
{
|
|
2874
|
+
name: "search",
|
|
2875
|
+
description: "Hybrid search across the codebase knowledge graph",
|
|
2876
|
+
inputSchema: {
|
|
2877
|
+
type: "object",
|
|
2878
|
+
properties: {
|
|
2879
|
+
query: { type: "string", description: "Search query" },
|
|
2880
|
+
limit: { type: "number", description: "Max results (default 20)" }
|
|
2881
|
+
},
|
|
2882
|
+
required: ["query"]
|
|
2883
|
+
}
|
|
2884
|
+
},
|
|
2885
|
+
{
|
|
2886
|
+
name: "inspect",
|
|
2887
|
+
description: "360\xB0 view of a symbol: definition, callers, callees, heritage, references",
|
|
2888
|
+
inputSchema: {
|
|
2889
|
+
type: "object",
|
|
2890
|
+
properties: {
|
|
2891
|
+
symbol_name: { type: "string", description: "Symbol name to inspect" }
|
|
2892
|
+
},
|
|
2893
|
+
required: ["symbol_name"]
|
|
2894
|
+
}
|
|
2895
|
+
},
|
|
2896
|
+
{
|
|
2897
|
+
name: "blast_radius",
|
|
2898
|
+
description: "Impact analysis: what depends on / is affected by this symbol",
|
|
2899
|
+
inputSchema: {
|
|
2900
|
+
type: "object",
|
|
2901
|
+
properties: {
|
|
2902
|
+
target: { type: "string", description: "Target symbol name" },
|
|
2903
|
+
direction: { type: "string", enum: ["callers", "callees", "both"], description: "Direction to trace" },
|
|
2904
|
+
max_hops: { type: "number", description: "Max hops (default 5)" }
|
|
2905
|
+
},
|
|
2906
|
+
required: ["target"]
|
|
2907
|
+
}
|
|
2908
|
+
},
|
|
2909
|
+
{
|
|
2910
|
+
name: "routes",
|
|
2911
|
+
description: "List route handler mappings in the codebase",
|
|
2912
|
+
inputSchema: { type: "object", properties: {} }
|
|
2913
|
+
},
|
|
2914
|
+
{
|
|
2915
|
+
name: "raw_query",
|
|
2916
|
+
description: "Execute a graph query (simplified Cypher-like)",
|
|
2917
|
+
inputSchema: {
|
|
2918
|
+
type: "object",
|
|
2919
|
+
properties: {
|
|
2920
|
+
cypher: { type: "string", description: "Query string (name='X' or :kind patterns)" }
|
|
2921
|
+
},
|
|
2922
|
+
required: ["cypher"]
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
]
|
|
2926
|
+
}));
|
|
2927
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
2928
|
+
const { name, arguments: args } = request.params;
|
|
2929
|
+
const a = args ?? {};
|
|
2930
|
+
switch (name) {
|
|
2931
|
+
case "repos": {
|
|
2932
|
+
return { content: [{ type: "text", text: JSON.stringify([{ name: repoName, nodes: graph.size.nodes, edges: graph.size.edges }], null, 2) }] };
|
|
2933
|
+
}
|
|
2934
|
+
case "search": {
|
|
2935
|
+
const query = a.query;
|
|
2936
|
+
const limit = a.limit ?? 20;
|
|
2937
|
+
const results = textSearch(graph, query, limit);
|
|
2938
|
+
return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] };
|
|
2939
|
+
}
|
|
2940
|
+
case "inspect": {
|
|
2941
|
+
const symbolName = a.symbol_name;
|
|
2942
|
+
const node = findNodeByName(graph, symbolName);
|
|
2943
|
+
if (!node) return { content: [{ type: "text", text: `Symbol "${symbolName}" not found` }] };
|
|
2944
|
+
const incoming = [...graph.findEdgesTo(node.id)];
|
|
2945
|
+
const outgoing = [...graph.findEdgesFrom(node.id)];
|
|
2946
|
+
return {
|
|
2947
|
+
content: [{
|
|
2948
|
+
type: "text",
|
|
2949
|
+
text: JSON.stringify({
|
|
2950
|
+
node: { id: node.id, kind: node.kind, name: node.name, filePath: node.filePath, startLine: node.startLine, endLine: node.endLine, exported: node.exported },
|
|
2951
|
+
callers: incoming.filter((e) => e.kind === "calls").map((e) => ({ id: e.source, name: graph.getNode(e.source)?.name })),
|
|
2952
|
+
callees: outgoing.filter((e) => e.kind === "calls").map((e) => ({ id: e.target, name: graph.getNode(e.target)?.name })),
|
|
2953
|
+
extends: outgoing.filter((e) => e.kind === "extends").map((e) => graph.getNode(e.target)?.name),
|
|
2954
|
+
implements: outgoing.filter((e) => e.kind === "implements").map((e) => graph.getNode(e.target)?.name),
|
|
2955
|
+
members: outgoing.filter((e) => e.kind === "has_member").map((e) => ({ name: graph.getNode(e.target)?.name, kind: graph.getNode(e.target)?.kind })),
|
|
2956
|
+
cluster: incoming.filter((e) => e.kind === "belongs_to").map((e) => graph.getNode(e.target)?.name)[0],
|
|
2957
|
+
content: node.content?.slice(0, 500)
|
|
2958
|
+
}, null, 2)
|
|
2959
|
+
}]
|
|
2960
|
+
};
|
|
2961
|
+
}
|
|
2962
|
+
case "blast_radius": {
|
|
2963
|
+
const target = a.target;
|
|
2964
|
+
const direction = a.direction ?? "both";
|
|
2965
|
+
const maxHops = a.max_hops ?? 5;
|
|
2966
|
+
const node = findNodeByName(graph, target);
|
|
2967
|
+
if (!node) return { content: [{ type: "text", text: `Symbol "${target}" not found` }] };
|
|
2968
|
+
const affected = /* @__PURE__ */ new Set();
|
|
2969
|
+
const queue = [{ id: node.id, depth: 0 }];
|
|
2970
|
+
const visited = /* @__PURE__ */ new Set();
|
|
2971
|
+
while (queue.length > 0) {
|
|
2972
|
+
const { id, depth } = queue.shift();
|
|
2973
|
+
if (visited.has(id) || depth > maxHops) continue;
|
|
2974
|
+
visited.add(id);
|
|
2975
|
+
affected.add(id);
|
|
2976
|
+
if (direction === "callers" || direction === "both") {
|
|
2977
|
+
for (const edge of graph.findEdgesTo(id)) {
|
|
2978
|
+
if (edge.kind === "calls" || edge.kind === "imports") queue.push({ id: edge.source, depth: depth + 1 });
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
2981
|
+
if (direction === "callees" || direction === "both") {
|
|
2982
|
+
for (const edge of graph.findEdgesFrom(id)) {
|
|
2983
|
+
if (edge.kind === "calls" || edge.kind === "imports") queue.push({ id: edge.target, depth: depth + 1 });
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2986
|
+
}
|
|
2987
|
+
const affectedDetails = [...affected].map((id) => {
|
|
2988
|
+
const n = graph.getNode(id);
|
|
2989
|
+
return n ? { id, name: n.name, kind: n.kind, filePath: n.filePath } : { id };
|
|
2990
|
+
});
|
|
2991
|
+
return { content: [{ type: "text", text: JSON.stringify({ target: node.name, affectedCount: affected.size, affected: affectedDetails }, null, 2) }] };
|
|
2992
|
+
}
|
|
2993
|
+
case "routes": {
|
|
2994
|
+
const routes = [];
|
|
2995
|
+
for (const node of graph.allNodes()) {
|
|
2996
|
+
if (node.kind === "route" || node.kind === "function" && /route|handler|controller/i.test(node.filePath)) {
|
|
2997
|
+
routes.push({ name: node.name, filePath: node.filePath });
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3000
|
+
return { content: [{ type: "text", text: JSON.stringify(routes, null, 2) }] };
|
|
3001
|
+
}
|
|
3002
|
+
case "raw_query": {
|
|
3003
|
+
const q = a.cypher;
|
|
3004
|
+
const nameMatch = q?.match(/name\s*=\s*['"]([^'"]+)['"]/i);
|
|
3005
|
+
if (nameMatch) {
|
|
3006
|
+
const results = [];
|
|
3007
|
+
for (const node of graph.allNodes()) {
|
|
3008
|
+
if (node.name === nameMatch[1]) results.push(node);
|
|
3009
|
+
}
|
|
3010
|
+
return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] };
|
|
3011
|
+
}
|
|
3012
|
+
const kindMatch = q?.match(/:\s*(\w+)/);
|
|
3013
|
+
if (kindMatch) {
|
|
3014
|
+
const results = [];
|
|
3015
|
+
for (const node of graph.allNodes()) {
|
|
3016
|
+
if (node.kind === kindMatch[1]) results.push(node);
|
|
3017
|
+
if (results.length >= 50) break;
|
|
3018
|
+
}
|
|
3019
|
+
return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] };
|
|
3020
|
+
}
|
|
3021
|
+
return { content: [{ type: "text", text: "Query not recognized" }] };
|
|
3022
|
+
}
|
|
3023
|
+
default:
|
|
3024
|
+
return { content: [{ type: "text", text: `Unknown tool: ${name}` }] };
|
|
3025
|
+
}
|
|
3026
|
+
});
|
|
3027
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
3028
|
+
resources: [
|
|
3029
|
+
{ uri: `codeintel://repo/${repoName}/overview`, name: `${repoName} Overview`, mimeType: "application/json" },
|
|
3030
|
+
{ uri: `codeintel://repo/${repoName}/clusters`, name: `${repoName} Clusters`, mimeType: "application/json" },
|
|
3031
|
+
{ uri: `codeintel://repo/${repoName}/flows`, name: `${repoName} Flows`, mimeType: "application/json" }
|
|
3032
|
+
]
|
|
3033
|
+
}));
|
|
3034
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
3035
|
+
const { uri } = request.params;
|
|
3036
|
+
if (uri.endsWith("/overview")) {
|
|
3037
|
+
const kindCounts = {};
|
|
3038
|
+
for (const node of graph.allNodes()) {
|
|
3039
|
+
kindCounts[node.kind] = (kindCounts[node.kind] ?? 0) + 1;
|
|
3040
|
+
}
|
|
3041
|
+
return { contents: [{ uri, mimeType: "application/json", text: JSON.stringify({ repo: repoName, stats: graph.size, nodeCounts: kindCounts }) }] };
|
|
3042
|
+
}
|
|
3043
|
+
if (uri.endsWith("/clusters")) {
|
|
3044
|
+
const clusters = [];
|
|
3045
|
+
for (const node of graph.allNodes()) {
|
|
3046
|
+
if (node.kind === "cluster") clusters.push({ id: node.id, name: node.name, memberCount: node.metadata?.memberCount });
|
|
3047
|
+
}
|
|
3048
|
+
return { contents: [{ uri, mimeType: "application/json", text: JSON.stringify(clusters) }] };
|
|
3049
|
+
}
|
|
3050
|
+
if (uri.endsWith("/flows")) {
|
|
3051
|
+
const flows = [];
|
|
3052
|
+
for (const node of graph.allNodes()) {
|
|
3053
|
+
if (node.kind === "flow") flows.push({ id: node.id, name: node.name, steps: node.metadata?.steps, entryPoint: node.metadata?.entryPoint });
|
|
3054
|
+
}
|
|
3055
|
+
return { contents: [{ uri, mimeType: "application/json", text: JSON.stringify(flows) }] };
|
|
3056
|
+
}
|
|
3057
|
+
throw new Error(`Unknown resource: ${uri}`);
|
|
3058
|
+
});
|
|
3059
|
+
return server;
|
|
3060
|
+
}
|
|
3061
|
+
async function startMcpStdio(graph, repoName) {
|
|
3062
|
+
const server = createMcpServer(graph, repoName);
|
|
3063
|
+
const transport = new StdioServerTransport();
|
|
3064
|
+
await server.connect(transport);
|
|
3065
|
+
}
|
|
3066
|
+
function findNodeByName(graph, name) {
|
|
3067
|
+
for (const node of graph.allNodes()) {
|
|
3068
|
+
if (node.name === name) return node;
|
|
3069
|
+
}
|
|
3070
|
+
return void 0;
|
|
3071
|
+
}
|
|
3072
|
+
var DbManager = class {
|
|
3073
|
+
db = null;
|
|
3074
|
+
conn = null;
|
|
3075
|
+
dbPath;
|
|
3076
|
+
constructor(dbPath) {
|
|
3077
|
+
this.dbPath = dbPath;
|
|
3078
|
+
}
|
|
3079
|
+
async init() {
|
|
3080
|
+
fs8.mkdirSync(path6.dirname(this.dbPath), { recursive: true });
|
|
3081
|
+
this.db = new Database(this.dbPath);
|
|
3082
|
+
await this.db.init();
|
|
3083
|
+
this.conn = new Connection(this.db);
|
|
3084
|
+
await this.conn.init();
|
|
3085
|
+
}
|
|
3086
|
+
async query(cypher) {
|
|
3087
|
+
if (!this.conn) throw new Error("Database not initialized");
|
|
3088
|
+
const result = await this.conn.query(cypher);
|
|
3089
|
+
const qr = Array.isArray(result) ? result[0] : result;
|
|
3090
|
+
const rows = await qr.getAll();
|
|
3091
|
+
qr.close();
|
|
3092
|
+
return rows;
|
|
3093
|
+
}
|
|
3094
|
+
async execute(cypher) {
|
|
3095
|
+
if (!this.conn) throw new Error("Database not initialized");
|
|
3096
|
+
const result = await this.conn.query(cypher);
|
|
3097
|
+
const qr = Array.isArray(result) ? result[0] : result;
|
|
3098
|
+
qr.close();
|
|
3099
|
+
}
|
|
3100
|
+
close() {
|
|
3101
|
+
try {
|
|
3102
|
+
this.conn?.close();
|
|
3103
|
+
} catch {
|
|
3104
|
+
}
|
|
3105
|
+
try {
|
|
3106
|
+
this.db?.close();
|
|
3107
|
+
} catch {
|
|
3108
|
+
}
|
|
3109
|
+
this.conn = null;
|
|
3110
|
+
this.db = null;
|
|
3111
|
+
}
|
|
3112
|
+
get isOpen() {
|
|
3113
|
+
return this.conn !== null;
|
|
3114
|
+
}
|
|
3115
|
+
};
|
|
3116
|
+
|
|
3117
|
+
// src/storage/schema.ts
|
|
3118
|
+
var NODE_TABLE_MAP = {
|
|
3119
|
+
file: "file_nodes",
|
|
3120
|
+
directory: "dir_nodes",
|
|
3121
|
+
function: "func_nodes",
|
|
3122
|
+
class: "class_nodes",
|
|
3123
|
+
interface: "iface_nodes",
|
|
3124
|
+
method: "method_nodes",
|
|
3125
|
+
constructor: "ctor_nodes",
|
|
3126
|
+
variable: "var_nodes",
|
|
3127
|
+
property: "prop_nodes",
|
|
3128
|
+
struct: "struct_nodes",
|
|
3129
|
+
enum: "enum_nodes",
|
|
3130
|
+
trait: "trait_nodes",
|
|
3131
|
+
namespace: "ns_nodes",
|
|
3132
|
+
module: "mod_nodes",
|
|
3133
|
+
type_alias: "type_nodes",
|
|
3134
|
+
constant: "const_nodes",
|
|
3135
|
+
route: "route_nodes",
|
|
3136
|
+
cluster: "cluster_nodes",
|
|
3137
|
+
flow: "flow_nodes"
|
|
3138
|
+
};
|
|
3139
|
+
var ALL_NODE_TABLES = [...new Set(Object.values(NODE_TABLE_MAP))];
|
|
3140
|
+
function getCreateNodeTableDDL(tableName) {
|
|
3141
|
+
return `CREATE NODE TABLE IF NOT EXISTS ${tableName} (
|
|
3142
|
+
id STRING,
|
|
3143
|
+
name STRING,
|
|
3144
|
+
file_path STRING,
|
|
3145
|
+
start_line INT64,
|
|
3146
|
+
end_line INT64,
|
|
3147
|
+
exported BOOLEAN,
|
|
3148
|
+
content STRING,
|
|
3149
|
+
metadata STRING,
|
|
3150
|
+
PRIMARY KEY (id)
|
|
3151
|
+
)`;
|
|
3152
|
+
}
|
|
3153
|
+
function getCreateEdgeTableDDL() {
|
|
3154
|
+
const ddls = [];
|
|
3155
|
+
const uniqueTables = ALL_NODE_TABLES;
|
|
3156
|
+
const fromToPairs = [];
|
|
3157
|
+
for (const from of uniqueTables) {
|
|
3158
|
+
for (const to of uniqueTables) {
|
|
3159
|
+
fromToPairs.push(`FROM ${from} TO ${to}`);
|
|
3160
|
+
}
|
|
3161
|
+
}
|
|
3162
|
+
ddls.push(`CREATE REL TABLE IF NOT EXISTS code_edges (
|
|
3163
|
+
${fromToPairs.join(",\n ")},
|
|
3164
|
+
kind STRING,
|
|
3165
|
+
weight DOUBLE,
|
|
3166
|
+
label STRING
|
|
3167
|
+
)`);
|
|
3168
|
+
return ddls;
|
|
3169
|
+
}
|
|
3170
|
+
|
|
3171
|
+
// src/storage/graph-loader.ts
|
|
3172
|
+
async function loadGraphToDB(graph, dbManager) {
|
|
3173
|
+
for (const table of ALL_NODE_TABLES) {
|
|
3174
|
+
await dbManager.execute(getCreateNodeTableDDL(table));
|
|
3175
|
+
}
|
|
3176
|
+
const edgeDDLs = getCreateEdgeTableDDL();
|
|
3177
|
+
for (const ddl of edgeDDLs) {
|
|
3178
|
+
try {
|
|
3179
|
+
await dbManager.execute(ddl);
|
|
3180
|
+
} catch {
|
|
3181
|
+
}
|
|
3182
|
+
}
|
|
3183
|
+
let nodeCount = 0;
|
|
3184
|
+
for (const node of graph.allNodes()) {
|
|
3185
|
+
const table = NODE_TABLE_MAP[node.kind];
|
|
3186
|
+
const props = buildNodeProps(node);
|
|
3187
|
+
try {
|
|
3188
|
+
await dbManager.execute(`CREATE (:${table} ${props})`);
|
|
3189
|
+
nodeCount++;
|
|
3190
|
+
} catch {
|
|
3191
|
+
}
|
|
3192
|
+
}
|
|
3193
|
+
let edgeCount = 0;
|
|
3194
|
+
for (const edge of graph.allEdges()) {
|
|
3195
|
+
const sourceNode = graph.getNode(edge.source);
|
|
3196
|
+
const targetNode = graph.getNode(edge.target);
|
|
3197
|
+
if (!sourceNode || !targetNode) continue;
|
|
3198
|
+
const fromTable = NODE_TABLE_MAP[sourceNode.kind];
|
|
3199
|
+
const toTable = NODE_TABLE_MAP[targetNode.kind];
|
|
3200
|
+
try {
|
|
3201
|
+
await dbManager.execute(
|
|
3202
|
+
`MATCH (a:${fromTable} {id: '${escCypher(edge.source)}'}), (b:${toTable} {id: '${escCypher(edge.target)}'}) CREATE (a)-[:code_edges {kind: '${edge.kind}', weight: ${edge.weight ?? 1}, label: '${escCypher(edge.label ?? "")}'}]->(b)`
|
|
3203
|
+
);
|
|
3204
|
+
edgeCount++;
|
|
3205
|
+
} catch {
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
3208
|
+
return { nodeCount, edgeCount };
|
|
3209
|
+
}
|
|
3210
|
+
function buildNodeProps(node) {
|
|
3211
|
+
const parts = [
|
|
3212
|
+
`id: '${escCypher(node.id)}'`,
|
|
3213
|
+
`name: '${escCypher(node.name)}'`,
|
|
3214
|
+
`file_path: '${escCypher(node.filePath)}'`
|
|
3215
|
+
];
|
|
3216
|
+
if (node.startLine !== void 0) parts.push(`start_line: ${node.startLine}`);
|
|
3217
|
+
if (node.endLine !== void 0) parts.push(`end_line: ${node.endLine}`);
|
|
3218
|
+
if (node.exported !== void 0) parts.push(`exported: ${node.exported}`);
|
|
3219
|
+
if (node.content) parts.push(`content: '${escCypher(node.content.slice(0, 500))}'`);
|
|
3220
|
+
if (node.metadata) parts.push(`metadata: '${escCypher(JSON.stringify(node.metadata))}'`);
|
|
3221
|
+
return `{${parts.join(", ")}}`;
|
|
3222
|
+
}
|
|
3223
|
+
function escCypher(s) {
|
|
3224
|
+
return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "");
|
|
3225
|
+
}
|
|
3226
|
+
var GLOBAL_DIR = path6.join(os2.homedir(), ".code-intel");
|
|
3227
|
+
var REPOS_FILE = path6.join(GLOBAL_DIR, "repos.json");
|
|
3228
|
+
function loadRegistry() {
|
|
3229
|
+
try {
|
|
3230
|
+
const data = fs8.readFileSync(REPOS_FILE, "utf-8");
|
|
3231
|
+
return JSON.parse(data);
|
|
3232
|
+
} catch {
|
|
3233
|
+
return [];
|
|
3234
|
+
}
|
|
3235
|
+
}
|
|
3236
|
+
function saveRegistry(entries) {
|
|
3237
|
+
fs8.mkdirSync(GLOBAL_DIR, { recursive: true });
|
|
3238
|
+
fs8.writeFileSync(REPOS_FILE, JSON.stringify(entries, null, 2));
|
|
3239
|
+
}
|
|
3240
|
+
function upsertRepo(entry) {
|
|
3241
|
+
const entries = loadRegistry();
|
|
3242
|
+
const idx = entries.findIndex((e) => e.path === entry.path);
|
|
3243
|
+
if (idx >= 0) {
|
|
3244
|
+
entries[idx] = entry;
|
|
3245
|
+
} else {
|
|
3246
|
+
entries.push(entry);
|
|
3247
|
+
}
|
|
3248
|
+
saveRegistry(entries);
|
|
3249
|
+
}
|
|
3250
|
+
function removeRepo(repoPath) {
|
|
3251
|
+
const entries = loadRegistry().filter((e) => e.path !== repoPath);
|
|
3252
|
+
saveRegistry(entries);
|
|
3253
|
+
}
|
|
3254
|
+
function saveMetadata(repoDir, metadata) {
|
|
3255
|
+
const metaDir = path6.join(repoDir, ".code-intel");
|
|
3256
|
+
fs8.mkdirSync(metaDir, { recursive: true });
|
|
3257
|
+
fs8.writeFileSync(path6.join(metaDir, "meta.json"), JSON.stringify(metadata, null, 2));
|
|
3258
|
+
}
|
|
3259
|
+
function loadMetadata(repoDir) {
|
|
3260
|
+
try {
|
|
3261
|
+
const data = fs8.readFileSync(path6.join(repoDir, ".code-intel", "meta.json"), "utf-8");
|
|
3262
|
+
return JSON.parse(data);
|
|
3263
|
+
} catch {
|
|
3264
|
+
return null;
|
|
3265
|
+
}
|
|
3266
|
+
}
|
|
3267
|
+
function getDbPath(repoDir) {
|
|
3268
|
+
return path6.join(repoDir, ".code-intel", "graph.db");
|
|
3269
|
+
}
|
|
3270
|
+
function getVectorDbPath(repoDir) {
|
|
3271
|
+
return path6.join(repoDir, ".code-intel", "vector.db");
|
|
3272
|
+
}
|
|
3273
|
+
|
|
3274
|
+
// src/http/app.ts
|
|
3275
|
+
init_group_registry();
|
|
3276
|
+
|
|
3277
|
+
// src/multi-repo/graph-from-db.ts
|
|
3278
|
+
var TABLE_TO_KIND = Object.fromEntries(
|
|
3279
|
+
Object.entries(NODE_TABLE_MAP).map(([kind, table]) => [table, kind])
|
|
3280
|
+
);
|
|
3281
|
+
function parseRow(row, kind) {
|
|
3282
|
+
return {
|
|
3283
|
+
id: String(row["id"] ?? ""),
|
|
3284
|
+
kind,
|
|
3285
|
+
name: String(row["name"] ?? ""),
|
|
3286
|
+
filePath: String(row["file_path"] ?? ""),
|
|
3287
|
+
startLine: row["start_line"] != null ? Number(row["start_line"]) : void 0,
|
|
3288
|
+
endLine: row["end_line"] != null ? Number(row["end_line"]) : void 0,
|
|
3289
|
+
exported: row["exported"] != null ? Boolean(row["exported"]) : void 0,
|
|
3290
|
+
content: row["content"] ? String(row["content"]) : void 0,
|
|
3291
|
+
metadata: row["metadata"] ? (() => {
|
|
3292
|
+
try {
|
|
3293
|
+
return JSON.parse(String(row["metadata"]));
|
|
3294
|
+
} catch {
|
|
3295
|
+
return void 0;
|
|
3296
|
+
}
|
|
3297
|
+
})() : void 0
|
|
3298
|
+
};
|
|
3299
|
+
}
|
|
3300
|
+
async function loadGraphFromDB(graph, db) {
|
|
3301
|
+
for (const table of ALL_NODE_TABLES) {
|
|
3302
|
+
const kind = TABLE_TO_KIND[table];
|
|
3303
|
+
if (!kind) continue;
|
|
3304
|
+
let rows = [];
|
|
3305
|
+
try {
|
|
3306
|
+
rows = await db.query(`MATCH (n:${table}) RETURN n.id, n.name, n.file_path, n.start_line, n.end_line, n.exported, n.content, n.metadata`);
|
|
3307
|
+
} catch {
|
|
3308
|
+
continue;
|
|
3309
|
+
}
|
|
3310
|
+
for (const row of rows) {
|
|
3311
|
+
const node = parseRow({
|
|
3312
|
+
id: row["n.id"],
|
|
3313
|
+
name: row["n.name"],
|
|
3314
|
+
file_path: row["n.file_path"],
|
|
3315
|
+
start_line: row["n.start_line"],
|
|
3316
|
+
end_line: row["n.end_line"],
|
|
3317
|
+
exported: row["n.exported"],
|
|
3318
|
+
content: row["n.content"],
|
|
3319
|
+
metadata: row["n.metadata"]
|
|
3320
|
+
}, kind);
|
|
3321
|
+
if (node.id && node.name) graph.addNode(node);
|
|
3322
|
+
}
|
|
3323
|
+
}
|
|
3324
|
+
try {
|
|
3325
|
+
const edgeRows = await db.query(
|
|
3326
|
+
`MATCH (a)-[e:code_edges]->(b) RETURN a.id, b.id, e.kind, e.weight, e.label`
|
|
3327
|
+
);
|
|
3328
|
+
for (const row of edgeRows) {
|
|
3329
|
+
const sourceId = String(row["a.id"] ?? "");
|
|
3330
|
+
const targetId = String(row["b.id"] ?? "");
|
|
3331
|
+
const kind = String(row["e.kind"] ?? "");
|
|
3332
|
+
if (!sourceId || !targetId || !kind) continue;
|
|
3333
|
+
const edge = {
|
|
3334
|
+
id: `${sourceId}::${kind}::${targetId}`,
|
|
3335
|
+
source: sourceId,
|
|
3336
|
+
target: targetId,
|
|
3337
|
+
kind,
|
|
3338
|
+
weight: row["e.weight"] != null ? Number(row["e.weight"]) : void 0,
|
|
3339
|
+
label: row["e.label"] ? String(row["e.label"]) : void 0
|
|
3340
|
+
};
|
|
3341
|
+
graph.addEdge(edge);
|
|
3342
|
+
}
|
|
3343
|
+
} catch {
|
|
3344
|
+
}
|
|
3345
|
+
}
|
|
3346
|
+
|
|
3347
|
+
// src/multi-repo/group-sync.ts
|
|
3348
|
+
function extractContracts(graph, repoName, repoPath) {
|
|
3349
|
+
const contracts = [];
|
|
3350
|
+
for (const node of graph.allNodes()) {
|
|
3351
|
+
if (node.exported === true && ["function", "class", "interface", "method", "type_alias", "constant", "enum", "struct", "trait"].includes(node.kind)) {
|
|
3352
|
+
contracts.push({
|
|
3353
|
+
repoName,
|
|
3354
|
+
repoPath,
|
|
3355
|
+
kind: "export",
|
|
3356
|
+
name: node.name,
|
|
3357
|
+
nodeId: node.id,
|
|
3358
|
+
nodeKind: node.kind,
|
|
3359
|
+
filePath: node.filePath,
|
|
3360
|
+
signature: node.content?.split("\n")[0]?.trim()
|
|
3361
|
+
});
|
|
3362
|
+
}
|
|
3363
|
+
if (node.kind === "route") {
|
|
3364
|
+
contracts.push({
|
|
3365
|
+
repoName,
|
|
3366
|
+
repoPath,
|
|
3367
|
+
kind: "route",
|
|
3368
|
+
name: node.name,
|
|
3369
|
+
nodeId: node.id,
|
|
3370
|
+
nodeKind: node.kind,
|
|
3371
|
+
filePath: node.filePath,
|
|
3372
|
+
signature: node.content?.split("\n")[0]?.trim()
|
|
3373
|
+
});
|
|
3374
|
+
}
|
|
3375
|
+
if (["interface", "type_alias"].includes(node.kind)) {
|
|
3376
|
+
const nameLower = node.name.toLowerCase();
|
|
3377
|
+
if (nameLower.includes("event") || nameLower.includes("message")) {
|
|
3378
|
+
contracts.push({
|
|
3379
|
+
repoName,
|
|
3380
|
+
repoPath,
|
|
3381
|
+
kind: "event",
|
|
3382
|
+
name: node.name,
|
|
3383
|
+
nodeId: node.id,
|
|
3384
|
+
nodeKind: node.kind,
|
|
3385
|
+
filePath: node.filePath
|
|
3386
|
+
});
|
|
3387
|
+
} else if (nameLower.includes("schema") || nameLower.includes("dto") || nameLower.includes("request") || nameLower.includes("response")) {
|
|
3388
|
+
contracts.push({
|
|
3389
|
+
repoName,
|
|
3390
|
+
repoPath,
|
|
3391
|
+
kind: "schema",
|
|
3392
|
+
name: node.name,
|
|
3393
|
+
nodeId: node.id,
|
|
3394
|
+
nodeKind: node.kind,
|
|
3395
|
+
filePath: node.filePath
|
|
3396
|
+
});
|
|
3397
|
+
}
|
|
3398
|
+
}
|
|
3399
|
+
}
|
|
3400
|
+
return contracts;
|
|
3401
|
+
}
|
|
3402
|
+
function matchContracts(allContracts) {
|
|
3403
|
+
const links = [];
|
|
3404
|
+
const byRepo = /* @__PURE__ */ new Map();
|
|
3405
|
+
for (const c of allContracts) {
|
|
3406
|
+
const arr = byRepo.get(c.repoName) ?? [];
|
|
3407
|
+
arr.push(c);
|
|
3408
|
+
byRepo.set(c.repoName, arr);
|
|
3409
|
+
}
|
|
3410
|
+
const repoNames = [...byRepo.keys()];
|
|
3411
|
+
for (let i = 0; i < repoNames.length; i++) {
|
|
3412
|
+
for (let j = 0; j < repoNames.length; j++) {
|
|
3413
|
+
if (i === j) continue;
|
|
3414
|
+
const providerContracts = byRepo.get(repoNames[i]);
|
|
3415
|
+
const consumerContracts = byRepo.get(repoNames[j]);
|
|
3416
|
+
const consumerByName = /* @__PURE__ */ new Map();
|
|
3417
|
+
for (const c of consumerContracts) consumerByName.set(c.name, c);
|
|
3418
|
+
for (const provider of providerContracts) {
|
|
3419
|
+
const consumer = consumerByName.get(provider.name);
|
|
3420
|
+
if (consumer) {
|
|
3421
|
+
const sameKind = provider.kind === consumer.kind;
|
|
3422
|
+
links.push({
|
|
3423
|
+
providerRepo: provider.repoName,
|
|
3424
|
+
providerContract: provider.name,
|
|
3425
|
+
consumerRepo: consumer.repoName,
|
|
3426
|
+
consumerContract: consumer.name,
|
|
3427
|
+
matchKind: provider.kind === "route" ? "route-match" : "name-match",
|
|
3428
|
+
confidence: sameKind ? 0.9 : 0.6
|
|
3429
|
+
});
|
|
3430
|
+
} else {
|
|
3431
|
+
const providerLC = provider.name.toLowerCase();
|
|
3432
|
+
for (const c of consumerContracts) {
|
|
3433
|
+
if (c.name.toLowerCase().includes(providerLC) || providerLC.includes(c.name.toLowerCase())) {
|
|
3434
|
+
if (c.name.length >= 4 && provider.name.length >= 4) {
|
|
3435
|
+
links.push({
|
|
3436
|
+
providerRepo: provider.repoName,
|
|
3437
|
+
providerContract: provider.name,
|
|
3438
|
+
consumerRepo: c.repoName,
|
|
3439
|
+
consumerContract: c.name,
|
|
3440
|
+
matchKind: "name-match",
|
|
3441
|
+
confidence: 0.4
|
|
3442
|
+
});
|
|
3443
|
+
}
|
|
3444
|
+
}
|
|
3445
|
+
}
|
|
3446
|
+
}
|
|
3447
|
+
}
|
|
3448
|
+
}
|
|
3449
|
+
}
|
|
3450
|
+
const seen = /* @__PURE__ */ new Map();
|
|
3451
|
+
for (const link of links) {
|
|
3452
|
+
const key = `${link.providerRepo}:${link.providerContract}:${link.consumerRepo}:${link.consumerContract}`;
|
|
3453
|
+
const existing = seen.get(key);
|
|
3454
|
+
if (!existing || link.confidence > existing.confidence) {
|
|
3455
|
+
seen.set(key, link);
|
|
3456
|
+
}
|
|
3457
|
+
}
|
|
3458
|
+
return [...seen.values()].sort((a, b) => b.confidence - a.confidence);
|
|
3459
|
+
}
|
|
3460
|
+
async function syncGroup(group) {
|
|
3461
|
+
const registry = loadRegistry();
|
|
3462
|
+
const allContracts = [];
|
|
3463
|
+
for (const member of group.members) {
|
|
3464
|
+
const regEntry = registry.find((r) => r.name === member.registryName);
|
|
3465
|
+
if (!regEntry) {
|
|
3466
|
+
console.warn(` \u26A0 Registry entry "${member.registryName}" not found \u2014 skipping ${member.groupPath}`);
|
|
3467
|
+
continue;
|
|
3468
|
+
}
|
|
3469
|
+
const dbPath = path6.join(regEntry.path, ".code-intel", "graph.db");
|
|
3470
|
+
if (!fs8.existsSync(dbPath)) {
|
|
3471
|
+
console.warn(` \u26A0 No index at ${dbPath} \u2014 run \`code-intel analyze ${regEntry.path}\` first`);
|
|
3472
|
+
continue;
|
|
3473
|
+
}
|
|
3474
|
+
const graph = createKnowledgeGraph();
|
|
3475
|
+
const db = new DbManager(dbPath);
|
|
3476
|
+
try {
|
|
3477
|
+
await db.init();
|
|
3478
|
+
await loadGraphFromDB(graph, db);
|
|
3479
|
+
db.close();
|
|
3480
|
+
} catch (err) {
|
|
3481
|
+
db.close();
|
|
3482
|
+
console.warn(` \u26A0 Could not load graph for "${member.registryName}": ${err instanceof Error ? err.message : err}`);
|
|
3483
|
+
continue;
|
|
3484
|
+
}
|
|
3485
|
+
const contracts = extractContracts(graph, member.registryName, regEntry.path);
|
|
3486
|
+
console.log(` \u2713 ${member.registryName} (${member.groupPath}): ${contracts.length} contracts`);
|
|
3487
|
+
allContracts.push(...contracts);
|
|
3488
|
+
}
|
|
3489
|
+
const links = matchContracts(allContracts);
|
|
3490
|
+
return {
|
|
3491
|
+
groupName: group.name,
|
|
3492
|
+
syncedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3493
|
+
memberCount: group.members.length,
|
|
3494
|
+
contracts: allContracts,
|
|
3495
|
+
links
|
|
3496
|
+
};
|
|
3497
|
+
}
|
|
3498
|
+
async function queryGroup(group, query, limit = 20) {
|
|
3499
|
+
const registry = loadRegistry();
|
|
3500
|
+
const perRepo = [];
|
|
3501
|
+
const allRankings = [];
|
|
3502
|
+
for (const member of group.members) {
|
|
3503
|
+
const regEntry = registry.find((r) => r.name === member.registryName);
|
|
3504
|
+
if (!regEntry) continue;
|
|
3505
|
+
const dbPath = path6.join(regEntry.path, ".code-intel", "graph.db");
|
|
3506
|
+
if (!fs8.existsSync(dbPath)) continue;
|
|
3507
|
+
const graph = createKnowledgeGraph();
|
|
3508
|
+
const db = new DbManager(dbPath);
|
|
3509
|
+
try {
|
|
3510
|
+
await db.init();
|
|
3511
|
+
await loadGraphFromDB(graph, db);
|
|
3512
|
+
db.close();
|
|
3513
|
+
} catch {
|
|
3514
|
+
db.close();
|
|
3515
|
+
continue;
|
|
3516
|
+
}
|
|
3517
|
+
const results = textSearch(graph, query, limit);
|
|
3518
|
+
const taggedResults = results.map((r) => ({
|
|
3519
|
+
...r,
|
|
3520
|
+
snippet: `[${member.registryName}] ${r.snippet ?? ""}`.trim()
|
|
3521
|
+
}));
|
|
3522
|
+
perRepo.push({
|
|
3523
|
+
repoName: member.registryName,
|
|
3524
|
+
repoPath: regEntry.path,
|
|
3525
|
+
groupPath: member.groupPath,
|
|
3526
|
+
results: taggedResults
|
|
3527
|
+
});
|
|
3528
|
+
allRankings.push(taggedResults);
|
|
3529
|
+
}
|
|
3530
|
+
const merged = reciprocalRankFusion(...allRankings).slice(0, limit);
|
|
3531
|
+
return { perRepo, merged };
|
|
3532
|
+
}
|
|
3533
|
+
|
|
3534
|
+
// src/http/app.ts
|
|
3535
|
+
var __dirname$1 = path6.dirname(fileURLToPath(import.meta.url));
|
|
3536
|
+
var WEB_DIST = path6.resolve(__dirname$1, "..", "..", "..", "web", "dist");
|
|
3537
|
+
function createApp(graph, repoName, workspaceRoot) {
|
|
3538
|
+
const app = express();
|
|
3539
|
+
app.use(cors({ origin: true }));
|
|
3540
|
+
app.use(express.json({ limit: "10mb" }));
|
|
3541
|
+
let vectorIndex = null;
|
|
3542
|
+
let vectorIndexBuilding = false;
|
|
3543
|
+
let vectorIndexReady = false;
|
|
3544
|
+
async function ensureVectorIndex() {
|
|
3545
|
+
if (vectorIndexReady && vectorIndex) return vectorIndex;
|
|
3546
|
+
if (!workspaceRoot || vectorIndexBuilding) return null;
|
|
3547
|
+
vectorIndexBuilding = true;
|
|
3548
|
+
try {
|
|
3549
|
+
const { embedNodes: embedNodes2 } = await Promise.resolve().then(() => (init_embedder(), embedder_exports));
|
|
3550
|
+
const dbPath = getVectorDbPath(workspaceRoot);
|
|
3551
|
+
const db = new DbManager(dbPath);
|
|
3552
|
+
await db.init();
|
|
3553
|
+
const idx = new VectorIndex(db);
|
|
3554
|
+
await idx.init();
|
|
3555
|
+
const alreadyBuilt = await idx.isBuilt();
|
|
3556
|
+
if (!alreadyBuilt) {
|
|
3557
|
+
console.log(" [vector] Building embeddings\u2026");
|
|
3558
|
+
const nodes = await embedNodes2(graph, {
|
|
3559
|
+
onProgress: (done, total) => {
|
|
3560
|
+
if (done % 50 === 0 || done === total) process.stdout.write(`\r [vector] ${done}/${total}`);
|
|
3561
|
+
}
|
|
3562
|
+
});
|
|
3563
|
+
console.log("");
|
|
3564
|
+
await idx.buildIndex(nodes);
|
|
3565
|
+
console.log(` [vector] Index built: ${nodes.length} embeddings`);
|
|
3566
|
+
} else {
|
|
3567
|
+
console.log(" [vector] Index already exists, skipping rebuild.");
|
|
3568
|
+
}
|
|
3569
|
+
vectorIndex = idx;
|
|
3570
|
+
vectorIndexReady = true;
|
|
3571
|
+
return idx;
|
|
3572
|
+
} catch (err) {
|
|
3573
|
+
console.warn(" [vector] Index build failed:", err instanceof Error ? err.message : err);
|
|
3574
|
+
return null;
|
|
3575
|
+
} finally {
|
|
3576
|
+
vectorIndexBuilding = false;
|
|
3577
|
+
}
|
|
3578
|
+
}
|
|
3579
|
+
if (workspaceRoot) {
|
|
3580
|
+
setImmediate(() => ensureVectorIndex().catch(() => {
|
|
3581
|
+
}));
|
|
3582
|
+
}
|
|
3583
|
+
app.get("/api/health", (_req, res) => {
|
|
3584
|
+
res.json({ status: "ok", nodes: graph.size.nodes, edges: graph.size.edges });
|
|
3585
|
+
});
|
|
3586
|
+
app.get("/api/repos", (_req, res) => {
|
|
3587
|
+
res.json([{ name: repoName, nodes: graph.size.nodes, edges: graph.size.edges }]);
|
|
3588
|
+
});
|
|
3589
|
+
app.get("/api/graph/:repo", (_req, res) => {
|
|
3590
|
+
const nodes = [...graph.allNodes()];
|
|
3591
|
+
const edges = [...graph.allEdges()];
|
|
3592
|
+
res.json({ nodes, edges });
|
|
3593
|
+
});
|
|
3594
|
+
app.post("/api/search", (req, res) => {
|
|
3595
|
+
const { query, limit } = req.body;
|
|
3596
|
+
const results = textSearch(graph, query, limit ?? 20);
|
|
3597
|
+
res.json({ results });
|
|
3598
|
+
});
|
|
3599
|
+
app.post("/api/vector-search", async (req, res) => {
|
|
3600
|
+
const { query, limit = 10 } = req.body;
|
|
3601
|
+
if (!query) {
|
|
3602
|
+
res.status(400).json({ error: "Missing query" });
|
|
3603
|
+
return;
|
|
3604
|
+
}
|
|
3605
|
+
const idx = await ensureVectorIndex();
|
|
3606
|
+
if (!idx) {
|
|
3607
|
+
const results = textSearch(graph, query, limit);
|
|
3608
|
+
res.json({ results, source: "text-fallback", vectorReady: false });
|
|
3609
|
+
return;
|
|
3610
|
+
}
|
|
3611
|
+
try {
|
|
3612
|
+
const { pipeline } = await import('@huggingface/transformers');
|
|
3613
|
+
const embedder = await pipeline("feature-extraction", "Xenova/all-MiniLM-L6-v2");
|
|
3614
|
+
const out = await embedder(query, { pooling: "mean", normalize: true });
|
|
3615
|
+
const queryEmbedding = Array.from(out.data);
|
|
3616
|
+
const hits = await idx.search(queryEmbedding, limit);
|
|
3617
|
+
const results = hits.map((h) => ({
|
|
3618
|
+
nodeId: h.nodeId,
|
|
3619
|
+
name: h.name,
|
|
3620
|
+
kind: h.kind,
|
|
3621
|
+
filePath: h.filePath,
|
|
3622
|
+
score: h.score
|
|
3623
|
+
}));
|
|
3624
|
+
res.json({ results, source: "vector", vectorReady: true });
|
|
3625
|
+
} catch (err) {
|
|
3626
|
+
const results = textSearch(graph, query, limit);
|
|
3627
|
+
res.json({ results, source: "text-fallback", vectorReady: false, error: err instanceof Error ? err.message : String(err) });
|
|
3628
|
+
}
|
|
3629
|
+
});
|
|
3630
|
+
app.get("/api/vector-status", (_req, res) => {
|
|
3631
|
+
res.json({ ready: vectorIndexReady, building: vectorIndexBuilding });
|
|
3632
|
+
});
|
|
3633
|
+
app.post("/api/files/read", (req, res) => {
|
|
3634
|
+
const { file_path } = req.body;
|
|
3635
|
+
try {
|
|
3636
|
+
const content = fs8.readFileSync(file_path, "utf-8");
|
|
3637
|
+
res.json({ content });
|
|
3638
|
+
} catch {
|
|
3639
|
+
res.status(404).json({ error: "File not found" });
|
|
3640
|
+
}
|
|
3641
|
+
});
|
|
3642
|
+
app.post("/api/grep", (req, res) => {
|
|
3643
|
+
const { pattern, file_paths } = req.body;
|
|
3644
|
+
const results = [];
|
|
3645
|
+
try {
|
|
3646
|
+
const regex = new RegExp(pattern, "gi");
|
|
3647
|
+
const paths = file_paths ?? [];
|
|
3648
|
+
if (paths.length === 0) {
|
|
3649
|
+
for (const node of graph.allNodes()) {
|
|
3650
|
+
if (node.kind === "file" && node.content) {
|
|
3651
|
+
const lines = node.content.split("\n");
|
|
3652
|
+
for (let i = 0; i < lines.length; i++) {
|
|
3653
|
+
if (regex.test(lines[i])) {
|
|
3654
|
+
results.push({ file: node.filePath, line: i + 1, text: lines[i].trim() });
|
|
3655
|
+
}
|
|
3656
|
+
regex.lastIndex = 0;
|
|
3657
|
+
}
|
|
3658
|
+
}
|
|
3659
|
+
}
|
|
3660
|
+
}
|
|
3661
|
+
res.json({ results: results.slice(0, 100) });
|
|
3662
|
+
} catch {
|
|
3663
|
+
res.status(400).json({ error: "Invalid regex pattern" });
|
|
3664
|
+
}
|
|
3665
|
+
});
|
|
3666
|
+
app.post("/api/cypher", async (req, res) => {
|
|
3667
|
+
const { query: q } = req.body;
|
|
3668
|
+
if (!q) {
|
|
3669
|
+
res.status(400).json({ error: "Missing query" });
|
|
3670
|
+
return;
|
|
3671
|
+
}
|
|
3672
|
+
if (workspaceRoot) {
|
|
3673
|
+
try {
|
|
3674
|
+
const dbPath = getDbPath(workspaceRoot);
|
|
3675
|
+
const dbm = new DbManager(dbPath);
|
|
3676
|
+
await dbm.init();
|
|
3677
|
+
const rows = await dbm.query(q);
|
|
3678
|
+
dbm.close();
|
|
3679
|
+
res.json({ results: rows });
|
|
3680
|
+
return;
|
|
3681
|
+
} catch (err) {
|
|
3682
|
+
}
|
|
3683
|
+
}
|
|
3684
|
+
try {
|
|
3685
|
+
const nameMatch = q?.match(/name\s*=\s*['"]([^'"]+)['"]/i);
|
|
3686
|
+
if (nameMatch) {
|
|
3687
|
+
const name = nameMatch[1];
|
|
3688
|
+
const results = [];
|
|
3689
|
+
for (const node of graph.allNodes()) {
|
|
3690
|
+
if (node.name === name) {
|
|
3691
|
+
const incoming = [...graph.findEdgesTo(node.id)];
|
|
3692
|
+
const outgoing = [...graph.findEdgesFrom(node.id)];
|
|
3693
|
+
results.push({ node, incoming: incoming.length, outgoing: outgoing.length });
|
|
3694
|
+
}
|
|
3695
|
+
}
|
|
3696
|
+
res.json({ results });
|
|
3697
|
+
return;
|
|
3698
|
+
}
|
|
3699
|
+
const kindMatch = q?.match(/:\s*(\w+)/);
|
|
3700
|
+
if (kindMatch) {
|
|
3701
|
+
const kind = kindMatch[1];
|
|
3702
|
+
const results = [];
|
|
3703
|
+
for (const node of graph.allNodes()) {
|
|
3704
|
+
if (node.kind === kind) results.push(node);
|
|
3705
|
+
if (results.length >= 50) break;
|
|
3706
|
+
}
|
|
3707
|
+
res.json({ results });
|
|
3708
|
+
return;
|
|
3709
|
+
}
|
|
3710
|
+
res.json({ results: [], message: "Query not recognized." });
|
|
3711
|
+
} catch {
|
|
3712
|
+
res.status(400).json({ error: "Invalid query" });
|
|
3713
|
+
}
|
|
3714
|
+
});
|
|
3715
|
+
app.get("/api/nodes/:id", (req, res) => {
|
|
3716
|
+
const nodeId = decodeURIComponent(req.params.id);
|
|
3717
|
+
const node = graph.getNode(nodeId);
|
|
3718
|
+
if (!node) {
|
|
3719
|
+
res.status(404).json({ error: "Node not found" });
|
|
3720
|
+
return;
|
|
3721
|
+
}
|
|
3722
|
+
const incoming = [...graph.findEdgesTo(nodeId)];
|
|
3723
|
+
const outgoing = [...graph.findEdgesFrom(nodeId)];
|
|
3724
|
+
res.json({
|
|
3725
|
+
node,
|
|
3726
|
+
callers: incoming.filter((e) => e.kind === "calls").map((e) => ({
|
|
3727
|
+
id: e.source,
|
|
3728
|
+
name: graph.getNode(e.source)?.name,
|
|
3729
|
+
weight: e.weight
|
|
3730
|
+
})),
|
|
3731
|
+
callees: outgoing.filter((e) => e.kind === "calls").map((e) => ({
|
|
3732
|
+
id: e.target,
|
|
3733
|
+
name: graph.getNode(e.target)?.name,
|
|
3734
|
+
weight: e.weight
|
|
3735
|
+
})),
|
|
3736
|
+
imports: outgoing.filter((e) => e.kind === "imports").map((e) => ({
|
|
3737
|
+
id: e.target,
|
|
3738
|
+
name: graph.getNode(e.target)?.name
|
|
3739
|
+
})),
|
|
3740
|
+
importedBy: incoming.filter((e) => e.kind === "imports").map((e) => ({
|
|
3741
|
+
id: e.source,
|
|
3742
|
+
name: graph.getNode(e.source)?.name
|
|
3743
|
+
})),
|
|
3744
|
+
extends: outgoing.filter((e) => e.kind === "extends").map((e) => ({
|
|
3745
|
+
id: e.target,
|
|
3746
|
+
name: graph.getNode(e.target)?.name
|
|
3747
|
+
})),
|
|
3748
|
+
implementsEdges: outgoing.filter((e) => e.kind === "implements").map((e) => ({
|
|
3749
|
+
id: e.target,
|
|
3750
|
+
name: graph.getNode(e.target)?.name
|
|
3751
|
+
})),
|
|
3752
|
+
members: outgoing.filter((e) => e.kind === "has_member").map((e) => ({
|
|
3753
|
+
id: e.target,
|
|
3754
|
+
name: graph.getNode(e.target)?.name,
|
|
3755
|
+
kind: graph.getNode(e.target)?.kind
|
|
3756
|
+
})),
|
|
3757
|
+
cluster: incoming.filter((e) => e.kind === "belongs_to").map((e) => graph.getNode(e.target)?.name)[0]
|
|
3758
|
+
});
|
|
3759
|
+
});
|
|
3760
|
+
app.post("/api/blast-radius", (req, res) => {
|
|
3761
|
+
const { target, direction = "both", max_hops = 5 } = req.body;
|
|
3762
|
+
let targetNode = null;
|
|
3763
|
+
for (const node of graph.allNodes()) {
|
|
3764
|
+
if (node.name === target || node.id === target) {
|
|
3765
|
+
targetNode = node;
|
|
3766
|
+
break;
|
|
3767
|
+
}
|
|
3768
|
+
}
|
|
3769
|
+
if (!targetNode) {
|
|
3770
|
+
res.status(404).json({ error: `Symbol "${target}" not found` });
|
|
3771
|
+
return;
|
|
3772
|
+
}
|
|
3773
|
+
const affected = /* @__PURE__ */ new Map();
|
|
3774
|
+
const queue = [{ id: targetNode.id, depth: 0 }];
|
|
3775
|
+
const visited = /* @__PURE__ */ new Set();
|
|
3776
|
+
while (queue.length > 0) {
|
|
3777
|
+
const { id, depth } = queue.shift();
|
|
3778
|
+
if (visited.has(id) || depth > max_hops) continue;
|
|
3779
|
+
visited.add(id);
|
|
3780
|
+
const node = graph.getNode(id);
|
|
3781
|
+
if (node) {
|
|
3782
|
+
affected.set(id, { name: node.name, kind: node.kind, depth });
|
|
3783
|
+
}
|
|
3784
|
+
if (direction === "callers" || direction === "both") {
|
|
3785
|
+
for (const edge of graph.findEdgesTo(id)) {
|
|
3786
|
+
if (edge.kind === "calls" || edge.kind === "imports") {
|
|
3787
|
+
queue.push({ id: edge.source, depth: depth + 1 });
|
|
3788
|
+
}
|
|
3789
|
+
}
|
|
3790
|
+
}
|
|
3791
|
+
if (direction === "callees" || direction === "both") {
|
|
3792
|
+
for (const edge of graph.findEdgesFrom(id)) {
|
|
3793
|
+
if (edge.kind === "calls" || edge.kind === "imports") {
|
|
3794
|
+
queue.push({ id: edge.target, depth: depth + 1 });
|
|
3795
|
+
}
|
|
3796
|
+
}
|
|
3797
|
+
}
|
|
3798
|
+
}
|
|
3799
|
+
res.json({
|
|
3800
|
+
target: targetNode.name,
|
|
3801
|
+
affectedCount: [...affected.values()].filter((a) => a.depth > 0).length,
|
|
3802
|
+
affected: [...affected.entries()].map(([id, info]) => ({ id, ...info })).filter((a) => a.depth > 0)
|
|
3803
|
+
});
|
|
3804
|
+
});
|
|
3805
|
+
app.get("/api/flows", (_req, res) => {
|
|
3806
|
+
const flows = [];
|
|
3807
|
+
for (const node of graph.allNodes()) {
|
|
3808
|
+
if (node.kind === "flow") {
|
|
3809
|
+
flows.push({
|
|
3810
|
+
id: node.id,
|
|
3811
|
+
name: node.name,
|
|
3812
|
+
steps: node.metadata?.steps
|
|
3813
|
+
});
|
|
3814
|
+
}
|
|
3815
|
+
}
|
|
3816
|
+
res.json({ flows });
|
|
3817
|
+
});
|
|
3818
|
+
app.get("/api/clusters", (_req, res) => {
|
|
3819
|
+
const clusters = [];
|
|
3820
|
+
for (const node of graph.allNodes()) {
|
|
3821
|
+
if (node.kind === "cluster") {
|
|
3822
|
+
clusters.push({
|
|
3823
|
+
id: node.id,
|
|
3824
|
+
name: node.name,
|
|
3825
|
+
memberCount: node.metadata?.memberCount ?? 0
|
|
3826
|
+
});
|
|
3827
|
+
}
|
|
3828
|
+
}
|
|
3829
|
+
res.json({ clusters });
|
|
3830
|
+
});
|
|
3831
|
+
app.get("/api/groups", (_req, res) => {
|
|
3832
|
+
const groups = listGroups();
|
|
3833
|
+
res.json(groups.map((g) => ({
|
|
3834
|
+
name: g.name,
|
|
3835
|
+
memberCount: g.members.length,
|
|
3836
|
+
lastSync: g.lastSync ?? null,
|
|
3837
|
+
createdAt: g.createdAt
|
|
3838
|
+
})));
|
|
3839
|
+
});
|
|
3840
|
+
app.get("/api/groups/:name", (req, res) => {
|
|
3841
|
+
const group = loadGroup(req.params.name);
|
|
3842
|
+
if (!group) {
|
|
3843
|
+
res.status(404).json({ error: "Group not found" });
|
|
3844
|
+
return;
|
|
3845
|
+
}
|
|
3846
|
+
res.json(group);
|
|
3847
|
+
});
|
|
3848
|
+
app.get("/api/groups/:name/contracts", (req, res) => {
|
|
3849
|
+
const result = loadSyncResult(req.params.name);
|
|
3850
|
+
if (!result) {
|
|
3851
|
+
res.status(404).json({ error: "No sync result. Run sync first." });
|
|
3852
|
+
return;
|
|
3853
|
+
}
|
|
3854
|
+
res.json(result);
|
|
3855
|
+
});
|
|
3856
|
+
app.post("/api/groups/:name/sync", async (req, res) => {
|
|
3857
|
+
const group = loadGroup(req.params.name);
|
|
3858
|
+
if (!group) {
|
|
3859
|
+
res.status(404).json({ error: "Group not found" });
|
|
3860
|
+
return;
|
|
3861
|
+
}
|
|
3862
|
+
try {
|
|
3863
|
+
const result = await syncGroup(group);
|
|
3864
|
+
saveSyncResult(result);
|
|
3865
|
+
group.lastSync = result.syncedAt;
|
|
3866
|
+
const { saveGroup: saveGroup2 } = await Promise.resolve().then(() => (init_group_registry(), group_registry_exports));
|
|
3867
|
+
saveGroup2(group);
|
|
3868
|
+
res.json(result);
|
|
3869
|
+
} catch (err) {
|
|
3870
|
+
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
3871
|
+
}
|
|
3872
|
+
});
|
|
3873
|
+
app.post("/api/groups/:name/search", async (req, res) => {
|
|
3874
|
+
const group = loadGroup(req.params.name);
|
|
3875
|
+
if (!group) {
|
|
3876
|
+
res.status(404).json({ error: "Group not found" });
|
|
3877
|
+
return;
|
|
3878
|
+
}
|
|
3879
|
+
const { q, limit = 20 } = req.body;
|
|
3880
|
+
if (!q) {
|
|
3881
|
+
res.status(400).json({ error: "Missing query q" });
|
|
3882
|
+
return;
|
|
3883
|
+
}
|
|
3884
|
+
try {
|
|
3885
|
+
const { perRepo, merged } = await queryGroup(group, q, limit);
|
|
3886
|
+
res.json({ perRepo, merged });
|
|
3887
|
+
} catch (err) {
|
|
3888
|
+
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
3889
|
+
}
|
|
3890
|
+
});
|
|
3891
|
+
app.get("/api/groups/:name/graph", async (req, res) => {
|
|
3892
|
+
const group = loadGroup(req.params.name);
|
|
3893
|
+
if (!group) {
|
|
3894
|
+
res.status(404).json({ error: "Group not found" });
|
|
3895
|
+
return;
|
|
3896
|
+
}
|
|
3897
|
+
const registry = loadRegistry();
|
|
3898
|
+
const mergedGraph = createKnowledgeGraph();
|
|
3899
|
+
for (const member of group.members) {
|
|
3900
|
+
const regEntry = registry.find((r) => r.name === member.registryName);
|
|
3901
|
+
if (!regEntry) continue;
|
|
3902
|
+
const dbPath = path6.join(regEntry.path, ".code-intel", "graph.db");
|
|
3903
|
+
if (!fs8.existsSync(dbPath)) continue;
|
|
3904
|
+
const db = new DbManager(dbPath);
|
|
3905
|
+
try {
|
|
3906
|
+
await db.init();
|
|
3907
|
+
await loadGraphFromDB(mergedGraph, db);
|
|
3908
|
+
db.close();
|
|
3909
|
+
} catch {
|
|
3910
|
+
db.close();
|
|
3911
|
+
}
|
|
3912
|
+
}
|
|
3913
|
+
res.json({ nodes: [...mergedGraph.allNodes()], edges: [...mergedGraph.allEdges()] });
|
|
3914
|
+
});
|
|
3915
|
+
if (fs8.existsSync(WEB_DIST)) {
|
|
3916
|
+
app.use(express.static(WEB_DIST));
|
|
3917
|
+
app.get("/{*path}", (_req, res) => {
|
|
3918
|
+
res.sendFile(path6.join(WEB_DIST, "index.html"));
|
|
3919
|
+
});
|
|
3920
|
+
}
|
|
3921
|
+
return app;
|
|
3922
|
+
}
|
|
3923
|
+
function startHttpServer(graph, repoName, port = 4747, workspaceRoot) {
|
|
3924
|
+
const app = createApp(graph, repoName, workspaceRoot);
|
|
3925
|
+
app.listen(port, () => {
|
|
3926
|
+
console.log(`Code Intelligence server running at http://localhost:${port}`);
|
|
3927
|
+
console.log(` Graph: ${graph.size.nodes} nodes, ${graph.size.edges} edges`);
|
|
3928
|
+
});
|
|
3929
|
+
}
|
|
3930
|
+
|
|
3931
|
+
// src/multi-repo/index.ts
|
|
3932
|
+
init_group_registry();
|
|
3933
|
+
|
|
3934
|
+
// src/multi-repo/cross-repo-search.ts
|
|
3935
|
+
function mergeSearchResults(...perRepoResults) {
|
|
3936
|
+
return reciprocalRankFusion(...perRepoResults);
|
|
3937
|
+
}
|
|
3938
|
+
|
|
3939
|
+
export { AstCache, BindingTracker, DbManager, addBinding, addClustersToGraph, addMember, buildCallEdges, buildHeritageEdges, classifyCall, clusterPhase, computeMRO, createApp, createKnowledgeGraph, createMcpServer, createScope, deleteGroup, detectCommunities, detectOverrides, findEntryPoints, flowPhase, generateEdgeId, generateNodeId, getAllLanguageModules, getDbPath, getLanguage, getLanguageModule, getParser, groupExists, initParser, listGroups, loadGraphToDB, loadGroup, loadMetadata, loadRegistry, loadSyncResult, mergeSearchResults, parsePhase, parseSource, queryGroup, reciprocalRankFusion, removeMember, removeRepo, resolveBinding, resolveImports, resolvePhase, runPipeline, runQuery, saveGroup, saveMetadata, saveSyncResult, scanPhase, startHttpServer, startMcpStdio, structurePhase, syncGroup, textSearch, topologicalSort, traceFlow, upsertRepo, validateDAG };
|
|
3940
|
+
//# sourceMappingURL=index.js.map
|
|
18
3941
|
//# sourceMappingURL=index.js.map
|