ctxgraph-code 0.1.0__tar.gz → 0.1.2__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.
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/PKG-INFO +37 -10
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/README.md +36 -9
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/pyproject.toml +1 -1
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code/cli.py +104 -10
- ctxgraph_code-0.1.2/src/ctxgraph_code/config/init.py +19 -0
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code/config/settings.py +41 -6
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code/graph/builder.py +4 -2
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code/render.py +101 -0
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code.egg-info/PKG-INFO +37 -10
- ctxgraph_code-0.1.0/src/ctxgraph_code/config/init.py +0 -14
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/setup.cfg +0 -0
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code/__init__.py +0 -0
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code/__main__.py +0 -0
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code/analyzers/__init__.py +0 -0
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code/analyzers/python/__init__.py +0 -0
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code/analyzers/python/importer.py +0 -0
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code/analyzers/python/semantic.py +0 -0
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code/analyzers/python/symbols.py +0 -0
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code/config/__init__.py +0 -0
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code/exclude/__init__.py +0 -0
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code/exclude/patterns.py +0 -0
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code/graph/__init__.py +0 -0
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code/graph/models.py +0 -0
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code/graph/query.py +0 -0
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code/graph/storage.py +0 -0
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code.egg-info/SOURCES.txt +0 -0
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code.egg-info/dependency_links.txt +0 -0
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code.egg-info/entry_points.txt +0 -0
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code.egg-info/requires.txt +0 -0
- {ctxgraph_code-0.1.0 → ctxgraph_code-0.1.2}/src/ctxgraph_code.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ctxgraph-code
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Code knowledge graph for Claude Code. Build a relationship graph of your Python codebase and query it during coding sessions.
|
|
5
5
|
Author: ctxgraph-code contributors
|
|
6
6
|
License: MIT
|
|
@@ -70,11 +70,21 @@ ctxgraph-code setup
|
|
|
70
70
|
ctxgraph-code setup
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
Interactive walkthrough — prompts for:
|
|
74
|
+
- **File extensions** to scan (`.py`, `.js`, `.ts`, etc.)
|
|
75
|
+
- **Exclude patterns** (folders like `tests/`, globs like `*.generated.py`)
|
|
76
|
+
|
|
73
77
|
Does everything in one step:
|
|
74
|
-
1. Creates `.ctxgraph/config.toml` with
|
|
75
|
-
2. Builds the knowledge graph from all
|
|
78
|
+
1. Creates `.ctxgraph/config.toml` with your chosen extensions and excludes
|
|
79
|
+
2. Builds the knowledge graph from all matching files
|
|
76
80
|
3. Creates `.claude/commands/ctxgraph-code.md` with instructions for Claude Code
|
|
77
81
|
|
|
82
|
+
Non-interactive mode (skip prompts):
|
|
83
|
+
```bash
|
|
84
|
+
ctxgraph-code setup --extensions .py,.js,.ts --exclude tests/,examples/
|
|
85
|
+
ctxgraph-code setup -y # all defaults
|
|
86
|
+
```
|
|
87
|
+
|
|
78
88
|
### `init`
|
|
79
89
|
|
|
80
90
|
```bash
|
|
@@ -87,10 +97,12 @@ Creates the `.ctxgraph/` directory with a default `config.toml`.
|
|
|
87
97
|
|
|
88
98
|
```bash
|
|
89
99
|
ctxgraph-code build
|
|
90
|
-
ctxgraph-code build --
|
|
100
|
+
ctxgraph-code build --extensions .py,.js,.ts
|
|
101
|
+
ctxgraph-code build --exclude tests/ --exclude *.generated.py
|
|
91
102
|
```
|
|
92
103
|
|
|
93
|
-
Scans all
|
|
104
|
+
Scans all matching files in the project, runs AST analysis. Extensions are read from config (`.py` by default, or whatever was set in `setup`).
|
|
105
|
+
|
|
94
106
|
- **Imports**: which files import other files
|
|
95
107
|
- **Class definitions**: class names, base classes, methods
|
|
96
108
|
- **Function definitions**: function names, arguments
|
|
@@ -99,6 +111,8 @@ Scans all `*.py` files in the project, runs AST analysis:
|
|
|
99
111
|
|
|
100
112
|
Stores the result in `.ctxgraph/graph.db`.
|
|
101
113
|
|
|
114
|
+
> The graph is a **static snapshot**. If code changes, run `ctxgraph-code build` again to refresh. Claude Code will also rebuild when it detects the graph is stale.
|
|
115
|
+
|
|
102
116
|
### `query`
|
|
103
117
|
|
|
104
118
|
```bash
|
|
@@ -148,6 +162,17 @@ ctxgraph-code context "add pagination to the users endpoint"
|
|
|
148
162
|
|
|
149
163
|
Generates a focused context summary: relevant files, their symbols, and dependency/call edges between them. This is the closest equivalent to `ctxgraph`'s capsule format.
|
|
150
164
|
|
|
165
|
+
### `view`
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
ctxgraph-code view
|
|
169
|
+
ctxgraph-code view --output tree.txt
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Prints a hierarchical directory tree from the graph showing every file and its symbols (classes marked `[C]`, functions/methods marked `[M]`). Also lists import and call edges at the bottom.
|
|
173
|
+
|
|
174
|
+
Useful for a quick visual scan of the project structure without reading every file.
|
|
175
|
+
|
|
151
176
|
### `info`
|
|
152
177
|
|
|
153
178
|
```bash
|
|
@@ -234,11 +259,13 @@ Claude then uses these commands as needed during the conversation.
|
|
|
234
259
|
|
|
235
260
|
## Configuration
|
|
236
261
|
|
|
237
|
-
Configure via `.ctxgraph/config.toml` (created by `
|
|
262
|
+
Configure via `.ctxgraph/config.toml` (created interactively by `setup` or manually):
|
|
238
263
|
|
|
239
264
|
```toml
|
|
240
265
|
[graph]
|
|
241
|
-
#
|
|
266
|
+
# File extensions to scan
|
|
267
|
+
extensions = [".py", ".js", ".ts"]
|
|
268
|
+
# Exclude patterns beyond built-in defaults
|
|
242
269
|
exclude = ["tests/", "examples/"]
|
|
243
270
|
# Follow symlinks when scanning
|
|
244
271
|
follow_symlinks = false
|
|
@@ -246,7 +273,7 @@ follow_symlinks = false
|
|
|
246
273
|
max_file_size_mb = 5
|
|
247
274
|
```
|
|
248
275
|
|
|
249
|
-
|
|
276
|
+
Built-in default exclusion patterns (always applied): `__pycache__`, `*.pyc`, `.git`, `node_modules`, `venv`, `.venv`, `dist`, `build`, `*.egg-info`, `.pytest_cache`, `.mypy_cache`, `.ruff_cache`, `.tox`, `migrations`, `*.min.js`, `*.min.css`.
|
|
250
277
|
|
|
251
278
|
---
|
|
252
279
|
|
|
@@ -256,10 +283,10 @@ Default exclusion patterns: `__pycache__`, `*.pyc`, `.git`, `node_modules`, `ven
|
|
|
256
283
|
|
|
257
284
|
| Feature | ctxgraph | ctxgraph-code |
|
|
258
285
|
|---------|----------|---------------|
|
|
259
|
-
| CLI commands | 9 (build, capsule, query, view, serve, info, init, ask, chat, history, skill) |
|
|
286
|
+
| CLI commands | 9 (build, capsule, query, view, serve, info, init, ask, chat, history, skill) | 9 (init, build, query, deps, usedby, overview, symbols, context, setup, view, info) |
|
|
260
287
|
| LLM integration | Built-in (Ollama, Claude, OpenAI, Azure) | None (delegates to Claude Code) |
|
|
261
288
|
| Chat sessions | Yes | No |
|
|
262
|
-
| Visualizer | D3.js HTML + SVG |
|
|
289
|
+
| Visualizer | D3.js HTML + SVG | Text tree (`view` command) |
|
|
263
290
|
| Skills system | Yes (customizable skill TOML files) | No |
|
|
264
291
|
| MCP server | Yes | No |
|
|
265
292
|
| Token savings | Yes (capsule DSL compression) | No |
|
|
@@ -47,11 +47,21 @@ ctxgraph-code setup
|
|
|
47
47
|
ctxgraph-code setup
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
+
Interactive walkthrough — prompts for:
|
|
51
|
+
- **File extensions** to scan (`.py`, `.js`, `.ts`, etc.)
|
|
52
|
+
- **Exclude patterns** (folders like `tests/`, globs like `*.generated.py`)
|
|
53
|
+
|
|
50
54
|
Does everything in one step:
|
|
51
|
-
1. Creates `.ctxgraph/config.toml` with
|
|
52
|
-
2. Builds the knowledge graph from all
|
|
55
|
+
1. Creates `.ctxgraph/config.toml` with your chosen extensions and excludes
|
|
56
|
+
2. Builds the knowledge graph from all matching files
|
|
53
57
|
3. Creates `.claude/commands/ctxgraph-code.md` with instructions for Claude Code
|
|
54
58
|
|
|
59
|
+
Non-interactive mode (skip prompts):
|
|
60
|
+
```bash
|
|
61
|
+
ctxgraph-code setup --extensions .py,.js,.ts --exclude tests/,examples/
|
|
62
|
+
ctxgraph-code setup -y # all defaults
|
|
63
|
+
```
|
|
64
|
+
|
|
55
65
|
### `init`
|
|
56
66
|
|
|
57
67
|
```bash
|
|
@@ -64,10 +74,12 @@ Creates the `.ctxgraph/` directory with a default `config.toml`.
|
|
|
64
74
|
|
|
65
75
|
```bash
|
|
66
76
|
ctxgraph-code build
|
|
67
|
-
ctxgraph-code build --
|
|
77
|
+
ctxgraph-code build --extensions .py,.js,.ts
|
|
78
|
+
ctxgraph-code build --exclude tests/ --exclude *.generated.py
|
|
68
79
|
```
|
|
69
80
|
|
|
70
|
-
Scans all
|
|
81
|
+
Scans all matching files in the project, runs AST analysis. Extensions are read from config (`.py` by default, or whatever was set in `setup`).
|
|
82
|
+
|
|
71
83
|
- **Imports**: which files import other files
|
|
72
84
|
- **Class definitions**: class names, base classes, methods
|
|
73
85
|
- **Function definitions**: function names, arguments
|
|
@@ -76,6 +88,8 @@ Scans all `*.py` files in the project, runs AST analysis:
|
|
|
76
88
|
|
|
77
89
|
Stores the result in `.ctxgraph/graph.db`.
|
|
78
90
|
|
|
91
|
+
> The graph is a **static snapshot**. If code changes, run `ctxgraph-code build` again to refresh. Claude Code will also rebuild when it detects the graph is stale.
|
|
92
|
+
|
|
79
93
|
### `query`
|
|
80
94
|
|
|
81
95
|
```bash
|
|
@@ -125,6 +139,17 @@ ctxgraph-code context "add pagination to the users endpoint"
|
|
|
125
139
|
|
|
126
140
|
Generates a focused context summary: relevant files, their symbols, and dependency/call edges between them. This is the closest equivalent to `ctxgraph`'s capsule format.
|
|
127
141
|
|
|
142
|
+
### `view`
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
ctxgraph-code view
|
|
146
|
+
ctxgraph-code view --output tree.txt
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Prints a hierarchical directory tree from the graph showing every file and its symbols (classes marked `[C]`, functions/methods marked `[M]`). Also lists import and call edges at the bottom.
|
|
150
|
+
|
|
151
|
+
Useful for a quick visual scan of the project structure without reading every file.
|
|
152
|
+
|
|
128
153
|
### `info`
|
|
129
154
|
|
|
130
155
|
```bash
|
|
@@ -211,11 +236,13 @@ Claude then uses these commands as needed during the conversation.
|
|
|
211
236
|
|
|
212
237
|
## Configuration
|
|
213
238
|
|
|
214
|
-
Configure via `.ctxgraph/config.toml` (created by `
|
|
239
|
+
Configure via `.ctxgraph/config.toml` (created interactively by `setup` or manually):
|
|
215
240
|
|
|
216
241
|
```toml
|
|
217
242
|
[graph]
|
|
218
|
-
#
|
|
243
|
+
# File extensions to scan
|
|
244
|
+
extensions = [".py", ".js", ".ts"]
|
|
245
|
+
# Exclude patterns beyond built-in defaults
|
|
219
246
|
exclude = ["tests/", "examples/"]
|
|
220
247
|
# Follow symlinks when scanning
|
|
221
248
|
follow_symlinks = false
|
|
@@ -223,7 +250,7 @@ follow_symlinks = false
|
|
|
223
250
|
max_file_size_mb = 5
|
|
224
251
|
```
|
|
225
252
|
|
|
226
|
-
|
|
253
|
+
Built-in default exclusion patterns (always applied): `__pycache__`, `*.pyc`, `.git`, `node_modules`, `venv`, `.venv`, `dist`, `build`, `*.egg-info`, `.pytest_cache`, `.mypy_cache`, `.ruff_cache`, `.tox`, `migrations`, `*.min.js`, `*.min.css`.
|
|
227
254
|
|
|
228
255
|
---
|
|
229
256
|
|
|
@@ -233,10 +260,10 @@ Default exclusion patterns: `__pycache__`, `*.pyc`, `.git`, `node_modules`, `ven
|
|
|
233
260
|
|
|
234
261
|
| Feature | ctxgraph | ctxgraph-code |
|
|
235
262
|
|---------|----------|---------------|
|
|
236
|
-
| CLI commands | 9 (build, capsule, query, view, serve, info, init, ask, chat, history, skill) |
|
|
263
|
+
| CLI commands | 9 (build, capsule, query, view, serve, info, init, ask, chat, history, skill) | 9 (init, build, query, deps, usedby, overview, symbols, context, setup, view, info) |
|
|
237
264
|
| LLM integration | Built-in (Ollama, Claude, OpenAI, Azure) | None (delegates to Claude Code) |
|
|
238
265
|
| Chat sessions | Yes | No |
|
|
239
|
-
| Visualizer | D3.js HTML + SVG |
|
|
266
|
+
| Visualizer | D3.js HTML + SVG | Text tree (`view` command) |
|
|
240
267
|
| Skills system | Yes (customizable skill TOML files) | No |
|
|
241
268
|
| MCP server | Yes | No |
|
|
242
269
|
| Token savings | Yes (capsule DSL compression) | No |
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ctxgraph-code"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.2"
|
|
8
8
|
description = "Code knowledge graph for Claude Code. Build a relationship graph of your Python codebase and query it during coding sessions."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -17,6 +17,7 @@ from ctxgraph_code.render import (
|
|
|
17
17
|
render_deps,
|
|
18
18
|
render_overview,
|
|
19
19
|
render_symbols,
|
|
20
|
+
render_treeview,
|
|
20
21
|
render_usedby,
|
|
21
22
|
)
|
|
22
23
|
|
|
@@ -24,11 +25,25 @@ app = typer.Typer(name="ctxgraph-code", help="Code knowledge graph for Claude Co
|
|
|
24
25
|
console = Console()
|
|
25
26
|
|
|
26
27
|
|
|
28
|
+
def _build_time_label(storage) -> str:
|
|
29
|
+
ts = storage.get_metadata("build_time")
|
|
30
|
+
if ts:
|
|
31
|
+
try:
|
|
32
|
+
from datetime import datetime
|
|
33
|
+
dt = datetime.fromtimestamp(float(ts))
|
|
34
|
+
return dt.strftime("%Y-%m-%d %H:%M")
|
|
35
|
+
except Exception:
|
|
36
|
+
return ts
|
|
37
|
+
return "unknown"
|
|
38
|
+
|
|
39
|
+
|
|
27
40
|
SLASH_COMMAND_TEMPLATE = """# ctxgraph-code: Code Relationship Graph
|
|
28
41
|
|
|
29
42
|
This project has a knowledge graph at `.ctxgraph/graph.db`.
|
|
30
43
|
The graph knows about imports, class hierarchies, and function calls.
|
|
31
44
|
|
|
45
|
+
**Last build:** {build_time}
|
|
46
|
+
|
|
32
47
|
**Available commands** (run these as shell commands in the terminal):
|
|
33
48
|
|
|
34
49
|
- `ctxgraph-code query "search terms"` -- Find relevant files, classes, and functions
|
|
@@ -43,6 +58,9 @@ The graph knows about imports, class hierarchies, and function calls.
|
|
|
43
58
|
- When exploring an unfamiliar area, run `query` to find relevant files, then read them.
|
|
44
59
|
- When asked about architecture, run `overview` for the big picture.
|
|
45
60
|
- For complex tasks, run `context "what I need to do"` for a focused summary.
|
|
61
|
+
|
|
62
|
+
**Note:** The graph is a static snapshot. If files have changed since the last build,
|
|
63
|
+
run `ctxgraph-code build` to refresh it.
|
|
46
64
|
"""
|
|
47
65
|
|
|
48
66
|
|
|
@@ -70,11 +88,14 @@ def build(
|
|
|
70
88
|
repo_path: Optional[str] = typer.Argument(
|
|
71
89
|
None, help="Path to repository (default: current directory)"
|
|
72
90
|
),
|
|
91
|
+
extensions: Optional[str] = typer.Option(
|
|
92
|
+
None, "--extensions", help="File extensions to scan, e.g. .py,.js,.ts"
|
|
93
|
+
),
|
|
73
94
|
exclude: Optional[list[str]] = typer.Option(
|
|
74
95
|
None, "--exclude", "-e", help="Additional exclude patterns"
|
|
75
96
|
),
|
|
76
97
|
):
|
|
77
|
-
"""Build the knowledge graph from
|
|
98
|
+
"""Build the knowledge graph from source files."""
|
|
78
99
|
path = Path(repo_path).resolve() if repo_path else Path.cwd()
|
|
79
100
|
|
|
80
101
|
settings = Settings(path)
|
|
@@ -82,11 +103,16 @@ def build(
|
|
|
82
103
|
if exclude:
|
|
83
104
|
user_patterns = list((user_patterns or []) + exclude)
|
|
84
105
|
|
|
106
|
+
exts = settings.extensions
|
|
107
|
+
if extensions:
|
|
108
|
+
exts = [e.strip() for e in extensions.split(",") if e.strip()]
|
|
109
|
+
|
|
85
110
|
if not (path / ".ctxgraph").exists():
|
|
86
111
|
(path / ".ctxgraph").mkdir(parents=True, exist_ok=True)
|
|
87
112
|
|
|
88
|
-
|
|
89
|
-
|
|
113
|
+
ext_label = ", ".join(exts)
|
|
114
|
+
with console.status(f"Scanning {ext_label} files in {path}..."):
|
|
115
|
+
stats = build_graph(path, exclude_patterns=user_patterns, extensions=exts)
|
|
90
116
|
|
|
91
117
|
table = Table(title="Graph Build Complete")
|
|
92
118
|
table.add_column("Metric", style="cyan")
|
|
@@ -247,16 +273,52 @@ def setup(
|
|
|
247
273
|
repo_path: Optional[str] = typer.Argument(
|
|
248
274
|
None, help="Path to repository (default: current directory)"
|
|
249
275
|
),
|
|
276
|
+
extensions: Optional[str] = typer.Option(
|
|
277
|
+
None, "--extensions", help="File extensions to scan, e.g. .py,.js,.ts"
|
|
278
|
+
),
|
|
279
|
+
exclude: Optional[str] = typer.Option(
|
|
280
|
+
None, "--exclude", help="Exclude patterns, e.g. tests/,examples/"
|
|
281
|
+
),
|
|
282
|
+
non_interactive: bool = typer.Option(
|
|
283
|
+
False, "--yes", "-y", help="Skip prompts, use defaults"
|
|
284
|
+
),
|
|
250
285
|
):
|
|
251
|
-
"""Initialize config, build the graph, and configure Claude Code
|
|
286
|
+
"""Initialize config, build the graph, and configure Claude Code."""
|
|
252
287
|
path = Path(repo_path).resolve() if repo_path else Path.cwd()
|
|
253
288
|
|
|
254
|
-
|
|
289
|
+
if non_interactive:
|
|
290
|
+
exts = [".py"]
|
|
291
|
+
excl = []
|
|
292
|
+
elif extensions:
|
|
293
|
+
exts = [e.strip() for e in extensions.split(",") if e.strip()]
|
|
294
|
+
excl = [e.strip() for e in exclude.split(",") if e.strip()] if exclude else []
|
|
295
|
+
else:
|
|
296
|
+
console.print("[bold cyan]ctxgraph-code setup[/bold cyan]")
|
|
297
|
+
console.print("Let's configure your project graph.\n")
|
|
298
|
+
|
|
299
|
+
ext_input = typer.prompt(
|
|
300
|
+
"File extensions to scan (comma-separated)",
|
|
301
|
+
default=".py",
|
|
302
|
+
prompt_suffix=": ",
|
|
303
|
+
)
|
|
304
|
+
exts = [e.strip() for e in ext_input.split(",") if e.strip()]
|
|
305
|
+
if not exts:
|
|
306
|
+
exts = [".py"]
|
|
307
|
+
|
|
308
|
+
excl_input = typer.prompt(
|
|
309
|
+
"Exclude patterns (comma-separated, e.g. tests/,examples/)",
|
|
310
|
+
default="",
|
|
311
|
+
prompt_suffix=": ",
|
|
312
|
+
)
|
|
313
|
+
excl = [e.strip() for e in excl_input.split(",") if e.strip()] if excl_input.strip() else []
|
|
314
|
+
|
|
315
|
+
console.print()
|
|
316
|
+
|
|
317
|
+
init_project(path, extensions=exts, exclude_patterns=excl)
|
|
255
318
|
console.print(f"[green][OK] Initialized .ctxgraph/[/green]")
|
|
256
319
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
stats = build_graph(path, exclude_patterns=settings.exclude_patterns)
|
|
320
|
+
with console.status(f"Scanning {', '.join(exts)} files in {path}..."):
|
|
321
|
+
stats = build_graph(path, exclude_patterns=excl, extensions=exts)
|
|
260
322
|
|
|
261
323
|
table = Table(title="Graph Build Complete")
|
|
262
324
|
table.add_column("Metric", style="cyan")
|
|
@@ -273,8 +335,13 @@ def setup(
|
|
|
273
335
|
claude_dir = path / ".claude" / "commands"
|
|
274
336
|
claude_dir.mkdir(parents=True, exist_ok=True)
|
|
275
337
|
slash_path = claude_dir / "ctxgraph-code.md"
|
|
338
|
+
|
|
339
|
+
storage = get_storage(path)
|
|
340
|
+
build_label = _build_time_label(storage) if storage else "unknown"
|
|
341
|
+
content = SLASH_COMMAND_TEMPLATE.format(build_time=build_label)
|
|
342
|
+
|
|
276
343
|
if not slash_path.exists():
|
|
277
|
-
slash_path.write_text(
|
|
344
|
+
slash_path.write_text(content, encoding="utf-8")
|
|
278
345
|
console.print(f"[green][OK] Created {slash_path}[/green]")
|
|
279
346
|
else:
|
|
280
347
|
console.print(f"[yellow] Skipped (already exists): {slash_path}[/yellow]")
|
|
@@ -284,6 +351,33 @@ def setup(
|
|
|
284
351
|
console.print("Open Claude Code in this project and type [bold]/ctxgraph-code[/bold] to get started.")
|
|
285
352
|
|
|
286
353
|
|
|
354
|
+
@app.command()
|
|
355
|
+
def view(
|
|
356
|
+
repo_path: Optional[str] = typer.Option(
|
|
357
|
+
None, "--repo", "-r", help="Repository path"
|
|
358
|
+
),
|
|
359
|
+
output: Optional[str] = typer.Option(
|
|
360
|
+
None, "--output", "-o", help="Save tree to file"
|
|
361
|
+
),
|
|
362
|
+
):
|
|
363
|
+
"""Visualize the graph as a directory tree with symbols and edges."""
|
|
364
|
+
path = Path(repo_path).resolve() if repo_path else Path.cwd()
|
|
365
|
+
|
|
366
|
+
storage = get_storage(path)
|
|
367
|
+
if storage is None:
|
|
368
|
+
console.print("[red]No graph found. Run [bold]ctxgraph-code build[/bold] first.[/red]")
|
|
369
|
+
raise typer.Exit(1)
|
|
370
|
+
|
|
371
|
+
tree = render_treeview(storage)
|
|
372
|
+
|
|
373
|
+
if output:
|
|
374
|
+
out_path = Path(output)
|
|
375
|
+
out_path.write_text(tree, encoding="utf-8")
|
|
376
|
+
console.print(f"Saved tree to [bold]{out_path}[/bold]")
|
|
377
|
+
else:
|
|
378
|
+
console.print(tree)
|
|
379
|
+
|
|
380
|
+
|
|
287
381
|
@app.command()
|
|
288
382
|
def info(
|
|
289
383
|
repo_path: Optional[str] = typer.Option(
|
|
@@ -329,7 +423,7 @@ def version():
|
|
|
329
423
|
try:
|
|
330
424
|
ver = _v("ctxgraph-code")
|
|
331
425
|
except Exception:
|
|
332
|
-
ver = "0.1.
|
|
426
|
+
ver = "0.1.2"
|
|
333
427
|
console.print(f"ctxgraph-code version [bold]{ver}[/bold]")
|
|
334
428
|
|
|
335
429
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from ctxgraph_code.config.settings import create_default_config
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def init_project(
|
|
10
|
+
repo_path: Path,
|
|
11
|
+
extensions: Optional[list[str]] = None,
|
|
12
|
+
exclude_patterns: Optional[list[str]] = None,
|
|
13
|
+
) -> Path:
|
|
14
|
+
cfg_dir = repo_path / ".ctxgraph"
|
|
15
|
+
cfg_dir.mkdir(parents=True, exist_ok=True)
|
|
16
|
+
|
|
17
|
+
create_default_config(repo_path, extensions=extensions, exclude_patterns=exclude_patterns)
|
|
18
|
+
|
|
19
|
+
return cfg_dir
|
|
@@ -8,6 +8,7 @@ from typing import Optional
|
|
|
8
8
|
|
|
9
9
|
DEFAULT_CONFIG = {
|
|
10
10
|
"graph": {
|
|
11
|
+
"extensions": [".py"],
|
|
11
12
|
"exclude": [],
|
|
12
13
|
"follow_symlinks": False,
|
|
13
14
|
"max_file_size_mb": 5,
|
|
@@ -43,6 +44,11 @@ class Settings:
|
|
|
43
44
|
parsed = self._parse_toml(text)
|
|
44
45
|
self._deep_merge(self._data, parsed)
|
|
45
46
|
|
|
47
|
+
@property
|
|
48
|
+
def extensions(self) -> list[str]:
|
|
49
|
+
exts = self._data["graph"].get("extensions", [".py"])
|
|
50
|
+
return [e if e.startswith(".") else f".{e}" for e in exts]
|
|
51
|
+
|
|
46
52
|
@property
|
|
47
53
|
def exclude_patterns(self) -> list[str]:
|
|
48
54
|
return self._data["graph"].get("exclude", [])
|
|
@@ -67,8 +73,10 @@ class Settings:
|
|
|
67
73
|
key = key.strip()
|
|
68
74
|
value = value.strip()
|
|
69
75
|
|
|
70
|
-
if
|
|
71
|
-
|
|
76
|
+
if value.startswith("[") and value.endswith("]"):
|
|
77
|
+
value = Settings._parse_toml_array(value)
|
|
78
|
+
elif (value.startswith('"') and value.endswith('"')) or \
|
|
79
|
+
(value.startswith("'") and value.endswith("'")):
|
|
72
80
|
value = value[1:-1]
|
|
73
81
|
else:
|
|
74
82
|
value = Settings._parse_toml_value(value)
|
|
@@ -77,6 +85,21 @@ class Settings:
|
|
|
77
85
|
|
|
78
86
|
return result
|
|
79
87
|
|
|
88
|
+
@staticmethod
|
|
89
|
+
def _parse_toml_array(text: str) -> list:
|
|
90
|
+
inner = text[1:-1].strip()
|
|
91
|
+
if not inner:
|
|
92
|
+
return []
|
|
93
|
+
items = []
|
|
94
|
+
for item in inner.split(","):
|
|
95
|
+
item = item.strip()
|
|
96
|
+
if (item.startswith('"') and item.endswith('"')) or \
|
|
97
|
+
(item.startswith("'") and item.endswith("'")):
|
|
98
|
+
items.append(item[1:-1])
|
|
99
|
+
else:
|
|
100
|
+
items.append(Settings._parse_toml_value(item))
|
|
101
|
+
return items
|
|
102
|
+
|
|
80
103
|
@staticmethod
|
|
81
104
|
def _parse_toml_value(value: str):
|
|
82
105
|
if value.lower() in ("true", "false"):
|
|
@@ -97,7 +120,11 @@ class Settings:
|
|
|
97
120
|
base[key] = value
|
|
98
121
|
|
|
99
122
|
|
|
100
|
-
def create_default_config(
|
|
123
|
+
def create_default_config(
|
|
124
|
+
repo_path: Path,
|
|
125
|
+
extensions: Optional[list[str]] = None,
|
|
126
|
+
exclude_patterns: Optional[list[str]] = None,
|
|
127
|
+
):
|
|
101
128
|
config_dir = repo_path / ".ctxgraph"
|
|
102
129
|
config_dir.mkdir(parents=True, exist_ok=True)
|
|
103
130
|
|
|
@@ -105,12 +132,20 @@ def create_default_config(repo_path: Path):
|
|
|
105
132
|
if config_path.exists():
|
|
106
133
|
return
|
|
107
134
|
|
|
135
|
+
ext_list = extensions or [".py"]
|
|
136
|
+
ext_line = ", ".join(f'"{e}"' for e in ext_list)
|
|
137
|
+
|
|
138
|
+
excl_list = exclude_patterns or []
|
|
139
|
+
excl_line = ", ".join(f'"{e}"' for e in excl_list) if excl_list else ""
|
|
140
|
+
|
|
108
141
|
config_path.write_text(
|
|
109
|
-
"""# ctxgraph-code configuration
|
|
142
|
+
f"""# ctxgraph-code configuration
|
|
110
143
|
|
|
111
144
|
[graph]
|
|
112
|
-
#
|
|
113
|
-
|
|
145
|
+
# File extensions to scan
|
|
146
|
+
extensions = [{ext_line}]
|
|
147
|
+
# Exclude patterns (gitignore patterns are excluded automatically)
|
|
148
|
+
exclude = [{excl_line}]
|
|
114
149
|
# Follow symlinks when scanning files
|
|
115
150
|
follow_symlinks = false
|
|
116
151
|
# Skip files larger than this many MB
|
|
@@ -16,6 +16,7 @@ def build_graph(
|
|
|
16
16
|
repo_path: str | Path,
|
|
17
17
|
db_path: Optional[str | Path] = None,
|
|
18
18
|
exclude_patterns: Optional[list[str]] = None,
|
|
19
|
+
extensions: Optional[list[str]] = None,
|
|
19
20
|
) -> dict:
|
|
20
21
|
repo_path = Path(repo_path).resolve()
|
|
21
22
|
if db_path is None:
|
|
@@ -29,8 +30,9 @@ def build_graph(
|
|
|
29
30
|
combined = Graph()
|
|
30
31
|
stats = {"files_analyzed": 0, "files_skipped": 0, "errors": 0}
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
for
|
|
33
|
+
exts = set(extensions or [".py"])
|
|
34
|
+
scan_files = [f for f in repo_path.rglob("*") if f.suffix in exts and f.is_file()]
|
|
35
|
+
for file_path in scan_files:
|
|
34
36
|
if should_exclude(file_path, repo_path, exclude_patterns):
|
|
35
37
|
stats["files_skipped"] += 1
|
|
36
38
|
continue
|
|
@@ -235,6 +235,107 @@ def render_context(storage: Storage, query: str, max_nodes: int = 15) -> str:
|
|
|
235
235
|
return "\n".join(lines)
|
|
236
236
|
|
|
237
237
|
|
|
238
|
+
def render_treeview(storage: Storage) -> str:
|
|
239
|
+
all_nodes = storage.get_all_nodes()
|
|
240
|
+
all_edges = storage.get_all_edges()
|
|
241
|
+
|
|
242
|
+
file_nodes = sorted([n for n in all_nodes if n.type == "file"], key=lambda n: n.path or "")
|
|
243
|
+
symbol_map: dict[str, list[Node]] = {}
|
|
244
|
+
for n in all_nodes:
|
|
245
|
+
if n.type != "file":
|
|
246
|
+
symbol_map.setdefault(n.parent_id or "", []).append(n)
|
|
247
|
+
|
|
248
|
+
dir_tree: dict[str, dict] = {}
|
|
249
|
+
for node in file_nodes:
|
|
250
|
+
parts = (node.path or node.name).split("/")
|
|
251
|
+
for i in range(len(parts)):
|
|
252
|
+
parent = "/".join(parts[:i]) if i > 0 else "."
|
|
253
|
+
child = parts[i]
|
|
254
|
+
if parent not in dir_tree:
|
|
255
|
+
dir_tree[parent] = {"dirs": set(), "files": []}
|
|
256
|
+
if i == len(parts) - 1:
|
|
257
|
+
dir_tree[parent]["files"].append(node)
|
|
258
|
+
else:
|
|
259
|
+
dir_tree[parent]["dirs"].add(child)
|
|
260
|
+
|
|
261
|
+
stats = storage.stats()
|
|
262
|
+
bt = storage.get_metadata("build_time")
|
|
263
|
+
build_label = ""
|
|
264
|
+
if bt:
|
|
265
|
+
try:
|
|
266
|
+
from datetime import datetime
|
|
267
|
+
build_label = f" (built {datetime.fromtimestamp(float(bt)).strftime('%Y-%m-%d %H:%M')})"
|
|
268
|
+
except Exception:
|
|
269
|
+
pass
|
|
270
|
+
|
|
271
|
+
lines = [
|
|
272
|
+
f".ctxgraph/graph.db ({stats['nodes']} nodes, {stats['edges']} edges){build_label}",
|
|
273
|
+
"",
|
|
274
|
+
]
|
|
275
|
+
|
|
276
|
+
def _render_dir(parent: str, prefix: str = ""):
|
|
277
|
+
entry = dir_tree.get(parent, {"dirs": set(), "files": []})
|
|
278
|
+
items: list[tuple[str, object]] = []
|
|
279
|
+
for d in sorted(entry["dirs"]):
|
|
280
|
+
items.append(("dir", d))
|
|
281
|
+
for f in sorted(entry["files"], key=lambda x: x.path or x.name):
|
|
282
|
+
items.append(("file", f))
|
|
283
|
+
|
|
284
|
+
for idx, (kind, obj) in enumerate(items):
|
|
285
|
+
last = idx == len(items) - 1
|
|
286
|
+
connector = "\\-- " if last else "+-- "
|
|
287
|
+
ext = " " if last else "| "
|
|
288
|
+
|
|
289
|
+
if kind == "dir":
|
|
290
|
+
name = str(obj)
|
|
291
|
+
lines.append(f"{prefix}{connector}{name}/")
|
|
292
|
+
child = name if parent == "." else parent + "/" + name
|
|
293
|
+
_render_dir(child, prefix + ext)
|
|
294
|
+
else:
|
|
295
|
+
node = obj
|
|
296
|
+
basename = (node.path or node.name).split("/")[-1]
|
|
297
|
+
lines.append(f"{prefix}{connector}{basename}")
|
|
298
|
+
symbols = sorted(symbol_map.get(node.id, []), key=lambda s: s.lineno)
|
|
299
|
+
if symbols:
|
|
300
|
+
sym_lines = []
|
|
301
|
+
for s in symbols:
|
|
302
|
+
tag = "C" if s.type == "class" else "M"
|
|
303
|
+
summary = f" -- {s.summary}" if s.summary else ""
|
|
304
|
+
sym_lines.append(f" [{tag}] {s.name}{summary}")
|
|
305
|
+
for sidx, sl in enumerate(sym_lines):
|
|
306
|
+
slast = sidx == len(sym_lines) - 1
|
|
307
|
+
sconn = "\\-- " if slast else "+-- "
|
|
308
|
+
lines.append(f"{prefix}{ext}{sconn}{sl}")
|
|
309
|
+
|
|
310
|
+
_render_dir(".")
|
|
311
|
+
lines.append("")
|
|
312
|
+
|
|
313
|
+
import_edges = [(s, t) for e in all_edges for s, t, r in [(e.source_id, e.target_id, e.relation)] if r == "imports"]
|
|
314
|
+
call_edges = [(s, t) for e in all_edges for s, t, r in [(e.source_id, e.target_id, e.relation)] if r == "calls"]
|
|
315
|
+
|
|
316
|
+
if import_edges:
|
|
317
|
+
lines.append(f"Imports ({len(import_edges)}):")
|
|
318
|
+
node_map = {n.id: n for n in all_nodes}
|
|
319
|
+
for src, tgt in sorted(import_edges, key=lambda x: (x[0], x[1]))[:20]:
|
|
320
|
+
sn = _short_name(src, node_map) or src
|
|
321
|
+
tn = _short_name(tgt, node_map) or tgt
|
|
322
|
+
lines.append(f" {sn} -> {tn}")
|
|
323
|
+
if len(import_edges) > 20:
|
|
324
|
+
lines.append(f" ... and {len(import_edges) - 20} more")
|
|
325
|
+
|
|
326
|
+
if call_edges:
|
|
327
|
+
lines.append(f"\nCalls ({len(call_edges)}):")
|
|
328
|
+
node_map = {n.id: n for n in all_nodes}
|
|
329
|
+
for src, tgt in sorted(call_edges, key=lambda x: (x[0], x[1]))[:15]:
|
|
330
|
+
sn = _short_name(src, node_map) or src
|
|
331
|
+
tn = _short_name(tgt, node_map) or tgt
|
|
332
|
+
lines.append(f" {sn} -> {tn}")
|
|
333
|
+
if len(call_edges) > 15:
|
|
334
|
+
lines.append(f" ... and {len(call_edges) - 15} more")
|
|
335
|
+
|
|
336
|
+
return "\n".join(lines)
|
|
337
|
+
|
|
338
|
+
|
|
238
339
|
def _short_name(node_id: str, node_map: dict[str, Node]) -> Optional[str]:
|
|
239
340
|
if node_id in node_map:
|
|
240
341
|
n = node_map[node_id]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ctxgraph-code
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Code knowledge graph for Claude Code. Build a relationship graph of your Python codebase and query it during coding sessions.
|
|
5
5
|
Author: ctxgraph-code contributors
|
|
6
6
|
License: MIT
|
|
@@ -70,11 +70,21 @@ ctxgraph-code setup
|
|
|
70
70
|
ctxgraph-code setup
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
Interactive walkthrough — prompts for:
|
|
74
|
+
- **File extensions** to scan (`.py`, `.js`, `.ts`, etc.)
|
|
75
|
+
- **Exclude patterns** (folders like `tests/`, globs like `*.generated.py`)
|
|
76
|
+
|
|
73
77
|
Does everything in one step:
|
|
74
|
-
1. Creates `.ctxgraph/config.toml` with
|
|
75
|
-
2. Builds the knowledge graph from all
|
|
78
|
+
1. Creates `.ctxgraph/config.toml` with your chosen extensions and excludes
|
|
79
|
+
2. Builds the knowledge graph from all matching files
|
|
76
80
|
3. Creates `.claude/commands/ctxgraph-code.md` with instructions for Claude Code
|
|
77
81
|
|
|
82
|
+
Non-interactive mode (skip prompts):
|
|
83
|
+
```bash
|
|
84
|
+
ctxgraph-code setup --extensions .py,.js,.ts --exclude tests/,examples/
|
|
85
|
+
ctxgraph-code setup -y # all defaults
|
|
86
|
+
```
|
|
87
|
+
|
|
78
88
|
### `init`
|
|
79
89
|
|
|
80
90
|
```bash
|
|
@@ -87,10 +97,12 @@ Creates the `.ctxgraph/` directory with a default `config.toml`.
|
|
|
87
97
|
|
|
88
98
|
```bash
|
|
89
99
|
ctxgraph-code build
|
|
90
|
-
ctxgraph-code build --
|
|
100
|
+
ctxgraph-code build --extensions .py,.js,.ts
|
|
101
|
+
ctxgraph-code build --exclude tests/ --exclude *.generated.py
|
|
91
102
|
```
|
|
92
103
|
|
|
93
|
-
Scans all
|
|
104
|
+
Scans all matching files in the project, runs AST analysis. Extensions are read from config (`.py` by default, or whatever was set in `setup`).
|
|
105
|
+
|
|
94
106
|
- **Imports**: which files import other files
|
|
95
107
|
- **Class definitions**: class names, base classes, methods
|
|
96
108
|
- **Function definitions**: function names, arguments
|
|
@@ -99,6 +111,8 @@ Scans all `*.py` files in the project, runs AST analysis:
|
|
|
99
111
|
|
|
100
112
|
Stores the result in `.ctxgraph/graph.db`.
|
|
101
113
|
|
|
114
|
+
> The graph is a **static snapshot**. If code changes, run `ctxgraph-code build` again to refresh. Claude Code will also rebuild when it detects the graph is stale.
|
|
115
|
+
|
|
102
116
|
### `query`
|
|
103
117
|
|
|
104
118
|
```bash
|
|
@@ -148,6 +162,17 @@ ctxgraph-code context "add pagination to the users endpoint"
|
|
|
148
162
|
|
|
149
163
|
Generates a focused context summary: relevant files, their symbols, and dependency/call edges between them. This is the closest equivalent to `ctxgraph`'s capsule format.
|
|
150
164
|
|
|
165
|
+
### `view`
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
ctxgraph-code view
|
|
169
|
+
ctxgraph-code view --output tree.txt
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Prints a hierarchical directory tree from the graph showing every file and its symbols (classes marked `[C]`, functions/methods marked `[M]`). Also lists import and call edges at the bottom.
|
|
173
|
+
|
|
174
|
+
Useful for a quick visual scan of the project structure without reading every file.
|
|
175
|
+
|
|
151
176
|
### `info`
|
|
152
177
|
|
|
153
178
|
```bash
|
|
@@ -234,11 +259,13 @@ Claude then uses these commands as needed during the conversation.
|
|
|
234
259
|
|
|
235
260
|
## Configuration
|
|
236
261
|
|
|
237
|
-
Configure via `.ctxgraph/config.toml` (created by `
|
|
262
|
+
Configure via `.ctxgraph/config.toml` (created interactively by `setup` or manually):
|
|
238
263
|
|
|
239
264
|
```toml
|
|
240
265
|
[graph]
|
|
241
|
-
#
|
|
266
|
+
# File extensions to scan
|
|
267
|
+
extensions = [".py", ".js", ".ts"]
|
|
268
|
+
# Exclude patterns beyond built-in defaults
|
|
242
269
|
exclude = ["tests/", "examples/"]
|
|
243
270
|
# Follow symlinks when scanning
|
|
244
271
|
follow_symlinks = false
|
|
@@ -246,7 +273,7 @@ follow_symlinks = false
|
|
|
246
273
|
max_file_size_mb = 5
|
|
247
274
|
```
|
|
248
275
|
|
|
249
|
-
|
|
276
|
+
Built-in default exclusion patterns (always applied): `__pycache__`, `*.pyc`, `.git`, `node_modules`, `venv`, `.venv`, `dist`, `build`, `*.egg-info`, `.pytest_cache`, `.mypy_cache`, `.ruff_cache`, `.tox`, `migrations`, `*.min.js`, `*.min.css`.
|
|
250
277
|
|
|
251
278
|
---
|
|
252
279
|
|
|
@@ -256,10 +283,10 @@ Default exclusion patterns: `__pycache__`, `*.pyc`, `.git`, `node_modules`, `ven
|
|
|
256
283
|
|
|
257
284
|
| Feature | ctxgraph | ctxgraph-code |
|
|
258
285
|
|---------|----------|---------------|
|
|
259
|
-
| CLI commands | 9 (build, capsule, query, view, serve, info, init, ask, chat, history, skill) |
|
|
286
|
+
| CLI commands | 9 (build, capsule, query, view, serve, info, init, ask, chat, history, skill) | 9 (init, build, query, deps, usedby, overview, symbols, context, setup, view, info) |
|
|
260
287
|
| LLM integration | Built-in (Ollama, Claude, OpenAI, Azure) | None (delegates to Claude Code) |
|
|
261
288
|
| Chat sessions | Yes | No |
|
|
262
|
-
| Visualizer | D3.js HTML + SVG |
|
|
289
|
+
| Visualizer | D3.js HTML + SVG | Text tree (`view` command) |
|
|
263
290
|
| Skills system | Yes (customizable skill TOML files) | No |
|
|
264
291
|
| MCP server | Yes | No |
|
|
265
292
|
| Token savings | Yes (capsule DSL compression) | No |
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
|
|
5
|
-
from ctxgraph_code.config.settings import create_default_config
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def init_project(repo_path: Path) -> Path:
|
|
9
|
-
cfg_dir = repo_path / ".ctxgraph"
|
|
10
|
-
cfg_dir.mkdir(parents=True, exist_ok=True)
|
|
11
|
-
|
|
12
|
-
create_default_config(repo_path)
|
|
13
|
-
|
|
14
|
-
return cfg_dir
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|