codebrain 0.1.0__py3-none-any.whl
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/__init__.py +3 -0
- codebrain/__main__.py +6 -0
- codebrain/agent_bridge.py +162 -0
- codebrain/analyzer.py +943 -0
- codebrain/api.py +578 -0
- codebrain/api_models.py +102 -0
- codebrain/cli.py +1927 -0
- codebrain/comprehension.py +1939 -0
- codebrain/config.py +46 -0
- codebrain/context.py +276 -0
- codebrain/export.py +334 -0
- codebrain/graph/__init__.py +0 -0
- codebrain/graph/query.py +656 -0
- codebrain/graph/schema.py +113 -0
- codebrain/graph/store.py +295 -0
- codebrain/hook_runner.py +71 -0
- codebrain/hooks.py +107 -0
- codebrain/indexer.py +450 -0
- codebrain/llm.py +676 -0
- codebrain/logging.py +42 -0
- codebrain/mcp_server.py +1635 -0
- codebrain/memory/__init__.py +5 -0
- codebrain/memory/store.py +270 -0
- codebrain/parser/__init__.py +0 -0
- codebrain/parser/base.py +27 -0
- codebrain/parser/config_parser.py +228 -0
- codebrain/parser/models.py +44 -0
- codebrain/parser/python_parser.py +658 -0
- codebrain/parser/registry.py +144 -0
- codebrain/parser/typescript_parser.py +1189 -0
- codebrain/parser/typescript_treesitter.py +535 -0
- codebrain/py.typed +0 -0
- codebrain/resolver.py +171 -0
- codebrain/settings.py +88 -0
- codebrain/utils.py +59 -0
- codebrain/validator.py +563 -0
- codebrain/watcher/__init__.py +0 -0
- codebrain/watcher/file_watcher.py +173 -0
- codebrain-0.1.0.dist-info/METADATA +360 -0
- codebrain-0.1.0.dist-info/RECORD +44 -0
- codebrain-0.1.0.dist-info/WHEEL +5 -0
- codebrain-0.1.0.dist-info/entry_points.txt +6 -0
- codebrain-0.1.0.dist-info/licenses/LICENSE +21 -0
- codebrain-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""Watchdog-based file monitor with debounced incremental updates."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import threading
|
|
6
|
+
import time
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from watchdog.events import FileSystemEvent, FileSystemEventHandler
|
|
10
|
+
from watchdog.observers import Observer
|
|
11
|
+
|
|
12
|
+
from codebrain.config import INDEXABLE_EXTENSIONS, WATCHER_DEBOUNCE_SECONDS
|
|
13
|
+
from codebrain.graph.store import GraphStore
|
|
14
|
+
from codebrain.indexer import incremental_update
|
|
15
|
+
from codebrain.logging import get_logger
|
|
16
|
+
from codebrain.settings import load_settings
|
|
17
|
+
|
|
18
|
+
_log = get_logger("watcher")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class _DebouncedHandler(FileSystemEventHandler):
|
|
22
|
+
"""Collects file-change events and flushes them after a debounce window."""
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
repo_root: Path,
|
|
27
|
+
store: GraphStore,
|
|
28
|
+
*,
|
|
29
|
+
debounce: float = WATCHER_DEBOUNCE_SECONDS,
|
|
30
|
+
extensions: frozenset[str] = INDEXABLE_EXTENSIONS,
|
|
31
|
+
) -> None:
|
|
32
|
+
super().__init__()
|
|
33
|
+
self.repo_root = repo_root
|
|
34
|
+
self.store = store
|
|
35
|
+
self._debounce = debounce
|
|
36
|
+
self._extensions = extensions
|
|
37
|
+
self._changed: set[Path] = set()
|
|
38
|
+
self._deleted: set[Path] = set()
|
|
39
|
+
self._lock = threading.Lock()
|
|
40
|
+
self._timer: threading.Timer | None = None
|
|
41
|
+
self._last_validation: dict[str, object] = {} # rel_path -> ValidationReport
|
|
42
|
+
|
|
43
|
+
def _schedule_flush(self) -> None:
|
|
44
|
+
if self._timer is not None:
|
|
45
|
+
self._timer.cancel()
|
|
46
|
+
self._timer = threading.Timer(self._debounce, self._flush)
|
|
47
|
+
self._timer.daemon = True
|
|
48
|
+
self._timer.start()
|
|
49
|
+
|
|
50
|
+
def _flush(self) -> None:
|
|
51
|
+
with self._lock:
|
|
52
|
+
changed = list(self._changed)
|
|
53
|
+
deleted = list(self._deleted)
|
|
54
|
+
self._changed.clear()
|
|
55
|
+
self._deleted.clear()
|
|
56
|
+
|
|
57
|
+
if not changed and not deleted:
|
|
58
|
+
return
|
|
59
|
+
|
|
60
|
+
# Validate changed files BEFORE re-indexing (graph still has old state)
|
|
61
|
+
if changed:
|
|
62
|
+
self._validate_changed(changed)
|
|
63
|
+
|
|
64
|
+
result = incremental_update(self.repo_root, changed, deleted, self.store)
|
|
65
|
+
total = result["files_updated"] + result["files_removed"]
|
|
66
|
+
if total:
|
|
67
|
+
_log.info(
|
|
68
|
+
"Updated %d, removed %d (%.3fs)",
|
|
69
|
+
result["files_updated"],
|
|
70
|
+
result["files_removed"],
|
|
71
|
+
result["elapsed_seconds"],
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
def _validate_changed(self, changed: list[Path]) -> None:
|
|
75
|
+
"""Run structural validation on recently changed files."""
|
|
76
|
+
from codebrain.validator import ChangeValidator
|
|
77
|
+
|
|
78
|
+
validator = ChangeValidator(self.store)
|
|
79
|
+
for abs_path in changed:
|
|
80
|
+
rel_path = abs_path.relative_to(self.repo_root).as_posix()
|
|
81
|
+
try:
|
|
82
|
+
report = validator.validate_file(abs_path, self.repo_root)
|
|
83
|
+
if not report.is_valid:
|
|
84
|
+
_log.warning(
|
|
85
|
+
"STRUCTURAL BREAKAGE in %s: %d violation(s)",
|
|
86
|
+
rel_path,
|
|
87
|
+
len(report.violations),
|
|
88
|
+
)
|
|
89
|
+
for v in report.violations:
|
|
90
|
+
if v.severity in ("critical", "high"):
|
|
91
|
+
_log.warning(" [%s] %s", v.severity.upper(), v.message)
|
|
92
|
+
self._last_validation[rel_path] = report
|
|
93
|
+
except Exception as e:
|
|
94
|
+
_log.debug("Validation failed for %s: %s", rel_path, e)
|
|
95
|
+
|
|
96
|
+
def get_recent_validations(self) -> dict[str, dict]:
|
|
97
|
+
"""Return validation results from the most recent flush."""
|
|
98
|
+
return {
|
|
99
|
+
path: report.to_dict()
|
|
100
|
+
for path, report in self._last_validation.items()
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
def _is_relevant(self, path: str) -> bool:
|
|
104
|
+
return Path(path).suffix in self._extensions
|
|
105
|
+
|
|
106
|
+
def on_modified(self, event: FileSystemEvent) -> None:
|
|
107
|
+
if event.is_directory or not self._is_relevant(event.src_path):
|
|
108
|
+
return
|
|
109
|
+
with self._lock:
|
|
110
|
+
self._changed.add(Path(event.src_path))
|
|
111
|
+
self._schedule_flush()
|
|
112
|
+
|
|
113
|
+
def on_created(self, event: FileSystemEvent) -> None:
|
|
114
|
+
if event.is_directory or not self._is_relevant(event.src_path):
|
|
115
|
+
return
|
|
116
|
+
with self._lock:
|
|
117
|
+
self._changed.add(Path(event.src_path))
|
|
118
|
+
self._schedule_flush()
|
|
119
|
+
|
|
120
|
+
def on_deleted(self, event: FileSystemEvent) -> None:
|
|
121
|
+
if event.is_directory or not self._is_relevant(event.src_path):
|
|
122
|
+
return
|
|
123
|
+
with self._lock:
|
|
124
|
+
self._deleted.add(Path(event.src_path))
|
|
125
|
+
self._changed.discard(Path(event.src_path))
|
|
126
|
+
self._schedule_flush()
|
|
127
|
+
|
|
128
|
+
def on_moved(self, event: FileSystemEvent) -> None:
|
|
129
|
+
if event.is_directory:
|
|
130
|
+
return
|
|
131
|
+
if self._is_relevant(event.src_path):
|
|
132
|
+
with self._lock:
|
|
133
|
+
self._deleted.add(Path(event.src_path))
|
|
134
|
+
if self._is_relevant(event.dest_path):
|
|
135
|
+
with self._lock:
|
|
136
|
+
self._changed.add(Path(event.dest_path))
|
|
137
|
+
self._schedule_flush()
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def start_watching_background(
|
|
141
|
+
repo_root: Path, db_path: Path,
|
|
142
|
+
) -> tuple[Observer, GraphStore, _DebouncedHandler]:
|
|
143
|
+
"""Start a non-blocking file watcher on a daemon thread.
|
|
144
|
+
|
|
145
|
+
Returns (observer, store, handler) so the caller can stop it later
|
|
146
|
+
and poll validation results via handler.get_recent_validations().
|
|
147
|
+
"""
|
|
148
|
+
settings = load_settings(repo_root)
|
|
149
|
+
store = GraphStore(db_path)
|
|
150
|
+
handler = _DebouncedHandler(
|
|
151
|
+
repo_root,
|
|
152
|
+
store,
|
|
153
|
+
debounce=settings.watcher_debounce,
|
|
154
|
+
extensions=settings.indexable_extensions,
|
|
155
|
+
)
|
|
156
|
+
observer = Observer()
|
|
157
|
+
observer.daemon = True
|
|
158
|
+
observer.schedule(handler, str(repo_root), recursive=True)
|
|
159
|
+
observer.start()
|
|
160
|
+
_log.info("Background watcher started for %s", repo_root)
|
|
161
|
+
return observer, store, handler
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def start_watching(repo_root: Path, db_path: Path) -> None:
|
|
165
|
+
"""Block forever, watching *repo_root* for file changes."""
|
|
166
|
+
observer, store, _handler = start_watching_background(repo_root, db_path)
|
|
167
|
+
try:
|
|
168
|
+
while True:
|
|
169
|
+
time.sleep(1)
|
|
170
|
+
except KeyboardInterrupt:
|
|
171
|
+
observer.stop()
|
|
172
|
+
observer.join()
|
|
173
|
+
store.close()
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: codebrain
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Persistent structural knowledge graph for codebases — lets LLM agents skip grep and understand repos in seconds.
|
|
5
|
+
Author: CodeBrain Contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/monk0062006/CodeBrain
|
|
8
|
+
Project-URL: Repository, https://github.com/monk0062006/CodeBrain
|
|
9
|
+
Project-URL: Issues, https://github.com/monk0062006/CodeBrain/issues
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: click>=8.1
|
|
23
|
+
Requires-Dist: watchdog>=3.0
|
|
24
|
+
Requires-Dist: mcp<1.20,>=1.0
|
|
25
|
+
Requires-Dist: jinja2>=3.1
|
|
26
|
+
Provides-Extra: api
|
|
27
|
+
Requires-Dist: fastapi>=0.110; extra == "api"
|
|
28
|
+
Requires-Dist: uvicorn>=0.27; extra == "api"
|
|
29
|
+
Provides-Extra: llm
|
|
30
|
+
Requires-Dist: httpx>=0.27; extra == "llm"
|
|
31
|
+
Provides-Extra: ts
|
|
32
|
+
Requires-Dist: tree-sitter>=0.21; extra == "ts"
|
|
33
|
+
Requires-Dist: tree-sitter-languages>=1.10; extra == "ts"
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-tmp-files>=0.0.2; extra == "dev"
|
|
37
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
38
|
+
Requires-Dist: mypy>=1.8; extra == "dev"
|
|
39
|
+
Requires-Dist: ruff>=0.3; extra == "dev"
|
|
40
|
+
Requires-Dist: httpx>=0.27; extra == "dev"
|
|
41
|
+
Provides-Extra: all
|
|
42
|
+
Requires-Dist: codebrain[api,llm,ts]; extra == "all"
|
|
43
|
+
Dynamic: license-file
|
|
44
|
+
|
|
45
|
+
# CodeBrain
|
|
46
|
+
|
|
47
|
+
Structural intelligence for AI-assisted development. CodeBrain builds a
|
|
48
|
+
persistent knowledge graph of your codebase and validates changes before
|
|
49
|
+
they land — preventing AI coding agents from silently breaking things.
|
|
50
|
+
|
|
51
|
+
## The Problem
|
|
52
|
+
|
|
53
|
+
AI coding agents (Claude Code, Cursor, Copilot) generate code faster than
|
|
54
|
+
you can review it. They grep fragments, apply local fixes, and don't
|
|
55
|
+
maintain a mental model. When the AI removes a function, it doesn't know
|
|
56
|
+
3 other files call it.
|
|
57
|
+
|
|
58
|
+
CodeBrain knows.
|
|
59
|
+
|
|
60
|
+
## Quick Start
|
|
61
|
+
|
|
62
|
+
### 1. Install
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install codebrain
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Optional extras:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install codebrain[api] # REST API server
|
|
72
|
+
pip install codebrain[llm] # LLM-enhanced explanations
|
|
73
|
+
pip install codebrain[ts] # TypeScript AST parser (tree-sitter)
|
|
74
|
+
pip install codebrain[all] # Everything
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 2. Index your project
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
cd your-project
|
|
81
|
+
brain init
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 3. Connect to Claude Code
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
brain agent # generates CLAUDE.md + MCP config
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Or add to your MCP config manually:
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"mcpServers": {
|
|
95
|
+
"codebrain": {
|
|
96
|
+
"command": "python",
|
|
97
|
+
"args": ["-m", "codebrain.mcp_server"],
|
|
98
|
+
"cwd": "/path/to/your/repo"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 4. That's it
|
|
105
|
+
|
|
106
|
+
CodeBrain will automatically validate changes before Claude writes them.
|
|
107
|
+
When a change would break something, it says so — with the specific files
|
|
108
|
+
and callers that would be affected.
|
|
109
|
+
|
|
110
|
+
## What It Does
|
|
111
|
+
|
|
112
|
+
### Structural Safety Gate
|
|
113
|
+
|
|
114
|
+
Before an AI agent writes a file, CodeBrain checks if the change would break
|
|
115
|
+
callers in other files. If it would, the agent is told to fix the breakage first.
|
|
116
|
+
|
|
117
|
+
### Impact Analysis
|
|
118
|
+
|
|
119
|
+
"What would break if I change this?" — answers with specific files, symbols,
|
|
120
|
+
and call chains. Not grep results. Deterministic graph traversal.
|
|
121
|
+
|
|
122
|
+
### Risk Hotspots
|
|
123
|
+
|
|
124
|
+
Identifies the most structurally dangerous code — functions called by many files,
|
|
125
|
+
modules with high coupling, symbols where a signature change would cascade.
|
|
126
|
+
|
|
127
|
+
### Dead Code Detection
|
|
128
|
+
|
|
129
|
+
Finds unused symbols with confidence levels. High-confidence means it's really dead.
|
|
130
|
+
Medium means the file uses dynamic patterns. Low means it might be used indirectly.
|
|
131
|
+
|
|
132
|
+
### Comprehension Narratives
|
|
133
|
+
|
|
134
|
+
Plain English explanations: "store.py is the most depended-on file — 8 modules
|
|
135
|
+
import from it. Changes here have the highest blast radius in the codebase."
|
|
136
|
+
|
|
137
|
+
## CLI Commands
|
|
138
|
+
|
|
139
|
+
| Command | Description |
|
|
140
|
+
|---------|-------------|
|
|
141
|
+
| `brain init` | Index the current repository |
|
|
142
|
+
| `brain reindex` | Force a full rebuild |
|
|
143
|
+
| `brain status [--json]` | Show index statistics |
|
|
144
|
+
| `brain search <query> [--json]` | Find symbols by name |
|
|
145
|
+
| `brain trace <name> [--depth N] [--json]` | Forward call chain |
|
|
146
|
+
| `brain impact <name> [--depth N] [--json]` | Reverse impact analysis |
|
|
147
|
+
| `brain deps <name> [--json]` | Dependencies of a symbol or file |
|
|
148
|
+
| `brain deadcode [--json]` | Find unused functions/classes |
|
|
149
|
+
| `brain cycles [--json]` | Detect import cycles |
|
|
150
|
+
| `brain validate <file> [--json]` | Check if a file change is safe |
|
|
151
|
+
| `brain overview [--json]` | System-level codebase overview |
|
|
152
|
+
| `brain module <file> [--json]` | Module-level view |
|
|
153
|
+
| `brain context <name> [--json]` | LLM-optimized symbol context |
|
|
154
|
+
| `brain hotspots [--top N] [--json]` | Riskiest symbols |
|
|
155
|
+
| `brain coupling [--json]` | Module coupling analysis |
|
|
156
|
+
| `brain contracts [--json]` | Implicit contract detection |
|
|
157
|
+
| `brain layers [--json]` | Architectural layer inference |
|
|
158
|
+
| `brain doctor` | Diagnostic health check |
|
|
159
|
+
| `brain zoom [target] [--json]` | Multi-resolution navigation (system/package/module/symbol) |
|
|
160
|
+
| `brain ci [--base B] [--fail-on F] [--json]` | CI validation of changed files |
|
|
161
|
+
| `brain diff` | Show files changed since last index |
|
|
162
|
+
| `brain watch` | Start file watcher daemon |
|
|
163
|
+
| `brain repair` | Check database integrity, rebuild if corrupted |
|
|
164
|
+
| `brain mcp` | Start MCP server (stdio) |
|
|
165
|
+
| `brain hook install` | Install pre-commit hook |
|
|
166
|
+
| `brain hook uninstall` | Remove pre-commit hook |
|
|
167
|
+
| `brain agent` | Generate agent integration files |
|
|
168
|
+
| `brain serve [--host H] [--port P]` | Start REST API server |
|
|
169
|
+
|
|
170
|
+
All commands accept `--repo <path>` to specify a different repository root, `--verbose` for debug logging, and `--timeout N` to set analysis timeout in seconds (default: 120).
|
|
171
|
+
|
|
172
|
+
## MCP Tools (for AI agents)
|
|
173
|
+
|
|
174
|
+
22+ tools available via MCP protocol. Key tools:
|
|
175
|
+
|
|
176
|
+
| Tool | Purpose |
|
|
177
|
+
|------|---------|
|
|
178
|
+
| `propose_change` | Validate before writing — the structural safety gate |
|
|
179
|
+
| `impact_analysis` | Trace transitive dependents of any symbol |
|
|
180
|
+
| `get_file_context` | Full file understanding for LLM context |
|
|
181
|
+
| `get_symbol_context` | Full symbol understanding for LLM context |
|
|
182
|
+
| `ask_codebase` | Natural language questions about the codebase |
|
|
183
|
+
| `validate_change` | Check if a file change would break callers |
|
|
184
|
+
| `risk_hotspots` | Find structurally dangerous symbols |
|
|
185
|
+
| `find_dead_code` | Unused symbols with confidence levels |
|
|
186
|
+
| `codebase_overview` | System-level architecture summary |
|
|
187
|
+
| `get_task_context` | Pull relevant context for a development task |
|
|
188
|
+
|
|
189
|
+
See [docs/mcp-tools.md](docs/mcp-tools.md) for full documentation.
|
|
190
|
+
|
|
191
|
+
## Configuration
|
|
192
|
+
|
|
193
|
+
Create `.codebrain.toml` in your repo root:
|
|
194
|
+
|
|
195
|
+
```toml
|
|
196
|
+
[codebrain]
|
|
197
|
+
# Extra directories to skip during indexing
|
|
198
|
+
skip_dirs = ["__pycache__", ".git", "node_modules", "vendor"]
|
|
199
|
+
|
|
200
|
+
# File extensions to index
|
|
201
|
+
extensions = [".py", ".ts", ".tsx", ".js", ".jsx"]
|
|
202
|
+
|
|
203
|
+
# Watcher debounce interval (seconds)
|
|
204
|
+
watcher_debounce = 0.5
|
|
205
|
+
|
|
206
|
+
# File count threshold for parallel parsing
|
|
207
|
+
parallel_threshold = 50
|
|
208
|
+
|
|
209
|
+
# Maximum file size to index (KB)
|
|
210
|
+
max_file_size_kb = 1024
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Environment variables override the config file:
|
|
214
|
+
|
|
215
|
+
| Variable | Description |
|
|
216
|
+
|----------|-------------|
|
|
217
|
+
| `CODEBRAIN_SKIP_DIRS` | Comma-separated skip directories |
|
|
218
|
+
| `CODEBRAIN_EXTENSIONS` | Comma-separated file extensions |
|
|
219
|
+
| `CODEBRAIN_DEBOUNCE` | Watcher debounce seconds |
|
|
220
|
+
| `CODEBRAIN_PARALLEL_THRESHOLD` | Parallel parsing threshold |
|
|
221
|
+
| `CODEBRAIN_MAX_WORKERS` | Max parallel worker processes |
|
|
222
|
+
| `CODEBRAIN_CLI_TIMEOUT` | CLI analysis timeout in seconds (default: 120) |
|
|
223
|
+
|
|
224
|
+
See [docs/configuration.md](docs/configuration.md) for full reference.
|
|
225
|
+
|
|
226
|
+
## Language Support
|
|
227
|
+
|
|
228
|
+
- **Python**: Full AST parsing (stable)
|
|
229
|
+
- **TypeScript/JavaScript**: tree-sitter parsing (`pip install codebrain[ts]`)
|
|
230
|
+
- **TypeScript fallback**: regex-based (experimental, limited coverage)
|
|
231
|
+
|
|
232
|
+
## CI Integration
|
|
233
|
+
|
|
234
|
+
### Pre-commit Hook
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
brain hook install # validates staged files before every commit
|
|
238
|
+
brain hook uninstall # remove the hook
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
The hook blocks commits with critical structural violations. Use `git commit --no-verify` to bypass.
|
|
242
|
+
|
|
243
|
+
### CI Pipeline
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
brain ci --base main # exits 1 if UNSAFE changes detected
|
|
247
|
+
brain ci --base main --json # machine-readable output
|
|
248
|
+
brain ci --fail-on caution # stricter: also fail on CAUTION
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### GitHub Action
|
|
252
|
+
|
|
253
|
+
```yaml
|
|
254
|
+
# .github/workflows/codebrain.yml
|
|
255
|
+
name: CodeBrain Validation
|
|
256
|
+
on: [pull_request]
|
|
257
|
+
jobs:
|
|
258
|
+
validate:
|
|
259
|
+
runs-on: ubuntu-latest
|
|
260
|
+
steps:
|
|
261
|
+
- uses: actions/checkout@v4
|
|
262
|
+
with:
|
|
263
|
+
fetch-depth: 0
|
|
264
|
+
- uses: actions/setup-python@v5
|
|
265
|
+
with:
|
|
266
|
+
python-version: '3.11'
|
|
267
|
+
- run: pip install codebrain
|
|
268
|
+
- run: brain ci --base origin/main --json
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Or use the reusable composite action:
|
|
272
|
+
|
|
273
|
+
```yaml
|
|
274
|
+
- uses: ./.github/actions/codebrain-validate
|
|
275
|
+
with:
|
|
276
|
+
base-branch: main
|
|
277
|
+
fail-on: unsafe
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## VS Code Extension
|
|
281
|
+
|
|
282
|
+
See [`vscode-extension/`](vscode-extension/) — 5 commands (impact, context, search, validate, hotspots) plus validate-on-save with inline diagnostics.
|
|
283
|
+
|
|
284
|
+
## REST API
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
pip install codebrain[api]
|
|
288
|
+
brain serve --port 8484
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
~20 endpoints at `/api/status`, `/api/search`, `/api/impact/{name}`, `/api/hotspots`, etc. Interactive docs at `/docs`.
|
|
292
|
+
|
|
293
|
+
## Plugin System
|
|
294
|
+
|
|
295
|
+
Add custom language parsers by implementing `BaseParser` and registering via entry points:
|
|
296
|
+
|
|
297
|
+
```python
|
|
298
|
+
from codebrain.parser.base import BaseParser
|
|
299
|
+
|
|
300
|
+
class RustParser(BaseParser):
|
|
301
|
+
def extensions(self) -> frozenset[str]:
|
|
302
|
+
return frozenset({".rs"})
|
|
303
|
+
|
|
304
|
+
def parse(self, path, repo_root):
|
|
305
|
+
... # return ParsedFile
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
```toml
|
|
309
|
+
# pyproject.toml
|
|
310
|
+
[project.entry-points."codebrain.parsers"]
|
|
311
|
+
rust = "your_package.parser:RustParser"
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Architecture
|
|
315
|
+
|
|
316
|
+
```
|
|
317
|
+
Source Files --> Parser (Python/TS) --> ParsedFile (Nodes + Edges)
|
|
318
|
+
|
|
|
319
|
+
GraphStore (SQLite)
|
|
320
|
+
|
|
|
321
|
+
QueryEngine
|
|
322
|
+
|
|
|
323
|
+
CLI / MCP / REST API / VS Code / Agent Bridge
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**Key abstractions:**
|
|
327
|
+
|
|
328
|
+
- **Node** — a code symbol (function, class, method, variable)
|
|
329
|
+
- **Edge** — a relationship (CALLS, IMPORTS, CONTAINS, EXTENDS, DATAFLOW)
|
|
330
|
+
- **GraphStore** — CRUD over the SQLite knowledge graph
|
|
331
|
+
- **QueryEngine** — impact analysis, call chains, dead code, cycles
|
|
332
|
+
|
|
333
|
+
## Validated on Real Codebases
|
|
334
|
+
|
|
335
|
+
CodeBrain has been tested on a 1,328-file mixed Python + TypeScript project (17,756 symbols, 111,793 edges):
|
|
336
|
+
|
|
337
|
+
- **Indexing**: 1,328 files in 135s, zero errors
|
|
338
|
+
- **Health score**: 93/100 in under 5s
|
|
339
|
+
- **Impact analysis**: Traces `getAstroData` → 48 dependents across 69 files
|
|
340
|
+
- **Contracts**: Found `Colors` + `Spacing` co-imported in 141/141 files (confidence 1.0)
|
|
341
|
+
- **Coupling**: Identified `logger.py` ↔ `main.py` (score 140)
|
|
342
|
+
- **Layers**: Detected architectural cycles in `kp-astrology` module
|
|
343
|
+
- **752 tests passing** across unit, integration, and real-world validation
|
|
344
|
+
|
|
345
|
+
## Development
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
git clone https://github.com/monk0062006/CodeBrain.git
|
|
349
|
+
cd CodeBrain
|
|
350
|
+
pip install -e ".[dev]"
|
|
351
|
+
|
|
352
|
+
pytest tests/ -v # Run tests
|
|
353
|
+
mypy codebrain/ # Type checking
|
|
354
|
+
ruff check codebrain/ # Linting
|
|
355
|
+
pytest --cov=codebrain # Coverage
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## License
|
|
359
|
+
|
|
360
|
+
MIT
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
codebrain/__init__.py,sha256=-WRZcHGUiNGGA052ikAc1EU5u5afbBeiPIkC4XAYGtU,96
|
|
2
|
+
codebrain/__main__.py,sha256=dgd9lRZovV1k1tScEW_wvPPjPEACXc-EcLtJ7AN3M48,115
|
|
3
|
+
codebrain/agent_bridge.py,sha256=JDny3232R6rfFsQTWOoYygGgykx6rb8ektLRENPUcDQ,6262
|
|
4
|
+
codebrain/analyzer.py,sha256=Y4GDvgkpIgQfjG6rHWvPielkiWwA81Bsr8P9t6V_nvY,39607
|
|
5
|
+
codebrain/api.py,sha256=uciazx-n97O5Q6hNvVdBu5w1kWxbhIXcDiSrBpTWQ54,21195
|
|
6
|
+
codebrain/api_models.py,sha256=mE5sIsf8WLEWjGm2w6-baeyVoJH_65FOglHwFe3aJhs,1989
|
|
7
|
+
codebrain/cli.py,sha256=M9EMI_4xMMGlZXRJ_4SM6DtcNK_1vuRWpv1e0-YXpj8,74305
|
|
8
|
+
codebrain/comprehension.py,sha256=66quIcwUxtij_EtfoxJksdcWCTtqVXSBckcpBF4F-Sk,79271
|
|
9
|
+
codebrain/config.py,sha256=90G-cem6OluNRzLUOFv6xZNdpqngrbafdVUdEHrPa6w,902
|
|
10
|
+
codebrain/context.py,sha256=DfKgOwL-3-3tDUtku5o1gfqaIZPAp4dKUQam2Bamd8I,10932
|
|
11
|
+
codebrain/export.py,sha256=A4zdzJ2MVmo-sxJQjwoZlMRkm-QXCxE14lYDm9RrQEY,11576
|
|
12
|
+
codebrain/hook_runner.py,sha256=R4h9KSWY0k9-pBtB4m9pHNXUxo3mc_9x6_SnKRuuQIg,2085
|
|
13
|
+
codebrain/hooks.py,sha256=x6VGEWKD863g2d6Nt-Yk1UYQz3nk3BKXDUCb4jFGR1g,3126
|
|
14
|
+
codebrain/indexer.py,sha256=Hz5hwa3HxCYe_rzZ7PCJHoF8009RoM4DsXkuV0OV1TM,15534
|
|
15
|
+
codebrain/llm.py,sha256=0D5c5BJMVkLz2OoybfMxlUdJEbz16cZoNgVmm-LzFH0,25606
|
|
16
|
+
codebrain/logging.py,sha256=ORR5L8REVlh4aJz9vqErmi76aqjLN2xVKoA2gSv_jas,1110
|
|
17
|
+
codebrain/mcp_server.py,sha256=q_NBNW4f8TwxeruHluk4lRefCQMljXhl9acEtgM-LWM,61329
|
|
18
|
+
codebrain/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
+
codebrain/resolver.py,sha256=rLKzfCrfEnEuBRn1OzukjgJoWL4jDvkUNXA3zuXr_ac,6388
|
|
20
|
+
codebrain/settings.py,sha256=mlsqsSFztSbcKYp8342S3OR8YOoByNVpM0PiGvQe3oA,3210
|
|
21
|
+
codebrain/utils.py,sha256=lO4cDMPlHgGAOkm_99x1hToKOye7NapFXj0DZ9bwAMg,1743
|
|
22
|
+
codebrain/validator.py,sha256=B-54GH-pl_XYKpsuNRtfv-5fYXKvkefC1vF_fChDOr0,25002
|
|
23
|
+
codebrain/graph/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
|
+
codebrain/graph/query.py,sha256=a2_z0yCXOWVEZeA0mI3dz9TaZMT7k3Z5jwep20qMVlw,28804
|
|
25
|
+
codebrain/graph/schema.py,sha256=yj0foabC7U4NJHOE2yp-FBUnOVCIxuAIwKaP3d5z_zA,3910
|
|
26
|
+
codebrain/graph/store.py,sha256=E__BQc_Aln5ilPkgSI-J03CWKZy6lLM4fnK985SOr64,12558
|
|
27
|
+
codebrain/memory/__init__.py,sha256=PuFR35m1GPIbRAuUxKu4JYBDlPXJWMPbyrWiggFT2sU,158
|
|
28
|
+
codebrain/memory/store.py,sha256=W31fe4aNTkdi-Woe8bZ8SZ9aUHpWrfBkb-9dQs0geyI,9394
|
|
29
|
+
codebrain/parser/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
|
+
codebrain/parser/base.py,sha256=EBP0_EtSgYcwxm8u9ZZNR4UdnsPEJm9tTUXiUEKAPoM,711
|
|
31
|
+
codebrain/parser/config_parser.py,sha256=q0N5Vt7kc8RSv5qOUAwRXh1ey1VxJczvHKnhwMqcZME,7612
|
|
32
|
+
codebrain/parser/models.py,sha256=zbDFbRb1eave-wcswW1Nw9DJBiyrtVJ5rvjeDfqDp7g,1281
|
|
33
|
+
codebrain/parser/python_parser.py,sha256=G_XGWcve8rrOXT2tPzZBPGkrWYTuh6W8ylsaiabMXl0,26110
|
|
34
|
+
codebrain/parser/registry.py,sha256=CR0uGVCNmQKb8h_7zaPwhnDD2R_TR28OOB2GysBcDVQ,5612
|
|
35
|
+
codebrain/parser/typescript_parser.py,sha256=fi0DoXLCi_L0aQzpadumDpFHaSyekfp3wmVFaASvuks,47891
|
|
36
|
+
codebrain/parser/typescript_treesitter.py,sha256=fxoettUXAEyNqqz1EWF54amAN8O9j7ry-xIlq_nU18o,23722
|
|
37
|
+
codebrain/watcher/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
|
+
codebrain/watcher/file_watcher.py,sha256=r1VYK6L5bkN9XuVSd8yQs0FMdLmu_8Z0q1hR1Kx_LGY,6139
|
|
39
|
+
codebrain-0.1.0.dist-info/licenses/LICENSE,sha256=2CvMb23aV7m-hC2tXAOjDGC6YOtScvtHlWiYIMhMBrk,1079
|
|
40
|
+
codebrain-0.1.0.dist-info/METADATA,sha256=A0tbwlBswqF33ebGSQ--jNp-VpOpTrVe5IIwMIEFhLg,11983
|
|
41
|
+
codebrain-0.1.0.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
|
|
42
|
+
codebrain-0.1.0.dist-info/entry_points.txt,sha256=BFbv0eKiaRBIvpCZKr-BB8MPHWPUKfvBCXuBxPbEMdc,183
|
|
43
|
+
codebrain-0.1.0.dist-info/top_level.txt,sha256=mUxCZc80EyNOMzd2vAm22uIhnOb1Aw7ZOAUT_u-ksx4,10
|
|
44
|
+
codebrain-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 CodeBrain Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
codebrain
|