@optave/codegraph 3.12.0 → 3.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +83 -46
- package/dist/ast-analysis/engine.d.ts.map +1 -1
- package/dist/ast-analysis/engine.js +38 -40
- package/dist/ast-analysis/engine.js.map +1 -1
- package/dist/ast-analysis/rules/b2.d.ts +7 -0
- package/dist/ast-analysis/rules/b2.d.ts.map +1 -0
- package/dist/ast-analysis/rules/b2.js +240 -0
- package/dist/ast-analysis/rules/b2.js.map +1 -0
- package/dist/ast-analysis/rules/b3.d.ts +6 -0
- package/dist/ast-analysis/rules/b3.d.ts.map +1 -0
- package/dist/ast-analysis/rules/b3.js +105 -0
- package/dist/ast-analysis/rules/b3.js.map +1 -0
- package/dist/ast-analysis/rules/b4.d.ts +9 -0
- package/dist/ast-analysis/rules/b4.d.ts.map +1 -0
- package/dist/ast-analysis/rules/b4.js +361 -0
- package/dist/ast-analysis/rules/b4.js.map +1 -0
- package/dist/ast-analysis/rules/b5.d.ts +4 -0
- package/dist/ast-analysis/rules/b5.d.ts.map +1 -0
- package/dist/ast-analysis/rules/b5.js +52 -0
- package/dist/ast-analysis/rules/b5.js.map +1 -0
- package/dist/ast-analysis/rules/c.d.ts +4 -0
- package/dist/ast-analysis/rules/c.d.ts.map +1 -0
- package/dist/ast-analysis/rules/c.js +143 -0
- package/dist/ast-analysis/rules/c.js.map +1 -0
- package/dist/ast-analysis/rules/index.d.ts.map +1 -1
- package/dist/ast-analysis/rules/index.js +34 -0
- package/dist/ast-analysis/rules/index.js.map +1 -1
- package/dist/ast-analysis/rules/javascript.d.ts.map +1 -1
- package/dist/ast-analysis/rules/javascript.js +3 -0
- package/dist/ast-analysis/rules/javascript.js.map +1 -1
- package/dist/ast-analysis/shared.d.ts.map +1 -1
- package/dist/ast-analysis/shared.js +2 -0
- package/dist/ast-analysis/shared.js.map +1 -1
- package/dist/ast-analysis/visitor-utils.d.ts +1 -0
- package/dist/ast-analysis/visitor-utils.d.ts.map +1 -1
- package/dist/ast-analysis/visitor-utils.js +5 -0
- package/dist/ast-analysis/visitor-utils.js.map +1 -1
- package/dist/ast-analysis/visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitor.js +60 -47
- package/dist/ast-analysis/visitor.js.map +1 -1
- package/dist/ast-analysis/visitors/cfg-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/cfg-visitor.js +126 -76
- package/dist/ast-analysis/visitors/cfg-visitor.js.map +1 -1
- package/dist/ast-analysis/visitors/complexity-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/complexity-visitor.js +27 -15
- package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -1
- package/dist/ast-analysis/visitors/dataflow-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/dataflow-visitor.js +54 -21
- package/dist/ast-analysis/visitors/dataflow-visitor.js.map +1 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/audit.js +2 -1
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/batch.d.ts.map +1 -1
- package/dist/cli/commands/batch.js +1 -0
- package/dist/cli/commands/batch.js.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/build.js +6 -1
- package/dist/cli/commands/build.js.map +1 -1
- package/dist/cli/commands/config.d.ts +3 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +275 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/roles.d.ts.map +1 -1
- package/dist/cli/commands/roles.js +6 -1
- package/dist/cli/commands/roles.js.map +1 -1
- package/dist/cli/commands/triage.js +1 -1
- package/dist/cli/commands/triage.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +10 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/shared/options.d.ts +2 -1
- package/dist/cli/shared/options.d.ts.map +1 -1
- package/dist/cli/shared/options.js +11 -1
- package/dist/cli/shared/options.js.map +1 -1
- package/dist/cli/types.d.ts +2 -0
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/db/better-sqlite3.d.ts +2 -1
- package/dist/db/better-sqlite3.d.ts.map +1 -1
- package/dist/db/better-sqlite3.js.map +1 -1
- package/dist/db/connection.d.ts +7 -1
- package/dist/db/connection.d.ts.map +1 -1
- package/dist/db/connection.js +20 -5
- package/dist/db/connection.js.map +1 -1
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +1 -1
- package/dist/db/index.js.map +1 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +69 -1
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/repository/build-stmts.d.ts.map +1 -1
- package/dist/db/repository/build-stmts.js +18 -0
- package/dist/db/repository/build-stmts.js.map +1 -1
- package/dist/db/repository/dataflow.d.ts +5 -0
- package/dist/db/repository/dataflow.d.ts.map +1 -1
- package/dist/db/repository/dataflow.js +14 -0
- package/dist/db/repository/dataflow.js.map +1 -1
- package/dist/db/repository/index.d.ts +1 -1
- package/dist/db/repository/index.d.ts.map +1 -1
- package/dist/db/repository/index.js +1 -1
- package/dist/db/repository/index.js.map +1 -1
- package/dist/db/repository/native-repository.d.ts.map +1 -1
- package/dist/db/repository/native-repository.js +47 -34
- package/dist/db/repository/native-repository.js.map +1 -1
- package/dist/domain/analysis/context.d.ts +2 -2
- package/dist/domain/analysis/dependencies.d.ts +2 -2
- package/dist/domain/analysis/diff-impact.d.ts +2 -2
- package/dist/domain/analysis/fn-impact.d.ts +3 -1
- package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
- package/dist/domain/analysis/fn-impact.js +4 -0
- package/dist/domain/analysis/fn-impact.js.map +1 -1
- package/dist/domain/analysis/implementations.d.ts +2 -2
- package/dist/domain/analysis/module-map.d.ts.map +1 -1
- package/dist/domain/analysis/module-map.js +32 -5
- package/dist/domain/analysis/module-map.js.map +1 -1
- package/dist/domain/analysis/roles.d.ts +7 -1
- package/dist/domain/analysis/roles.d.ts.map +1 -1
- package/dist/domain/analysis/roles.js +16 -0
- package/dist/domain/analysis/roles.js.map +1 -1
- package/dist/domain/analysis/symbol-lookup.d.ts +4 -4
- package/dist/domain/graph/builder/call-resolver.d.ts +29 -13
- package/dist/domain/graph/builder/call-resolver.d.ts.map +1 -1
- package/dist/domain/graph/builder/call-resolver.js +125 -205
- package/dist/domain/graph/builder/call-resolver.js.map +1 -1
- package/dist/domain/graph/builder/cha.d.ts +9 -1
- package/dist/domain/graph/builder/cha.d.ts.map +1 -1
- package/dist/domain/graph/builder/cha.js +17 -2
- package/dist/domain/graph/builder/cha.js.map +1 -1
- package/dist/domain/graph/builder/context.d.ts +1 -0
- package/dist/domain/graph/builder/context.d.ts.map +1 -1
- package/dist/domain/graph/builder/context.js.map +1 -1
- package/dist/domain/graph/builder/helpers.d.ts +24 -1
- package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
- package/dist/domain/graph/builder/helpers.js +174 -65
- package/dist/domain/graph/builder/helpers.js.map +1 -1
- package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
- package/dist/domain/graph/builder/incremental.js +166 -97
- package/dist/domain/graph/builder/incremental.js.map +1 -1
- package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
- package/dist/domain/graph/builder/pipeline.js +46 -5
- package/dist/domain/graph/builder/pipeline.js.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.d.ts +0 -2
- package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.js +554 -538
- package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
- package/dist/domain/graph/builder/stages/collect-files.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/collect-files.js +10 -7
- package/dist/domain/graph/builder/stages/collect-files.js.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.js +3 -2
- package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
- package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/finalize.js +4 -0
- package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
- package/dist/domain/graph/builder/stages/native-orchestrator.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/native-orchestrator.js +952 -343
- package/dist/domain/graph/builder/stages/native-orchestrator.js.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.js +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
- package/dist/domain/graph/resolver/points-to.d.ts.map +1 -1
- package/dist/domain/graph/resolver/points-to.js +105 -57
- package/dist/domain/graph/resolver/points-to.js.map +1 -1
- package/dist/domain/graph/resolver/strategy.d.ts +61 -0
- package/dist/domain/graph/resolver/strategy.d.ts.map +1 -0
- package/dist/domain/graph/resolver/strategy.js +222 -0
- package/dist/domain/graph/resolver/strategy.js.map +1 -0
- package/dist/domain/graph/watcher.d.ts.map +1 -1
- package/dist/domain/graph/watcher.js +16 -9
- package/dist/domain/graph/watcher.js.map +1 -1
- package/dist/domain/parser.d.ts +16 -5
- package/dist/domain/parser.d.ts.map +1 -1
- package/dist/domain/parser.js +58 -17
- package/dist/domain/parser.js.map +1 -1
- package/dist/domain/queries.d.ts +1 -1
- package/dist/domain/queries.d.ts.map +1 -1
- package/dist/domain/queries.js +1 -1
- package/dist/domain/queries.js.map +1 -1
- package/dist/domain/wasm-worker-entry.js +13 -2
- package/dist/domain/wasm-worker-entry.js.map +1 -1
- package/dist/domain/wasm-worker-pool.d.ts.map +1 -1
- package/dist/domain/wasm-worker-pool.js +26 -5
- package/dist/domain/wasm-worker-pool.js.map +1 -1
- package/dist/domain/wasm-worker-protocol.d.ts +8 -0
- package/dist/domain/wasm-worker-protocol.d.ts.map +1 -1
- package/dist/extractors/cpp.d.ts.map +1 -1
- package/dist/extractors/cpp.js +42 -1
- package/dist/extractors/cpp.js.map +1 -1
- package/dist/extractors/cuda.d.ts.map +1 -1
- package/dist/extractors/cuda.js +42 -1
- package/dist/extractors/cuda.js.map +1 -1
- package/dist/extractors/dart.js +48 -3
- package/dist/extractors/dart.js.map +1 -1
- package/dist/extractors/groovy.js +62 -3
- package/dist/extractors/groovy.js.map +1 -1
- package/dist/extractors/helpers.d.ts +15 -2
- package/dist/extractors/helpers.d.ts.map +1 -1
- package/dist/extractors/helpers.js +45 -1
- package/dist/extractors/helpers.js.map +1 -1
- package/dist/extractors/java.d.ts.map +1 -1
- package/dist/extractors/java.js +85 -8
- package/dist/extractors/java.js.map +1 -1
- package/dist/extractors/javascript.d.ts.map +1 -1
- package/dist/extractors/javascript.js +686 -169
- package/dist/extractors/javascript.js.map +1 -1
- package/dist/extractors/kotlin.js +58 -3
- package/dist/extractors/kotlin.js.map +1 -1
- package/dist/extractors/objc.js +25 -2
- package/dist/extractors/objc.js.map +1 -1
- package/dist/extractors/scala.js +62 -2
- package/dist/extractors/scala.js.map +1 -1
- package/dist/extractors/swift.js +52 -3
- package/dist/extractors/swift.js.map +1 -1
- package/dist/features/audit.js +26 -23
- package/dist/features/audit.js.map +1 -1
- package/dist/features/boundaries.d.ts.map +1 -1
- package/dist/features/boundaries.js +12 -9
- package/dist/features/boundaries.js.map +1 -1
- package/dist/features/cfg.d.ts.map +1 -1
- package/dist/features/cfg.js +25 -18
- package/dist/features/cfg.js.map +1 -1
- package/dist/features/check.d.ts.map +1 -1
- package/dist/features/check.js +18 -5
- package/dist/features/check.js.map +1 -1
- package/dist/features/communities.d.ts +4 -2
- package/dist/features/communities.d.ts.map +1 -1
- package/dist/features/communities.js +6 -4
- package/dist/features/communities.js.map +1 -1
- package/dist/features/dataflow.d.ts +60 -0
- package/dist/features/dataflow.d.ts.map +1 -1
- package/dist/features/dataflow.js +530 -6
- package/dist/features/dataflow.js.map +1 -1
- package/dist/features/manifesto.d.ts.map +1 -1
- package/dist/features/manifesto.js +59 -72
- package/dist/features/manifesto.js.map +1 -1
- package/dist/features/sequence.d.ts.map +1 -1
- package/dist/features/sequence.js +27 -22
- package/dist/features/sequence.js.map +1 -1
- package/dist/features/snapshot.d.ts.map +1 -1
- package/dist/features/snapshot.js +36 -28
- package/dist/features/snapshot.js.map +1 -1
- package/dist/features/structure-query.d.ts +1 -1
- package/dist/features/structure-query.d.ts.map +1 -1
- package/dist/features/structure-query.js +6 -6
- package/dist/features/structure-query.js.map +1 -1
- package/dist/features/structure.d.ts.map +1 -1
- package/dist/features/structure.js +150 -62
- package/dist/features/structure.js.map +1 -1
- package/dist/features/triage.d.ts.map +1 -1
- package/dist/features/triage.js +18 -11
- package/dist/features/triage.js.map +1 -1
- package/dist/graph/algorithms/bfs.d.ts +1 -1
- package/dist/graph/algorithms/bfs.d.ts.map +1 -1
- package/dist/graph/algorithms/bfs.js +14 -13
- package/dist/graph/algorithms/bfs.js.map +1 -1
- package/dist/graph/algorithms/tarjan.d.ts.map +1 -1
- package/dist/graph/algorithms/tarjan.js +5 -0
- package/dist/graph/algorithms/tarjan.js.map +1 -1
- package/dist/graph/builders/dependency.js +28 -22
- package/dist/graph/builders/dependency.js.map +1 -1
- package/dist/graph/classifiers/roles.d.ts +10 -1
- package/dist/graph/classifiers/roles.d.ts.map +1 -1
- package/dist/graph/classifiers/roles.js +60 -6
- package/dist/graph/classifiers/roles.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/config.d.ts +87 -4
- package/dist/infrastructure/config.d.ts.map +1 -1
- package/dist/infrastructure/config.js +424 -22
- package/dist/infrastructure/config.js.map +1 -1
- package/dist/infrastructure/registry.d.ts +27 -7
- package/dist/infrastructure/registry.d.ts.map +1 -1
- package/dist/infrastructure/registry.js +79 -5
- package/dist/infrastructure/registry.js.map +1 -1
- package/dist/infrastructure/update-check.d.ts.map +1 -1
- package/dist/infrastructure/update-check.js +49 -31
- package/dist/infrastructure/update-check.js.map +1 -1
- package/dist/mcp/server.d.ts +2 -10
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools/ast-query.d.ts +1 -1
- package/dist/mcp/tools/ast-query.d.ts.map +1 -1
- package/dist/mcp/tools/audit.d.ts +1 -1
- package/dist/mcp/tools/audit.d.ts.map +1 -1
- package/dist/mcp/tools/batch-query.d.ts +1 -1
- package/dist/mcp/tools/batch-query.d.ts.map +1 -1
- package/dist/mcp/tools/branch-compare.d.ts +1 -1
- package/dist/mcp/tools/branch-compare.d.ts.map +1 -1
- package/dist/mcp/tools/brief.d.ts +1 -1
- package/dist/mcp/tools/brief.d.ts.map +1 -1
- package/dist/mcp/tools/cfg.d.ts +1 -1
- package/dist/mcp/tools/cfg.d.ts.map +1 -1
- package/dist/mcp/tools/check.d.ts +1 -1
- package/dist/mcp/tools/check.d.ts.map +1 -1
- package/dist/mcp/tools/co-changes.d.ts +1 -1
- package/dist/mcp/tools/co-changes.d.ts.map +1 -1
- package/dist/mcp/tools/code-owners.d.ts +1 -1
- package/dist/mcp/tools/code-owners.d.ts.map +1 -1
- package/dist/mcp/tools/communities.d.ts +1 -1
- package/dist/mcp/tools/communities.d.ts.map +1 -1
- package/dist/mcp/tools/complexity.d.ts +1 -1
- package/dist/mcp/tools/complexity.d.ts.map +1 -1
- package/dist/mcp/tools/context.d.ts +1 -1
- package/dist/mcp/tools/context.d.ts.map +1 -1
- package/dist/mcp/tools/dataflow.d.ts +1 -1
- package/dist/mcp/tools/dataflow.d.ts.map +1 -1
- package/dist/mcp/tools/diff-impact.d.ts +1 -1
- package/dist/mcp/tools/diff-impact.d.ts.map +1 -1
- package/dist/mcp/tools/execution-flow.d.ts +1 -1
- package/dist/mcp/tools/execution-flow.d.ts.map +1 -1
- package/dist/mcp/tools/export-graph.d.ts +1 -1
- package/dist/mcp/tools/export-graph.d.ts.map +1 -1
- package/dist/mcp/tools/file-deps.d.ts +1 -1
- package/dist/mcp/tools/file-deps.d.ts.map +1 -1
- package/dist/mcp/tools/file-exports.d.ts +1 -1
- package/dist/mcp/tools/file-exports.d.ts.map +1 -1
- package/dist/mcp/tools/find-cycles.d.ts +1 -1
- package/dist/mcp/tools/find-cycles.d.ts.map +1 -1
- package/dist/mcp/tools/fn-impact.d.ts +1 -1
- package/dist/mcp/tools/fn-impact.d.ts.map +1 -1
- package/dist/mcp/tools/impact-analysis.d.ts +1 -1
- package/dist/mcp/tools/impact-analysis.d.ts.map +1 -1
- package/dist/mcp/tools/implementations.d.ts +1 -1
- package/dist/mcp/tools/implementations.d.ts.map +1 -1
- package/dist/mcp/tools/index.d.ts +2 -5
- package/dist/mcp/tools/index.d.ts.map +1 -1
- package/dist/mcp/tools/index.js.map +1 -1
- package/dist/mcp/tools/interfaces.d.ts +1 -1
- package/dist/mcp/tools/interfaces.d.ts.map +1 -1
- package/dist/mcp/tools/list-functions.d.ts +1 -1
- package/dist/mcp/tools/list-functions.d.ts.map +1 -1
- package/dist/mcp/tools/list-repos.d.ts +1 -1
- package/dist/mcp/tools/list-repos.d.ts.map +1 -1
- package/dist/mcp/tools/module-map.d.ts +1 -1
- package/dist/mcp/tools/module-map.d.ts.map +1 -1
- package/dist/mcp/tools/node-roles.d.ts +1 -1
- package/dist/mcp/tools/node-roles.d.ts.map +1 -1
- package/dist/mcp/tools/path.d.ts +1 -1
- package/dist/mcp/tools/path.d.ts.map +1 -1
- package/dist/mcp/tools/query.d.ts +1 -1
- package/dist/mcp/tools/query.d.ts.map +1 -1
- package/dist/mcp/tools/semantic-search.d.ts +1 -1
- package/dist/mcp/tools/semantic-search.d.ts.map +1 -1
- package/dist/mcp/tools/sequence.d.ts +1 -1
- package/dist/mcp/tools/sequence.d.ts.map +1 -1
- package/dist/mcp/tools/structure.d.ts +1 -1
- package/dist/mcp/tools/structure.d.ts.map +1 -1
- package/dist/mcp/tools/symbol-children.d.ts +1 -1
- package/dist/mcp/tools/symbol-children.d.ts.map +1 -1
- package/dist/mcp/tools/triage.d.ts +1 -1
- package/dist/mcp/tools/triage.d.ts.map +1 -1
- package/dist/mcp/tools/where.d.ts +1 -1
- package/dist/mcp/tools/where.d.ts.map +1 -1
- package/dist/mcp/types.d.ts +19 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +6 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/presentation/queries-cli/index.d.ts +1 -1
- package/dist/presentation/queries-cli/index.d.ts.map +1 -1
- package/dist/presentation/queries-cli/index.js +1 -1
- package/dist/presentation/queries-cli/index.js.map +1 -1
- package/dist/presentation/queries-cli/overview.d.ts +1 -0
- package/dist/presentation/queries-cli/overview.d.ts.map +1 -1
- package/dist/presentation/queries-cli/overview.js +20 -1
- package/dist/presentation/queries-cli/overview.js.map +1 -1
- package/dist/presentation/queries-cli.d.ts +1 -1
- package/dist/presentation/queries-cli.d.ts.map +1 -1
- package/dist/presentation/queries-cli.js +1 -1
- package/dist/presentation/queries-cli.js.map +1 -1
- package/dist/presentation/structure.d.ts +1 -1
- package/dist/presentation/structure.d.ts.map +1 -1
- package/dist/presentation/structure.js +2 -2
- package/dist/presentation/structure.js.map +1 -1
- package/dist/presentation/viewer.d.ts.map +1 -1
- package/dist/presentation/viewer.js +45 -32
- package/dist/presentation/viewer.js.map +1 -1
- package/dist/shared/constants.d.ts +21 -0
- package/dist/shared/constants.d.ts.map +1 -1
- package/dist/shared/constants.js +25 -0
- package/dist/shared/constants.js.map +1 -1
- package/dist/shared/normalize.d.ts.map +1 -1
- package/dist/shared/normalize.js +12 -22
- package/dist/shared/normalize.js.map +1 -1
- package/dist/shared/paginate.d.ts +4 -17
- package/dist/shared/paginate.d.ts.map +1 -1
- package/dist/shared/paginate.js.map +1 -1
- package/dist/types.d.ts +113 -1
- package/dist/types.d.ts.map +1 -1
- package/grammars/tree-sitter-erlang.wasm +0 -0
- package/grammars/tree-sitter-gleam.wasm +0 -0
- package/package.json +7 -8
- package/src/ast-analysis/engine.ts +43 -63
- package/src/ast-analysis/rules/b2.ts +263 -0
- package/src/ast-analysis/rules/b3.ts +127 -0
- package/src/ast-analysis/rules/b4.ts +378 -0
- package/src/ast-analysis/rules/b5.ts +65 -0
- package/src/ast-analysis/rules/c.ts +157 -0
- package/src/ast-analysis/rules/index.ts +34 -0
- package/src/ast-analysis/rules/javascript.ts +3 -0
- package/src/ast-analysis/shared.ts +2 -0
- package/src/ast-analysis/visitor-utils.ts +5 -0
- package/src/ast-analysis/visitor.ts +82 -52
- package/src/ast-analysis/visitors/cfg-visitor.ts +198 -84
- package/src/ast-analysis/visitors/complexity-visitor.ts +44 -16
- package/src/ast-analysis/visitors/dataflow-visitor.ts +68 -29
- package/src/cli/commands/audit.ts +2 -1
- package/src/cli/commands/batch.ts +1 -0
- package/src/cli/commands/build.ts +6 -1
- package/src/cli/commands/config.ts +353 -0
- package/src/cli/commands/roles.ts +6 -1
- package/src/cli/commands/triage.ts +1 -1
- package/src/cli/index.ts +10 -0
- package/src/cli/shared/options.ts +11 -1
- package/src/cli/types.ts +2 -0
- package/src/db/better-sqlite3.ts +5 -4
- package/src/db/connection.ts +23 -5
- package/src/db/index.ts +1 -0
- package/src/db/migrations.ts +69 -1
- package/src/db/repository/build-stmts.ts +30 -0
- package/src/db/repository/dataflow.ts +16 -0
- package/src/db/repository/index.ts +1 -1
- package/src/db/repository/native-repository.ts +56 -40
- package/src/domain/analysis/fn-impact.ts +4 -0
- package/src/domain/analysis/module-map.ts +38 -6
- package/src/domain/analysis/roles.ts +23 -0
- package/src/domain/graph/builder/call-resolver.ts +156 -218
- package/src/domain/graph/builder/cha.ts +18 -1
- package/src/domain/graph/builder/context.ts +1 -0
- package/src/domain/graph/builder/helpers.ts +205 -67
- package/src/domain/graph/builder/incremental.ts +249 -119
- package/src/domain/graph/builder/pipeline.ts +59 -6
- package/src/domain/graph/builder/stages/build-edges.ts +783 -652
- package/src/domain/graph/builder/stages/collect-files.ts +12 -6
- package/src/domain/graph/builder/stages/detect-changes.ts +4 -2
- package/src/domain/graph/builder/stages/finalize.ts +4 -0
- package/src/domain/graph/builder/stages/native-orchestrator.ts +1214 -398
- package/src/domain/graph/builder/stages/resolve-imports.ts +1 -1
- package/src/domain/graph/resolver/points-to.ts +182 -59
- package/src/domain/graph/resolver/strategy.ts +265 -0
- package/src/domain/graph/watcher.ts +19 -9
- package/src/domain/parser.ts +57 -16
- package/src/domain/queries.ts +1 -1
- package/src/domain/wasm-worker-entry.ts +13 -2
- package/src/domain/wasm-worker-pool.ts +29 -4
- package/src/domain/wasm-worker-protocol.ts +5 -0
- package/src/extractors/cpp.ts +44 -1
- package/src/extractors/cuda.ts +44 -1
- package/src/extractors/dart.ts +48 -3
- package/src/extractors/groovy.ts +62 -2
- package/src/extractors/helpers.ts +48 -2
- package/src/extractors/java.ts +88 -8
- package/src/extractors/javascript.ts +693 -167
- package/src/extractors/kotlin.ts +57 -3
- package/src/extractors/objc.ts +25 -1
- package/src/extractors/scala.ts +63 -1
- package/src/extractors/swift.ts +46 -3
- package/src/features/audit.ts +43 -34
- package/src/features/boundaries.ts +17 -9
- package/src/features/cfg.ts +31 -22
- package/src/features/check.ts +21 -5
- package/src/features/communities.ts +28 -19
- package/src/features/dataflow.ts +755 -6
- package/src/features/manifesto.ts +76 -75
- package/src/features/sequence.ts +29 -23
- package/src/features/snapshot.ts +36 -25
- package/src/features/structure-query.ts +7 -7
- package/src/features/structure.ts +185 -55
- package/src/features/triage.ts +28 -15
- package/src/graph/algorithms/bfs.ts +13 -12
- package/src/graph/algorithms/tarjan.ts +5 -0
- package/src/graph/builders/dependency.ts +35 -23
- package/src/graph/classifiers/roles.ts +74 -7
- package/src/index.ts +5 -1
- package/src/infrastructure/config.ts +511 -23
- package/src/infrastructure/registry.ts +117 -12
- package/src/infrastructure/update-check.ts +55 -33
- package/src/mcp/server.ts +2 -8
- package/src/mcp/tools/ast-query.ts +1 -1
- package/src/mcp/tools/audit.ts +1 -1
- package/src/mcp/tools/batch-query.ts +1 -1
- package/src/mcp/tools/branch-compare.ts +1 -1
- package/src/mcp/tools/brief.ts +1 -1
- package/src/mcp/tools/cfg.ts +1 -1
- package/src/mcp/tools/check.ts +1 -1
- package/src/mcp/tools/co-changes.ts +1 -1
- package/src/mcp/tools/code-owners.ts +1 -1
- package/src/mcp/tools/communities.ts +1 -1
- package/src/mcp/tools/complexity.ts +1 -1
- package/src/mcp/tools/context.ts +1 -1
- package/src/mcp/tools/dataflow.ts +1 -1
- package/src/mcp/tools/diff-impact.ts +1 -1
- package/src/mcp/tools/execution-flow.ts +1 -1
- package/src/mcp/tools/export-graph.ts +1 -1
- package/src/mcp/tools/file-deps.ts +1 -1
- package/src/mcp/tools/file-exports.ts +1 -1
- package/src/mcp/tools/find-cycles.ts +1 -1
- package/src/mcp/tools/fn-impact.ts +1 -1
- package/src/mcp/tools/impact-analysis.ts +1 -1
- package/src/mcp/tools/implementations.ts +1 -1
- package/src/mcp/tools/index.ts +2 -5
- package/src/mcp/tools/interfaces.ts +1 -1
- package/src/mcp/tools/list-functions.ts +1 -1
- package/src/mcp/tools/list-repos.ts +1 -1
- package/src/mcp/tools/module-map.ts +1 -1
- package/src/mcp/tools/node-roles.ts +1 -1
- package/src/mcp/tools/path.ts +1 -1
- package/src/mcp/tools/query.ts +1 -1
- package/src/mcp/tools/semantic-search.ts +1 -1
- package/src/mcp/tools/sequence.ts +1 -1
- package/src/mcp/tools/structure.ts +1 -1
- package/src/mcp/tools/symbol-children.ts +1 -1
- package/src/mcp/tools/triage.ts +1 -1
- package/src/mcp/tools/where.ts +1 -1
- package/src/mcp/types.ts +21 -0
- package/src/presentation/queries-cli/index.ts +1 -1
- package/src/presentation/queries-cli/overview.ts +35 -1
- package/src/presentation/queries-cli.ts +1 -0
- package/src/presentation/structure.ts +3 -3
- package/src/presentation/viewer.ts +98 -87
- package/src/shared/constants.ts +26 -0
- package/src/shared/normalize.ts +13 -22
- package/src/shared/paginate.ts +4 -18
- package/src/types.ts +127 -1
|
@@ -90,6 +90,44 @@ interface SqliteStatement {
|
|
|
90
90
|
run(...params: unknown[]): unknown;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
/** Insert file→parent-directory contains edges (incremental-aware). */
|
|
94
|
+
function insertFileToParentEdges(
|
|
95
|
+
insertEdge: SqliteStatement,
|
|
96
|
+
getNodeIdStmt: NodeIdStmt,
|
|
97
|
+
fileSymbols: Map<string, FileSymbolData>,
|
|
98
|
+
affectedDirs: Set<string> | null,
|
|
99
|
+
): void {
|
|
100
|
+
for (const relPath of fileSymbols.keys()) {
|
|
101
|
+
const dir = normalizePath(path.dirname(relPath));
|
|
102
|
+
if (!dir || dir === '.') continue;
|
|
103
|
+
if (affectedDirs && !affectedDirs.has(dir)) continue;
|
|
104
|
+
const dirRow = getNodeIdStmt.get(dir, 'directory', dir, 0);
|
|
105
|
+
const fileRow = getNodeIdStmt.get(relPath, 'file', relPath, 0);
|
|
106
|
+
if (dirRow && fileRow) {
|
|
107
|
+
insertEdge.run(dirRow.id, fileRow.id, 'contains', 1.0, 0);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Insert child-directory→parent-directory contains edges (incremental-aware). */
|
|
113
|
+
function insertDirToParentEdges(
|
|
114
|
+
insertEdge: SqliteStatement,
|
|
115
|
+
getNodeIdStmt: NodeIdStmt,
|
|
116
|
+
allDirs: Set<string>,
|
|
117
|
+
affectedDirs: Set<string> | null,
|
|
118
|
+
): void {
|
|
119
|
+
for (const dir of allDirs) {
|
|
120
|
+
const parent = normalizePath(path.dirname(dir));
|
|
121
|
+
if (!parent || parent === '.' || parent === dir) continue;
|
|
122
|
+
if (affectedDirs && !affectedDirs.has(parent)) continue;
|
|
123
|
+
const parentRow = getNodeIdStmt.get(parent, 'directory', parent, 0);
|
|
124
|
+
const childRow = getNodeIdStmt.get(dir, 'directory', dir, 0);
|
|
125
|
+
if (parentRow && childRow) {
|
|
126
|
+
insertEdge.run(parentRow.id, childRow.id, 'contains', 1.0, 0);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
93
131
|
function insertContainsEdges(
|
|
94
132
|
db: BetterSqlite3Database,
|
|
95
133
|
insertEdge: SqliteStatement,
|
|
@@ -102,26 +140,8 @@ function insertContainsEdges(
|
|
|
102
140
|
const affectedDirs = isIncremental ? getAncestorDirs(changedFiles ?? []) : null;
|
|
103
141
|
|
|
104
142
|
db.transaction(() => {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if (!dir || dir === '.') continue;
|
|
108
|
-
if (affectedDirs && !affectedDirs.has(dir)) continue;
|
|
109
|
-
const dirRow = getNodeIdStmt.get(dir, 'directory', dir, 0);
|
|
110
|
-
const fileRow = getNodeIdStmt.get(relPath, 'file', relPath, 0);
|
|
111
|
-
if (dirRow && fileRow) {
|
|
112
|
-
insertEdge.run(dirRow.id, fileRow.id, 'contains', 1.0, 0);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
for (const dir of allDirs) {
|
|
116
|
-
const parent = normalizePath(path.dirname(dir));
|
|
117
|
-
if (!parent || parent === '.' || parent === dir) continue;
|
|
118
|
-
if (affectedDirs && !affectedDirs.has(parent)) continue;
|
|
119
|
-
const parentRow = getNodeIdStmt.get(parent, 'directory', parent, 0);
|
|
120
|
-
const childRow = getNodeIdStmt.get(dir, 'directory', dir, 0);
|
|
121
|
-
if (parentRow && childRow) {
|
|
122
|
-
insertEdge.run(parentRow.id, childRow.id, 'contains', 1.0, 0);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
143
|
+
insertFileToParentEdges(insertEdge, getNodeIdStmt, fileSymbols, affectedDirs);
|
|
144
|
+
insertDirToParentEdges(insertEdge, getNodeIdStmt, allDirs, affectedDirs);
|
|
125
145
|
})();
|
|
126
146
|
}
|
|
127
147
|
|
|
@@ -249,40 +269,59 @@ function buildFileToAncestorDirs(dirFiles: Map<string, string[]>): Map<string, S
|
|
|
249
269
|
return fileToAncestorDirs;
|
|
250
270
|
}
|
|
251
271
|
|
|
272
|
+
/** Initialise a zero-count map for all known directories. */
|
|
273
|
+
function initDirEdgeCounts(
|
|
274
|
+
allDirs: Set<string>,
|
|
275
|
+
): Map<string, { intra: number; fanIn: number; fanOut: number }> {
|
|
276
|
+
const m = new Map<string, { intra: number; fanIn: number; fanOut: number }>();
|
|
277
|
+
for (const dir of allDirs) m.set(dir, { intra: 0, fanIn: 0, fanOut: 0 });
|
|
278
|
+
return m;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/** Accumulate source-side (intra / fanOut) counts for one import edge. */
|
|
282
|
+
function accumulateSrcDirCounts(
|
|
283
|
+
srcDirs: Set<string>,
|
|
284
|
+
tgtDirs: Set<string> | undefined,
|
|
285
|
+
dirEdgeCounts: Map<string, { intra: number; fanIn: number; fanOut: number }>,
|
|
286
|
+
): void {
|
|
287
|
+
for (const dir of srcDirs) {
|
|
288
|
+
const counts = dirEdgeCounts.get(dir);
|
|
289
|
+
if (!counts) continue;
|
|
290
|
+
if (tgtDirs?.has(dir)) {
|
|
291
|
+
counts.intra++;
|
|
292
|
+
} else {
|
|
293
|
+
counts.fanOut++;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/** Accumulate target-side (fanIn) counts for one import edge. */
|
|
299
|
+
function accumulateTgtDirCounts(
|
|
300
|
+
tgtDirs: Set<string>,
|
|
301
|
+
srcDirs: Set<string> | undefined,
|
|
302
|
+
dirEdgeCounts: Map<string, { intra: number; fanIn: number; fanOut: number }>,
|
|
303
|
+
): void {
|
|
304
|
+
for (const dir of tgtDirs) {
|
|
305
|
+
if (srcDirs?.has(dir)) continue;
|
|
306
|
+
const counts = dirEdgeCounts.get(dir);
|
|
307
|
+
if (!counts) continue;
|
|
308
|
+
counts.fanIn++;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
252
312
|
/** Count intra-directory, fan-in, and fan-out edges per directory. */
|
|
253
313
|
function countDirectoryEdges(
|
|
254
314
|
allDirs: Set<string>,
|
|
255
315
|
importEdges: ImportEdge[],
|
|
256
316
|
fileToAncestorDirs: Map<string, Set<string>>,
|
|
257
317
|
): Map<string, { intra: number; fanIn: number; fanOut: number }> {
|
|
258
|
-
const dirEdgeCounts =
|
|
259
|
-
for (const dir of allDirs) {
|
|
260
|
-
dirEdgeCounts.set(dir, { intra: 0, fanIn: 0, fanOut: 0 });
|
|
261
|
-
}
|
|
318
|
+
const dirEdgeCounts = initDirEdgeCounts(allDirs);
|
|
262
319
|
for (const { source_file, target_file } of importEdges) {
|
|
263
320
|
const srcDirs = fileToAncestorDirs.get(source_file);
|
|
264
321
|
const tgtDirs = fileToAncestorDirs.get(target_file);
|
|
265
322
|
if (!srcDirs && !tgtDirs) continue;
|
|
266
|
-
|
|
267
|
-
if (srcDirs)
|
|
268
|
-
for (const dir of srcDirs) {
|
|
269
|
-
const counts = dirEdgeCounts.get(dir);
|
|
270
|
-
if (!counts) continue;
|
|
271
|
-
if (tgtDirs?.has(dir)) {
|
|
272
|
-
counts.intra++;
|
|
273
|
-
} else {
|
|
274
|
-
counts.fanOut++;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
if (tgtDirs) {
|
|
279
|
-
for (const dir of tgtDirs) {
|
|
280
|
-
if (srcDirs?.has(dir)) continue;
|
|
281
|
-
const counts = dirEdgeCounts.get(dir);
|
|
282
|
-
if (!counts) continue;
|
|
283
|
-
counts.fanIn++;
|
|
284
|
-
}
|
|
285
|
-
}
|
|
323
|
+
if (srcDirs) accumulateSrcDirCounts(srcDirs, tgtDirs, dirEdgeCounts);
|
|
324
|
+
if (tgtDirs) accumulateTgtDirCounts(tgtDirs, srcDirs, dirEdgeCounts);
|
|
286
325
|
}
|
|
287
326
|
return dirEdgeCounts;
|
|
288
327
|
}
|
|
@@ -541,15 +580,50 @@ interface CallableNodeRow {
|
|
|
541
580
|
fan_out: number;
|
|
542
581
|
}
|
|
543
582
|
|
|
544
|
-
/**
|
|
545
|
-
|
|
583
|
+
/**
|
|
584
|
+
* Kinds that are consumed via annotations/references rather than calls.
|
|
585
|
+
* These do not count as "active callables" for the hasActiveFileSiblings heuristic.
|
|
586
|
+
*/
|
|
587
|
+
const ANNOTATION_ONLY_KINDS = new Set([
|
|
588
|
+
'constant',
|
|
589
|
+
'struct',
|
|
590
|
+
'enum',
|
|
591
|
+
'trait',
|
|
592
|
+
'type',
|
|
593
|
+
'interface',
|
|
594
|
+
'record',
|
|
595
|
+
]);
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Build two active-files sets from callable rows:
|
|
599
|
+
*
|
|
600
|
+
* - `activeFiles`: files with at least one non-annotation-only callable with
|
|
601
|
+
* `fan_in > 0 || fan_out > 0`. Used for annotation-only kinds (constants,
|
|
602
|
+
* type defs) which have no callers by design.
|
|
603
|
+
*
|
|
604
|
+
* - `calledActiveFiles`: files with at least one non-annotation-only callable
|
|
605
|
+
* with `fan_in > 0` (strictly called). Used for method/function kinds to
|
|
606
|
+
* prevent a self-sibling loop: a function with `fanIn=0, fanOut>0` as the
|
|
607
|
+
* only callable in its file must NOT count itself as an "active sibling" and
|
|
608
|
+
* thus promote itself to `leaf`.
|
|
609
|
+
*/
|
|
610
|
+
function buildActiveFilesSet(rows: CallableNodeRow[]): {
|
|
611
|
+
activeFiles: Set<string>;
|
|
612
|
+
calledActiveFiles: Set<string>;
|
|
613
|
+
} {
|
|
546
614
|
const activeFiles = new Set<string>();
|
|
615
|
+
const calledActiveFiles = new Set<string>();
|
|
547
616
|
for (const r of rows) {
|
|
548
|
-
if ((r.
|
|
549
|
-
|
|
617
|
+
if (!ANNOTATION_ONLY_KINDS.has(r.kind)) {
|
|
618
|
+
if (r.fan_in > 0 || r.fan_out > 0) {
|
|
619
|
+
activeFiles.add(r.file);
|
|
620
|
+
}
|
|
621
|
+
if (r.fan_in > 0) {
|
|
622
|
+
calledActiveFiles.add(r.file);
|
|
623
|
+
}
|
|
550
624
|
}
|
|
551
625
|
}
|
|
552
|
-
return activeFiles;
|
|
626
|
+
return { activeFiles, calledActiveFiles };
|
|
553
627
|
}
|
|
554
628
|
|
|
555
629
|
/** Map callable rows to classifier input objects, attaching exported/prod-fan-in/active-file metadata. */
|
|
@@ -558,6 +632,7 @@ function buildClassifierInput(
|
|
|
558
632
|
exportedIds: Set<number>,
|
|
559
633
|
prodFanInMap: Map<number, number>,
|
|
560
634
|
activeFiles: Set<string>,
|
|
635
|
+
calledActiveFiles: Set<string>,
|
|
561
636
|
): Array<{
|
|
562
637
|
id: string;
|
|
563
638
|
name: string;
|
|
@@ -578,7 +653,20 @@ function buildClassifierInput(
|
|
|
578
653
|
fanOut: r.fan_out,
|
|
579
654
|
isExported: exportedIds.has(r.id),
|
|
580
655
|
productionFanIn: prodFanInMap.get(r.id) || 0,
|
|
581
|
-
hasActiveFileSiblings
|
|
656
|
+
// Set hasActiveFileSiblings for annotation-only kinds (constants, type defs)
|
|
657
|
+
// AND for method/function — the latter two can have fanIn === 0 due to
|
|
658
|
+
// untraced call-site patterns (interface dispatch, logical-or defaults).
|
|
659
|
+
// The classifier interprets this field differently per kind (see classifyUnreferencedNode).
|
|
660
|
+
//
|
|
661
|
+
// IMPORTANT: method/function use calledActiveFiles (fan_in > 0 only) to
|
|
662
|
+
// prevent a self-sibling false negative: a function with fanIn=0, fanOut>0
|
|
663
|
+
// as the sole callable in its file must NOT see its own file as "active"
|
|
664
|
+
// and promote itself to leaf.
|
|
665
|
+
hasActiveFileSiblings: ANNOTATION_ONLY_KINDS.has(r.kind)
|
|
666
|
+
? activeFiles.has(r.file)
|
|
667
|
+
: r.kind === 'method' || r.kind === 'function'
|
|
668
|
+
? calledActiveFiles.has(r.file)
|
|
669
|
+
: undefined,
|
|
582
670
|
}));
|
|
583
671
|
}
|
|
584
672
|
|
|
@@ -660,7 +748,8 @@ function readCachedMedians(db: BetterSqlite3Database): { fanIn: number; fanOut:
|
|
|
660
748
|
)
|
|
661
749
|
return null;
|
|
662
750
|
return { fanIn: cached.fanIn, fanOut: cached.fanOut };
|
|
663
|
-
} catch {
|
|
751
|
+
} catch (e) {
|
|
752
|
+
debug(`readCachedMedians: failed to parse cached medians — ${e}`);
|
|
664
753
|
return null;
|
|
665
754
|
}
|
|
666
755
|
}
|
|
@@ -761,6 +850,20 @@ function classifyNodeRolesFull(db: BetterSqlite3Database, emptySummary: RoleSumm
|
|
|
761
850
|
.all() as { id: number }[];
|
|
762
851
|
for (const r of reexportExported) exportedIds.add(r.id);
|
|
763
852
|
|
|
853
|
+
// Mark symbols with exported=1 as exported — the extractor sets this flag when the
|
|
854
|
+
// author writes `export interface Foo { }` / `export type Bar = ...` / `export function`.
|
|
855
|
+
// Cross-file edge inference misses these when the symbol is only used as a type annotation
|
|
856
|
+
// within the same file (no calls/imports-type edge is produced for same-file type usage).
|
|
857
|
+
// This fixes false dead-unresolved classification for exported interfaces with no external callers (#1583).
|
|
858
|
+
const explicitlyExported = db
|
|
859
|
+
.prepare(
|
|
860
|
+
`SELECT id FROM nodes
|
|
861
|
+
WHERE exported = 1
|
|
862
|
+
AND kind NOT IN ('file', 'directory', 'parameter', 'property')`,
|
|
863
|
+
)
|
|
864
|
+
.all() as { id: number }[];
|
|
865
|
+
for (const r of explicitlyExported) exportedIds.add(r.id);
|
|
866
|
+
|
|
764
867
|
// Compute production fan-in (excluding callers in test files)
|
|
765
868
|
const prodFanInMap = new Map<number, number>();
|
|
766
869
|
const prodRows = db
|
|
@@ -781,8 +884,14 @@ function classifyNodeRolesFull(db: BetterSqlite3Database, emptySummary: RoleSumm
|
|
|
781
884
|
// Compute medians from the already-loaded rows (no extra DB round-trip),
|
|
782
885
|
// pass them as overrides to avoid recomputing inside classifyRoles,
|
|
783
886
|
// and cache them for subsequent incremental builds.
|
|
784
|
-
const activeFiles = buildActiveFilesSet(rows);
|
|
785
|
-
const classifierInput = buildClassifierInput(
|
|
887
|
+
const { activeFiles, calledActiveFiles } = buildActiveFilesSet(rows);
|
|
888
|
+
const classifierInput = buildClassifierInput(
|
|
889
|
+
rows,
|
|
890
|
+
exportedIds,
|
|
891
|
+
prodFanInMap,
|
|
892
|
+
activeFiles,
|
|
893
|
+
calledActiveFiles,
|
|
894
|
+
);
|
|
786
895
|
const nonZeroFanIn = classifierInput
|
|
787
896
|
.filter((n) => n.fanIn > 0)
|
|
788
897
|
.map((n) => n.fanIn)
|
|
@@ -928,6 +1037,21 @@ function classifyNodeRolesIncremental(
|
|
|
928
1037
|
.all(...allAffectedFiles) as { id: number }[];
|
|
929
1038
|
for (const r of reexportExported) exportedIds.add(r.id);
|
|
930
1039
|
|
|
1040
|
+
// 3c. Mark symbols with exported=1 as exported — the extractor sets this flag when the
|
|
1041
|
+
// author writes `export interface Foo { }` / `export type Bar = ...` / `export function`.
|
|
1042
|
+
// Cross-file edge inference misses these when the symbol is only used as a type annotation
|
|
1043
|
+
// within the same file (no calls/imports-type edge is produced for same-file type usage).
|
|
1044
|
+
// Scoped to affected files only for the incremental path (#1583).
|
|
1045
|
+
const explicitlyExported = db
|
|
1046
|
+
.prepare(
|
|
1047
|
+
`SELECT id FROM nodes
|
|
1048
|
+
WHERE exported = 1
|
|
1049
|
+
AND kind NOT IN ('file', 'directory', 'parameter', 'property')
|
|
1050
|
+
AND file IN (${placeholders})`,
|
|
1051
|
+
)
|
|
1052
|
+
.all(...allAffectedFiles) as { id: number }[];
|
|
1053
|
+
for (const r of explicitlyExported) exportedIds.add(r.id);
|
|
1054
|
+
|
|
931
1055
|
// 4. Production fan-in for affected nodes only
|
|
932
1056
|
const prodFanInMap = new Map<number, number>();
|
|
933
1057
|
const prodRows = db
|
|
@@ -947,8 +1071,14 @@ function classifyNodeRolesIncremental(
|
|
|
947
1071
|
}
|
|
948
1072
|
|
|
949
1073
|
// 5. Classify affected nodes using global medians
|
|
950
|
-
const activeFiles = buildActiveFilesSet(rows);
|
|
951
|
-
const classifierInput = buildClassifierInput(
|
|
1074
|
+
const { activeFiles, calledActiveFiles } = buildActiveFilesSet(rows);
|
|
1075
|
+
const classifierInput = buildClassifierInput(
|
|
1076
|
+
rows,
|
|
1077
|
+
exportedIds,
|
|
1078
|
+
prodFanInMap,
|
|
1079
|
+
activeFiles,
|
|
1080
|
+
calledActiveFiles,
|
|
1081
|
+
);
|
|
952
1082
|
const roleMap = classifyRoles(classifierInput, globalMedians);
|
|
953
1083
|
|
|
954
1084
|
// 6. Build summary (only for affected nodes) and update only those nodes
|
package/src/features/triage.ts
CHANGED
|
@@ -116,6 +116,33 @@ interface TriageDataOpts {
|
|
|
116
116
|
repo?: Repository;
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
interface ResolvedRiskConfig {
|
|
120
|
+
weights: RiskWeights;
|
|
121
|
+
riskOpts: { roleWeights?: Record<string, number>; defaultRoleWeight?: number };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Resolve risk weights and role-weight options from config + opts overrides. */
|
|
125
|
+
function resolveRiskConfig(opts: TriageDataOpts): ResolvedRiskConfig {
|
|
126
|
+
const config = opts.config || loadConfig();
|
|
127
|
+
const riskConfig = ((config as unknown as Record<string, unknown>).risk || {}) as {
|
|
128
|
+
weights?: Partial<RiskWeights>;
|
|
129
|
+
roleWeights?: Record<string, number>;
|
|
130
|
+
defaultRoleWeight?: number;
|
|
131
|
+
};
|
|
132
|
+
const weights: RiskWeights = {
|
|
133
|
+
...DEFAULT_WEIGHTS,
|
|
134
|
+
...(riskConfig.weights || {}),
|
|
135
|
+
...(opts.weights || {}),
|
|
136
|
+
};
|
|
137
|
+
return {
|
|
138
|
+
weights,
|
|
139
|
+
riskOpts: {
|
|
140
|
+
roleWeights: riskConfig.roleWeights,
|
|
141
|
+
defaultRoleWeight: riskConfig.defaultRoleWeight,
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
119
146
|
export function triageData(
|
|
120
147
|
customDbPath?: string,
|
|
121
148
|
opts: TriageDataOpts = {},
|
|
@@ -125,21 +152,7 @@ export function triageData(
|
|
|
125
152
|
const noTests = opts.noTests || false;
|
|
126
153
|
const minScore = opts.minScore != null ? Number(opts.minScore) : null;
|
|
127
154
|
const sort = opts.sort || 'risk';
|
|
128
|
-
const
|
|
129
|
-
const riskConfig = ((config as unknown as Record<string, unknown>).risk || {}) as {
|
|
130
|
-
weights?: Partial<RiskWeights>;
|
|
131
|
-
roleWeights?: Record<string, number>;
|
|
132
|
-
defaultRoleWeight?: number;
|
|
133
|
-
};
|
|
134
|
-
const weights: RiskWeights = {
|
|
135
|
-
...DEFAULT_WEIGHTS,
|
|
136
|
-
...(riskConfig.weights || {}),
|
|
137
|
-
...(opts.weights || {}),
|
|
138
|
-
};
|
|
139
|
-
const riskOpts = {
|
|
140
|
-
roleWeights: riskConfig.roleWeights,
|
|
141
|
-
defaultRoleWeight: riskConfig.defaultRoleWeight,
|
|
142
|
-
};
|
|
155
|
+
const { weights, riskOpts } = resolveRiskConfig(opts);
|
|
143
156
|
|
|
144
157
|
let rows: TriageNodeRow[];
|
|
145
158
|
try {
|
|
@@ -6,10 +6,17 @@ export interface BfsOpts {
|
|
|
6
6
|
direction?: 'forward' | 'backward' | 'both';
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
/** Resolve the neighbor list for a node given traversal direction. */
|
|
10
|
+
function getNeighbors(graph: CodeGraph, node: string, direction: string): string[] {
|
|
11
|
+
if (direction === 'forward') return graph.successors(node);
|
|
12
|
+
if (direction === 'backward') return graph.predecessors(node);
|
|
13
|
+
return graph.neighbors(node);
|
|
14
|
+
}
|
|
15
|
+
|
|
9
16
|
/**
|
|
10
17
|
* Breadth-first traversal on a CodeGraph.
|
|
11
18
|
*
|
|
12
|
-
* Tries the native Rust implementation first, falls back to JS.
|
|
19
|
+
* Tries the native Rust implementation first, falls back to a pure-JS queue.
|
|
13
20
|
*
|
|
14
21
|
* @returns nodeId → depth from nearest start node
|
|
15
22
|
*/
|
|
@@ -46,7 +53,10 @@ export function bfs(
|
|
|
46
53
|
return bfsJS(graph, starts, maxDepth, direction);
|
|
47
54
|
}
|
|
48
55
|
|
|
49
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* Pure-JS BFS queue (used when native addon is unavailable).
|
|
58
|
+
* Separated from bfs() to keep each function's complexity within thresholds.
|
|
59
|
+
*/
|
|
50
60
|
function bfsJS(
|
|
51
61
|
graph: CodeGraph,
|
|
52
62
|
starts: string[],
|
|
@@ -70,16 +80,7 @@ function bfsJS(
|
|
|
70
80
|
const depth = depths.get(current)!;
|
|
71
81
|
if (depth >= maxDepth) continue;
|
|
72
82
|
|
|
73
|
-
|
|
74
|
-
if (direction === 'forward') {
|
|
75
|
-
neighbors = graph.successors(current);
|
|
76
|
-
} else if (direction === 'backward') {
|
|
77
|
-
neighbors = graph.predecessors(current);
|
|
78
|
-
} else {
|
|
79
|
-
neighbors = graph.neighbors(current);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
for (const n of neighbors) {
|
|
83
|
+
for (const n of getNeighbors(graph, current, direction)) {
|
|
83
84
|
if (!depths.has(n)) {
|
|
84
85
|
depths.set(n, depth + 1);
|
|
85
86
|
queue.push(n);
|
|
@@ -15,6 +15,7 @@ export function tarjan(graph: CodeGraph): string[][] {
|
|
|
15
15
|
const sccs: string[][] = [];
|
|
16
16
|
|
|
17
17
|
function strongconnect(v: string): void {
|
|
18
|
+
// Assign the next discovery index and initialise lowlink to self
|
|
18
19
|
indices.set(v, index);
|
|
19
20
|
lowlinks.set(v, index);
|
|
20
21
|
index++;
|
|
@@ -23,13 +24,16 @@ export function tarjan(graph: CodeGraph): string[][] {
|
|
|
23
24
|
|
|
24
25
|
for (const w of graph.successors(v)) {
|
|
25
26
|
if (!indices.has(w)) {
|
|
27
|
+
// Tree edge: recurse then propagate lowlink upward
|
|
26
28
|
strongconnect(w);
|
|
27
29
|
lowlinks.set(v, Math.min(lowlinks.get(v)!, lowlinks.get(w)!));
|
|
28
30
|
} else if (onStack.has(w)) {
|
|
31
|
+
// Back/cross edge to a node still on the stack: update lowlink via index
|
|
29
32
|
lowlinks.set(v, Math.min(lowlinks.get(v)!, indices.get(w)!));
|
|
30
33
|
}
|
|
31
34
|
}
|
|
32
35
|
|
|
36
|
+
// v is the root of an SCC when its lowlink equals its own discovery index
|
|
33
37
|
if (lowlinks.get(v) === indices.get(v)) {
|
|
34
38
|
const scc: string[] = [];
|
|
35
39
|
let w: string | undefined;
|
|
@@ -38,6 +42,7 @@ export function tarjan(graph: CodeGraph): string[][] {
|
|
|
38
42
|
onStack.delete(w);
|
|
39
43
|
scc.push(w);
|
|
40
44
|
} while (w !== v);
|
|
45
|
+
// Only report non-trivial SCCs (length > 1 = a real cycle)
|
|
41
46
|
if (scc.length > 1) sccs.push(scc);
|
|
42
47
|
}
|
|
43
48
|
}
|
|
@@ -78,6 +78,37 @@ interface MinConfidenceEdgeRow {
|
|
|
78
78
|
target_id: number;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Fetch call edges from `dbOrRepo`, optionally filtered by a minimum confidence
|
|
83
|
+
* threshold. When `minConfidence` is unset, all call edges are returned.
|
|
84
|
+
*/
|
|
85
|
+
function resolveCallEdges(
|
|
86
|
+
dbOrRepo: BetterSqlite3Database | Repository,
|
|
87
|
+
isRepo: boolean,
|
|
88
|
+
minConfidence?: number,
|
|
89
|
+
): CallEdgeRow[] | MinConfidenceEdgeRow[] {
|
|
90
|
+
if (minConfidence == null) {
|
|
91
|
+
return isRepo
|
|
92
|
+
? (dbOrRepo as Repository).getCallEdges()
|
|
93
|
+
: getCallEdges(dbOrRepo as BetterSqlite3Database);
|
|
94
|
+
}
|
|
95
|
+
if (isRepo) {
|
|
96
|
+
// Trade-off: Repository.getCallEdges() returns all call edges, so we
|
|
97
|
+
// filter in JS. This is O(all call edges) rather than the SQL path's
|
|
98
|
+
// indexed WHERE clause. Acceptable for current data sizes; a dedicated
|
|
99
|
+
// getCallEdgesByMinConfidence(threshold) method on the Repository
|
|
100
|
+
// interface would be the proper fix if this becomes a bottleneck.
|
|
101
|
+
return (dbOrRepo as Repository)
|
|
102
|
+
.getCallEdges()
|
|
103
|
+
.filter((e) => e.confidence != null && e.confidence >= minConfidence);
|
|
104
|
+
}
|
|
105
|
+
return (dbOrRepo as BetterSqlite3Database)
|
|
106
|
+
.prepare<MinConfidenceEdgeRow>(
|
|
107
|
+
"SELECT source_id, target_id FROM edges WHERE kind = 'calls' AND confidence >= ?",
|
|
108
|
+
)
|
|
109
|
+
.all(minConfidence);
|
|
110
|
+
}
|
|
111
|
+
|
|
81
112
|
function buildFunctionLevelGraph(
|
|
82
113
|
dbOrRepo: BetterSqlite3Database | Repository,
|
|
83
114
|
noTests: boolean,
|
|
@@ -86,7 +117,9 @@ function buildFunctionLevelGraph(
|
|
|
86
117
|
const graph = new CodeGraph();
|
|
87
118
|
const isRepo = dbOrRepo instanceof Repository;
|
|
88
119
|
|
|
89
|
-
let nodes: CallableNodeRow[] = isRepo
|
|
120
|
+
let nodes: CallableNodeRow[] = isRepo
|
|
121
|
+
? (dbOrRepo as Repository).getCallableNodes()
|
|
122
|
+
: getCallableNodes(dbOrRepo as BetterSqlite3Database);
|
|
90
123
|
if (noTests) nodes = nodes.filter((n) => !isTestFile(n.file));
|
|
91
124
|
|
|
92
125
|
const nodeIds = new Set<number>();
|
|
@@ -100,28 +133,7 @@ function buildFunctionLevelGraph(
|
|
|
100
133
|
nodeIds.add(n.id);
|
|
101
134
|
}
|
|
102
135
|
|
|
103
|
-
|
|
104
|
-
if (minConfidence != null) {
|
|
105
|
-
if (isRepo) {
|
|
106
|
-
// Trade-off: Repository.getCallEdges() returns all call edges, so we
|
|
107
|
-
// filter in JS. This is O(all call edges) rather than the SQL path's
|
|
108
|
-
// indexed WHERE clause. Acceptable for current data sizes; a dedicated
|
|
109
|
-
// getCallEdgesByMinConfidence(threshold) method on the Repository
|
|
110
|
-
// interface would be the proper fix if this becomes a bottleneck.
|
|
111
|
-
edges = dbOrRepo
|
|
112
|
-
.getCallEdges()
|
|
113
|
-
.filter((e) => e.confidence != null && e.confidence >= minConfidence);
|
|
114
|
-
} else {
|
|
115
|
-
edges = (dbOrRepo as BetterSqlite3Database)
|
|
116
|
-
.prepare<MinConfidenceEdgeRow>(
|
|
117
|
-
"SELECT source_id, target_id FROM edges WHERE kind = 'calls' AND confidence >= ?",
|
|
118
|
-
)
|
|
119
|
-
.all(minConfidence);
|
|
120
|
-
}
|
|
121
|
-
} else {
|
|
122
|
-
edges = isRepo ? dbOrRepo.getCallEdges() : getCallEdges(dbOrRepo);
|
|
123
|
-
}
|
|
124
|
-
|
|
136
|
+
const edges = resolveCallEdges(dbOrRepo, isRepo, minConfidence);
|
|
125
137
|
for (const e of edges) {
|
|
126
138
|
if (!nodeIds.has(e.source_id) || !nodeIds.has(e.target_id)) continue;
|
|
127
139
|
const src = String(e.source_id);
|
|
@@ -18,6 +18,14 @@ export const FRAMEWORK_ENTRY_PREFIXES: readonly string[] = ['route:', 'event:',
|
|
|
18
18
|
|
|
19
19
|
const LEAF_KINDS = new Set(['parameter', 'property', 'constant']);
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Type definition kinds that are consumed via type annotations rather than calls.
|
|
23
|
+
* These have no inbound call edges by design — they are "used" by type references,
|
|
24
|
+
* struct literals, and generic parameters, none of which produce call edges.
|
|
25
|
+
* If the same file has active callables, type definitions are almost certainly live.
|
|
26
|
+
*/
|
|
27
|
+
const TYPE_DEF_KINDS = new Set(['struct', 'enum', 'trait', 'type', 'interface', 'record']);
|
|
28
|
+
|
|
21
29
|
const FFI_EXTENSIONS = new Set(['.rs', '.c', '.cpp', '.h', '.go', '.java', '.cs']);
|
|
22
30
|
|
|
23
31
|
/** Path patterns indicating framework-dispatched entry points. */
|
|
@@ -29,6 +37,17 @@ const ENTRY_PATH_PATTERNS: readonly RegExp[] = [
|
|
|
29
37
|
/middleware[/\\]/,
|
|
30
38
|
];
|
|
31
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Well-known Commander.js dispatch method names.
|
|
42
|
+
* When a method with one of these names lives in a file that matches
|
|
43
|
+
* ENTRY_PATH_PATTERNS, it is the actual framework entry point — not merely a
|
|
44
|
+
* candidate — so it must be classified as `entry` rather than `dead-entry`.
|
|
45
|
+
*
|
|
46
|
+
* `execute` — the action callback invoked by Commander on `program.action()`.
|
|
47
|
+
* `validate` — a pre-execution argument/option validator called before `execute`.
|
|
48
|
+
*/
|
|
49
|
+
const COMMANDER_DISPATCH_NAMES = new Set(['execute', 'validate']);
|
|
50
|
+
|
|
32
51
|
export interface ClassifiableNode {
|
|
33
52
|
kind?: string;
|
|
34
53
|
file?: string;
|
|
@@ -74,7 +93,16 @@ export interface RoleClassificationNode {
|
|
|
74
93
|
isExported: boolean;
|
|
75
94
|
testOnlyFanIn?: number;
|
|
76
95
|
productionFanIn?: number;
|
|
77
|
-
/**
|
|
96
|
+
/**
|
|
97
|
+
* True when the same file contains at least one callable connected to the graph
|
|
98
|
+
* (fanIn > 0 or fanOut > 0) that is not itself an annotation-only kind.
|
|
99
|
+
* Annotation-only kinds are `constant` and all members of `TYPE_DEF_KINDS`
|
|
100
|
+
* (struct, enum, trait, type, interface, record) — these are excluded because
|
|
101
|
+
* they are consumed via references/type-annotations rather than call edges and
|
|
102
|
+
* would otherwise produce a circular dependency in the active-file heuristic.
|
|
103
|
+
* Populated only for `constant` and `TYPE_DEF_KINDS` nodes; `undefined` for
|
|
104
|
+
* regular callables (functions, methods, classes, etc.) which don't need it.
|
|
105
|
+
*/
|
|
78
106
|
hasActiveFileSiblings?: boolean;
|
|
79
107
|
}
|
|
80
108
|
|
|
@@ -99,11 +127,37 @@ function computeFanMedians(nodes: RoleClassificationNode[]): { fanIn: number; fa
|
|
|
99
127
|
* Covers framework-active constants, test-only callables, and the dead-* family.
|
|
100
128
|
*/
|
|
101
129
|
function classifyUnreferencedNode(node: RoleClassificationNode): Role {
|
|
102
|
-
if (node.
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
130
|
+
if (node.hasActiveFileSiblings) {
|
|
131
|
+
if (node.kind === 'constant') {
|
|
132
|
+
// Constants consumed via identifier reference (not calls) have no
|
|
133
|
+
// inbound call edges. If the same file has active callables, the
|
|
134
|
+
// constant is almost certainly used locally — classify as leaf.
|
|
135
|
+
return 'leaf';
|
|
136
|
+
}
|
|
137
|
+
if (node.kind && TYPE_DEF_KINDS.has(node.kind)) {
|
|
138
|
+
// Type definitions (struct, enum, trait, type, interface, record) are
|
|
139
|
+
// consumed via type annotations and struct literals — not calls — so they
|
|
140
|
+
// never get inbound call edges. If the same file has active callables,
|
|
141
|
+
// these types are almost certainly live — classify as leaf.
|
|
142
|
+
return 'leaf';
|
|
143
|
+
}
|
|
144
|
+
if (node.kind === 'method' && node.fanOut > 0) {
|
|
145
|
+
// Methods implementing interfaces are dispatched via conditional property
|
|
146
|
+
// access e.g. `if (v.enterFunction) v.enterFunction(...)`. Codegraph
|
|
147
|
+
// resolves the call to the property accessor rather than to the concrete
|
|
148
|
+
// method implementation, so the method has no inbound call edge. We
|
|
149
|
+
// require `fanOut > 0` as evidence of non-triviality, mirroring the
|
|
150
|
+
// function case — trivially-inert dead helper methods remain visible.
|
|
151
|
+
return 'leaf';
|
|
152
|
+
}
|
|
153
|
+
if (node.kind === 'function' && node.fanOut > 0) {
|
|
154
|
+
// Functions referenced as logical-or fallback defaults — e.g.
|
|
155
|
+
// `const fn = options._fetchLatest || fetchLatestVersion` — appear as
|
|
156
|
+
// value references, not call sites, so no call edge is produced. We
|
|
157
|
+
// require `fanOut > 0` as evidence that the function is non-trivial
|
|
158
|
+
// (i.e. it calls something), ruling out truly inert dead helpers.
|
|
159
|
+
return 'leaf';
|
|
160
|
+
}
|
|
107
161
|
}
|
|
108
162
|
if (node.testOnlyFanIn != null && node.testOnlyFanIn > 0) return 'test-only';
|
|
109
163
|
return classifyDeadSubRole(node);
|
|
@@ -129,7 +183,20 @@ function classifyNodeRole(node: RoleClassificationNode, medFanIn: number, medFan
|
|
|
129
183
|
if (FRAMEWORK_ENTRY_PREFIXES.some((p) => node.name.startsWith(p))) return 'entry';
|
|
130
184
|
|
|
131
185
|
if (node.fanIn === 0) {
|
|
132
|
-
|
|
186
|
+
if (!node.isExported) {
|
|
187
|
+
// Well-known Commander.js dispatch methods (execute, validate) in framework
|
|
188
|
+
// directories are confirmed entry points, not candidates. Promote them to
|
|
189
|
+
// `entry` directly so they don't appear in `--role dead` output.
|
|
190
|
+
if (
|
|
191
|
+
node.file &&
|
|
192
|
+
COMMANDER_DISPATCH_NAMES.has(node.name) &&
|
|
193
|
+
ENTRY_PATH_PATTERNS.some((p) => p.test(node.file!))
|
|
194
|
+
) {
|
|
195
|
+
return 'entry';
|
|
196
|
+
}
|
|
197
|
+
return classifyUnreferencedNode(node);
|
|
198
|
+
}
|
|
199
|
+
return 'entry';
|
|
133
200
|
}
|
|
134
201
|
|
|
135
202
|
const hasProdFanIn = typeof node.productionFanIn === 'number';
|
package/src/index.ts
CHANGED
|
@@ -52,7 +52,11 @@ export { ownersData } from './features/owners.js';
|
|
|
52
52
|
export { sequenceData } from './features/sequence.js';
|
|
53
53
|
export { hotspotsData, moduleBoundariesData, structureData } from './features/structure.js';
|
|
54
54
|
export { triageData } from './features/triage.js';
|
|
55
|
-
export {
|
|
55
|
+
export {
|
|
56
|
+
loadConfig,
|
|
57
|
+
loadConfigWithProvenance,
|
|
58
|
+
resolveUserConfigPath,
|
|
59
|
+
} from './infrastructure/config.js';
|
|
56
60
|
export type { ArrayCompatSet } from './shared/constants.js';
|
|
57
61
|
export { EXTENSIONS, IGNORE_DIRS } from './shared/constants.js';
|
|
58
62
|
export {
|