codd-dev 0.2.0a5__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/.gitignore +1 -1
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/PKG-INFO +38 -5
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/README.md +27 -4
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/codd/cli.py +27 -39
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/codd/config.py +24 -1
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/codd/extractor.py +221 -252
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/codd/hooks.py +12 -6
- codd_dev-0.3.0/codd/parsing.py +2136 -0
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/codd/planner.py +6 -2
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/codd/scanner.py +55 -43
- codd_dev-0.3.0/codd/synth.py +782 -0
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/codd/templates/codd.yaml.tmpl +13 -13
- codd_dev-0.3.0/codd/templates/extracted/api-contract.md.j2 +76 -0
- codd_dev-0.3.0/codd/templates/extracted/architecture-overview.md.j2 +125 -0
- codd_dev-0.3.0/codd/templates/extracted/module-detail.md.j2 +102 -0
- codd_dev-0.3.0/codd/templates/extracted/schema-design.md.j2 +72 -0
- codd_dev-0.3.0/codd/templates/extracted/system-context.md.j2 +114 -0
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/codd/templates/gitignore.tmpl +2 -4
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/codd/verifier.py +307 -54
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/pyproject.toml +15 -1
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/LICENSE +0 -0
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/codd/__init__.py +0 -0
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/codd/defaults.yaml +0 -0
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/codd/generator.py +0 -0
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/codd/graph.py +0 -0
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/codd/implementer.py +0 -0
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/codd/propagate.py +0 -0
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/codd/templates/conventions.yaml.tmpl +0 -0
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/codd/templates/data_dependencies.yaml.tmpl +0 -0
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/codd/templates/doc_links.yaml.tmpl +0 -0
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/codd/templates/overrides.yaml.tmpl +0 -0
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/codd/validator.py +0 -0
- {codd_dev-0.2.0a5 → codd_dev-0.3.0}/hooks/pre-commit +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codd-dev
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: CoDD: Coherence-Driven Development — cross-artifact change impact analysis
|
|
5
5
|
Project-URL: Homepage, https://github.com/yohey-w/codd-dev
|
|
6
6
|
Project-URL: Repository, https://github.com/yohey-w/codd-dev
|
|
@@ -16,13 +16,23 @@ Classifier: Programming Language :: Python :: 3
|
|
|
16
16
|
Classifier: Topic :: Software Development :: Quality Assurance
|
|
17
17
|
Requires-Python: >=3.10
|
|
18
18
|
Requires-Dist: click>=8.0
|
|
19
|
+
Requires-Dist: jinja2>=3.1.0
|
|
19
20
|
Requires-Dist: pyyaml>=6.0
|
|
21
|
+
Requires-Dist: tomli>=2.0.1; python_version < '3.11'
|
|
22
|
+
Provides-Extra: api-parsers
|
|
23
|
+
Requires-Dist: graphql-core>=3.2.0; extra == 'api-parsers'
|
|
24
|
+
Provides-Extra: infra
|
|
25
|
+
Requires-Dist: python-hcl2>=7.0.0; extra == 'infra'
|
|
20
26
|
Provides-Extra: mcp
|
|
21
27
|
Provides-Extra: scan
|
|
22
28
|
Requires-Dist: tree-sitter-java>=0.22; extra == 'scan'
|
|
23
29
|
Requires-Dist: tree-sitter-python>=0.22; extra == 'scan'
|
|
24
30
|
Requires-Dist: tree-sitter-typescript>=0.22; extra == 'scan'
|
|
25
31
|
Requires-Dist: tree-sitter>=0.22; extra == 'scan'
|
|
32
|
+
Provides-Extra: tree-sitter
|
|
33
|
+
Requires-Dist: tree-sitter-python<0.26.0,>=0.25.0; extra == 'tree-sitter'
|
|
34
|
+
Requires-Dist: tree-sitter-typescript<0.24.0,>=0.23.0; extra == 'tree-sitter'
|
|
35
|
+
Requires-Dist: tree-sitter<0.26.0,>=0.25.0; extra == 'tree-sitter'
|
|
26
36
|
Description-Content-Type: text/markdown
|
|
27
37
|
|
|
28
38
|
<p align="center">
|
|
@@ -49,7 +59,7 @@ Description-Content-Type: text/markdown
|
|
|
49
59
|
pip install codd-dev
|
|
50
60
|
```
|
|
51
61
|
|
|
52
|
-
**Public Alpha** — `init` / `scan` / `impact`
|
|
62
|
+
**Public Alpha** — `init` / `scan` / `impact` are stable; `validate` is alpha.
|
|
53
63
|
|
|
54
64
|
---
|
|
55
65
|
|
|
@@ -256,7 +266,17 @@ codd:
|
|
|
256
266
|
---
|
|
257
267
|
```
|
|
258
268
|
|
|
259
|
-
`
|
|
269
|
+
`codd/scan/` is a cache — regenerated on every `codd scan`.
|
|
270
|
+
|
|
271
|
+
## Config Directory Discovery
|
|
272
|
+
|
|
273
|
+
By default, `codd init` creates a `codd/` directory. If your project already has a `codd/` directory (e.g., it's your source code package), use `--config-dir`:
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
codd init --config-dir .codd --project-name "my-project" --language "python"
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
All other commands (`scan`, `impact`, `generate`, etc.) automatically discover whichever config directory exists — `codd/` first, then `.codd/`. No extra flags needed.
|
|
260
280
|
|
|
261
281
|
## Brownfield? Start Here
|
|
262
282
|
|
|
@@ -291,7 +311,7 @@ codd impact
|
|
|
291
311
|
|
|
292
312
|
| Command | Status | Description |
|
|
293
313
|
|---------|--------|-------------|
|
|
294
|
-
| `codd init` | **Stable** | Initialize CoDD in any project |
|
|
314
|
+
| `codd init` | **Stable** | Initialize CoDD in any project (`--config-dir .codd` for projects where `codd/` exists) |
|
|
295
315
|
| `codd scan` | **Stable** | Build dependency graph from frontmatter |
|
|
296
316
|
| `codd impact` | **Stable** | Change impact analysis (Green / Amber / Gray) |
|
|
297
317
|
| `codd validate` | **Alpha** | Frontmatter integrity & graph consistency check |
|
|
@@ -395,11 +415,24 @@ docs/
|
|
|
395
415
|
└── infra/ # Infrastructure design
|
|
396
416
|
```
|
|
397
417
|
|
|
418
|
+
### CoDD Manages Its Own Development
|
|
419
|
+
|
|
420
|
+
CoDD dogfoods itself. The `.codd/` directory contains CoDD's own config, and `codd extract` reverse-engineers design docs from its own source code. The full V-Model lifecycle runs on itself:
|
|
421
|
+
|
|
422
|
+
```bash
|
|
423
|
+
codd init --config-dir .codd --project-name "codd-dev" --language "python"
|
|
424
|
+
codd extract # 15 modules → design docs with dependency frontmatter
|
|
425
|
+
codd scan # 49 nodes, 83 edges
|
|
426
|
+
codd verify # mypy + pytest (127/127 tests pass)
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
If CoDD can't manage itself, it shouldn't manage your project.
|
|
430
|
+
|
|
398
431
|
## Roadmap
|
|
399
432
|
|
|
400
433
|
- [ ] Semantic dependency types (`requires`, `affects`, `verifies`, `implements`)
|
|
401
434
|
- [x] `codd extract` — reverse-generate design docs from existing codebases (brownfield support)
|
|
402
|
-
- [
|
|
435
|
+
- [x] `codd verify` — language-agnostic verification (Python: mypy + pytest, TypeScript: tsc + jest)
|
|
403
436
|
- [ ] Multi-harness integration examples (Claude Code, Copilot, Cursor)
|
|
404
437
|
- [ ] VS Code extension for impact visualization
|
|
405
438
|
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
pip install codd-dev
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
**Public Alpha** — `init` / `scan` / `impact`
|
|
25
|
+
**Public Alpha** — `init` / `scan` / `impact` are stable; `validate` is alpha.
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
@@ -229,7 +229,17 @@ codd:
|
|
|
229
229
|
---
|
|
230
230
|
```
|
|
231
231
|
|
|
232
|
-
`
|
|
232
|
+
`codd/scan/` is a cache — regenerated on every `codd scan`.
|
|
233
|
+
|
|
234
|
+
## Config Directory Discovery
|
|
235
|
+
|
|
236
|
+
By default, `codd init` creates a `codd/` directory. If your project already has a `codd/` directory (e.g., it's your source code package), use `--config-dir`:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
codd init --config-dir .codd --project-name "my-project" --language "python"
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
All other commands (`scan`, `impact`, `generate`, etc.) automatically discover whichever config directory exists — `codd/` first, then `.codd/`. No extra flags needed.
|
|
233
243
|
|
|
234
244
|
## Brownfield? Start Here
|
|
235
245
|
|
|
@@ -264,7 +274,7 @@ codd impact
|
|
|
264
274
|
|
|
265
275
|
| Command | Status | Description |
|
|
266
276
|
|---------|--------|-------------|
|
|
267
|
-
| `codd init` | **Stable** | Initialize CoDD in any project |
|
|
277
|
+
| `codd init` | **Stable** | Initialize CoDD in any project (`--config-dir .codd` for projects where `codd/` exists) |
|
|
268
278
|
| `codd scan` | **Stable** | Build dependency graph from frontmatter |
|
|
269
279
|
| `codd impact` | **Stable** | Change impact analysis (Green / Amber / Gray) |
|
|
270
280
|
| `codd validate` | **Alpha** | Frontmatter integrity & graph consistency check |
|
|
@@ -368,11 +378,24 @@ docs/
|
|
|
368
378
|
└── infra/ # Infrastructure design
|
|
369
379
|
```
|
|
370
380
|
|
|
381
|
+
### CoDD Manages Its Own Development
|
|
382
|
+
|
|
383
|
+
CoDD dogfoods itself. The `.codd/` directory contains CoDD's own config, and `codd extract` reverse-engineers design docs from its own source code. The full V-Model lifecycle runs on itself:
|
|
384
|
+
|
|
385
|
+
```bash
|
|
386
|
+
codd init --config-dir .codd --project-name "codd-dev" --language "python"
|
|
387
|
+
codd extract # 15 modules → design docs with dependency frontmatter
|
|
388
|
+
codd scan # 49 nodes, 83 edges
|
|
389
|
+
codd verify # mypy + pytest (127/127 tests pass)
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
If CoDD can't manage itself, it shouldn't manage your project.
|
|
393
|
+
|
|
371
394
|
## Roadmap
|
|
372
395
|
|
|
373
396
|
- [ ] Semantic dependency types (`requires`, `affects`, `verifies`, `implements`)
|
|
374
397
|
- [x] `codd extract` — reverse-generate design docs from existing codebases (brownfield support)
|
|
375
|
-
- [
|
|
398
|
+
- [x] `codd verify` — language-agnostic verification (Python: mypy + pytest, TypeScript: tsc + jest)
|
|
376
399
|
- [ ] Multi-harness integration examples (Claude Code, Copilot, Cursor)
|
|
377
400
|
- [ ] VS Code extension for impact visualization
|
|
378
401
|
|
|
@@ -6,9 +6,20 @@ import os
|
|
|
6
6
|
import shutil
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
|
+
from codd.config import find_codd_dir
|
|
10
|
+
|
|
9
11
|
TEMPLATES_DIR = Path(__file__).parent / "templates"
|
|
10
12
|
|
|
11
13
|
|
|
14
|
+
def _require_codd_dir(project_root: Path) -> Path:
|
|
15
|
+
"""Return the CoDD config dir or exit with a helpful message."""
|
|
16
|
+
codd_dir = find_codd_dir(project_root)
|
|
17
|
+
if codd_dir is None:
|
|
18
|
+
click.echo("Error: CoDD config dir not found (looked for codd/ and .codd/). Run 'codd init' first.")
|
|
19
|
+
raise SystemExit(1)
|
|
20
|
+
return codd_dir
|
|
21
|
+
|
|
22
|
+
|
|
12
23
|
@click.group()
|
|
13
24
|
@click.version_option(package_name="codd-dev")
|
|
14
25
|
def main():
|
|
@@ -18,7 +29,7 @@ def main():
|
|
|
18
29
|
|
|
19
30
|
@main.command()
|
|
20
31
|
@click.option("--project-name", prompt="Project name", help="Name of the project")
|
|
21
|
-
@click.option("--language", prompt="Primary language", help="Primary language (python/typescript/
|
|
32
|
+
@click.option("--language", prompt="Primary language", help="Primary language (python/typescript/javascript/go — full support; java — symbols only)")
|
|
22
33
|
@click.option("--dest", default=".", help="Destination directory (default: current dir)")
|
|
23
34
|
@click.option(
|
|
24
35
|
"--requirements",
|
|
@@ -26,10 +37,15 @@ def main():
|
|
|
26
37
|
type=click.Path(exists=True),
|
|
27
38
|
help="Import a requirements file (any format: .md, .txt, .doc). CoDD adds frontmatter automatically.",
|
|
28
39
|
)
|
|
29
|
-
|
|
40
|
+
@click.option(
|
|
41
|
+
"--config-dir",
|
|
42
|
+
default="codd",
|
|
43
|
+
help="Name of the CoDD config directory (default: codd). Use .codd when codd/ is your source directory.",
|
|
44
|
+
)
|
|
45
|
+
def init(project_name: str, language: str, dest: str, requirements: str | None, config_dir: str):
|
|
30
46
|
"""Initialize CoDD in a project directory."""
|
|
31
47
|
dest_path = Path(dest).resolve()
|
|
32
|
-
codd_dir = dest_path /
|
|
48
|
+
codd_dir = dest_path / config_dir
|
|
33
49
|
|
|
34
50
|
if codd_dir.exists():
|
|
35
51
|
if requirements:
|
|
@@ -81,11 +97,7 @@ def scan(path: str):
|
|
|
81
97
|
"""Scan codebase and update dependency graph (Stage 1)."""
|
|
82
98
|
from codd.scanner import run_scan
|
|
83
99
|
project_root = Path(path).resolve()
|
|
84
|
-
codd_dir = project_root
|
|
85
|
-
|
|
86
|
-
if not codd_dir.exists():
|
|
87
|
-
click.echo("Error: codd/ not found. Run 'codd init' first.")
|
|
88
|
-
raise SystemExit(1)
|
|
100
|
+
codd_dir = _require_codd_dir(project_root)
|
|
89
101
|
|
|
90
102
|
run_scan(project_root, codd_dir)
|
|
91
103
|
|
|
@@ -98,11 +110,7 @@ def impact(diff: str, path: str, output: str):
|
|
|
98
110
|
"""Analyze change impact from git diff."""
|
|
99
111
|
from codd.propagate import run_impact
|
|
100
112
|
project_root = Path(path).resolve()
|
|
101
|
-
codd_dir = project_root
|
|
102
|
-
|
|
103
|
-
if not codd_dir.exists():
|
|
104
|
-
click.echo("Error: codd/ not found. Run 'codd init' first.")
|
|
105
|
-
raise SystemExit(1)
|
|
113
|
+
codd_dir = _require_codd_dir(project_root)
|
|
106
114
|
|
|
107
115
|
run_impact(project_root, codd_dir, diff, output)
|
|
108
116
|
|
|
@@ -121,11 +129,7 @@ def generate(wave: int, path: str, force: bool, ai_cmd: str | None):
|
|
|
121
129
|
from codd.generator import generate_wave, _load_project_config
|
|
122
130
|
|
|
123
131
|
project_root = Path(path).resolve()
|
|
124
|
-
codd_dir = project_root
|
|
125
|
-
|
|
126
|
-
if not codd_dir.exists():
|
|
127
|
-
click.echo("Error: codd/ not found. Run 'codd init' first.")
|
|
128
|
-
raise SystemExit(1)
|
|
132
|
+
codd_dir = _require_codd_dir(project_root)
|
|
129
133
|
|
|
130
134
|
# Auto-generate wave_config if missing
|
|
131
135
|
config = _load_project_config(project_root)
|
|
@@ -174,11 +178,7 @@ def implement(sprint: int, path: str, task: str | None, ai_cmd: str | None):
|
|
|
174
178
|
from codd.implementer import implement_sprint
|
|
175
179
|
|
|
176
180
|
project_root = Path(path).resolve()
|
|
177
|
-
codd_dir = project_root
|
|
178
|
-
|
|
179
|
-
if not codd_dir.exists():
|
|
180
|
-
click.echo("Error: codd/ not found. Run 'codd init' first.")
|
|
181
|
-
raise SystemExit(1)
|
|
181
|
+
codd_dir = _require_codd_dir(project_root)
|
|
182
182
|
|
|
183
183
|
try:
|
|
184
184
|
results = implement_sprint(project_root, sprint, task=task, ai_command=ai_cmd)
|
|
@@ -204,11 +204,7 @@ def verify(path: str, sprint: int | None) -> None:
|
|
|
204
204
|
from codd.verifier import VerifyPreflightError, run_verify
|
|
205
205
|
|
|
206
206
|
project_root = Path(path).resolve()
|
|
207
|
-
codd_dir = project_root
|
|
208
|
-
|
|
209
|
-
if not codd_dir.exists():
|
|
210
|
-
click.echo("Error: codd/ not found. Run 'codd init' first.")
|
|
211
|
-
raise SystemExit(1)
|
|
207
|
+
codd_dir = _require_codd_dir(project_root)
|
|
212
208
|
|
|
213
209
|
try:
|
|
214
210
|
result = run_verify(project_root, sprint=sprint)
|
|
@@ -248,7 +244,7 @@ def verify(path: str, sprint: int | None) -> None:
|
|
|
248
244
|
|
|
249
245
|
@main.command()
|
|
250
246
|
@click.option("--path", default=".", help="Project root directory")
|
|
251
|
-
@click.option("--language", default=None, help="Override language detection (python/typescript/javascript/java
|
|
247
|
+
@click.option("--language", default=None, help="Override language detection (python/typescript/javascript/go — full support; java — symbols only)")
|
|
252
248
|
@click.option("--source-dirs", default=None, help="Comma-separated source directories (default: auto-detect)")
|
|
253
249
|
@click.option("--output", default=None, help="Output directory (default: codd/extracted/)")
|
|
254
250
|
def extract(path: str, language: str | None, source_dirs: str | None, output: str | None):
|
|
@@ -289,11 +285,7 @@ def validate(path: str):
|
|
|
289
285
|
from codd.validator import run_validate
|
|
290
286
|
|
|
291
287
|
project_root = Path(path).resolve()
|
|
292
|
-
codd_dir = project_root
|
|
293
|
-
|
|
294
|
-
if not codd_dir.exists():
|
|
295
|
-
click.echo("Error: codd/ not found. Run 'codd init' first.")
|
|
296
|
-
raise SystemExit(1)
|
|
288
|
+
codd_dir = _require_codd_dir(project_root)
|
|
297
289
|
|
|
298
290
|
raise SystemExit(run_validate(project_root, codd_dir))
|
|
299
291
|
|
|
@@ -313,11 +305,7 @@ def plan(path: str, as_json: bool, initialize: bool, force: bool, ai_cmd: str |
|
|
|
313
305
|
from codd.planner import build_plan, plan_init, plan_to_dict, render_plan_text
|
|
314
306
|
|
|
315
307
|
project_root = Path(path).resolve()
|
|
316
|
-
codd_dir = project_root
|
|
317
|
-
|
|
318
|
-
if not codd_dir.exists():
|
|
319
|
-
click.echo("Error: codd/ not found. Run 'codd init' first.")
|
|
320
|
-
raise SystemExit(1)
|
|
308
|
+
codd_dir = _require_codd_dir(project_root)
|
|
321
309
|
|
|
322
310
|
if initialize:
|
|
323
311
|
if as_json:
|
|
@@ -12,10 +12,33 @@ import yaml
|
|
|
12
12
|
|
|
13
13
|
DEFAULTS_PATH = Path(__file__).with_name("defaults.yaml")
|
|
14
14
|
|
|
15
|
+
# Supported CoDD config directory names, in priority order.
|
|
16
|
+
CODD_DIR_CANDIDATES = ("codd", ".codd")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def find_codd_dir(project_root: Path) -> Path | None:
|
|
20
|
+
"""Discover the CoDD config directory under *project_root*.
|
|
21
|
+
|
|
22
|
+
A valid CoDD config directory must contain ``codd.yaml``.
|
|
23
|
+
Checks ``codd/`` first, then ``.codd/``. Returns ``None`` when
|
|
24
|
+
neither qualifies (caller decides whether that is an error).
|
|
25
|
+
"""
|
|
26
|
+
for name in CODD_DIR_CANDIDATES:
|
|
27
|
+
candidate = project_root / name
|
|
28
|
+
if candidate.is_dir() and (candidate / "codd.yaml").exists():
|
|
29
|
+
return candidate
|
|
30
|
+
return None
|
|
31
|
+
|
|
15
32
|
|
|
16
33
|
def load_project_config(project_root: Path) -> dict[str, Any]:
|
|
17
34
|
"""Load CoDD defaults and merge project-local overrides."""
|
|
18
|
-
|
|
35
|
+
codd_dir = find_codd_dir(project_root)
|
|
36
|
+
if codd_dir is None:
|
|
37
|
+
raise FileNotFoundError(
|
|
38
|
+
f"CoDD config dir not found in {project_root} "
|
|
39
|
+
f"(looked for {', '.join(CODD_DIR_CANDIDATES)})"
|
|
40
|
+
)
|
|
41
|
+
config_path = codd_dir / "codd.yaml"
|
|
19
42
|
if not config_path.exists():
|
|
20
43
|
raise FileNotFoundError(f"{config_path} not found")
|
|
21
44
|
|