codebrain 0.1.1__tar.gz → 0.3.0__tar.gz

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 (176) hide show
  1. {codebrain-0.1.1 → codebrain-0.3.0}/LICENSE +1 -1
  2. {codebrain-0.1.1 → codebrain-0.3.0}/PKG-INFO +49 -8
  3. {codebrain-0.1.1 → codebrain-0.3.0}/README.md +25 -6
  4. codebrain-0.3.0/codebrain/__init__.py +10 -0
  5. codebrain-0.3.0/codebrain/actions/__init__.py +16 -0
  6. codebrain-0.3.0/codebrain/actions/base.py +139 -0
  7. codebrain-0.3.0/codebrain/actions/refactor.py +365 -0
  8. codebrain-0.3.0/codebrain/actions/reviewer.py +313 -0
  9. codebrain-0.3.0/codebrain/actions/test_gen.py +283 -0
  10. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/analyzer.py +953 -943
  11. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/api.py +330 -0
  12. codebrain-0.3.0/codebrain/architecture.py +824 -0
  13. codebrain-0.3.0/codebrain/cli.py +4282 -0
  14. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/comprehension.py +98 -31
  15. codebrain-0.3.0/codebrain/config.py +67 -0
  16. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/context.py +1 -0
  17. codebrain-0.3.0/codebrain/cross_query.py +450 -0
  18. codebrain-0.3.0/codebrain/cross_registry.py +328 -0
  19. codebrain-0.3.0/codebrain/diff_impact.py +400 -0
  20. codebrain-0.3.0/codebrain/env_migration.py +560 -0
  21. codebrain-0.3.0/codebrain/equivalence.py +584 -0
  22. codebrain-0.3.0/codebrain/frontend.py +443 -0
  23. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/graph/query.py +308 -18
  24. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/graph/schema.py +66 -1
  25. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/graph/store.py +81 -3
  26. codebrain-0.3.0/codebrain/hook_runner.py +176 -0
  27. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/hooks.py +2 -2
  28. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/indexer.py +85 -1
  29. codebrain-0.3.0/codebrain/kt.py +401 -0
  30. codebrain-0.3.0/codebrain/kt_video.py +948 -0
  31. codebrain-0.3.0/codebrain/mcp_lifecycle.py +327 -0
  32. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/mcp_server.py +2992 -1635
  33. codebrain-0.3.0/codebrain/migration.py +729 -0
  34. codebrain-0.3.0/codebrain/modernize.py +962 -0
  35. codebrain-0.3.0/codebrain/onboard.py +352 -0
  36. codebrain-0.3.0/codebrain/parser/cobol_parser.py +294 -0
  37. codebrain-0.3.0/codebrain/parser/config_parser.py +657 -0
  38. codebrain-0.3.0/codebrain/parser/csharp_parser.py +797 -0
  39. codebrain-0.3.0/codebrain/parser/dart_parser.py +865 -0
  40. codebrain-0.3.0/codebrain/parser/fortran_parser.py +281 -0
  41. codebrain-0.3.0/codebrain/parser/frontend_parser.py +1047 -0
  42. codebrain-0.3.0/codebrain/parser/go_parser.py +560 -0
  43. codebrain-0.3.0/codebrain/parser/java_parser.py +813 -0
  44. codebrain-0.3.0/codebrain/parser/kotlin_parser.py +823 -0
  45. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/parser/models.py +1 -0
  46. codebrain-0.3.0/codebrain/parser/mumps_parser.py +250 -0
  47. codebrain-0.3.0/codebrain/parser/plsql_parser.py +242 -0
  48. codebrain-0.3.0/codebrain/parser/python_parser.py +1255 -0
  49. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/parser/registry.py +97 -1
  50. codebrain-0.3.0/codebrain/parser/rust_parser.py +709 -0
  51. codebrain-0.3.0/codebrain/parser/schema_parser.py +491 -0
  52. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/parser/typescript_treesitter.py +70 -10
  53. codebrain-0.3.0/codebrain/parser/vue_parser.py +353 -0
  54. codebrain-0.3.0/codebrain/rewriter.py +2527 -0
  55. codebrain-0.3.0/codebrain/schema_migration.py +548 -0
  56. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/settings.py +3 -0
  57. codebrain-0.3.0/codebrain/susa_auth.py +157 -0
  58. codebrain-0.3.0/codebrain/test_gaps.py +325 -0
  59. codebrain-0.3.0/codebrain/test_runner.py +878 -0
  60. codebrain-0.3.0/codebrain/tour.py +475 -0
  61. codebrain-0.3.0/codebrain/ui_migration.py +394 -0
  62. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/utils.py +27 -7
  63. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/watcher/file_watcher.py +23 -13
  64. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain.egg-info/PKG-INFO +49 -8
  65. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain.egg-info/SOURCES.txt +75 -0
  66. codebrain-0.3.0/codebrain.egg-info/entry_points.txt +2 -0
  67. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain.egg-info/requires.txt +1 -0
  68. {codebrain-0.1.1 → codebrain-0.3.0}/pyproject.toml +16 -5
  69. codebrain-0.3.0/tests/test_actions.py +614 -0
  70. codebrain-0.3.0/tests/test_architecture.py +569 -0
  71. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_cli.py +2 -1
  72. codebrain-0.3.0/tests/test_coverage_gaps.py +517 -0
  73. codebrain-0.3.0/tests/test_cross_repo.py +479 -0
  74. codebrain-0.3.0/tests/test_csharp_parser.py +456 -0
  75. codebrain-0.3.0/tests/test_dart_parser.py +487 -0
  76. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_dead_code_confidence.py +17 -12
  77. codebrain-0.3.0/tests/test_diff_impact.py +122 -0
  78. codebrain-0.3.0/tests/test_env_migration.py +243 -0
  79. codebrain-0.3.0/tests/test_equivalence.py +385 -0
  80. codebrain-0.3.0/tests/test_fingerprints.py +327 -0
  81. codebrain-0.3.0/tests/test_frontend.py +1964 -0
  82. codebrain-0.3.0/tests/test_gate_battle.py +321 -0
  83. codebrain-0.3.0/tests/test_go_parser.py +437 -0
  84. codebrain-0.3.0/tests/test_hooks.py +316 -0
  85. codebrain-0.3.0/tests/test_infra_parser.py +239 -0
  86. codebrain-0.3.0/tests/test_java_parser.py +589 -0
  87. codebrain-0.3.0/tests/test_kotlin_parser.py +426 -0
  88. codebrain-0.3.0/tests/test_kt.py +143 -0
  89. codebrain-0.3.0/tests/test_legacy_parsers.py +463 -0
  90. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_llm.py +4 -2
  91. codebrain-0.3.0/tests/test_mcp_lifecycle.py +319 -0
  92. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_mcp_server.py +623 -615
  93. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_memory.py +470 -462
  94. codebrain-0.3.0/tests/test_migration.py +365 -0
  95. codebrain-0.3.0/tests/test_modernize.py +367 -0
  96. codebrain-0.3.0/tests/test_onboard.py +90 -0
  97. codebrain-0.3.0/tests/test_orm_detection.py +293 -0
  98. codebrain-0.3.0/tests/test_output_quality.py +384 -0
  99. codebrain-0.3.0/tests/test_real_codebase.py +223 -0
  100. codebrain-0.3.0/tests/test_real_features.py +448 -0
  101. codebrain-0.3.0/tests/test_real_frontend.py +434 -0
  102. codebrain-0.3.0/tests/test_real_repos.py +878 -0
  103. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_real_world.py +3 -2
  104. codebrain-0.3.0/tests/test_rewriter.py +1331 -0
  105. codebrain-0.3.0/tests/test_rust_parser.py +595 -0
  106. codebrain-0.3.0/tests/test_schema_migration.py +533 -0
  107. codebrain-0.3.0/tests/test_schema_parser.py +328 -0
  108. codebrain-0.3.0/tests/test_test_runner.py +546 -0
  109. codebrain-0.3.0/tests/test_tour.py +101 -0
  110. codebrain-0.3.0/tests/test_translate.py +524 -0
  111. codebrain-0.3.0/tests/test_ui_migration.py +686 -0
  112. codebrain-0.3.0/tests/test_vscode_extension.py +278 -0
  113. codebrain-0.1.1/codebrain/__init__.py +0 -3
  114. codebrain-0.1.1/codebrain/cli.py +0 -1927
  115. codebrain-0.1.1/codebrain/config.py +0 -46
  116. codebrain-0.1.1/codebrain/hook_runner.py +0 -71
  117. codebrain-0.1.1/codebrain/parser/config_parser.py +0 -228
  118. codebrain-0.1.1/codebrain/parser/python_parser.py +0 -658
  119. codebrain-0.1.1/codebrain.egg-info/entry_points.txt +0 -6
  120. codebrain-0.1.1/tests/test_hooks.py +0 -142
  121. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/__main__.py +0 -0
  122. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/agent_bridge.py +0 -0
  123. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/api_models.py +0 -0
  124. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/export.py +0 -0
  125. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/graph/__init__.py +0 -0
  126. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/llm.py +0 -0
  127. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/logging.py +0 -0
  128. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/memory/__init__.py +0 -0
  129. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/memory/store.py +0 -0
  130. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/parser/__init__.py +0 -0
  131. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/parser/base.py +0 -0
  132. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/parser/typescript_parser.py +0 -0
  133. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/py.typed +0 -0
  134. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/resolver.py +0 -0
  135. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/validator.py +0 -0
  136. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain/watcher/__init__.py +0 -0
  137. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain.egg-info/dependency_links.txt +0 -0
  138. {codebrain-0.1.1 → codebrain-0.3.0}/codebrain.egg-info/top_level.txt +0 -0
  139. {codebrain-0.1.1 → codebrain-0.3.0}/setup.cfg +0 -0
  140. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_agent_bridge.py +0 -0
  141. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_analyzer.py +0 -0
  142. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_api.py +0 -0
  143. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_ci.py +0 -0
  144. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_comprehension.py +0 -0
  145. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_context.py +0 -0
  146. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_contracts_real.py +0 -0
  147. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_dataflow.py +0 -0
  148. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_error_recovery.py +0 -0
  149. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_export.py +0 -0
  150. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_indexer.py +0 -0
  151. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_install.py +0 -0
  152. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_integration.py +0 -0
  153. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_jyotishyamitra.py +0 -0
  154. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_multi_project_cli.py +0 -0
  155. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_narratives.py +0 -0
  156. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_parser.py +0 -0
  157. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_plugin_system.py +0 -0
  158. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_production_hardening.py +0 -0
  159. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_query.py +0 -0
  160. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_resolver.py +0 -0
  161. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_scale.py +0 -0
  162. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_scale_optimizations.py +0 -0
  163. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_scale_real.py +0 -0
  164. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_schema.py +0 -0
  165. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_settings.py +0 -0
  166. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_store.py +0 -0
  167. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_ts_ast_parser.py +0 -0
  168. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_ts_parser_enhanced.py +0 -0
  169. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_typescript_parser.py +0 -0
  170. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_utils.py +0 -0
  171. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_validation_narratives.py +0 -0
  172. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_validator.py +0 -0
  173. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_validator_scenarios.py +0 -0
  174. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_watch_validate.py +0 -0
  175. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_watcher.py +0 -0
  176. {codebrain-0.1.1 → codebrain-0.3.0}/tests/test_zoom.py +0 -0
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 CodeBrain Contributors
3
+ Copyright (c) 2026 CodeBrain Contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,9 +1,30 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codebrain
3
- Version: 0.1.1
3
+ Version: 0.3.0
4
4
  Summary: Know what breaks before you break it. Structural knowledge graph for codebases — impact analysis, dead code detection, health scores. No LLM required.
5
5
  Author: CodeBrain Contributors
6
- License: MIT
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 CodeBrain Contributors
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
7
28
  Project-URL: Homepage, https://github.com/monk0062006/CodeBrain
8
29
  Project-URL: Repository, https://github.com/monk0062006/CodeBrain
9
30
  Project-URL: Issues, https://github.com/monk0062006/CodeBrain/issues
@@ -28,6 +49,7 @@ Requires-Dist: click>=8.1
28
49
  Requires-Dist: watchdog>=3.0
29
50
  Requires-Dist: mcp<1.20,>=1.0
30
51
  Requires-Dist: jinja2>=3.1
52
+ Requires-Dist: psutil>=5.9
31
53
  Provides-Extra: api
32
54
  Requires-Dist: fastapi>=0.110; extra == "api"
33
55
  Requires-Dist: uvicorn>=0.27; extra == "api"
@@ -59,14 +81,26 @@ cd your-project
59
81
  brain init
60
82
  ```
61
83
 
62
- That's it. Now you can:
84
+ You'll immediately see:
85
+
86
+ ```
87
+ Indexing my-project (93 files) ...
88
+ Done in 1.2s — 1861 nodes, 8837 edges
89
+
90
+ === Instant Findings ===
91
+ Health: 60/100 (B)
92
+ Riskiest symbols: Flask (34 files), App (35 files), Scaffold (28 files)
93
+ Dead code: 11 candidates (none high-confidence)
94
+ ```
95
+
96
+ Then explore:
63
97
 
64
98
  ```bash
65
99
  brain impact my_function # What breaks if I change this?
100
+ brain callers my_function # Who calls this?
66
101
  brain health # Codebase health score (0-100)
67
102
  brain hotspots # Riskiest symbols in the codebase
68
103
  brain deadcode # Unused functions with confidence levels
69
- brain coupling # Which files are too tightly coupled?
70
104
  brain zoom # Google Maps-style navigation of your architecture
71
105
  ```
72
106
 
@@ -173,7 +207,7 @@ Module: main.py — 429 symbols, 15853 lines. Isolated (no dependents).
173
207
  ### Claude Code (MCP)
174
208
 
175
209
  ```bash
176
- brain agent # auto-generates CLAUDE.md + MCP config
210
+ brain setup # auto-generates CLAUDE.md + MCP config
177
211
  ```
178
212
 
179
213
  Or add manually to your MCP config:
@@ -214,6 +248,7 @@ The `propose_change` MCP tool validates changes **before** the AI writes them. W
214
248
  | `brain status` | Show index statistics |
215
249
  | `brain search <query>` | Find symbols by name |
216
250
  | `brain impact <name>` | What breaks if this changes? |
251
+ | `brain callers <name>` | Who calls this function? (reverse trace) |
217
252
  | `brain trace <name>` | Forward call chain from a symbol |
218
253
  | `brain deps <name>` | Dependencies of a symbol or file |
219
254
  | `brain deadcode` | Find unused functions/classes |
@@ -265,7 +300,13 @@ Or use environment variables:
265
300
  | Python | AST (stdlib) | Full — functions, classes, imports, calls, dataflow |
266
301
  | TypeScript/JSX | tree-sitter | Full — requires `pip install codebrain[ts]` |
267
302
  | JavaScript/JSX | tree-sitter | Full — requires `pip install codebrain[ts]` |
268
- | TypeScript (fallback) | regex | Experimentalused when tree-sitter not installed |
303
+ | Java | tree-sitter | FullSpring Boot aware (DI, endpoints, JPA) |
304
+ | Go | tree-sitter | Full — interfaces, goroutines, struct methods |
305
+ | Rust | tree-sitter | Full — traits, impls, modules, derive macros |
306
+ | C# | tree-sitter | Full — async/await, LINQ, attributes |
307
+ | Kotlin | tree-sitter | Full — coroutines, extensions, data classes |
308
+ | Dart/Flutter | regex | Good — classes, mixins, extensions |
309
+ | Vue SFC | regex | Good — components, props, events |
269
310
 
270
311
  ### Adding Languages
271
312
 
@@ -275,9 +316,9 @@ Implement `BaseParser` and register via entry points:
275
316
  from codebrain.parser.base import BaseParser
276
317
  from codebrain.parser.models import ParsedFile
277
318
 
278
- class RustParser(BaseParser):
319
+ class MyParser(BaseParser):
279
320
  def extensions(self) -> frozenset[str]:
280
- return frozenset({".rs"})
321
+ return frozenset({".xyz"})
281
322
 
282
323
  def parse(self, path, repo_root) -> ParsedFile:
283
324
  ... # parse and return nodes + edges
@@ -10,14 +10,26 @@ cd your-project
10
10
  brain init
11
11
  ```
12
12
 
13
- That's it. Now you can:
13
+ You'll immediately see:
14
+
15
+ ```
16
+ Indexing my-project (93 files) ...
17
+ Done in 1.2s — 1861 nodes, 8837 edges
18
+
19
+ === Instant Findings ===
20
+ Health: 60/100 (B)
21
+ Riskiest symbols: Flask (34 files), App (35 files), Scaffold (28 files)
22
+ Dead code: 11 candidates (none high-confidence)
23
+ ```
24
+
25
+ Then explore:
14
26
 
15
27
  ```bash
16
28
  brain impact my_function # What breaks if I change this?
29
+ brain callers my_function # Who calls this?
17
30
  brain health # Codebase health score (0-100)
18
31
  brain hotspots # Riskiest symbols in the codebase
19
32
  brain deadcode # Unused functions with confidence levels
20
- brain coupling # Which files are too tightly coupled?
21
33
  brain zoom # Google Maps-style navigation of your architecture
22
34
  ```
23
35
 
@@ -124,7 +136,7 @@ Module: main.py — 429 symbols, 15853 lines. Isolated (no dependents).
124
136
  ### Claude Code (MCP)
125
137
 
126
138
  ```bash
127
- brain agent # auto-generates CLAUDE.md + MCP config
139
+ brain setup # auto-generates CLAUDE.md + MCP config
128
140
  ```
129
141
 
130
142
  Or add manually to your MCP config:
@@ -165,6 +177,7 @@ The `propose_change` MCP tool validates changes **before** the AI writes them. W
165
177
  | `brain status` | Show index statistics |
166
178
  | `brain search <query>` | Find symbols by name |
167
179
  | `brain impact <name>` | What breaks if this changes? |
180
+ | `brain callers <name>` | Who calls this function? (reverse trace) |
168
181
  | `brain trace <name>` | Forward call chain from a symbol |
169
182
  | `brain deps <name>` | Dependencies of a symbol or file |
170
183
  | `brain deadcode` | Find unused functions/classes |
@@ -216,7 +229,13 @@ Or use environment variables:
216
229
  | Python | AST (stdlib) | Full — functions, classes, imports, calls, dataflow |
217
230
  | TypeScript/JSX | tree-sitter | Full — requires `pip install codebrain[ts]` |
218
231
  | JavaScript/JSX | tree-sitter | Full — requires `pip install codebrain[ts]` |
219
- | TypeScript (fallback) | regex | Experimentalused when tree-sitter not installed |
232
+ | Java | tree-sitter | FullSpring Boot aware (DI, endpoints, JPA) |
233
+ | Go | tree-sitter | Full — interfaces, goroutines, struct methods |
234
+ | Rust | tree-sitter | Full — traits, impls, modules, derive macros |
235
+ | C# | tree-sitter | Full — async/await, LINQ, attributes |
236
+ | Kotlin | tree-sitter | Full — coroutines, extensions, data classes |
237
+ | Dart/Flutter | regex | Good — classes, mixins, extensions |
238
+ | Vue SFC | regex | Good — components, props, events |
220
239
 
221
240
  ### Adding Languages
222
241
 
@@ -226,9 +245,9 @@ Implement `BaseParser` and register via entry points:
226
245
  from codebrain.parser.base import BaseParser
227
246
  from codebrain.parser.models import ParsedFile
228
247
 
229
- class RustParser(BaseParser):
248
+ class MyParser(BaseParser):
230
249
  def extensions(self) -> frozenset[str]:
231
- return frozenset({".rs"})
250
+ return frozenset({".xyz"})
232
251
 
233
252
  def parse(self, path, repo_root) -> ParsedFile:
234
253
  ... # parse and return nodes + edges
@@ -0,0 +1,10 @@
1
+ """CodeBrain — persistent structural knowledge graph for codebases."""
2
+
3
+ from importlib.metadata import PackageNotFoundError, version as _pkg_version
4
+
5
+ try:
6
+ __version__ = _pkg_version("codebrain")
7
+ except PackageNotFoundError:
8
+ # Source checkout without installation (e.g. running from a worktree).
9
+ # Keep in sync with [project.version] in pyproject.toml.
10
+ __version__ = "0.3.0"
@@ -0,0 +1,16 @@
1
+ """Autonomous actions engine — CodeBrain acts, not just analyzes."""
2
+
3
+ from codebrain.actions.test_gen import TestGenerator, GeneratedTest
4
+ from codebrain.actions.reviewer import CodeReviewer, CodeReview, ReviewFinding
5
+ from codebrain.actions.refactor import Refactorer, RefactorSuggestion, RefactorResult
6
+
7
+ __all__ = [
8
+ "TestGenerator",
9
+ "GeneratedTest",
10
+ "CodeReviewer",
11
+ "CodeReview",
12
+ "ReviewFinding",
13
+ "Refactorer",
14
+ "RefactorSuggestion",
15
+ "RefactorResult",
16
+ ]
@@ -0,0 +1,139 @@
1
+ """Shared infrastructure for autonomous actions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import ast
6
+ import re
7
+ from pathlib import Path
8
+
9
+ from codebrain.context import ContextGenerator
10
+ from codebrain.graph.query import QueryEngine
11
+ from codebrain.graph.store import GraphStore
12
+ from codebrain.rewriter import LLMClient
13
+ from codebrain.utils import is_test_file
14
+
15
+
16
+ class ActionEngine:
17
+ """Base class for all autonomous actions."""
18
+
19
+ def __init__(self, store: GraphStore, repo_root: Path, llm: LLMClient):
20
+ self.store = store
21
+ self.repo_root = repo_root
22
+ self.llm = llm
23
+ self.context = ContextGenerator(store)
24
+ self.engine = QueryEngine(store)
25
+
26
+ def _get_symbol_context(self, name: str) -> list[dict]:
27
+ """Full structural context for a symbol."""
28
+ return self.context.for_symbol(name)
29
+
30
+ def _get_file_source(self, file_path: str) -> str:
31
+ """Read actual source code from disk."""
32
+ full = self.repo_root / file_path
33
+ if not full.exists():
34
+ return ""
35
+ try:
36
+ return full.read_text(encoding="utf-8", errors="replace")
37
+ except Exception:
38
+ return ""
39
+
40
+ def _get_function_source(self, file_path: str, name: str, line_start: int) -> str:
41
+ """Extract a single function/class source from a file."""
42
+ source = self._get_file_source(file_path)
43
+ if not source:
44
+ return ""
45
+ try:
46
+ tree = ast.parse(source)
47
+ except SyntaxError:
48
+ return ""
49
+ for node in ast.walk(tree):
50
+ if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
51
+ if node.name == name:
52
+ lines = source.splitlines()
53
+ end = getattr(node, "end_lineno", None) or (node.lineno + 20)
54
+ return "\n".join(lines[node.lineno - 1 : end])
55
+ # Fallback: return from line_start
56
+ if line_start > 0:
57
+ lines = source.splitlines()
58
+ return "\n".join(lines[line_start - 1 : line_start + 30])
59
+ return ""
60
+
61
+ def _get_existing_tests(self, file_path: str) -> str:
62
+ """Find existing test files and return a sample of test patterns."""
63
+ # Look for test files in tests/ directory
64
+ tests_dir = self.repo_root / "tests"
65
+ if not tests_dir.exists():
66
+ tests_dir = self.repo_root / "test"
67
+ if not tests_dir.exists():
68
+ return "# No existing test directory found"
69
+
70
+ samples = []
71
+ for tf in sorted(tests_dir.iterdir()):
72
+ if tf.name.startswith("test_") and tf.suffix == ".py":
73
+ try:
74
+ content = tf.read_text(encoding="utf-8", errors="replace")
75
+ # Extract first test function as pattern example
76
+ for match in re.finditer(
77
+ r"((?:@\w+.*\n)*def test_\w+\(.*?\):.*?)(?=\ndef |\nclass |\Z)",
78
+ content,
79
+ re.DOTALL,
80
+ ):
81
+ sample = match.group(1).strip()
82
+ if len(sample) < 500:
83
+ samples.append(f"# From {tf.name}:\n{sample}")
84
+ break
85
+ except Exception:
86
+ continue
87
+ if len(samples) >= 3:
88
+ break
89
+
90
+ return "\n\n".join(samples) if samples else "# No test examples found"
91
+
92
+ def _validate_python(self, code: str) -> list[str]:
93
+ """Check Python syntax and basic correctness."""
94
+ errors = []
95
+ try:
96
+ ast.parse(code)
97
+ except SyntaxError as e:
98
+ errors.append(f"Syntax error: {e.msg} at line {e.lineno}")
99
+ return errors
100
+
101
+ def _extract_code(self, response: str) -> str:
102
+ """Strip markdown fences from LLM output."""
103
+ pattern = r"```(?:python|java|typescript|javascript)?\s*\n(.*?)```"
104
+ matches = re.findall(pattern, response, re.DOTALL)
105
+ if matches:
106
+ return max(matches, key=len).strip()
107
+ # If no fences, return as-is but trim non-code lines at start
108
+ lines = response.strip().split("\n")
109
+ for i, line in enumerate(lines):
110
+ s = line.strip()
111
+ if s.startswith(("import ", "from ", "def ", "class ", "#", '"""', "@", "async ")):
112
+ return "\n".join(lines[i:]).strip()
113
+ return response.strip()
114
+
115
+ def _interpret_fingerprint(self, fingerprint: str) -> str:
116
+ """Convert structural fingerprint to actionable guidance."""
117
+ if not fingerprint:
118
+ return "- No structural fingerprint available."
119
+ guidance = []
120
+ if "returns:" in fingerprint:
121
+ returns = fingerprint.split("returns:")[1].split("|")[0].strip()
122
+ guidance.append(f"- Returns: {returns}. Test each return path.")
123
+ if "raises:" in fingerprint:
124
+ exc = fingerprint.split("raises:")[1].split("|")[0].strip()
125
+ guidance.append(f"- Raises: {exc}. Test exception paths.")
126
+ if "mutates:" in fingerprint:
127
+ mut = fingerprint.split("mutates:")[1].split("|")[0].strip()
128
+ guidance.append(f"- Mutates: {mut}. Verify state changes.")
129
+ if "io:" in fingerprint:
130
+ io = fingerprint.split("io:")[1].split("|")[0].strip()
131
+ guidance.append(f"- I/O: {io}. Mock these in tests.")
132
+ if "yields" in fingerprint:
133
+ guidance.append("- Generator function. Test iteration and empty case.")
134
+ if "async" in fingerprint:
135
+ guidance.append("- Async function. Use @pytest.mark.asyncio.")
136
+ if "control:" in fingerprint:
137
+ ctrl = fingerprint.split("control:")[1].split("|")[0].strip()
138
+ guidance.append(f"- Control flow: {ctrl}. Test each branch.")
139
+ return "\n".join(guidance) if guidance else "- No special patterns detected."