codebrain 0.1.1__tar.gz → 0.3.1__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.
- {codebrain-0.1.1 → codebrain-0.3.1}/LICENSE +1 -1
- codebrain-0.3.1/PKG-INFO +300 -0
- codebrain-0.3.1/README.md +229 -0
- codebrain-0.3.1/codebrain/__init__.py +10 -0
- codebrain-0.3.1/codebrain/actions/__init__.py +16 -0
- codebrain-0.3.1/codebrain/actions/base.py +139 -0
- codebrain-0.3.1/codebrain/actions/refactor.py +365 -0
- codebrain-0.3.1/codebrain/actions/reviewer.py +313 -0
- codebrain-0.3.1/codebrain/actions/test_gen.py +283 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/analyzer.py +953 -943
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/api.py +330 -0
- codebrain-0.3.1/codebrain/architecture.py +824 -0
- codebrain-0.3.1/codebrain/cli.py +4282 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/comprehension.py +98 -31
- codebrain-0.3.1/codebrain/config.py +67 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/context.py +1 -0
- codebrain-0.3.1/codebrain/cross_query.py +450 -0
- codebrain-0.3.1/codebrain/cross_registry.py +328 -0
- codebrain-0.3.1/codebrain/diff_impact.py +400 -0
- codebrain-0.3.1/codebrain/env_migration.py +560 -0
- codebrain-0.3.1/codebrain/equivalence.py +584 -0
- codebrain-0.3.1/codebrain/frontend.py +443 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/graph/query.py +308 -18
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/graph/schema.py +66 -1
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/graph/store.py +81 -3
- codebrain-0.3.1/codebrain/hook_runner.py +176 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/hooks.py +2 -2
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/indexer.py +85 -1
- codebrain-0.3.1/codebrain/kt.py +401 -0
- codebrain-0.3.1/codebrain/kt_video.py +948 -0
- codebrain-0.3.1/codebrain/mcp_lifecycle.py +327 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/mcp_server.py +2992 -1635
- codebrain-0.3.1/codebrain/migration.py +729 -0
- codebrain-0.3.1/codebrain/modernize.py +962 -0
- codebrain-0.3.1/codebrain/onboard.py +352 -0
- codebrain-0.3.1/codebrain/parser/cobol_parser.py +294 -0
- codebrain-0.3.1/codebrain/parser/config_parser.py +657 -0
- codebrain-0.3.1/codebrain/parser/csharp_parser.py +797 -0
- codebrain-0.3.1/codebrain/parser/dart_parser.py +865 -0
- codebrain-0.3.1/codebrain/parser/fortran_parser.py +281 -0
- codebrain-0.3.1/codebrain/parser/frontend_parser.py +1047 -0
- codebrain-0.3.1/codebrain/parser/go_parser.py +560 -0
- codebrain-0.3.1/codebrain/parser/java_parser.py +813 -0
- codebrain-0.3.1/codebrain/parser/kotlin_parser.py +823 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/parser/models.py +1 -0
- codebrain-0.3.1/codebrain/parser/mumps_parser.py +250 -0
- codebrain-0.3.1/codebrain/parser/plsql_parser.py +242 -0
- codebrain-0.3.1/codebrain/parser/python_parser.py +1255 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/parser/registry.py +97 -1
- codebrain-0.3.1/codebrain/parser/rust_parser.py +709 -0
- codebrain-0.3.1/codebrain/parser/schema_parser.py +491 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/parser/typescript_treesitter.py +70 -10
- codebrain-0.3.1/codebrain/parser/vue_parser.py +353 -0
- codebrain-0.3.1/codebrain/rewriter.py +2527 -0
- codebrain-0.3.1/codebrain/schema_migration.py +548 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/settings.py +3 -0
- codebrain-0.3.1/codebrain/susa_auth.py +157 -0
- codebrain-0.3.1/codebrain/test_gaps.py +325 -0
- codebrain-0.3.1/codebrain/test_runner.py +878 -0
- codebrain-0.3.1/codebrain/tour.py +475 -0
- codebrain-0.3.1/codebrain/ui_migration.py +394 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/utils.py +27 -7
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/watcher/file_watcher.py +23 -13
- codebrain-0.3.1/codebrain.egg-info/PKG-INFO +300 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain.egg-info/SOURCES.txt +75 -0
- codebrain-0.3.1/codebrain.egg-info/entry_points.txt +2 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain.egg-info/requires.txt +1 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/pyproject.toml +16 -5
- codebrain-0.3.1/tests/test_actions.py +614 -0
- codebrain-0.3.1/tests/test_architecture.py +569 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_cli.py +2 -1
- codebrain-0.3.1/tests/test_coverage_gaps.py +517 -0
- codebrain-0.3.1/tests/test_cross_repo.py +479 -0
- codebrain-0.3.1/tests/test_csharp_parser.py +456 -0
- codebrain-0.3.1/tests/test_dart_parser.py +487 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_dead_code_confidence.py +17 -12
- codebrain-0.3.1/tests/test_diff_impact.py +122 -0
- codebrain-0.3.1/tests/test_env_migration.py +243 -0
- codebrain-0.3.1/tests/test_equivalence.py +385 -0
- codebrain-0.3.1/tests/test_fingerprints.py +327 -0
- codebrain-0.3.1/tests/test_frontend.py +1964 -0
- codebrain-0.3.1/tests/test_gate_battle.py +321 -0
- codebrain-0.3.1/tests/test_go_parser.py +437 -0
- codebrain-0.3.1/tests/test_hooks.py +316 -0
- codebrain-0.3.1/tests/test_infra_parser.py +239 -0
- codebrain-0.3.1/tests/test_java_parser.py +589 -0
- codebrain-0.3.1/tests/test_kotlin_parser.py +426 -0
- codebrain-0.3.1/tests/test_kt.py +143 -0
- codebrain-0.3.1/tests/test_legacy_parsers.py +463 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_llm.py +4 -2
- codebrain-0.3.1/tests/test_mcp_lifecycle.py +319 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_mcp_server.py +623 -615
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_memory.py +470 -462
- codebrain-0.3.1/tests/test_migration.py +365 -0
- codebrain-0.3.1/tests/test_modernize.py +367 -0
- codebrain-0.3.1/tests/test_onboard.py +90 -0
- codebrain-0.3.1/tests/test_orm_detection.py +293 -0
- codebrain-0.3.1/tests/test_output_quality.py +384 -0
- codebrain-0.3.1/tests/test_real_codebase.py +223 -0
- codebrain-0.3.1/tests/test_real_features.py +448 -0
- codebrain-0.3.1/tests/test_real_frontend.py +434 -0
- codebrain-0.3.1/tests/test_real_repos.py +878 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_real_world.py +3 -2
- codebrain-0.3.1/tests/test_rewriter.py +1331 -0
- codebrain-0.3.1/tests/test_rust_parser.py +595 -0
- codebrain-0.3.1/tests/test_schema_migration.py +533 -0
- codebrain-0.3.1/tests/test_schema_parser.py +328 -0
- codebrain-0.3.1/tests/test_test_runner.py +546 -0
- codebrain-0.3.1/tests/test_tour.py +101 -0
- codebrain-0.3.1/tests/test_translate.py +524 -0
- codebrain-0.3.1/tests/test_ui_migration.py +686 -0
- codebrain-0.3.1/tests/test_vscode_extension.py +278 -0
- codebrain-0.1.1/PKG-INFO +0 -388
- codebrain-0.1.1/README.md +0 -339
- codebrain-0.1.1/codebrain/__init__.py +0 -3
- codebrain-0.1.1/codebrain/cli.py +0 -1927
- codebrain-0.1.1/codebrain/config.py +0 -46
- codebrain-0.1.1/codebrain/hook_runner.py +0 -71
- codebrain-0.1.1/codebrain/parser/config_parser.py +0 -228
- codebrain-0.1.1/codebrain/parser/python_parser.py +0 -658
- codebrain-0.1.1/codebrain.egg-info/PKG-INFO +0 -388
- codebrain-0.1.1/codebrain.egg-info/entry_points.txt +0 -6
- codebrain-0.1.1/tests/test_hooks.py +0 -142
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/__main__.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/agent_bridge.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/api_models.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/export.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/graph/__init__.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/llm.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/logging.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/memory/__init__.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/memory/store.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/parser/__init__.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/parser/base.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/parser/typescript_parser.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/py.typed +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/resolver.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/validator.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain/watcher/__init__.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain.egg-info/dependency_links.txt +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/codebrain.egg-info/top_level.txt +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/setup.cfg +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_agent_bridge.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_analyzer.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_api.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_ci.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_comprehension.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_context.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_contracts_real.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_dataflow.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_error_recovery.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_export.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_indexer.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_install.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_integration.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_jyotishyamitra.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_multi_project_cli.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_narratives.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_parser.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_plugin_system.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_production_hardening.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_query.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_resolver.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_scale.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_scale_optimizations.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_scale_real.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_schema.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_settings.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_store.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_ts_ast_parser.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_ts_parser_enhanced.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_typescript_parser.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_utils.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_validation_narratives.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_validator.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_validator_scenarios.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_watch_validate.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_watcher.py +0 -0
- {codebrain-0.1.1 → codebrain-0.3.1}/tests/test_zoom.py +0 -0
codebrain-0.3.1/PKG-INFO
ADDED
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: codebrain
|
|
3
|
+
Version: 0.3.1
|
|
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
|
+
Author: CodeBrain Contributors
|
|
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
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/monk0062006/CodeBrain
|
|
29
|
+
Project-URL: Repository, https://github.com/monk0062006/CodeBrain
|
|
30
|
+
Project-URL: Issues, https://github.com/monk0062006/CodeBrain/issues
|
|
31
|
+
Keywords: code-analysis,static-analysis,knowledge-graph,impact-analysis,dead-code,codebase-health,mcp,ai-coding,structural-analysis,refactoring
|
|
32
|
+
Classifier: Development Status :: 4 - Beta
|
|
33
|
+
Classifier: Intended Audience :: Developers
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
39
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
40
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
41
|
+
Classifier: Topic :: Software Development :: Testing
|
|
42
|
+
Classifier: Environment :: Console
|
|
43
|
+
Classifier: Operating System :: OS Independent
|
|
44
|
+
Classifier: Typing :: Typed
|
|
45
|
+
Requires-Python: >=3.11
|
|
46
|
+
Description-Content-Type: text/markdown
|
|
47
|
+
License-File: LICENSE
|
|
48
|
+
Requires-Dist: click>=8.1
|
|
49
|
+
Requires-Dist: watchdog>=3.0
|
|
50
|
+
Requires-Dist: mcp<1.20,>=1.0
|
|
51
|
+
Requires-Dist: jinja2>=3.1
|
|
52
|
+
Requires-Dist: psutil>=5.9
|
|
53
|
+
Provides-Extra: api
|
|
54
|
+
Requires-Dist: fastapi>=0.110; extra == "api"
|
|
55
|
+
Requires-Dist: uvicorn>=0.27; extra == "api"
|
|
56
|
+
Provides-Extra: llm
|
|
57
|
+
Requires-Dist: httpx>=0.27; extra == "llm"
|
|
58
|
+
Provides-Extra: ts
|
|
59
|
+
Requires-Dist: tree-sitter>=0.21; extra == "ts"
|
|
60
|
+
Requires-Dist: tree-sitter-languages>=1.10; extra == "ts"
|
|
61
|
+
Provides-Extra: dev
|
|
62
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
63
|
+
Requires-Dist: pytest-tmp-files>=0.0.2; extra == "dev"
|
|
64
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
65
|
+
Requires-Dist: mypy>=1.8; extra == "dev"
|
|
66
|
+
Requires-Dist: ruff>=0.3; extra == "dev"
|
|
67
|
+
Requires-Dist: httpx>=0.27; extra == "dev"
|
|
68
|
+
Provides-Extra: all
|
|
69
|
+
Requires-Dist: codebrain[api,llm,ts]; extra == "all"
|
|
70
|
+
Dynamic: license-file
|
|
71
|
+
|
|
72
|
+
# CodeBrain
|
|
73
|
+
|
|
74
|
+
**Know what breaks before you break it.**
|
|
75
|
+
|
|
76
|
+
CodeBrain builds a structural knowledge graph of your codebase — every
|
|
77
|
+
function, class, import, and call chain — and stores it locally in
|
|
78
|
+
SQLite. Wire it into Claude Code, Cursor, or any MCP-compatible agent
|
|
79
|
+
and your AI suddenly knows the structure of your code instead of
|
|
80
|
+
guessing.
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
pip install codebrain
|
|
84
|
+
cd your-project
|
|
85
|
+
brain init
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
Indexing your-project (1,328 files) ...
|
|
90
|
+
Done in 135s — 17,756 nodes, 111,793 edges
|
|
91
|
+
Health: 93/100 (A)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Free. MIT-licensed. No cloud. No LLM required for the core features.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Why
|
|
99
|
+
|
|
100
|
+
AI coding agents (Claude Code, Cursor, Copilot) generate code faster
|
|
101
|
+
than you can review it. They read fragments of code, lack persistent
|
|
102
|
+
structural memory, and apply local fixes. When an agent removes a
|
|
103
|
+
function, it doesn't know 3 other files call it. When it changes a
|
|
104
|
+
signature, it doesn't know what depends on the old shape.
|
|
105
|
+
|
|
106
|
+
CodeBrain knows. It maintains a persistent graph of every symbol and
|
|
107
|
+
relationship and gives agents tools (via MCP) to query it.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Wire it into Claude Code
|
|
112
|
+
|
|
113
|
+
The killer feature. One command:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
brain setup
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Indexes the repo, drops a `CLAUDE.md` with project context, writes the
|
|
120
|
+
MCP config. Restart Claude Code and it has tools like
|
|
121
|
+
`mcp__codebrain__impact_analysis`, `mcp__codebrain__find_dead_code`,
|
|
122
|
+
`mcp__codebrain__call_chain`, `mcp__codebrain__zoom`,
|
|
123
|
+
`mcp__codebrain__ask_codebase`, plus a few dozen more. It uses them on
|
|
124
|
+
its own.
|
|
125
|
+
|
|
126
|
+
Manual config (any MCP-compatible client):
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"mcpServers": {
|
|
131
|
+
"codebrain": {
|
|
132
|
+
"command": "python",
|
|
133
|
+
"args": ["-m", "codebrain.mcp_server"],
|
|
134
|
+
"env": { "CODEBRAIN_PROJECT": "/absolute/path/to/repo" }
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## What you can do from the CLI
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
brain impact create_user # what breaks if I change this?
|
|
146
|
+
brain callers create_user # who calls this?
|
|
147
|
+
brain trace create_user # what does it call, recursively?
|
|
148
|
+
brain deadcode # actually-unused functions, with confidence levels
|
|
149
|
+
brain hotspots # riskiest symbols (most depended on)
|
|
150
|
+
brain cycles # import cycles
|
|
151
|
+
brain health # codebase score 0-100
|
|
152
|
+
brain coupling # module-to-module coupling
|
|
153
|
+
brain layers # architectural layers inferred from imports
|
|
154
|
+
brain zoom system|module|symbol # Google Maps for your architecture
|
|
155
|
+
brain ask "where does login flow live?"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Sample output:
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
$ brain impact getAstroData
|
|
162
|
+
Impact of changing predictions_api.py::getAstroData:
|
|
163
|
+
[1] Ascendant.py::compileAstroDetails (CALLS)
|
|
164
|
+
[1] AsthaKoota.py::getNakAndRasi (CALLS)
|
|
165
|
+
[2] ProfileBuilder.py::buildProfile (CALLS via compileAstroDetails)
|
|
166
|
+
... 48 dependents across 69 files
|
|
167
|
+
Blast radius: 5.2% of the codebase
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
$ brain hotspots
|
|
172
|
+
Risk hotspots (top 3):
|
|
173
|
+
48.2 function getAstroData 48 deps 69 files
|
|
174
|
+
35.1 function compileAstroDetails 35 deps 52 files
|
|
175
|
+
28.7 class ProfileBuilder 28 deps 41 files
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Run `brain --help` for the full command list (60+).
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Pre-commit and CI
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
brain hook install # validates staged Python files before each commit
|
|
186
|
+
brain ci --base origin/main # exit 1 on structural regressions in a PR
|
|
187
|
+
brain diff-impact # blast radius of currently-staged changes
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
GitHub Action:
|
|
191
|
+
|
|
192
|
+
```yaml
|
|
193
|
+
- run: pip install codebrain
|
|
194
|
+
- run: brain ci --base origin/main --json
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Language support
|
|
200
|
+
|
|
201
|
+
| Language | Parser | Status |
|
|
202
|
+
|---|---|---|
|
|
203
|
+
| Python | AST (stdlib) | full |
|
|
204
|
+
| TypeScript / JS / JSX / Vue | tree-sitter | full — `pip install "codebrain[ts]"` |
|
|
205
|
+
| Java | tree-sitter | full — Spring Boot aware |
|
|
206
|
+
| Go, Rust, C#, Kotlin, Dart | tree-sitter / regex | good |
|
|
207
|
+
| COBOL, Fortran, MUMPS, PL/SQL | regex | basic — for legacy migration |
|
|
208
|
+
|
|
209
|
+
Adding a parser: implement `BaseParser`, register via the
|
|
210
|
+
`codebrain.parsers` entry point. See `docs/USAGE.md`.
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Optional extras
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
pip install "codebrain[ts]" # TypeScript / JS / Vue
|
|
218
|
+
pip install "codebrain[api]" # FastAPI REST server
|
|
219
|
+
pip install "codebrain[llm]" # AI-powered explain / ask / rewrite
|
|
220
|
+
pip install "codebrain[all]" # everything
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Core install (`pip install codebrain`) is enough for Python projects
|
|
224
|
+
and the MCP server.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Configuration
|
|
229
|
+
|
|
230
|
+
`.codebrain.toml` at repo root, or `CODEBRAIN_*` env vars:
|
|
231
|
+
|
|
232
|
+
```toml
|
|
233
|
+
[index]
|
|
234
|
+
exclude = ["vendor/", "**/__generated__/**"]
|
|
235
|
+
|
|
236
|
+
[mcp]
|
|
237
|
+
tool_timeout = 25
|
|
238
|
+
idle_timeout = 1800
|
|
239
|
+
|
|
240
|
+
[parser]
|
|
241
|
+
languages = ["python", "typescript", "java"]
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## How it works
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
Source files ─► Parser ─► Nodes + Edges ─► SQLite (.codebrain/graph.db)
|
|
250
|
+
│
|
|
251
|
+
┌─────────────────────┴───────────────────────┐
|
|
252
|
+
▼ ▼
|
|
253
|
+
brain CLI MCP server / REST API
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
- **Node** — a symbol (function, class, method, file)
|
|
257
|
+
- **Edge** — a relationship (CALLS, IMPORTS, CONTAINS, EXTENDS, DATAFLOW)
|
|
258
|
+
- **GraphStore** — SQLite with WAL mode, lives in `.codebrain/` (auto-gitignored)
|
|
259
|
+
- **QueryEngine** — BFS/DFS for impact, call chains, dead code, cycles
|
|
260
|
+
|
|
261
|
+
Everything stays on your machine. The only thing that leaves is what
|
|
262
|
+
you explicitly send to an LLM via `brain ask` / `brain explain` /
|
|
263
|
+
`brain rewrite`.
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## Documentation
|
|
268
|
+
|
|
269
|
+
- **[docs/USAGE.md](docs/USAGE.md)** — full usage guide: workflows,
|
|
270
|
+
every command, MCP setup, troubleshooting.
|
|
271
|
+
- **[docs/cli-reference.md](docs/cli-reference.md)** — generated CLI
|
|
272
|
+
reference.
|
|
273
|
+
- **[docs/mcp-tools.md](docs/mcp-tools.md)** — every MCP tool with
|
|
274
|
+
examples.
|
|
275
|
+
- **[docs/PRD.md](docs/PRD.md)** — product requirements.
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Development
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
git clone https://github.com/monk0062006/CodeBrain.git
|
|
283
|
+
cd CodeBrain
|
|
284
|
+
pip install -e ".[dev]"
|
|
285
|
+
|
|
286
|
+
pytest tests/ # 1,900+ tests
|
|
287
|
+
ruff check codebrain/
|
|
288
|
+
mypy codebrain/
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## License
|
|
294
|
+
|
|
295
|
+
MIT. Use it however you want.
|
|
296
|
+
|
|
297
|
+
## Links
|
|
298
|
+
|
|
299
|
+
- PyPI: https://pypi.org/project/codebrain/
|
|
300
|
+
- Issues: https://github.com/monk0062006/CodeBrain/issues
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# CodeBrain
|
|
2
|
+
|
|
3
|
+
**Know what breaks before you break it.**
|
|
4
|
+
|
|
5
|
+
CodeBrain builds a structural knowledge graph of your codebase — every
|
|
6
|
+
function, class, import, and call chain — and stores it locally in
|
|
7
|
+
SQLite. Wire it into Claude Code, Cursor, or any MCP-compatible agent
|
|
8
|
+
and your AI suddenly knows the structure of your code instead of
|
|
9
|
+
guessing.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install codebrain
|
|
13
|
+
cd your-project
|
|
14
|
+
brain init
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
Indexing your-project (1,328 files) ...
|
|
19
|
+
Done in 135s — 17,756 nodes, 111,793 edges
|
|
20
|
+
Health: 93/100 (A)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Free. MIT-licensed. No cloud. No LLM required for the core features.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Why
|
|
28
|
+
|
|
29
|
+
AI coding agents (Claude Code, Cursor, Copilot) generate code faster
|
|
30
|
+
than you can review it. They read fragments of code, lack persistent
|
|
31
|
+
structural memory, and apply local fixes. When an agent removes a
|
|
32
|
+
function, it doesn't know 3 other files call it. When it changes a
|
|
33
|
+
signature, it doesn't know what depends on the old shape.
|
|
34
|
+
|
|
35
|
+
CodeBrain knows. It maintains a persistent graph of every symbol and
|
|
36
|
+
relationship and gives agents tools (via MCP) to query it.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Wire it into Claude Code
|
|
41
|
+
|
|
42
|
+
The killer feature. One command:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
brain setup
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Indexes the repo, drops a `CLAUDE.md` with project context, writes the
|
|
49
|
+
MCP config. Restart Claude Code and it has tools like
|
|
50
|
+
`mcp__codebrain__impact_analysis`, `mcp__codebrain__find_dead_code`,
|
|
51
|
+
`mcp__codebrain__call_chain`, `mcp__codebrain__zoom`,
|
|
52
|
+
`mcp__codebrain__ask_codebase`, plus a few dozen more. It uses them on
|
|
53
|
+
its own.
|
|
54
|
+
|
|
55
|
+
Manual config (any MCP-compatible client):
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"mcpServers": {
|
|
60
|
+
"codebrain": {
|
|
61
|
+
"command": "python",
|
|
62
|
+
"args": ["-m", "codebrain.mcp_server"],
|
|
63
|
+
"env": { "CODEBRAIN_PROJECT": "/absolute/path/to/repo" }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## What you can do from the CLI
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
brain impact create_user # what breaks if I change this?
|
|
75
|
+
brain callers create_user # who calls this?
|
|
76
|
+
brain trace create_user # what does it call, recursively?
|
|
77
|
+
brain deadcode # actually-unused functions, with confidence levels
|
|
78
|
+
brain hotspots # riskiest symbols (most depended on)
|
|
79
|
+
brain cycles # import cycles
|
|
80
|
+
brain health # codebase score 0-100
|
|
81
|
+
brain coupling # module-to-module coupling
|
|
82
|
+
brain layers # architectural layers inferred from imports
|
|
83
|
+
brain zoom system|module|symbol # Google Maps for your architecture
|
|
84
|
+
brain ask "where does login flow live?"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Sample output:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
$ brain impact getAstroData
|
|
91
|
+
Impact of changing predictions_api.py::getAstroData:
|
|
92
|
+
[1] Ascendant.py::compileAstroDetails (CALLS)
|
|
93
|
+
[1] AsthaKoota.py::getNakAndRasi (CALLS)
|
|
94
|
+
[2] ProfileBuilder.py::buildProfile (CALLS via compileAstroDetails)
|
|
95
|
+
... 48 dependents across 69 files
|
|
96
|
+
Blast radius: 5.2% of the codebase
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
$ brain hotspots
|
|
101
|
+
Risk hotspots (top 3):
|
|
102
|
+
48.2 function getAstroData 48 deps 69 files
|
|
103
|
+
35.1 function compileAstroDetails 35 deps 52 files
|
|
104
|
+
28.7 class ProfileBuilder 28 deps 41 files
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Run `brain --help` for the full command list (60+).
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Pre-commit and CI
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
brain hook install # validates staged Python files before each commit
|
|
115
|
+
brain ci --base origin/main # exit 1 on structural regressions in a PR
|
|
116
|
+
brain diff-impact # blast radius of currently-staged changes
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
GitHub Action:
|
|
120
|
+
|
|
121
|
+
```yaml
|
|
122
|
+
- run: pip install codebrain
|
|
123
|
+
- run: brain ci --base origin/main --json
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Language support
|
|
129
|
+
|
|
130
|
+
| Language | Parser | Status |
|
|
131
|
+
|---|---|---|
|
|
132
|
+
| Python | AST (stdlib) | full |
|
|
133
|
+
| TypeScript / JS / JSX / Vue | tree-sitter | full — `pip install "codebrain[ts]"` |
|
|
134
|
+
| Java | tree-sitter | full — Spring Boot aware |
|
|
135
|
+
| Go, Rust, C#, Kotlin, Dart | tree-sitter / regex | good |
|
|
136
|
+
| COBOL, Fortran, MUMPS, PL/SQL | regex | basic — for legacy migration |
|
|
137
|
+
|
|
138
|
+
Adding a parser: implement `BaseParser`, register via the
|
|
139
|
+
`codebrain.parsers` entry point. See `docs/USAGE.md`.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Optional extras
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
pip install "codebrain[ts]" # TypeScript / JS / Vue
|
|
147
|
+
pip install "codebrain[api]" # FastAPI REST server
|
|
148
|
+
pip install "codebrain[llm]" # AI-powered explain / ask / rewrite
|
|
149
|
+
pip install "codebrain[all]" # everything
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Core install (`pip install codebrain`) is enough for Python projects
|
|
153
|
+
and the MCP server.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Configuration
|
|
158
|
+
|
|
159
|
+
`.codebrain.toml` at repo root, or `CODEBRAIN_*` env vars:
|
|
160
|
+
|
|
161
|
+
```toml
|
|
162
|
+
[index]
|
|
163
|
+
exclude = ["vendor/", "**/__generated__/**"]
|
|
164
|
+
|
|
165
|
+
[mcp]
|
|
166
|
+
tool_timeout = 25
|
|
167
|
+
idle_timeout = 1800
|
|
168
|
+
|
|
169
|
+
[parser]
|
|
170
|
+
languages = ["python", "typescript", "java"]
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## How it works
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
Source files ─► Parser ─► Nodes + Edges ─► SQLite (.codebrain/graph.db)
|
|
179
|
+
│
|
|
180
|
+
┌─────────────────────┴───────────────────────┐
|
|
181
|
+
▼ ▼
|
|
182
|
+
brain CLI MCP server / REST API
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
- **Node** — a symbol (function, class, method, file)
|
|
186
|
+
- **Edge** — a relationship (CALLS, IMPORTS, CONTAINS, EXTENDS, DATAFLOW)
|
|
187
|
+
- **GraphStore** — SQLite with WAL mode, lives in `.codebrain/` (auto-gitignored)
|
|
188
|
+
- **QueryEngine** — BFS/DFS for impact, call chains, dead code, cycles
|
|
189
|
+
|
|
190
|
+
Everything stays on your machine. The only thing that leaves is what
|
|
191
|
+
you explicitly send to an LLM via `brain ask` / `brain explain` /
|
|
192
|
+
`brain rewrite`.
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Documentation
|
|
197
|
+
|
|
198
|
+
- **[docs/USAGE.md](docs/USAGE.md)** — full usage guide: workflows,
|
|
199
|
+
every command, MCP setup, troubleshooting.
|
|
200
|
+
- **[docs/cli-reference.md](docs/cli-reference.md)** — generated CLI
|
|
201
|
+
reference.
|
|
202
|
+
- **[docs/mcp-tools.md](docs/mcp-tools.md)** — every MCP tool with
|
|
203
|
+
examples.
|
|
204
|
+
- **[docs/PRD.md](docs/PRD.md)** — product requirements.
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Development
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
git clone https://github.com/monk0062006/CodeBrain.git
|
|
212
|
+
cd CodeBrain
|
|
213
|
+
pip install -e ".[dev]"
|
|
214
|
+
|
|
215
|
+
pytest tests/ # 1,900+ tests
|
|
216
|
+
ruff check codebrain/
|
|
217
|
+
mypy codebrain/
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## License
|
|
223
|
+
|
|
224
|
+
MIT. Use it however you want.
|
|
225
|
+
|
|
226
|
+
## Links
|
|
227
|
+
|
|
228
|
+
- PyPI: https://pypi.org/project/codebrain/
|
|
229
|
+
- Issues: https://github.com/monk0062006/CodeBrain/issues
|
|
@@ -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.1"
|
|
@@ -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."
|