@optave/codegraph 3.11.2 → 3.13.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.
Files changed (236) hide show
  1. package/README.md +73 -37
  2. package/dist/cli/commands/audit.d.ts.map +1 -1
  3. package/dist/cli/commands/audit.js +2 -1
  4. package/dist/cli/commands/audit.js.map +1 -1
  5. package/dist/cli/commands/batch.d.ts.map +1 -1
  6. package/dist/cli/commands/batch.js +1 -0
  7. package/dist/cli/commands/batch.js.map +1 -1
  8. package/dist/cli/commands/build.d.ts.map +1 -1
  9. package/dist/cli/commands/build.js +6 -1
  10. package/dist/cli/commands/build.js.map +1 -1
  11. package/dist/cli/commands/config.d.ts +3 -0
  12. package/dist/cli/commands/config.d.ts.map +1 -0
  13. package/dist/cli/commands/config.js +272 -0
  14. package/dist/cli/commands/config.js.map +1 -0
  15. package/dist/cli/commands/triage.js +1 -1
  16. package/dist/cli/commands/triage.js.map +1 -1
  17. package/dist/cli/index.d.ts.map +1 -1
  18. package/dist/cli/index.js +10 -0
  19. package/dist/cli/index.js.map +1 -1
  20. package/dist/cli/shared/options.d.ts +2 -1
  21. package/dist/cli/shared/options.d.ts.map +1 -1
  22. package/dist/cli/shared/options.js +11 -1
  23. package/dist/cli/shared/options.js.map +1 -1
  24. package/dist/cli/types.d.ts +2 -0
  25. package/dist/cli/types.d.ts.map +1 -1
  26. package/dist/db/migrations.d.ts.map +1 -1
  27. package/dist/db/migrations.js +8 -1
  28. package/dist/db/migrations.js.map +1 -1
  29. package/dist/domain/analysis/module-map.d.ts +2 -0
  30. package/dist/domain/analysis/module-map.d.ts.map +1 -1
  31. package/dist/domain/analysis/module-map.js +24 -2
  32. package/dist/domain/analysis/module-map.js.map +1 -1
  33. package/dist/domain/graph/builder/call-resolver.d.ts +16 -10
  34. package/dist/domain/graph/builder/call-resolver.d.ts.map +1 -1
  35. package/dist/domain/graph/builder/call-resolver.js +251 -34
  36. package/dist/domain/graph/builder/call-resolver.js.map +1 -1
  37. package/dist/domain/graph/builder/cha.d.ts +69 -0
  38. package/dist/domain/graph/builder/cha.d.ts.map +1 -0
  39. package/dist/domain/graph/builder/cha.js +158 -0
  40. package/dist/domain/graph/builder/cha.js.map +1 -0
  41. package/dist/domain/graph/builder/context.d.ts +3 -0
  42. package/dist/domain/graph/builder/context.d.ts.map +1 -1
  43. package/dist/domain/graph/builder/context.js +2 -0
  44. package/dist/domain/graph/builder/context.js.map +1 -1
  45. package/dist/domain/graph/builder/helpers.d.ts +25 -1
  46. package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
  47. package/dist/domain/graph/builder/helpers.js +178 -5
  48. package/dist/domain/graph/builder/helpers.js.map +1 -1
  49. package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
  50. package/dist/domain/graph/builder/incremental.js +74 -2
  51. package/dist/domain/graph/builder/incremental.js.map +1 -1
  52. package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
  53. package/dist/domain/graph/builder/pipeline.js +37 -2
  54. package/dist/domain/graph/builder/pipeline.js.map +1 -1
  55. package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
  56. package/dist/domain/graph/builder/stages/build-edges.js +704 -34
  57. package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
  58. package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
  59. package/dist/domain/graph/builder/stages/detect-changes.js +3 -2
  60. package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
  61. package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
  62. package/dist/domain/graph/builder/stages/finalize.js +4 -0
  63. package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
  64. package/dist/domain/graph/builder/stages/native-orchestrator.d.ts.map +1 -1
  65. package/dist/domain/graph/builder/stages/native-orchestrator.js +783 -37
  66. package/dist/domain/graph/builder/stages/native-orchestrator.js.map +1 -1
  67. package/dist/domain/graph/builder/stages/resolve-imports.d.ts +1 -0
  68. package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
  69. package/dist/domain/graph/builder/stages/resolve-imports.js +10 -1
  70. package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
  71. package/dist/domain/graph/journal.js +1 -1
  72. package/dist/domain/graph/journal.js.map +1 -1
  73. package/dist/domain/graph/resolver/points-to.d.ts +53 -0
  74. package/dist/domain/graph/resolver/points-to.d.ts.map +1 -0
  75. package/dist/domain/graph/resolver/points-to.js +213 -0
  76. package/dist/domain/graph/resolver/points-to.js.map +1 -0
  77. package/dist/domain/graph/resolver/ts-resolver.d.ts +9 -0
  78. package/dist/domain/graph/resolver/ts-resolver.d.ts.map +1 -0
  79. package/dist/domain/graph/resolver/ts-resolver.js +476 -0
  80. package/dist/domain/graph/resolver/ts-resolver.js.map +1 -0
  81. package/dist/domain/parser.d.ts +12 -4
  82. package/dist/domain/parser.d.ts.map +1 -1
  83. package/dist/domain/parser.js +83 -20
  84. package/dist/domain/parser.js.map +1 -1
  85. package/dist/domain/wasm-worker-entry.js +35 -2
  86. package/dist/domain/wasm-worker-entry.js.map +1 -1
  87. package/dist/domain/wasm-worker-pool.d.ts.map +1 -1
  88. package/dist/domain/wasm-worker-pool.js +34 -0
  89. package/dist/domain/wasm-worker-pool.js.map +1 -1
  90. package/dist/domain/wasm-worker-protocol.d.ts +15 -1
  91. package/dist/domain/wasm-worker-protocol.d.ts.map +1 -1
  92. package/dist/extractors/c.js +3 -3
  93. package/dist/extractors/c.js.map +1 -1
  94. package/dist/extractors/clojure.js +1 -1
  95. package/dist/extractors/clojure.js.map +1 -1
  96. package/dist/extractors/cpp.d.ts.map +1 -1
  97. package/dist/extractors/cpp.js +45 -4
  98. package/dist/extractors/cpp.js.map +1 -1
  99. package/dist/extractors/csharp.d.ts.map +1 -1
  100. package/dist/extractors/csharp.js +37 -8
  101. package/dist/extractors/csharp.js.map +1 -1
  102. package/dist/extractors/cuda.d.ts.map +1 -1
  103. package/dist/extractors/cuda.js +45 -4
  104. package/dist/extractors/cuda.js.map +1 -1
  105. package/dist/extractors/elixir.js +6 -6
  106. package/dist/extractors/elixir.js.map +1 -1
  107. package/dist/extractors/fsharp.js +1 -1
  108. package/dist/extractors/fsharp.js.map +1 -1
  109. package/dist/extractors/go.js +5 -5
  110. package/dist/extractors/go.js.map +1 -1
  111. package/dist/extractors/haskell.js +1 -1
  112. package/dist/extractors/haskell.js.map +1 -1
  113. package/dist/extractors/helpers.d.ts +11 -0
  114. package/dist/extractors/helpers.d.ts.map +1 -1
  115. package/dist/extractors/helpers.js +40 -0
  116. package/dist/extractors/helpers.js.map +1 -1
  117. package/dist/extractors/java.d.ts.map +1 -1
  118. package/dist/extractors/java.js +10 -9
  119. package/dist/extractors/java.js.map +1 -1
  120. package/dist/extractors/javascript.d.ts +2 -0
  121. package/dist/extractors/javascript.d.ts.map +1 -1
  122. package/dist/extractors/javascript.js +1812 -71
  123. package/dist/extractors/javascript.js.map +1 -1
  124. package/dist/extractors/kotlin.js +5 -5
  125. package/dist/extractors/kotlin.js.map +1 -1
  126. package/dist/extractors/lua.js +1 -1
  127. package/dist/extractors/lua.js.map +1 -1
  128. package/dist/extractors/objc.js +3 -3
  129. package/dist/extractors/objc.js.map +1 -1
  130. package/dist/extractors/ocaml.js +1 -1
  131. package/dist/extractors/ocaml.js.map +1 -1
  132. package/dist/extractors/php.js +2 -2
  133. package/dist/extractors/php.js.map +1 -1
  134. package/dist/extractors/python.js +7 -7
  135. package/dist/extractors/python.js.map +1 -1
  136. package/dist/extractors/ruby.js +2 -2
  137. package/dist/extractors/ruby.js.map +1 -1
  138. package/dist/extractors/scala.js +1 -1
  139. package/dist/extractors/scala.js.map +1 -1
  140. package/dist/extractors/solidity.js +1 -1
  141. package/dist/extractors/solidity.js.map +1 -1
  142. package/dist/extractors/swift.js +4 -4
  143. package/dist/extractors/swift.js.map +1 -1
  144. package/dist/extractors/zig.js +4 -4
  145. package/dist/extractors/zig.js.map +1 -1
  146. package/dist/features/structure-query.d.ts +1 -1
  147. package/dist/features/structure-query.d.ts.map +1 -1
  148. package/dist/features/structure-query.js +6 -6
  149. package/dist/features/structure-query.js.map +1 -1
  150. package/dist/index.d.ts +1 -1
  151. package/dist/index.d.ts.map +1 -1
  152. package/dist/index.js +1 -1
  153. package/dist/index.js.map +1 -1
  154. package/dist/infrastructure/config.d.ts +85 -2
  155. package/dist/infrastructure/config.d.ts.map +1 -1
  156. package/dist/infrastructure/config.js +408 -19
  157. package/dist/infrastructure/config.js.map +1 -1
  158. package/dist/infrastructure/native.d.ts +11 -0
  159. package/dist/infrastructure/native.d.ts.map +1 -1
  160. package/dist/infrastructure/native.js +78 -5
  161. package/dist/infrastructure/native.js.map +1 -1
  162. package/dist/infrastructure/registry.d.ts +27 -0
  163. package/dist/infrastructure/registry.d.ts.map +1 -1
  164. package/dist/infrastructure/registry.js +59 -1
  165. package/dist/infrastructure/registry.js.map +1 -1
  166. package/dist/presentation/queries-cli/overview.d.ts.map +1 -1
  167. package/dist/presentation/queries-cli/overview.js +5 -0
  168. package/dist/presentation/queries-cli/overview.js.map +1 -1
  169. package/dist/presentation/structure.d.ts +1 -1
  170. package/dist/presentation/structure.d.ts.map +1 -1
  171. package/dist/presentation/structure.js +2 -2
  172. package/dist/presentation/structure.js.map +1 -1
  173. package/dist/types.d.ts +221 -0
  174. package/dist/types.d.ts.map +1 -1
  175. package/grammars/tree-sitter-gleam.wasm +0 -0
  176. package/package.json +7 -8
  177. package/src/cli/commands/audit.ts +2 -1
  178. package/src/cli/commands/batch.ts +1 -0
  179. package/src/cli/commands/build.ts +6 -1
  180. package/src/cli/commands/config.ts +353 -0
  181. package/src/cli/commands/triage.ts +1 -1
  182. package/src/cli/index.ts +10 -0
  183. package/src/cli/shared/options.ts +11 -1
  184. package/src/cli/types.ts +2 -0
  185. package/src/db/migrations.ts +8 -1
  186. package/src/domain/analysis/module-map.ts +29 -1
  187. package/src/domain/graph/builder/call-resolver.ts +263 -35
  188. package/src/domain/graph/builder/cha.ts +192 -0
  189. package/src/domain/graph/builder/context.ts +3 -0
  190. package/src/domain/graph/builder/helpers.ts +195 -5
  191. package/src/domain/graph/builder/incremental.ts +80 -1
  192. package/src/domain/graph/builder/pipeline.ts +49 -2
  193. package/src/domain/graph/builder/stages/build-edges.ts +867 -32
  194. package/src/domain/graph/builder/stages/detect-changes.ts +4 -2
  195. package/src/domain/graph/builder/stages/finalize.ts +4 -0
  196. package/src/domain/graph/builder/stages/native-orchestrator.ts +910 -43
  197. package/src/domain/graph/builder/stages/resolve-imports.ts +15 -1
  198. package/src/domain/graph/journal.ts +1 -1
  199. package/src/domain/graph/resolver/points-to.ts +254 -0
  200. package/src/domain/graph/resolver/ts-resolver.ts +536 -0
  201. package/src/domain/parser.ts +86 -17
  202. package/src/domain/wasm-worker-entry.ts +35 -2
  203. package/src/domain/wasm-worker-pool.ts +22 -0
  204. package/src/domain/wasm-worker-protocol.ts +15 -0
  205. package/src/extractors/c.ts +3 -3
  206. package/src/extractors/clojure.ts +1 -1
  207. package/src/extractors/cpp.ts +47 -4
  208. package/src/extractors/csharp.ts +33 -9
  209. package/src/extractors/cuda.ts +47 -4
  210. package/src/extractors/elixir.ts +6 -6
  211. package/src/extractors/fsharp.ts +1 -1
  212. package/src/extractors/go.ts +5 -5
  213. package/src/extractors/haskell.ts +1 -1
  214. package/src/extractors/helpers.ts +43 -0
  215. package/src/extractors/java.ts +10 -9
  216. package/src/extractors/javascript.ts +1929 -72
  217. package/src/extractors/kotlin.ts +5 -5
  218. package/src/extractors/lua.ts +1 -1
  219. package/src/extractors/objc.ts +3 -3
  220. package/src/extractors/ocaml.ts +1 -1
  221. package/src/extractors/php.ts +2 -2
  222. package/src/extractors/python.ts +7 -7
  223. package/src/extractors/ruby.ts +2 -2
  224. package/src/extractors/scala.ts +1 -1
  225. package/src/extractors/solidity.ts +1 -1
  226. package/src/extractors/swift.ts +4 -4
  227. package/src/extractors/zig.ts +4 -4
  228. package/src/features/structure-query.ts +7 -7
  229. package/src/index.ts +5 -1
  230. package/src/infrastructure/config.ts +494 -20
  231. package/src/infrastructure/native.ts +87 -5
  232. package/src/infrastructure/registry.ts +82 -1
  233. package/src/presentation/queries-cli/overview.ts +15 -1
  234. package/src/presentation/structure.ts +3 -3
  235. package/src/types.ts +235 -0
  236. package/grammars/tree-sitter-erlang.wasm +0 -0
package/README.md CHANGED
@@ -43,7 +43,7 @@ Codegraph builds a function-level dependency graph of your entire codebase — e
43
43
 
44
44
  It parses your code with [tree-sitter](https://tree-sitter.github.io/) (native Rust or WASM), stores the graph in SQLite, and exposes it where it matters most:
45
45
 
46
- - **MCP server** — AI agents query the graph directly through 30 tools — one call instead of 30 `grep`/`find`/`cat` invocations
46
+ - **MCP server** — AI agents query the graph directly through 34 tools — one call instead of dozens of `grep`/`find`/`cat` invocations
47
47
  - **CLI** — developers and agents explore, query, and audit code from the terminal
48
48
  - **CI gates** — `check` and `manifesto` commands enforce quality thresholds with exit codes
49
49
  - **Programmatic API** — embed codegraph in your own tools via `npm install`
@@ -76,7 +76,7 @@ No config files, no Docker, no JVM, no API keys, no accounts. Point your agent a
76
76
 
77
77
  ### Feature comparison
78
78
 
79
- <sub>Comparison last verified: May 2026. Claims verified against each repo's README/docs. Full analysis: <a href="generated/competitive/COMPETITIVE_ANALYSIS.md">COMPETITIVE_ANALYSIS.md</a></sub>
79
+ <sub>Comparison last verified: June 2026. Claims verified against each repo's README/docs. Full analysis: <a href="generated/competitive/COMPETITIVE_ANALYSIS.md">COMPETITIVE_ANALYSIS.md</a></sub>
80
80
 
81
81
  | Capability | codegraph (this repo) | [code-review-graph](https://github.com/tirth8205/code-review-graph) | [narsil-mcp](https://github.com/postrv/narsil-mcp) | [codegraph (other)¹](https://github.com/colbymchenry/codegraph) | [axon](https://github.com/harshkedia177/axon) | [GitNexus](https://github.com/abhigyanpatwari/GitNexus) |
82
82
  |---|:---:|:---:|:---:|:---:|:---:|:---:|
@@ -100,7 +100,7 @@ No config files, no Docker, no JVM, no API keys, no accounts. Point your agent a
100
100
 
101
101
  | | Differentiator | In practice |
102
102
  |---|---|---|
103
- | **🤖** | **AI-first architecture** | 30-tool [MCP server](https://modelcontextprotocol.io/) — agents query the graph directly instead of scraping the filesystem. One call replaces 20+ grep/find/cat invocations |
103
+ | **🤖** | **AI-first architecture** | 34-tool [MCP server](https://modelcontextprotocol.io/) — agents query the graph directly instead of scraping the filesystem. One call replaces 20+ grep/find/cat invocations |
104
104
  | **🏷️** | **Role classification** | Every symbol auto-tagged as `entry`/`core`/`utility`/`adapter`/`dead`/`leaf` — agents understand a symbol's architectural role without reading surrounding code |
105
105
  | **🔬** | **Function-level, not just files** | Traces `handleAuth()` → `validateToken()` → `decryptJWT()` and shows 14 callers across 9 files break if `decryptJWT` changes |
106
106
  | **⚡** | **Always-fresh graph** | Three-tier change detection: journal (O(changed)) → mtime+size (O(n) stats) → hash (O(changed) reads). Sub-second rebuilds — agents work with current data |
@@ -124,10 +124,10 @@ That's it. The graph is ready. Now connect your AI agent.
124
124
 
125
125
  ### For AI agents (primary use case)
126
126
 
127
- Connect directly via MCP — your agent gets 30 tools to query the graph:
127
+ Connect directly via MCP — your agent gets 34 tools to query the graph:
128
128
 
129
129
  ```bash
130
- codegraph mcp # 33-tool MCP server — AI queries the graph directly
130
+ codegraph mcp # 34-tool MCP server — AI queries the graph directly
131
131
  ```
132
132
 
133
133
  Or add codegraph to your agent's instructions (e.g. `CLAUDE.md`):
@@ -169,7 +169,7 @@ cd codegraph && npm install && npm link
169
169
 
170
170
  | | Feature | Description |
171
171
  |---|---|---|
172
- | 🤖 | **MCP server** | 33-tool MCP server for AI assistants; single-repo by default, opt-in multi-repo |
172
+ | 🤖 | **MCP server** | 34-tool MCP server for AI assistants; single-repo by default, opt-in multi-repo |
173
173
  | 🎯 | **Deep context** | `context` gives agents source, deps, callers, signature, and tests for a function in one call; `audit --quick` gives structural summaries |
174
174
  | 🏷️ | **Node role classification** | Every symbol auto-tagged as `entry`/`core`/`utility`/`adapter`/`dead`/`leaf` based on connectivity — agents instantly know architectural role |
175
175
  | 📦 | **Batch querying** | Accept a list of targets and return all results in one JSON payload — enables multi-agent parallel dispatch |
@@ -332,6 +332,7 @@ Composite commands for risk-driven workflows and multi-agent dispatch.
332
332
  codegraph audit <file-or-function> # Combined structural summary + impact + health in one report
333
333
  codegraph audit <target> --quick # Structural summary only (skip impact and health)
334
334
  codegraph audit src/queries.js -T # Audit all functions in a file
335
+ codegraph explain <target> # Alias for audit — same output, easier to discover
335
336
  codegraph triage # Ranked audit priority queue (connectivity + hotspots + roles)
336
337
  codegraph triage -T --limit 20 # Top 20 riskiest functions, excluding tests
337
338
  codegraph triage --level file -T # File-level hotspot analysis
@@ -456,6 +457,22 @@ codegraph registry remove <name> # Unregister
456
457
 
457
458
  `codegraph build` auto-registers the project — no manual setup needed.
458
459
 
460
+ ### Configuration
461
+
462
+ Inspect and manage `.codegraphrc.json` settings.
463
+
464
+ ```bash
465
+ codegraph config # Show all config keys with values and sources
466
+ codegraph config --json # JSON output of the merged config
467
+ codegraph config --init # Scaffold a .codegraphrc.json with all sections pre-populated
468
+ codegraph config --edit # Open .codegraphrc.json in $EDITOR
469
+ codegraph config --enable-global # Opt this repo into user-level global config
470
+ codegraph config --disable-global # Opt this repo out of user-level global config
471
+ codegraph config --list-global # Show the contents of the global config file
472
+ ```
473
+
474
+ A user-level config file at `~/.config/codegraph/config.json` (XDG) or `~/.codegraph/config.json` lets you set personal defaults once and apply them to opted-in repos. The merge order is: DEFAULTS → global (if consented) → project → env. Non-interactive contexts (CI, MCP) never apply the global config without explicit consent. See [docs/guides/configuration.md](docs/guides/configuration.md) for full details.
475
+
459
476
  ### Common Flags
460
477
 
461
478
  | Flag | Description |
@@ -475,6 +492,8 @@ codegraph registry remove <name> # Unregister
475
492
  | `--limit <n>` | Limit number of results |
476
493
  | `--offset <n>` | Skip first N results (pagination) |
477
494
  | `--rrf-k <n>` | RRF smoothing constant for multi-query search (default 60) |
495
+ | `--user-config [path]` | Apply global user config for this run; optionally specify a custom path instead of the XDG default (`~/.config/codegraph/config.json`) |
496
+ | `--no-user-config` | Skip global user config for this run (CI/non-interactive safe) |
478
497
 
479
498
  ## 🌐 Language Support
480
499
 
@@ -624,36 +643,38 @@ Codegraph also extracts symbols from common callback patterns: Commander `.comma
624
643
 
625
644
  Self-measured on every release via CI ([build benchmarks](generated/benchmarks/BUILD-BENCHMARKS.md) | [embedding benchmarks](generated/benchmarks/EMBEDDING-BENCHMARKS.md) | [query benchmarks](generated/benchmarks/QUERY-BENCHMARKS.md) | [incremental benchmarks](generated/benchmarks/INCREMENTAL-BENCHMARKS.md) | [resolution precision/recall](tests/benchmarks/resolution/)):
626
645
 
627
- *Last updated: v3.11.1 (2026-05-30)*
646
+ *Last updated: v3.12.0 (2026-06-11)*
628
647
 
629
648
  | Metric | Native | WASM |
630
649
  |---|---|---|
631
- | Build speed | **3.7 ms/file** | **18.4 ms/file** |
632
- | Query time | **34ms** | **46ms** |
633
- | No-op rebuild | **24ms** | **20ms** |
634
- | 1-file rebuild | **81ms** | **68ms** |
635
- | Query: fn-deps | **2.5ms** | **2.3ms** |
636
- | Query: path | **2.5ms** | **2.3ms** |
637
- | ~50,000 files (est.) | **~185.0s build** | **~920.0s build** |
638
- | Resolution precision | **89.9%** | — |
639
- | Resolution recall | **42.3%** | — |
640
-
641
- Metrics are normalized per file for cross-version comparability. Times above are for a full initial build — incremental rebuilds only re-parse changed files.
650
+ | Build speed | **4.4 ms/file** | **21.2 ms/file** |
651
+ | Query time | **38ms** | **48ms** |
652
+ | No-op rebuild | **30ms** | **27ms** |
653
+ | 1-file rebuild | **121ms** | **76ms** |
654
+ | Query: fn-deps | **2.7ms** | **2.6ms** |
655
+ | Query: path | **2.8ms** | **2.5ms** |
656
+ | ~50,000 files (est.) | **~220.0s build** | **~1060.0s build** |
657
+ | Resolution precision | **84.4%** | — |
658
+ | Resolution recall | **56.1%** | — |
659
+
660
+ Metrics are normalized per file for cross-version comparability. Times above are for a full initial build — incremental rebuilds only re-parse changed files. v3.12.0 note: native build speed regressed ~22% (3.6→4.4 ms/file) and native 1-file incremental rebuild regressed ~41% (86→121 ms); tracked in [#1446](https://github.com/optave/ops-codegraph-tool/issues/1446).
642
661
 
643
662
  <details><summary>Per-language resolution precision/recall</summary>
644
663
 
664
+ v3.12.0 note: global precision dropped 89.9%→84.4%, driven by new false positives in `elixir` (+17 FP), `julia` (+11 FP), and `objc` (+5 FP) — all three still have 0% recall; tracked in [#1447](https://github.com/optave/ops-codegraph-tool/issues/1447). Global recall improved substantially (42.3%→56.1%).
665
+
645
666
  | Language | Precision | Recall | TP | FP | FN | Edges | Dynamic |
646
667
  |----------|----------:|-------:|---:|---:|---:|------:|--------:|
647
- | javascript | 100.0% | 66.7% | 12 | 0 | 6 | 18 | 14/28 |
648
- | typescript | 100.0% | 75.0% | 15 | 0 | 5 | 20 | — |
668
+ | javascript | 100.0% | 97.6% | 41 | 0 | 1 | 42 | 14/32 |
669
+ | typescript | 100.0% | 100.0% | 47 | 0 | 0 | 47 | — |
649
670
  | bash | 100.0% | 100.0% | 12 | 0 | 0 | 12 | 0/1 |
650
671
  | c | 100.0% | 100.0% | 9 | 0 | 0 | 9 | — |
651
672
  | clojure | 80.0% | 26.7% | 4 | 1 | 11 | 15 | — |
652
673
  | cpp | 100.0% | 57.1% | 8 | 0 | 6 | 14 | — |
653
- | csharp | 100.0% | 52.6% | 10 | 0 | 9 | 19 | — |
674
+ | csharp | 100.0% | 100.0% | 23 | 0 | 0 | 23 | — |
654
675
  | cuda | 50.0% | 33.3% | 4 | 4 | 8 | 12 | — |
655
676
  | dart | 0.0% | 0.0% | 0 | 0 | 18 | 18 | — |
656
- | elixir | 0.0% | 0.0% | 0 | 0 | 21 | 21 | — |
677
+ | elixir | 0.0% | 0.0% | 0 | 17 | 21 | 21 | — |
657
678
  | erlang | 100.0% | 100.0% | 12 | 0 | 0 | 12 | — |
658
679
  | fsharp | 0.0% | 0.0% | 0 | 11 | 12 | 12 | — |
659
680
  | gleam | 100.0% | 26.7% | 4 | 0 | 11 | 15 | — |
@@ -661,18 +682,19 @@ Metrics are normalized per file for cross-version comparability. Times above are
661
682
  | groovy | 100.0% | 7.7% | 1 | 0 | 12 | 13 | — |
662
683
  | haskell | 100.0% | 33.3% | 4 | 0 | 8 | 12 | — |
663
684
  | hcl | 0.0% | 0.0% | 0 | 0 | 2 | 2 | — |
664
- | java | 100.0% | 52.9% | 9 | 0 | 8 | 17 | — |
665
- | julia | 0.0% | 0.0% | 0 | 0 | 15 | 15 | — |
685
+ | java | 100.0% | 76.5% | 13 | 0 | 4 | 17 | — |
686
+ | julia | 0.0% | 0.0% | 0 | 11 | 15 | 15 | — |
666
687
  | kotlin | 92.3% | 63.2% | 12 | 1 | 7 | 19 | — |
667
688
  | lua | 100.0% | 15.4% | 2 | 0 | 11 | 13 | — |
668
- | objc | 0.0% | 0.0% | 0 | 1 | 12 | 12 | — |
689
+ | objc | 0.0% | 0.0% | 0 | 6 | 12 | 12 | — |
669
690
  | ocaml | 100.0% | 8.3% | 1 | 0 | 11 | 12 | — |
670
- | php | 100.0% | 31.6% | 6 | 0 | 13 | 19 | — |
691
+ | php | 100.0% | 57.9% | 11 | 0 | 8 | 19 | — |
692
+ | pts-javascript | 100.0% | 100.0% | 13 | 0 | 0 | 13 | — |
671
693
  | python | 100.0% | 60.0% | 9 | 0 | 6 | 15 | 15/15 |
672
694
  | r | 100.0% | 100.0% | 11 | 0 | 0 | 11 | — |
673
695
  | ruby | 100.0% | 100.0% | 11 | 0 | 0 | 11 | 11/11 |
674
- | rust | 100.0% | 35.7% | 5 | 0 | 9 | 14 | — |
675
- | scala | 100.0% | 71.4% | 5 | 0 | 2 | 7 | — |
696
+ | rust | 100.0% | 64.3% | 9 | 0 | 5 | 14 | — |
697
+ | scala | 100.0% | 100.0% | 7 | 0 | 0 | 7 | — |
676
698
  | solidity | 33.3% | 7.7% | 1 | 2 | 12 | 13 | — |
677
699
  | swift | 75.0% | 42.9% | 6 | 2 | 8 | 14 | 9/9 |
678
700
  | tsx | 100.0% | 100.0% | 13 | 0 | 0 | 13 | — |
@@ -683,13 +705,25 @@ Metrics are normalized per file for cross-version comparability. Times above are
683
705
 
684
706
  | Mode | Resolved | Expected | Recall |
685
707
  |------|--------:|---------:|-------:|
708
+ | receiver-typed | 32 | 112 | 28.6% |
686
709
  | module-function | 16 | 112 | 14.3% |
687
- | receiver-typed | 17 | 104 | 16.3% |
688
- | static | 66 | 93 | 71.0% |
689
- | same-file | 48 | 86 | 55.8% |
690
- | interface-dispatched | 7 | 12 | 58.3% |
691
- | class-inheritance | 0 | 4 | 0.0% |
710
+ | static | 78 | 96 | 81.3% |
711
+ | same-file | 66 | 90 | 73.3% |
712
+ | interface-dispatched | 19 | 19 | 100.0% |
713
+ | class-inheritance | 8 | 12 | 66.7% |
714
+ | callback | 7 | 7 | 100.0% |
715
+ | pts-spread | 4 | 4 | 100.0% |
716
+ | pts-define-property | 3 | 3 | 100.0% |
717
+ | dynamic | 3 | 3 | 100.0% |
718
+ | pts-create-prototype | 2 | 2 | 100.0% |
719
+ | points-to | 1 | 2 | 50.0% |
720
+ | re-export | 2 | 2 | 100.0% |
721
+ | pts-for-of | 2 | 2 | 100.0% |
722
+ | pts-set | 2 | 2 | 100.0% |
723
+ | pts-array-from | 2 | 2 | 100.0% |
692
724
  | trait-dispatch | 0 | 2 | 0.0% |
725
+ | define-property | 1 | 1 | 100.0% |
726
+ | defineProperty-accessor | 1 | 1 | 100.0% |
693
727
  | package-function | 1 | 1 | 100.0% |
694
728
 
695
729
  </details>
@@ -712,7 +746,7 @@ Optional: `@huggingface/transformers` (semantic search), `@modelcontextprotocol/
712
746
 
713
747
  ### MCP Server
714
748
 
715
- Codegraph is built around a [Model Context Protocol](https://modelcontextprotocol.io/) server with 30 tools (31 in multi-repo mode) — the primary way agents consume the graph:
749
+ Codegraph is built around a [Model Context Protocol](https://modelcontextprotocol.io/) server with 34 tools (35 in multi-repo mode) — the primary way agents consume the graph:
716
750
 
717
751
  ```bash
718
752
  codegraph mcp # Single-repo mode (default) — only local project
@@ -782,6 +816,8 @@ Copy `.github/workflows/codegraph-impact.yml` to your repo, and every PR will ge
782
816
 
783
817
  Create a `.codegraphrc.json` in your project root to customize behavior. The snippets below cover the most-used keys — see **[docs/guides/configuration.md](docs/guides/configuration.md)** for the full reference (every group, every key, every default).
784
818
 
819
+ **Global (user-level) config:** you can also define personal defaults once at `~/.config/codegraph/config.json` and opt individual repos into it with `codegraph config --enable-global`. The global layer merges below the project config so repos always win, and non-interactive contexts (CI, MCP) never apply it without explicit consent. See [docs/guides/configuration.md#user-level-global-configuration](docs/guides/configuration.md#user-level-global-configuration).
820
+
785
821
  ```json
786
822
  {
787
823
  "include": ["src/**", "lib/**"],
@@ -842,7 +878,7 @@ Works with any secret manager: 1Password CLI (`op`), Bitwarden (`bw`), `pass`, H
842
878
 
843
879
  ### MCP tool filtering
844
880
 
845
- Codegraph's MCP server exposes 30+ tools by default. For models with a small context window, you can shrink the schema by disabling tools you don't use:
881
+ Codegraph's MCP server exposes 34 tools by default. For models with a small context window, you can shrink the schema by disabling tools you don't use:
846
882
 
847
883
  ```json
848
884
  {
@@ -900,7 +936,7 @@ const { results: fused } = await multiSearchData(
900
936
 
901
937
  ## ⚠️ Limitations
902
938
 
903
- - **No TypeScript type-checker integration** — type inference resolves annotations, `new` expressions, and assignment chains, but does not invoke `tsc` for overload resolution or complex generics
939
+ - **TypeScript compiler integration is auto-enabled** — when `typescript` is installed and a `tsconfig.json` is found, the TypeScript compiler API pass runs automatically; disable with `"build": { "typescriptResolver": false }` in `.codegraphrc.json` if you want faster builds without it; heuristic type inference (annotations, `new` expressions, assignment chains) is always active as a baseline
904
940
  - **Dynamic calls are best-effort** — complex computed property access and `eval` patterns are not resolved
905
941
  - **Python imports** — resolves relative imports but doesn't follow `sys.path` or virtual environment packages
906
942
  - **Dataflow analysis** — intraprocedural (single-function scope), not interprocedural
@@ -918,7 +954,7 @@ See **[ROADMAP.md](docs/roadmap/ROADMAP.md)** for the full development roadmap a
918
954
  7. ~~**TypeScript Migration**~~ — **Complete** (v3.4.0) — all 271 source files migrated from JS to TS, zero `.js` remaining
919
955
  8. ~~**Native Analysis Acceleration**~~ — **Complete** (v3.5.0) — all build phases in Rust/rusqlite, sub-100ms incremental rebuilds, better-sqlite3 lazy-loaded as fallback only
920
956
  9. ~~**Expanded Language Support**~~ — **Complete** (v3.8.0) — 23 new languages in 4 batches (11 → 34), dual-engine WASM + Rust support for all
921
- 10. **Analysis Depth** — TypeScript-native resolution, inter-procedural type propagation, field-based points-to analysis
957
+ 10. ~~**Analysis Depth**~~ — **Complete** (v3.12.0) — TypeScript-native resolution, inter-procedural type propagation, field-based points-to analysis, barrel re-export chain resolution, CHA+RTA dynamic dispatch
922
958
  11. **Runtime & Extensibility** — event-driven pipeline, plugin system, query caching, pagination
923
959
  12. **Quality, Security & Technical Debt** — supply-chain security (SBOM, SLSA), CI coverage gates, timer cleanup, tech debt kill list
924
960
  13. **Intelligent Embeddings** — LLM-generated descriptions, enhanced embeddings, module summaries
@@ -1 +1 @@
1
- {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/audit.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,eAAO,MAAM,OAAO,EAAE,iBAuCrB,CAAC"}
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/audit.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,eAAO,MAAM,OAAO,EAAE,iBAwCrB,CAAC"}
@@ -5,7 +5,8 @@ import { explain } from '../../presentation/queries-cli.js';
5
5
  import { config } from '../shared/options.js';
6
6
  export const command = {
7
7
  name: 'audit <target>',
8
- description: 'Composite report: explain + impact + health metrics per function',
8
+ alias: 'explain',
9
+ description: 'Composite report: explain + impact + health metrics per function (alias: explain)',
9
10
  options: [
10
11
  ['-d, --db <path>', 'Path to graph.db'],
11
12
  ['--quick', 'Structural summary only (skip impact analysis and health metrics)'],
@@ -1 +1 @@
1
- {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../../src/cli/commands/audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,mCAAmC,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAG9C,MAAM,CAAC,MAAM,OAAO,GAAsB;IACxC,IAAI,EAAE,gBAAgB;IACtB,WAAW,EAAE,kEAAkE;IAC/E,OAAO,EAAE;QACP,CAAC,iBAAiB,EAAE,kBAAkB,CAAC;QACvC,CAAC,SAAS,EAAE,mEAAmE,CAAC;QAChF,CAAC,aAAa,EAAE,sBAAsB,EAAE,GAAG,CAAC;QAC5C,CAAC,mBAAmB,EAAE,2CAA2C,EAAE,WAAW,CAAC;QAC/E,CAAC,mBAAmB,EAAE,uBAAuB,CAAC;QAC9C,CAAC,gBAAgB,EAAE,sCAAsC,CAAC;QAC1D,CAAC,iBAAiB,EAAE,yDAAyD,CAAC;QAC9E,CAAC,YAAY,EAAE,gBAAgB,CAAC;QAChC,CAAC,sBAAsB,EAAE,oCAAoC,CAAC;QAC9D,CAAC,mBAAmB,EAAE,6BAA6B,CAAC;QACpD,CAAC,UAAU,EAAE,4CAA4C,CAAC;KAC3D;IACD,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI;QACtB,IAAI,IAAI,CAAC,IAAI,IAAI,CAAE,iBAAuC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/E,OAAO,iBAAiB,IAAI,CAAC,IAAI,aAAa,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/E,CAAC;IACH,CAAC;IACD,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,GAAG;QACzB,MAAM,KAAK,GAAG,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,MAAO,EAAE,IAAI,CAAC,EAAE,EAAE;gBACxB,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAe,EAAE,EAAE,CAAC;gBACzC,GAAG,KAAK;aACT,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QACD,KAAK,CAAC,MAAO,EAAE,IAAI,CAAC,EAAE,EAAE;YACtB,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAe,EAAE,EAAE,CAAC;YACzC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,MAAM;SACP,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../../src/cli/commands/audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,mCAAmC,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAG9C,MAAM,CAAC,MAAM,OAAO,GAAsB;IACxC,IAAI,EAAE,gBAAgB;IACtB,KAAK,EAAE,SAAS;IAChB,WAAW,EAAE,mFAAmF;IAChG,OAAO,EAAE;QACP,CAAC,iBAAiB,EAAE,kBAAkB,CAAC;QACvC,CAAC,SAAS,EAAE,mEAAmE,CAAC;QAChF,CAAC,aAAa,EAAE,sBAAsB,EAAE,GAAG,CAAC;QAC5C,CAAC,mBAAmB,EAAE,2CAA2C,EAAE,WAAW,CAAC;QAC/E,CAAC,mBAAmB,EAAE,uBAAuB,CAAC;QAC9C,CAAC,gBAAgB,EAAE,sCAAsC,CAAC;QAC1D,CAAC,iBAAiB,EAAE,yDAAyD,CAAC;QAC9E,CAAC,YAAY,EAAE,gBAAgB,CAAC;QAChC,CAAC,sBAAsB,EAAE,oCAAoC,CAAC;QAC9D,CAAC,mBAAmB,EAAE,6BAA6B,CAAC;QACpD,CAAC,UAAU,EAAE,4CAA4C,CAAC;KAC3D;IACD,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI;QACtB,IAAI,IAAI,CAAC,IAAI,IAAI,CAAE,iBAAuC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/E,OAAO,iBAAiB,IAAI,CAAC,IAAI,aAAa,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/E,CAAC;IACH,CAAC;IACD,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,GAAG;QACzB,MAAM,KAAK,GAAG,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,MAAO,EAAE,IAAI,CAAC,EAAE,EAAE;gBACxB,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAe,EAAE,EAAE,CAAC;gBACzC,GAAG,KAAK;aACT,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QACD,KAAK,CAAC,MAAO,EAAE,IAAI,CAAC,EAAE,EAAE;YACtB,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAe,EAAE,EAAE,CAAC;YACzC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,MAAM;SACP,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/batch.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,eAAO,MAAM,OAAO,EAAE,iBAwDrB,CAAC"}
1
+ {"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/batch.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,eAAO,MAAM,OAAO,EAAE,iBAyDrB,CAAC"}
@@ -16,6 +16,7 @@ export const command = {
16
16
  ['-k, --kind <kind>', 'Filter by symbol kind'],
17
17
  ['-T, --no-tests', 'Exclude test/spec files from results'],
18
18
  ['--include-tests', 'Include test/spec files (overrides excludeTests config)'],
19
+ ['-j, --json', 'Accepted for script compatibility (batch always outputs JSON)'],
19
20
  ],
20
21
  validate([_command, _targets], opts) {
21
22
  if (opts.kind && !EVERY_SYMBOL_KIND.includes(opts.kind)) {
@@ -1 +1 @@
1
- {"version":3,"file":"batch.js","sourceRoot":"","sources":["../../../src/cli/commands/batch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"batch.js","sourceRoot":"","sources":["../../../src/cli/commands/batch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAGrE,MAAM,CAAC,MAAM,OAAO,GAAsB;IACxC,IAAI,EAAE,8BAA8B;IACpC,WAAW,EAAE,6FAA6F,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;IAClJ,OAAO,EAAE;QACP,CAAC,iBAAiB,EAAE,kBAAkB,CAAC;QACvC,CAAC,oBAAoB,EAAE,0DAA0D,CAAC;QAClF,CAAC,SAAS,EAAE,sCAAsC,CAAC;QACnD,CAAC,aAAa,EAAE,8CAA8C,CAAC;QAC/D,CAAC,mBAAmB,EAAE,2CAA2C,EAAE,WAAW,CAAC;QAC/E,CAAC,mBAAmB,EAAE,uBAAuB,CAAC;QAC9C,CAAC,gBAAgB,EAAE,sCAAsC,CAAC;QAC1D,CAAC,iBAAiB,EAAE,yDAAyD,CAAC;QAC9E,CAAC,YAAY,EAAE,+DAA+D,CAAC;KAChF;IACD,QAAQ,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,IAAI;QACjC,IAAI,IAAI,CAAC,IAAI,IAAI,CAAE,iBAAuC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/E,OAAO,iBAAiB,IAAI,CAAC,IAAI,aAAa,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/E,CAAC;IACH,CAAC;IACD,KAAK,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,iBAAiB,CAAC,EAAE,IAAI,EAAE,GAAG;QACnD,IAAI,OAAkB,CAAC;QACvB,IAAI,CAAC;YACH,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,QAAkB,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;gBACrE,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBACxB,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC5B,CAAC;qBAAM,CAAC;oBACN,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBAC/C,CAAC;YACH,CAAC;iBAAM,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACtB,MAAM,MAAM,GAAa,EAAE,CAAC;gBAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK;oBAAE,MAAM,CAAC,IAAI,CAAC,KAAe,CAAC,CAAC;gBACtE,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;gBAC3D,OAAO,GAAG,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACvF,CAAC;iBAAM,CAAC;gBACN,OAAO,GAAG,YAAY,CAAC,iBAAwC,CAAC,CAAC;YACnE,CAAC;QACH,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,IAAI,WAAW,CAAC,4BAA4B,cAAc,CAAC,GAAG,CAAC,EAAE,EAAE;gBACvE,KAAK,EAAE,GAAY;aACpB,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrC,MAAM,IAAI,WAAW,CACnB,0EAA0E,CAC3E,CAAC;QACJ,CAAC;QAED,UAAU,CAAC,OAA8D,EAAE,IAAI,CAAC,EAAE,EAAE;YAClF,OAAO;YACP,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAe,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;YAClE,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC;SAClC,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/build.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,eAAO,MAAM,OAAO,EAAE,iBAwBrB,CAAC"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/build.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,eAAO,MAAM,OAAO,EAAE,iBA6BrB,CAAC"}
@@ -13,7 +13,10 @@ export const command = {
13
13
  ],
14
14
  async execute([dir], opts, ctx) {
15
15
  const root = path.resolve(dir || '.');
16
- const engine = ctx.program.opts().engine;
16
+ const globalOpts = ctx.program.opts();
17
+ const engine = globalOpts.engine;
18
+ // Prompt for global-config consent on interactive TTY builds (§4.3).
19
+ const promptForConsent = !process.env.CI && !!process.stdin.isTTY && !!process.stdout.isTTY;
17
20
  await buildGraph(root, {
18
21
  incremental: opts.incremental,
19
22
  ast: opts.ast,
@@ -22,6 +25,8 @@ export const command = {
22
25
  dataflow: opts.dataflow,
23
26
  cfg: opts.cfg,
24
27
  dbPath: opts.db ? path.resolve(opts.db) : undefined,
28
+ userConfig: globalOpts.userConfig,
29
+ promptForConsent,
25
30
  });
26
31
  },
27
32
  };
@@ -1 +1 @@
1
- {"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/cli/commands/build.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAI3D,MAAM,CAAC,MAAM,OAAO,GAAsB;IACxC,IAAI,EAAE,aAAa;IACnB,WAAW,EAAE,mDAAmD;IAChE,OAAO,EAAE;QACP,CAAC,iBAAiB,EAAE,uDAAuD,CAAC;QAC5E,CAAC,kBAAkB,EAAE,yCAAyC,CAAC;QAC/D,CAAC,UAAU,EAAE,oEAAoE,CAAC;QAClF,CAAC,iBAAiB,EAAE,qCAAqC,CAAC;QAC1D,CAAC,eAAe,EAAE,gCAAgC,CAAC;QACnD,CAAC,UAAU,EAAE,kCAAkC,CAAC;KACjD;IACD,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,GAAG;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC;QACzC,MAAM,UAAU,CAAC,IAAI,EAAE;YACrB,WAAW,EAAE,IAAI,CAAC,WAAsB;YACxC,GAAG,EAAE,IAAI,CAAC,GAAc;YACxB,UAAU,EAAE,IAAI,CAAC,UAAqB;YACtC,MAAM,EAAE,MAAoB;YAC5B,QAAQ,EAAE,IAAI,CAAC,QAAmB;YAClC,GAAG,EAAE,IAAI,CAAC,GAAc;YACxB,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAY,CAAC,CAAC,CAAC,CAAC,SAAS;SAC9D,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/cli/commands/build.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAI3D,MAAM,CAAC,MAAM,OAAO,GAAsB;IACxC,IAAI,EAAE,aAAa;IACnB,WAAW,EAAE,mDAAmD;IAChE,OAAO,EAAE;QACP,CAAC,iBAAiB,EAAE,uDAAuD,CAAC;QAC5E,CAAC,kBAAkB,EAAE,yCAAyC,CAAC;QAC/D,CAAC,UAAU,EAAE,oEAAoE,CAAC;QAClF,CAAC,iBAAiB,EAAE,qCAAqC,CAAC;QAC1D,CAAC,eAAe,EAAE,gCAAgC,CAAC;QACnD,CAAC,UAAU,EAAE,kCAAkC,CAAC;KACjD;IACD,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,GAAG;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC;QACtC,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACtC,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;QACjC,qEAAqE;QACrE,MAAM,gBAAgB,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;QAC5F,MAAM,UAAU,CAAC,IAAI,EAAE;YACrB,WAAW,EAAE,IAAI,CAAC,WAAsB;YACxC,GAAG,EAAE,IAAI,CAAC,GAAc;YACxB,UAAU,EAAE,IAAI,CAAC,UAAqB;YACtC,MAAM,EAAE,MAAoB;YAC5B,QAAQ,EAAE,IAAI,CAAC,QAAmB;YAClC,GAAG,EAAE,IAAI,CAAC,GAAc;YACxB,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAY,CAAC,CAAC,CAAC,CAAC,SAAS;YAC7D,UAAU,EAAE,UAAU,CAAC,UAA0C;YACjE,gBAAgB;SACjB,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { CommandDefinition } from '../types.js';
2
+ export declare const command: CommandDefinition;
3
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/config.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAmIrD,eAAO,MAAM,OAAO,EAAE,iBA0MrB,CAAC"}
@@ -0,0 +1,272 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { clearConfigCache, DEFAULTS, getDefaultUserConfigPath, loadConfig, loadConfigWithProvenance, resolveUserConfigPath, } from '../../infrastructure/config.js';
5
+ import { getUserConfigConsent, listUserConfigConsent, REGISTRY_PATH, setUserConfigConsent, } from '../../infrastructure/registry.js';
6
+ import { formatTable } from '../../presentation/table.js';
7
+ /**
8
+ * Recursively flatten a nested config object to dot-notation key/value pairs.
9
+ * Arrays and null values are serialised to strings.
10
+ */
11
+ function flattenConfig(obj, prefix = '') {
12
+ const out = [];
13
+ for (const [k, v] of Object.entries(obj)) {
14
+ const fullKey = prefix ? `${prefix}.${k}` : k;
15
+ if (v !== null && typeof v === 'object' && !Array.isArray(v)) {
16
+ out.push(...flattenConfig(v, fullKey));
17
+ }
18
+ else if (Array.isArray(v)) {
19
+ out.push({ key: fullKey, value: v.length === 0 ? '[]' : JSON.stringify(v) });
20
+ }
21
+ else {
22
+ out.push({ key: fullKey, value: v === null ? 'null' : String(v) });
23
+ }
24
+ }
25
+ return out;
26
+ }
27
+ /**
28
+ * Expand a top-level provenance map (e.g. { build: 'project' }) to cover every
29
+ * flattened dot-notation key (e.g. 'build.incremental' → 'project').
30
+ */
31
+ function expandProvenance(flatEntries, provenance) {
32
+ const map = new Map();
33
+ for (const { key } of flatEntries) {
34
+ // Provenance is keyed by top-level section (e.g. 'build', 'llm'), so
35
+ // extract the first segment to find the governing provenance entry.
36
+ const topLevel = key.split('.')[0] ?? key;
37
+ map.set(key, provenance[topLevel] ?? 'default');
38
+ }
39
+ return map;
40
+ }
41
+ /**
42
+ * Render the effective config as a human-readable Key/Value/Source table.
43
+ * All rows are shown, sorted so non-default overrides appear first, then
44
+ * remaining defaults alphabetically.
45
+ */
46
+ function renderConfigTable(config, provenance) {
47
+ const flat = flattenConfig(config);
48
+ const sourceMap = expandProvenance(flat, provenance);
49
+ // Show all entries — sorting non-defaults first, then alphabetically
50
+ const rows = flat
51
+ .slice()
52
+ .sort((a, b) => {
53
+ const sa = sourceMap.get(a.key) ?? 'default';
54
+ const sb = sourceMap.get(b.key) ?? 'default';
55
+ // Non-defaults first
56
+ if (sa !== 'default' && sb === 'default')
57
+ return -1;
58
+ if (sa === 'default' && sb !== 'default')
59
+ return 1;
60
+ return a.key.localeCompare(b.key);
61
+ })
62
+ .map(({ key, value }) => [key, value, sourceMap.get(key) ?? 'default']);
63
+ const keyWidth = Math.max(3, ...rows.map((r) => r[0].length));
64
+ const valWidth = Math.max(5, ...rows.map((r) => r[1].length));
65
+ // Source column is always short ('default', 'user', 'project', 'env')
66
+ const srcWidth = 7;
67
+ return `${formatTable({
68
+ columns: [
69
+ { header: 'Key', width: keyWidth },
70
+ { header: 'Value', width: valWidth },
71
+ { header: 'Source', width: srcWidth },
72
+ ],
73
+ rows: rows,
74
+ indent: 0,
75
+ })}\n`;
76
+ }
77
+ /**
78
+ * Build a scaffolded global config JSON file.
79
+ * Produces valid JSON with common sections pre-populated at their defaults.
80
+ * Uses DEFAULTS so the values always reflect the current schema.
81
+ *
82
+ * All keys are optional — users can delete sections they don't need.
83
+ */
84
+ function buildInitTemplate() {
85
+ // Build a plain object — no comments in JSON, but keep it self-explanatory.
86
+ // Unknown top-level keys are silently ignored by mergeConfig.
87
+ const template = {
88
+ // LLM provider for AI features (codegraph explain, context, etc.)
89
+ // Use apiKeyCommand to pull the key from a secret manager at runtime.
90
+ // Scope to specific repos with:
91
+ // { "appliesTo": ["~/projects/*"], "config": { ... } }
92
+ llm: {
93
+ provider: DEFAULTS.llm.provider,
94
+ model: DEFAULTS.llm.model,
95
+ baseUrl: DEFAULTS.llm.baseUrl,
96
+ apiKey: DEFAULTS.llm.apiKey,
97
+ apiKeyCommand: DEFAULTS.llm.apiKeyCommand,
98
+ },
99
+ query: {
100
+ defaultDepth: DEFAULTS.query.defaultDepth,
101
+ defaultLimit: DEFAULTS.query.defaultLimit,
102
+ excludeTests: DEFAULTS.query.excludeTests,
103
+ },
104
+ build: {
105
+ incremental: DEFAULTS.build.incremental,
106
+ typescriptResolver: DEFAULTS.build.typescriptResolver,
107
+ },
108
+ ci: {
109
+ failOnCycles: DEFAULTS.ci.failOnCycles,
110
+ impactThreshold: DEFAULTS.ci.impactThreshold,
111
+ },
112
+ search: {
113
+ defaultMinScore: DEFAULTS.search.defaultMinScore,
114
+ topK: DEFAULTS.search.topK,
115
+ },
116
+ };
117
+ return `${JSON.stringify(template, null, 2)}\n`;
118
+ }
119
+ export const command = {
120
+ name: 'config',
121
+ description: 'Show or manage codegraph configuration (project + user-level global config)',
122
+ options: [
123
+ ['-j, --json', 'Output as JSON'],
124
+ ['--explain', 'Show per-key provenance (default / user / project / env)'],
125
+ ['--enable-global', 'Record consent to apply the global config to this repo'],
126
+ ['--disable-global', 'Record consent to skip the global config for this repo'],
127
+ ['--list-global', 'List all repos with a recorded consent decision'],
128
+ [
129
+ '--init',
130
+ 'Scaffold a global config file at the default XDG location with all sections pre-populated',
131
+ ],
132
+ ['--edit', 'Open the global config file in $EDITOR (prints the path if $EDITOR is unset)'],
133
+ ],
134
+ execute(_args, opts, ctx) {
135
+ const rootDir = path.resolve('.');
136
+ // ── Init: scaffold global config ───────────────────────────────────
137
+ if (opts.init) {
138
+ const targetPath = getDefaultUserConfigPath();
139
+ if (fs.existsSync(targetPath)) {
140
+ process.stderr.write(`Global config already exists at ${targetPath}\n` +
141
+ `Run \`codegraph config --edit\` to open it, or delete it and re-run --init.\n`);
142
+ process.exit(1);
143
+ }
144
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
145
+ fs.writeFileSync(targetPath, buildInitTemplate(), 'utf-8');
146
+ process.stdout.write(`Created global config at ${targetPath}\n`);
147
+ process.stdout.write(`Next steps:\n` +
148
+ ` 1. Edit the file: codegraph config --edit\n` +
149
+ ` 2. Enable it for this repo: codegraph config --enable-global\n`);
150
+ return;
151
+ }
152
+ // ── Edit: open global config in $EDITOR ────────────────────────────
153
+ if (opts.edit) {
154
+ // Prefer the existing file; fall back to the default path so the user
155
+ // can create-and-edit in one step even before running --init.
156
+ const filePath = resolveUserConfigPath() ?? getDefaultUserConfigPath();
157
+ const editor = process.env.EDITOR || process.env.VISUAL;
158
+ if (!editor) {
159
+ process.stdout.write(`${filePath}\n`);
160
+ process.stderr.write(`$EDITOR is not set. Set it in your shell profile (e.g. export EDITOR=nano)\n` +
161
+ `or open the file manually at the path printed above.\n`);
162
+ return;
163
+ }
164
+ // Ensure the directory exists so the editor can create the file
165
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
166
+ const result = spawnSync(editor, [filePath], { stdio: 'inherit' });
167
+ if (result.error) {
168
+ process.stderr.write(`Failed to launch editor "${editor}": ${result.error.message}\n`);
169
+ process.exit(1);
170
+ }
171
+ if (result.status !== 0) {
172
+ process.exit(result.status ?? 1);
173
+ }
174
+ return;
175
+ }
176
+ // ── Consent management ─────────────────────────────────────────────
177
+ if (opts.enableGlobal) {
178
+ setUserConfigConsent(rootDir, 'enabled');
179
+ clearConfigCache();
180
+ const globalPath = resolveUserConfigPath();
181
+ if (!globalPath) {
182
+ process.stderr.write(`Consent recorded: "enabled" for ${rootDir}\n` +
183
+ `Note: no global config file found. Create one at ~/.config/codegraph/config.json\n`);
184
+ }
185
+ else {
186
+ process.stderr.write(`Consent recorded: "enabled" for ${rootDir}\n` + `Global config: ${globalPath}\n`);
187
+ }
188
+ return;
189
+ }
190
+ if (opts.disableGlobal) {
191
+ setUserConfigConsent(rootDir, 'disabled');
192
+ clearConfigCache();
193
+ process.stderr.write(`Consent recorded: "disabled" for ${rootDir}\n`);
194
+ return;
195
+ }
196
+ if (opts.listGlobal) {
197
+ const entries = listUserConfigConsent(REGISTRY_PATH);
198
+ if (opts.json) {
199
+ process.stdout.write(`${JSON.stringify(entries, null, 2)}\n`);
200
+ return;
201
+ }
202
+ if (entries.length === 0) {
203
+ process.stdout.write('No repos have a recorded global-config consent decision.\n');
204
+ return;
205
+ }
206
+ process.stdout.write('Global config consent decisions:\n\n');
207
+ for (const { path: p, decision } of entries) {
208
+ process.stdout.write(` ${decision === 'enabled' ? '✔' : '✘'} ${decision.padEnd(8)} ${p}\n`);
209
+ }
210
+ return;
211
+ }
212
+ // ── Explain mode ───────────────────────────────────────────────────
213
+ if (opts.explain) {
214
+ const { config, provenance, appliedGlobalPath, consentDecision } = loadConfigWithProvenance(rootDir, {
215
+ userConfig: ctx.program.opts().userConfig,
216
+ });
217
+ const globalPath = resolveUserConfigPath();
218
+ const consent = getUserConfigConsent(rootDir);
219
+ if (opts.json) {
220
+ process.stdout.write(`${JSON.stringify({
221
+ config,
222
+ provenance,
223
+ appliedGlobalPath,
224
+ globalFilePath: globalPath,
225
+ consentDecision: consentDecision ?? consent ?? 'undecided',
226
+ }, null, 2)}\n`);
227
+ return;
228
+ }
229
+ // Human-readable explain output
230
+ process.stdout.write('=== Codegraph config provenance ===\n\n');
231
+ const consentStr = consentDecision ?? consent ?? 'undecided';
232
+ process.stdout.write(`Global config file : ${globalPath ?? '(none found)'}\n`);
233
+ process.stdout.write(`Applied this run : ${appliedGlobalPath ? 'yes' : 'no'}\n`);
234
+ process.stdout.write(`Consent for repo : ${consentStr}\n`);
235
+ process.stdout.write(` (change with \`codegraph config --enable-global\` or \`--disable-global\`)\n`);
236
+ if (!globalPath) {
237
+ process.stdout.write(`\nDiscovery hint: create a global config at ~/.config/codegraph/config.json\n` +
238
+ `then run \`codegraph config --enable-global\` in repos where you want it applied.\n`);
239
+ }
240
+ else if (!appliedGlobalPath) {
241
+ process.stdout.write(`\nDiscovery hint: global config exists but is not applied to this repo.\n` +
242
+ `Run \`codegraph config --enable-global\` to enable it here.\n`);
243
+ }
244
+ process.stdout.write('\n--- Per-key provenance ---\n\n');
245
+ const provenanceEntries = Object.entries(provenance).sort(([a], [b]) => a.localeCompare(b));
246
+ for (const [key, source] of provenanceEntries) {
247
+ process.stdout.write(` ${source.padEnd(8)} ${key}\n`);
248
+ }
249
+ return;
250
+ }
251
+ // ── Default: print effective config ────────────────────────────────
252
+ const globalPath = resolveUserConfigPath();
253
+ const consent = getUserConfigConsent(rootDir);
254
+ if (opts.json) {
255
+ const config = loadConfig(rootDir, { userConfig: ctx.program.opts().userConfig });
256
+ process.stdout.write(`${JSON.stringify(config, null, 2)}\n`);
257
+ }
258
+ else {
259
+ // Human-readable table: Key | Value | Source
260
+ const { config, provenance } = loadConfigWithProvenance(rootDir, {
261
+ userConfig: ctx.program.opts().userConfig,
262
+ });
263
+ process.stdout.write(renderConfigTable(config, provenance));
264
+ if (globalPath && !consent) {
265
+ process.stderr.write(`\nℹ Global config found at ${globalPath} — not applied to this repo.\n` +
266
+ ` Run \`codegraph config --enable-global\` to opt in, or\n` +
267
+ ` \`codegraph config --disable-global\` to dismiss this notice.\n`);
268
+ }
269
+ }
270
+ },
271
+ };
272
+ //# sourceMappingURL=config.js.map