codedebrief 0.11.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.
- codedebrief/__init__.py +12 -0
- codedebrief/analysis/__init__.py +16 -0
- codedebrief/analysis/common.py +527 -0
- codedebrief/analysis/discovery.py +100 -0
- codedebrief/analysis/languages/__init__.py +6 -0
- codedebrief/analysis/languages/_common.py +68 -0
- codedebrief/analysis/languages/c.py +96 -0
- codedebrief/analysis/languages/cpp.py +146 -0
- codedebrief/analysis/languages/csharp.py +137 -0
- codedebrief/analysis/languages/go.py +157 -0
- codedebrief/analysis/languages/java.py +158 -0
- codedebrief/analysis/languages/php.py +83 -0
- codedebrief/analysis/languages/ruby.py +75 -0
- codedebrief/analysis/languages/rust.py +96 -0
- codedebrief/analysis/project.py +373 -0
- codedebrief/analysis/python.py +939 -0
- codedebrief/analysis/registry.py +320 -0
- codedebrief/analysis/treesitter.py +884 -0
- codedebrief/analysis/typescript.py +1019 -0
- codedebrief/artifacts.py +49 -0
- codedebrief/cli.py +585 -0
- codedebrief/config.py +226 -0
- codedebrief/doctor.py +175 -0
- codedebrief/install.py +441 -0
- codedebrief/mcp_server.py +2720 -0
- codedebrief/model.py +189 -0
- codedebrief/py.typed +1 -0
- codedebrief/quality.py +392 -0
- codedebrief/query.py +641 -0
- codedebrief/render/__init__.py +6 -0
- codedebrief/render/assets/generated/codedebrief-viewer-runtime.iife.js +10 -0
- codedebrief/render/assets/panels.js +462 -0
- codedebrief/render/assets/shell.js +1649 -0
- codedebrief/render/assets/styles.css +1715 -0
- codedebrief/render/assets/tree.js +616 -0
- codedebrief/render/html.py +191 -0
- codedebrief/render/markdown.py +153 -0
- codedebrief/render/payload.py +326 -0
- codedebrief/render/snapshot.py +769 -0
- codedebrief/schema/codedebrief.schema.json +449 -0
- codedebrief/util.py +65 -0
- codedebrief/validation.py +214 -0
- codedebrief-0.11.0.dist-info/METADATA +426 -0
- codedebrief-0.11.0.dist-info/RECORD +48 -0
- codedebrief-0.11.0.dist-info/WHEEL +4 -0
- codedebrief-0.11.0.dist-info/entry_points.txt +2 -0
- codedebrief-0.11.0.dist-info/licenses/LICENSE +176 -0
- codedebrief-0.11.0.dist-info/licenses/NOTICE +9 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from importlib import resources
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any, cast
|
|
8
|
+
|
|
9
|
+
from codedebrief.analysis import ProjectAnalyzer
|
|
10
|
+
from codedebrief.analysis.registry import supported_language_ids
|
|
11
|
+
from codedebrief.artifacts import output_paths
|
|
12
|
+
from codedebrief.config import CodeDebriefConfig
|
|
13
|
+
from codedebrief.model import ProjectModel
|
|
14
|
+
from codedebrief.quality import model_quality
|
|
15
|
+
from codedebrief.util import read_json
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass(slots=True)
|
|
19
|
+
class ValidationReport:
|
|
20
|
+
ok: bool = True
|
|
21
|
+
errors: list[str] = field(default_factory=list)
|
|
22
|
+
warnings: list[str] = field(default_factory=list)
|
|
23
|
+
artifact: str = ""
|
|
24
|
+
quality: dict[str, Any] | None = None
|
|
25
|
+
|
|
26
|
+
def add_error(self, message: str) -> None:
|
|
27
|
+
self.ok = False
|
|
28
|
+
self.errors.append(message)
|
|
29
|
+
|
|
30
|
+
def to_dict(self) -> dict[str, Any]:
|
|
31
|
+
payload = {
|
|
32
|
+
"ok": self.ok,
|
|
33
|
+
"artifact": self.artifact,
|
|
34
|
+
"errors": self.errors,
|
|
35
|
+
"warnings": self.warnings,
|
|
36
|
+
}
|
|
37
|
+
if self.quality is not None:
|
|
38
|
+
payload["quality"] = self.quality
|
|
39
|
+
return payload
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def validate_codedebrief(
|
|
43
|
+
root: Path,
|
|
44
|
+
*,
|
|
45
|
+
config: CodeDebriefConfig | None = None,
|
|
46
|
+
check_sync: bool = False,
|
|
47
|
+
include_quality: bool = False,
|
|
48
|
+
quality_thresholds: dict[str, float | int] | None = None,
|
|
49
|
+
) -> ValidationReport:
|
|
50
|
+
"""Validate the persisted CodeDebrief artifact and optional source sync.
|
|
51
|
+
|
|
52
|
+
The baseline validation is read-only: it loads the JSON model, checks it against the
|
|
53
|
+
bundled JSON Schema when `jsonschema` is installed, and verifies that every language in
|
|
54
|
+
the artifact is registered by the current analyzer. `check_sync` intentionally runs the
|
|
55
|
+
analyzer to compare the current source tree against the committed model.
|
|
56
|
+
"""
|
|
57
|
+
active_config = config or CodeDebriefConfig.load(root)
|
|
58
|
+
json_path, _, _ = output_paths(root, active_config)
|
|
59
|
+
report = ValidationReport(artifact=str(json_path))
|
|
60
|
+
|
|
61
|
+
try:
|
|
62
|
+
artifact = read_json(json_path)
|
|
63
|
+
except OSError as error:
|
|
64
|
+
report.add_error(f"Could not read {json_path}: {error}")
|
|
65
|
+
return report
|
|
66
|
+
except ValueError as error:
|
|
67
|
+
report.add_error(f"Malformed JSON in {json_path}: {error}")
|
|
68
|
+
return report
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
model = ProjectModel.from_dict(artifact)
|
|
72
|
+
except ValueError as error:
|
|
73
|
+
report.add_error(str(error))
|
|
74
|
+
return report
|
|
75
|
+
|
|
76
|
+
_validate_languages(model, report)
|
|
77
|
+
_validate_json_schema(artifact, report)
|
|
78
|
+
active_thresholds = quality_thresholds or {}
|
|
79
|
+
if include_quality or active_thresholds:
|
|
80
|
+
report.quality = model.metadata.get("quality") or model_quality(model)
|
|
81
|
+
if active_thresholds and report.quality is not None:
|
|
82
|
+
_validate_quality_thresholds(report, report.quality, active_thresholds)
|
|
83
|
+
|
|
84
|
+
if check_sync:
|
|
85
|
+
try:
|
|
86
|
+
fresh = ProjectAnalyzer(root, active_config).analyze(full=True).model
|
|
87
|
+
except (OSError, ValueError, SyntaxError) as error:
|
|
88
|
+
report.add_error(f"Could not re-analyze sources for sync check: {error}")
|
|
89
|
+
else:
|
|
90
|
+
if _without_generated_at(fresh.to_dict()) != _without_generated_at(model.to_dict()):
|
|
91
|
+
report.add_error(
|
|
92
|
+
"codedebrief.json is stale; run `codedebrief update` and commit the artifacts."
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
return report
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def schema_language_ids(schema: dict[str, Any]) -> tuple[str, ...]:
|
|
99
|
+
return _schema_language_ids(schema, "flow")
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def schema_file_language_ids(schema: dict[str, Any]) -> tuple[str, ...]:
|
|
103
|
+
return _schema_language_ids(schema, "file")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _schema_language_ids(schema: dict[str, Any], definition: str) -> tuple[str, ...]:
|
|
107
|
+
flow_language = (
|
|
108
|
+
schema.get("$defs", {})
|
|
109
|
+
.get(definition, {})
|
|
110
|
+
.get("properties", {})
|
|
111
|
+
.get("language", {})
|
|
112
|
+
.get("enum", [])
|
|
113
|
+
)
|
|
114
|
+
return tuple(str(item) for item in flow_language)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _validate_languages(model: ProjectModel, report: ValidationReport) -> None:
|
|
118
|
+
supported = set(supported_language_ids())
|
|
119
|
+
found = {flow.language for flow in model.flows} | {record.language for record in model.files}
|
|
120
|
+
unknown = sorted(found - supported)
|
|
121
|
+
if unknown:
|
|
122
|
+
report.add_error("Artifact uses unregistered language ids: " + ", ".join(unknown))
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _validate_json_schema(artifact: dict[str, Any], report: ValidationReport) -> None:
|
|
126
|
+
try:
|
|
127
|
+
schema = _read_bundled_schema()
|
|
128
|
+
except (OSError, ValueError) as error:
|
|
129
|
+
report.add_error(f"Could not read bundled schema: {error}")
|
|
130
|
+
return
|
|
131
|
+
|
|
132
|
+
schema_languages = set(schema_language_ids(schema))
|
|
133
|
+
schema_file_languages = set(schema_file_language_ids(schema))
|
|
134
|
+
supported = set(supported_language_ids())
|
|
135
|
+
if schema_languages != supported or schema_file_languages != supported:
|
|
136
|
+
report.add_error(
|
|
137
|
+
"Schema language enums are out of sync with registry: "
|
|
138
|
+
f"flow={sorted(schema_languages)} file={sorted(schema_file_languages)} "
|
|
139
|
+
f"registry={sorted(supported)}"
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
from jsonschema import Draft202012Validator # type: ignore[import-untyped]
|
|
144
|
+
except ImportError:
|
|
145
|
+
report.warnings.append("jsonschema is not installed; skipped JSON Schema validation.")
|
|
146
|
+
return
|
|
147
|
+
|
|
148
|
+
validator = Draft202012Validator(schema)
|
|
149
|
+
errors = sorted(validator.iter_errors(artifact), key=lambda item: list(item.path))
|
|
150
|
+
for validation_error in errors:
|
|
151
|
+
location = "/".join(str(part) for part in validation_error.path) or "<root>"
|
|
152
|
+
report.add_error(f"{location}: {validation_error.message}")
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _validate_quality_thresholds(
|
|
156
|
+
report: ValidationReport, quality: dict[str, Any], thresholds: dict[str, float | int]
|
|
157
|
+
) -> None:
|
|
158
|
+
files = quality.get("files", {})
|
|
159
|
+
calls = quality.get("calls", {})
|
|
160
|
+
labels = quality.get("labels", {})
|
|
161
|
+
skipped = files.get("skipped", {}) if isinstance(files, dict) else {}
|
|
162
|
+
parse_errors = files.get("parse_errors", {}) if isinstance(files, dict) else {}
|
|
163
|
+
if "max_skipped_files" in thresholds:
|
|
164
|
+
actual_skipped = int(_number(skipped.get("total"), 0))
|
|
165
|
+
skipped_limit = int(thresholds["max_skipped_files"])
|
|
166
|
+
if actual_skipped > skipped_limit:
|
|
167
|
+
report.add_error(
|
|
168
|
+
f"quality threshold failed: skipped files {actual_skipped} > max {skipped_limit}"
|
|
169
|
+
)
|
|
170
|
+
if "max_parse_warnings" in thresholds:
|
|
171
|
+
actual_parse_warnings = int(_number(parse_errors.get("total"), 0))
|
|
172
|
+
parse_warning_limit = int(thresholds["max_parse_warnings"])
|
|
173
|
+
if actual_parse_warnings > parse_warning_limit:
|
|
174
|
+
report.add_error(
|
|
175
|
+
"quality threshold failed: parse warnings "
|
|
176
|
+
f"{actual_parse_warnings} > max {parse_warning_limit}"
|
|
177
|
+
)
|
|
178
|
+
if "min_call_resolution" in thresholds:
|
|
179
|
+
actual_resolution = _number(calls.get("resolution_rate"), 0.0)
|
|
180
|
+
resolution_limit = float(thresholds["min_call_resolution"])
|
|
181
|
+
if actual_resolution < resolution_limit:
|
|
182
|
+
report.add_error(
|
|
183
|
+
"quality threshold failed: call resolution "
|
|
184
|
+
f"{actual_resolution:.0%} < min {resolution_limit:.0%}"
|
|
185
|
+
)
|
|
186
|
+
if "max_generic_label_ratio" in thresholds:
|
|
187
|
+
actual_generic = _number(labels.get("generic_ratio"), 0.0)
|
|
188
|
+
generic_limit = float(thresholds["max_generic_label_ratio"])
|
|
189
|
+
if actual_generic > generic_limit:
|
|
190
|
+
report.add_error(
|
|
191
|
+
"quality threshold failed: generic label ratio "
|
|
192
|
+
f"{actual_generic:.0%} > max {generic_limit:.0%}"
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _number(value: Any, default: float) -> float:
|
|
197
|
+
return float(value) if isinstance(value, (int, float)) else default
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def _without_generated_at(payload: dict[str, Any]) -> dict[str, Any]:
|
|
201
|
+
clone = dict(payload)
|
|
202
|
+
clone.pop("generated_at", None)
|
|
203
|
+
return clone
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _read_bundled_schema() -> dict[str, Any]:
|
|
207
|
+
checkout_schema = Path(__file__).parents[2] / "schema" / "codedebrief.schema.json"
|
|
208
|
+
if checkout_schema.exists():
|
|
209
|
+
return read_json(checkout_schema)
|
|
210
|
+
|
|
211
|
+
schema_resource = (
|
|
212
|
+
resources.files("codedebrief").joinpath("schema").joinpath("codedebrief.schema.json")
|
|
213
|
+
)
|
|
214
|
+
return cast(dict[str, Any], json.loads(schema_resource.read_text(encoding="utf-8")))
|
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: codedebrief
|
|
3
|
+
Version: 0.11.0
|
|
4
|
+
Summary: Visual code workflow explorer for coding agents. Builds deterministic, source-grounded Mermaid flowcharts via MCP, local-first, with no API key.
|
|
5
|
+
Project-URL: Homepage, https://github.com/ferdinandobons/CodeDebrief
|
|
6
|
+
Project-URL: Documentation, https://github.com/ferdinandobons/CodeDebrief#readme
|
|
7
|
+
Project-URL: Issues, https://github.com/ferdinandobons/CodeDebrief/issues
|
|
8
|
+
Project-URL: Source, https://github.com/ferdinandobons/CodeDebrief
|
|
9
|
+
Author: Ferdinando Bonsegna
|
|
10
|
+
License-Expression: Apache-2.0
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
License-File: NOTICE
|
|
13
|
+
Keywords: ai-agents,code-comprehension,code-navigation,coding-agents,cpp,developer-tools,flowchart,javascript,local-first,mcp,mcp-server,mermaid,model-context-protocol,python,source-code-analysis,static-analysis,tree-sitter,typescript,visualization,workflow
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Environment :: Console
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
25
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Requires-Dist: jsonschema>=4.23
|
|
28
|
+
Requires-Dist: mcp<2,>=1.27
|
|
29
|
+
Requires-Dist: tomli>=2.0; python_version < '3.11'
|
|
30
|
+
Requires-Dist: tree-sitter-c-sharp<0.24,>=0.23
|
|
31
|
+
Requires-Dist: tree-sitter-c<0.24,>=0.23
|
|
32
|
+
Requires-Dist: tree-sitter-cpp<0.24,>=0.23
|
|
33
|
+
Requires-Dist: tree-sitter-go<0.24,>=0.23
|
|
34
|
+
Requires-Dist: tree-sitter-java<0.24,>=0.23
|
|
35
|
+
Requires-Dist: tree-sitter-php<0.24,>=0.23
|
|
36
|
+
Requires-Dist: tree-sitter-ruby<0.24,>=0.23
|
|
37
|
+
Requires-Dist: tree-sitter-rust<0.24,>=0.23
|
|
38
|
+
Requires-Dist: tree-sitter-typescript<0.24,>=0.23.2
|
|
39
|
+
Requires-Dist: tree-sitter<0.26,>=0.25.2
|
|
40
|
+
Provides-Extra: dev
|
|
41
|
+
Requires-Dist: mypy>=1.15; extra == 'dev'
|
|
42
|
+
Requires-Dist: pytest-cov>=6; extra == 'dev'
|
|
43
|
+
Requires-Dist: pytest>=8.3; extra == 'dev'
|
|
44
|
+
Requires-Dist: ruff>=0.11; extra == 'dev'
|
|
45
|
+
Requires-Dist: tomli>=2.0; extra == 'dev'
|
|
46
|
+
Provides-Extra: mcp
|
|
47
|
+
Description-Content-Type: text/markdown
|
|
48
|
+
|
|
49
|
+
# CodeDebrief
|
|
50
|
+
|
|
51
|
+
CodeDebrief turns source code into deterministic, source-grounded workflow flowcharts for
|
|
52
|
+
humans and coding agents.
|
|
53
|
+
|
|
54
|
+
It is a local-first code comprehension tool that builds a source-grounded workflow model
|
|
55
|
+
of a codebase and exposes that model in two ways:
|
|
56
|
+
|
|
57
|
+
- `codedebrief view` for manual exploration of the complete graph.
|
|
58
|
+
- MCP `agent_context` for coding agents that need a bounded, source-grounded
|
|
59
|
+
`workflow_slice`.
|
|
60
|
+
|
|
61
|
+
The product unit is the `workflow_slice`: a deterministic slice of the modeled code
|
|
62
|
+
logic selected from a question, changed file, symbol, state, flow id, or dependency path.
|
|
63
|
+
Agents can render that slice visually, explain it, expand it, or trace a path without
|
|
64
|
+
inventing steps that are not in the graph.
|
|
65
|
+
|
|
66
|
+
CodeDebrief is not a bug finder, a generic graph database, or an LLM enrichment service.
|
|
67
|
+
The core workflow is deterministic, local, and offline. No LLM provider key is required.
|
|
68
|
+
|
|
69
|
+

|
|
70
|
+
|
|
71
|
+
Example output: a compact presentation layer generated from local CodeDebrief artifacts.
|
|
72
|
+
Canonical workflow visuals are vertical by default; horizontal diagrams are used when the
|
|
73
|
+
user explicitly asks for a compact overview.
|
|
74
|
+
|
|
75
|
+
> Status: pre-1.0 alpha. The model is versioned, but schema and MCP payloads may evolve
|
|
76
|
+
> before 1.0.
|
|
77
|
+
>
|
|
78
|
+
> Latest release: [v0.11.0](https://github.com/ferdinandobons/CodeDebrief/releases/tag/v0.11.0)
|
|
79
|
+
> · [Changelog](CHANGELOG.md)
|
|
80
|
+
|
|
81
|
+
## Why It Exists
|
|
82
|
+
|
|
83
|
+
Coding agents are useful only when they understand the logic they are about to explain or
|
|
84
|
+
change. Reading files one by one is slow and inconsistent; asking an LLM to reconstruct a
|
|
85
|
+
workflow from source often produces different diagrams for the same prompt.
|
|
86
|
+
|
|
87
|
+
CodeDebrief gives agents a deterministic navigation layer:
|
|
88
|
+
|
|
89
|
+
- entrypoints, decisions, branches, calls, outcomes, and source ranges;
|
|
90
|
+
- domain concepts such as statuses, roles, permissions, enums, and feature flags;
|
|
91
|
+
- affected-workflow context for changed files, symbols, flows, and dependency paths;
|
|
92
|
+
- canonical visual slices with stable diagram hashes;
|
|
93
|
+
- optional language-friendly labels derived as a presentation layer from analyzer facts.
|
|
94
|
+
|
|
95
|
+
## Quick Start
|
|
96
|
+
|
|
97
|
+
Install from PyPI. MCP support is included by default:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
uv tool install codedebrief
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
To install a pinned GitHub release instead:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
uv tool install "git+https://github.com/ferdinandobons/CodeDebrief.git@v0.11.0"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Or install from a source checkout:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
git clone https://github.com/ferdinandobons/CodeDebrief.git codedebrief
|
|
113
|
+
cd codedebrief
|
|
114
|
+
uv tool install .
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
From the codebase you want to analyze:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
codedebrief setup-agent codex
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`setup-agent` creates `codedebrief.toml` when needed, installs the selected agent
|
|
124
|
+
instruction file, installs a provider-native CodeDebrief skill where supported, registers
|
|
125
|
+
project-scoped MCP where supported, generates initial artifacts, runs `doctor`, and
|
|
126
|
+
validates the result.
|
|
127
|
+
|
|
128
|
+
After setup, ask the coding agent ordinary questions:
|
|
129
|
+
|
|
130
|
+
```text
|
|
131
|
+
How does checkout work?
|
|
132
|
+
Show me the workflow for certificate upload.
|
|
133
|
+
Which workflows are affected by this change?
|
|
134
|
+
Where is this status handled?
|
|
135
|
+
What should I test after editing this file?
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
For manual exploration:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
codedebrief view
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
For explicit refresh during development:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
codedebrief update
|
|
148
|
+
codedebrief validate --check-sync
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The generated agent instructions treat CodeDebrief artifacts as part of done for
|
|
152
|
+
workflow-relevant changes: after meaningful source, route, config, or agent-instruction
|
|
153
|
+
edits, run `codedebrief update` and `codedebrief validate --check-sync` before finalizing
|
|
154
|
+
or committing so MCP answers and `codedebrief view` use current graphs.
|
|
155
|
+
|
|
156
|
+
## Ask Your Agent
|
|
157
|
+
|
|
158
|
+
Once `setup-agent` has configured the project MCP server and agent instructions, ask
|
|
159
|
+
ordinary code-logic questions:
|
|
160
|
+
|
|
161
|
+
```text
|
|
162
|
+
Show me a visual workflow for the invitation system.
|
|
163
|
+
Explain this code path with a source-grounded flowchart.
|
|
164
|
+
Which workflows are affected by this change?
|
|
165
|
+
Where is this status handled?
|
|
166
|
+
Expand the omitted branches in this workflow_slice.
|
|
167
|
+
Rewrite the diagram labels in plain English.
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The agent should use CodeDebrief first, then decide how much of the deterministic graph to
|
|
171
|
+
show for the specific question.
|
|
172
|
+
|
|
173
|
+
## Setup-Agent
|
|
174
|
+
|
|
175
|
+
Supported targets:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
codedebrief setup-agent codex
|
|
179
|
+
codedebrief setup-agent claude ../my-app
|
|
180
|
+
codedebrief setup-agent gemini
|
|
181
|
+
codedebrief setup-agent cursor --full
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
The selected target controls which files are written:
|
|
185
|
+
|
|
186
|
+
| Target | Files |
|
|
187
|
+
| --- | --- |
|
|
188
|
+
| `codex` | `AGENTS.md`, `.agents/skills/codedebrief/SKILL.md`, project MCP config |
|
|
189
|
+
| `claude` | `CLAUDE.md`, `.claude/skills/codedebrief/SKILL.md`, project MCP config |
|
|
190
|
+
| `gemini` | `GEMINI.md`, `.gemini/skills/codedebrief/SKILL.md`, `.gemini/settings.json` MCP config |
|
|
191
|
+
| `cursor` | `.cursor/rules/codedebrief.mdc`, project MCP config |
|
|
192
|
+
|
|
193
|
+
`setup-agent <target>` writes only that target's files. Run it separately for each agent
|
|
194
|
+
surface you want to configure.
|
|
195
|
+
|
|
196
|
+
The `gemini` target follows Gemini CLI / Antigravity conventions: `GEMINI.md` provides
|
|
197
|
+
project context, `.gemini/skills/codedebrief/SKILL.md` provides provider-native workflow
|
|
198
|
+
guidance, and `.gemini/settings.json` registers the project-scoped CodeDebrief MCP server.
|
|
199
|
+
|
|
200
|
+
## Agent Workflow
|
|
201
|
+
|
|
202
|
+
For natural-language questions, agents should start with MCP `agent_context`.
|
|
203
|
+
|
|
204
|
+
`agent_context` returns a `workflow_slice` with:
|
|
205
|
+
|
|
206
|
+
- normalized intent and task type;
|
|
207
|
+
- primary and supporting flows;
|
|
208
|
+
- ordered source-grounded steps;
|
|
209
|
+
- decision nodes, branches, values, and outcomes;
|
|
210
|
+
- calls, callers, callees, and unresolved call context;
|
|
211
|
+
- domain logic for relevant state-like concepts;
|
|
212
|
+
- source ranges the agent can cite;
|
|
213
|
+
- visual handles for `snapshot_slice` and `codedebrief view`;
|
|
214
|
+
- omissions caused by token budget, ambiguity, stale artifacts, or unsupported capability;
|
|
215
|
+
- follow-up tools for expansion, path tracing, focused explanation, and snapshots.
|
|
216
|
+
|
|
217
|
+
When a user asks for a visual workflow, the agent should first render the deterministic
|
|
218
|
+
Mermaid visual returned by CodeDebrief:
|
|
219
|
+
|
|
220
|
+
1. Render `workflow_slice.presentation.canonical_visual.diagram` exactly as returned only
|
|
221
|
+
when the client renders Mermaid inline.
|
|
222
|
+
2. If the client cannot render Mermaid inline, use `snapshot_slice` with
|
|
223
|
+
`include_svg=false` and provide the returned `.mmd` or Mermaid Markdown artifact
|
|
224
|
+
before prose. Do not paste a long Mermaid code block as the primary visual unless the
|
|
225
|
+
user asks for raw or copyable Mermaid. These generated files are meant to be opened
|
|
226
|
+
with the best available local preview path, for example opening the Markdown artifact
|
|
227
|
+
in VS Code and using Markdown/Mermaid preview support.
|
|
228
|
+
3. Use SVG snapshot artifacts only when the user explicitly asks for SVG or local
|
|
229
|
+
inspection; they are not the canonical chat visual.
|
|
230
|
+
|
|
231
|
+
The model may choose the first visible depth, but the text inside shown blocks must come
|
|
232
|
+
from CodeDebrief payloads. The answer should say that the diagram is a bounded summary and
|
|
233
|
+
can be expanded. If the user wants a more language-friendly view, the agent may rewrite
|
|
234
|
+
labels in the user's language as a separate presentation layer, preserving ids or source
|
|
235
|
+
anchors and without adding facts.
|
|
236
|
+
|
|
237
|
+
## MCP Surface
|
|
238
|
+
|
|
239
|
+
Primary MCP tools:
|
|
240
|
+
|
|
241
|
+
| Tool | Purpose |
|
|
242
|
+
| --- | --- |
|
|
243
|
+
| `agent_context` | Default entrypoint for natural-language questions and changed-code context. |
|
|
244
|
+
| `expand_slice` | Widen or deepen a workflow slice from stable flow handles. |
|
|
245
|
+
| `workflow_path` | Trace a deterministic path between flows, symbols, or concepts. |
|
|
246
|
+
| `snapshot_slice` | Render a deterministic visual snapshot for a slice. |
|
|
247
|
+
| `explain_flow` | Explain one flow with ordered steps, decisions, calls, and source anchors. |
|
|
248
|
+
| `explain_node` | Explain one flowchart node with local edge and source context. |
|
|
249
|
+
| `explain_edge` | Explain one modeled edge with source context. |
|
|
250
|
+
| `validate_artifacts` | Check generated model validity and optional sync. |
|
|
251
|
+
| `update_codedebrief` | Refresh JSON, Markdown, and HTML artifacts from local source. |
|
|
252
|
+
|
|
253
|
+
Use `codedebrief view` for the manual UI. The CLI intentionally stays small:
|
|
254
|
+
`setup-agent`, `update`, `view`, `validate`, `doctor`, and `mcp`.
|
|
255
|
+
|
|
256
|
+
## Generated Artifacts
|
|
257
|
+
|
|
258
|
+
CodeDebrief writes deterministic artifacts under `codedebrief-out/`:
|
|
259
|
+
|
|
260
|
+
| File | Commit? | Purpose |
|
|
261
|
+
| --- | --- | --- |
|
|
262
|
+
| `codedebrief.json` | Yes | Canonical model consumed by MCP, CI, scripts, and the viewer. |
|
|
263
|
+
| `codedebrief.md` | Yes | Human-readable Markdown summary with Mermaid flowcharts. |
|
|
264
|
+
| `codedebrief.html` | Usually no | Local interactive viewer generated from the model. |
|
|
265
|
+
|
|
266
|
+
Commit `codedebrief.json` and `codedebrief.md` when CodeDebrief is part of the project
|
|
267
|
+
workflow. Regenerate HTML locally when a human needs the viewer.
|
|
268
|
+
|
|
269
|
+
## Manual Viewer
|
|
270
|
+
|
|
271
|
+
`codedebrief view` opens the complete interactive flowchart for a human. It is the official
|
|
272
|
+
manual experience for broad exploration:
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
codedebrief view
|
|
276
|
+
codedebrief view --render-only --no-open
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Use the viewer when you need to inspect the whole project graph, navigate scopes, compare
|
|
280
|
+
neighboring flows, or visually follow callers and callees. Use MCP when an agent should
|
|
281
|
+
answer a bounded question with a focused `workflow_slice`.
|
|
282
|
+
|
|
283
|
+
## Domain Logic
|
|
284
|
+
|
|
285
|
+
CodeDebrief extracts and aggregates domain concepts such as:
|
|
286
|
+
|
|
287
|
+
- enum members;
|
|
288
|
+
- status and lifecycle states;
|
|
289
|
+
- roles and permissions;
|
|
290
|
+
- feature flags;
|
|
291
|
+
- handled values and the decisions that branch on them.
|
|
292
|
+
|
|
293
|
+
`agent_context` includes relevant domain logic inside the returned `workflow_slice`, with
|
|
294
|
+
links back to flows, nodes, source ranges, snapshots, and viewer targets. Value matching
|
|
295
|
+
uses modeled code facts, including enum-style suffix matches such as `PAID` for
|
|
296
|
+
`Status.PAID`.
|
|
297
|
+
|
|
298
|
+
## Supported Code
|
|
299
|
+
|
|
300
|
+
CodeDebrief currently extracts control flow for 11 language ids:
|
|
301
|
+
|
|
302
|
+
| Language | Current coverage |
|
|
303
|
+
| --- | --- |
|
|
304
|
+
| Python (`.py`) | AST analyzer with functions, methods, decisions, loops, calls, returns, exceptions, tests, enum harvest, and import dependencies. |
|
|
305
|
+
| TypeScript / TSX (`.ts`, `.tsx`) | Tree-sitter analyzer with Next.js and React entrypoint detection, decisions, loops, calls, returns, expression-bodied arrows, tests, enum harvest, and import dependencies. |
|
|
306
|
+
| JavaScript / JSX (`.js`, `.jsx`, `.mjs`, `.cjs`) | Tree-sitter analyzer with JavaScript labeling, decisions, loops, calls, returns, expression-bodied arrows, tests, and import dependencies. |
|
|
307
|
+
| Go (`.go`) | Profile-driven tree-sitter analyzer with functions, methods, decisions, loops, calls, returns, tests, and import dependencies. |
|
|
308
|
+
| Java (`.java`) | Profile-driven tree-sitter analyzer with methods, decisions, loops, calls, returns, exceptions, tests, imports, and Spring route annotations. |
|
|
309
|
+
| C# (`.cs`) | Profile-driven tree-sitter analyzer with methods, decisions, loops, calls, returns, exceptions, and tests. |
|
|
310
|
+
| PHP (`.php`) | Profile-driven tree-sitter analyzer with functions, methods, decisions, loops, calls, returns, exceptions, and tests. |
|
|
311
|
+
| C (`.c`, `.h`) | Profile-driven tree-sitter analyzer with functions, decisions, loops, calls, returns, and tests. |
|
|
312
|
+
| C++ (`.cc`, `.cpp`, `.cxx`, `.hh`, `.hpp`, `.hxx`, `.ipp`, `.tpp`) | Profile-driven tree-sitter analyzer with functions, methods, decisions, loops, calls, returns, exceptions, and tests. |
|
|
313
|
+
| Rust (`.rs`) | Profile-driven tree-sitter analyzer with functions, decisions, loops, calls, match handling, returns, and tests. |
|
|
314
|
+
| Ruby (`.rb`) | Profile-driven tree-sitter analyzer with methods, decisions, loops, calls, returns, and tests. |
|
|
315
|
+
|
|
316
|
+
Generated models include `metadata.language_capabilities`, with feature flags and
|
|
317
|
+
limitation notes per language. Agents should use that contract when explaining analyzer
|
|
318
|
+
depth.
|
|
319
|
+
|
|
320
|
+
## Configuration
|
|
321
|
+
|
|
322
|
+
CodeDebrief works without config. Add `codedebrief.toml` only when defaults are not enough:
|
|
323
|
+
|
|
324
|
+
```toml
|
|
325
|
+
[codedebrief]
|
|
326
|
+
source_roots = ["."]
|
|
327
|
+
exclude = []
|
|
328
|
+
exclude_dirs = []
|
|
329
|
+
include_public_functions = true
|
|
330
|
+
max_call_depth = 4
|
|
331
|
+
output_dir = "codedebrief-out"
|
|
332
|
+
self_exclude = true
|
|
333
|
+
|
|
334
|
+
[codedebrief.entrypoints]
|
|
335
|
+
include = []
|
|
336
|
+
exclude = []
|
|
337
|
+
|
|
338
|
+
[codedebrief.scopes]
|
|
339
|
+
backend = ["backend/**", "services/**"]
|
|
340
|
+
frontend = ["frontend/**", "web/**"]
|
|
341
|
+
edge = ["edge/**", "workers/**"]
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Defaults prune common VCS, dependency, cache, temporary, generated, and output
|
|
345
|
+
directories, including `.git`, `node_modules`, virtualenv folders, `.next`, `.turbo`,
|
|
346
|
+
`.svelte-kit`, `dist`, `build`, `out`, `target`, `coverage`, `vendor`, `Pods`, and
|
|
347
|
+
`codedebrief-out`.
|
|
348
|
+
|
|
349
|
+
## Limitations
|
|
350
|
+
|
|
351
|
+
CodeDebrief does not run code, observe runtime state, perform full symbolic execution,
|
|
352
|
+
prove business correctness, or reconstruct deep framework state. It statically models
|
|
353
|
+
source files, control flow, selected framework conventions, and resolvable internal calls.
|
|
354
|
+
|
|
355
|
+
Important practical limits:
|
|
356
|
+
|
|
357
|
+
- dynamic dispatch may remain unresolved;
|
|
358
|
+
- language capability varies by analyzer frontend;
|
|
359
|
+
- generated or unsupported files may be skipped;
|
|
360
|
+
- large slices are token-budgeted and report omissions;
|
|
361
|
+
- the displayed first slice is a bounded summary and can be expanded with MCP tools.
|
|
362
|
+
|
|
363
|
+
## FAQ
|
|
364
|
+
|
|
365
|
+
### Is CodeDebrief an AI code review tool?
|
|
366
|
+
|
|
367
|
+
No. CodeDebrief is for code comprehension and workflow navigation. It helps humans and
|
|
368
|
+
coding agents understand modeled logic; it does not present possible defects as product
|
|
369
|
+
output.
|
|
370
|
+
|
|
371
|
+
### Does CodeDebrief require an LLM API key?
|
|
372
|
+
|
|
373
|
+
No. The analyzer, artifacts, Mermaid diagrams, manual viewer, and MCP server are
|
|
374
|
+
local-first and deterministic. Coding agents can use the MCP tools without any required
|
|
375
|
+
provider key.
|
|
376
|
+
|
|
377
|
+
### How is CodeDebrief different from a call graph?
|
|
378
|
+
|
|
379
|
+
A call graph shows relationships between symbols. CodeDebrief models workflow slices with
|
|
380
|
+
entrypoints, decisions, branches, ordered steps, source ranges, domain concepts, visual
|
|
381
|
+
targets, and expansion tools for coding agents.
|
|
382
|
+
|
|
383
|
+
### Can CodeDebrief generate Mermaid workflow diagrams from code?
|
|
384
|
+
|
|
385
|
+
Yes. `agent_context` returns a canonical top-to-bottom Mermaid visual for the selected
|
|
386
|
+
`workflow_slice`, and `snapshot_slice` can persist Mermaid files for clients that cannot
|
|
387
|
+
render Mermaid inline.
|
|
388
|
+
|
|
389
|
+
### Can I use CodeDebrief only as a manual visual explorer?
|
|
390
|
+
|
|
391
|
+
Yes. Run `codedebrief view` to open the interactive local viewer. MCP is the primary agent
|
|
392
|
+
surface, but the viewer remains the official manual exploration surface.
|
|
393
|
+
|
|
394
|
+
## Development
|
|
395
|
+
|
|
396
|
+
For local development in this repository:
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
uv sync --extra dev
|
|
400
|
+
uv run codedebrief --help
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Standard gates:
|
|
404
|
+
|
|
405
|
+
```bash
|
|
406
|
+
UV_CACHE_DIR=/tmp/codedebrief-uv-cache uv run ruff check .
|
|
407
|
+
UV_CACHE_DIR=/tmp/codedebrief-uv-cache uv run ruff format --check .
|
|
408
|
+
UV_CACHE_DIR=/tmp/codedebrief-uv-cache uv run mypy
|
|
409
|
+
UV_CACHE_DIR=/tmp/codedebrief-uv-cache uv run pytest --cov
|
|
410
|
+
UV_CACHE_DIR=/tmp/codedebrief-uv-cache uv run codedebrief validate . --check-sync --json
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
Viewer gates:
|
|
414
|
+
|
|
415
|
+
```bash
|
|
416
|
+
npm run viewer:typecheck
|
|
417
|
+
npm run viewer:test
|
|
418
|
+
npm run viewer:build
|
|
419
|
+
UV_CACHE_DIR=/tmp/codedebrief-uv-cache uv run codedebrief update
|
|
420
|
+
UV_CACHE_DIR=/tmp/codedebrief-uv-cache uv run codedebrief view --render-only --no-open
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
Schemas:
|
|
424
|
+
|
|
425
|
+
- [schema/codedebrief.schema.json](schema/codedebrief.schema.json) documents the canonical
|
|
426
|
+
artifact model.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
codedebrief/__init__.py,sha256=AX7wdOPFDwuJYbfG8VSiyc509n5WPKfhut2L0zMaXU4,375
|
|
2
|
+
codedebrief/artifacts.py,sha256=BIAgDjcP2Y3GxjaIXkSR-nvpYTuZq_3FzwhYrfXEbB4,1809
|
|
3
|
+
codedebrief/cli.py,sha256=LI6PK91cn9YnQhIJaWbe01vqLGb-UfMU413mg-04Uf0,19723
|
|
4
|
+
codedebrief/config.py,sha256=SqWIvGm8qx8mn2n6uIy5ICC_QFHUe5LUFwDhDabnnXQ,7632
|
|
5
|
+
codedebrief/doctor.py,sha256=qMKgBqZJXEzfWQ_TQxlZViTjta1fqD1YkjjNbLwFhOU,5943
|
|
6
|
+
codedebrief/install.py,sha256=BacXTwP99t0RLBRgBFZacXC3AJeNMLzuiYcgPESKb9s,21243
|
|
7
|
+
codedebrief/mcp_server.py,sha256=BDi_-COX7ktPGBO-wIo5JhV88a70xmZ8u1Ksm01txTs,98619
|
|
8
|
+
codedebrief/model.py,sha256=VIUKL9sSVHsNn2CSB0W-Q9slgUZ1Gvfjkg9PWLF1DuA,5623
|
|
9
|
+
codedebrief/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
10
|
+
codedebrief/quality.py,sha256=Z0LX9yR_IHaLR61Ej7FULSWmFCiXu15rz7BbkT5M1Hw,15403
|
|
11
|
+
codedebrief/query.py,sha256=qpEI3jcsuswQVElzqZY63HT4wPE9b5gVRF2zQzeHMV0,23074
|
|
12
|
+
codedebrief/util.py,sha256=5vTbub_uikjd6U3xpRSBYQWTC52tYVmYaRSmUJ__TqU,1970
|
|
13
|
+
codedebrief/validation.py,sha256=fhhVbztDoDvdA_I5tr4QuCOH-2qrczlxgysvxsC1iHU,8315
|
|
14
|
+
codedebrief/analysis/__init__.py,sha256=wSpZMiXlX6G5hU8dIk85BH4xuWwMsSRl25l9o42REog,554
|
|
15
|
+
codedebrief/analysis/common.py,sha256=pQQNDrTwG0QnWWSvxOYXlBw2d240Y5UQDfR0Qub7p-I,17920
|
|
16
|
+
codedebrief/analysis/discovery.py,sha256=rpTcTSMylAHb0x9w4nwcT4BlAlRR3pg69fiQOgqD6lc,4232
|
|
17
|
+
codedebrief/analysis/project.py,sha256=y7dQeBKBhzloN__xQ5vON37rsf0IWw68oTT0P3wrrb4,16151
|
|
18
|
+
codedebrief/analysis/python.py,sha256=kCKbomOi7GUCUd3Y-x7nerTJrOWW2Siosxt53w6Itjs,34408
|
|
19
|
+
codedebrief/analysis/registry.py,sha256=5YFUbbTleyVoCLZeHAl6mzxRNSlqffIIDWASxUJJvgA,10442
|
|
20
|
+
codedebrief/analysis/treesitter.py,sha256=y6KVLiuL5TzxiTg90g3E8f1g75GI70gFGGD0oriLWzo,36200
|
|
21
|
+
codedebrief/analysis/typescript.py,sha256=5DOFFuHr6IB4Uc0v84r6dLZEO3jbVqdX8KxS9_IhVB4,38420
|
|
22
|
+
codedebrief/analysis/languages/__init__.py,sha256=u-Fa3xrUW5AAhVGPt2bk0XiZfRFDSPDwc106bGU8noY,320
|
|
23
|
+
codedebrief/analysis/languages/_common.py,sha256=7UBqj0sHJf1aaozzkrq7lNavLRTGkU04vlvdSpo3JPk,2526
|
|
24
|
+
codedebrief/analysis/languages/c.py,sha256=S7PoP2T_WtnhkV9JK74-_rRJLyzCiDjVFX0NvJxoNoQ,3403
|
|
25
|
+
codedebrief/analysis/languages/cpp.py,sha256=X2XlZYnYgktjwXtU1YpPyv1cLOpRDJy9ABGEBfzPJu0,5020
|
|
26
|
+
codedebrief/analysis/languages/csharp.py,sha256=M_lSGjj1ZjiFOjwsRDt9V_7kRAzHUrmMDrM0CLH6fCk,5420
|
|
27
|
+
codedebrief/analysis/languages/go.py,sha256=dkHPfk-6RHTkSfMBO2G7X-05AaFl0Vj-YLchFMYLYQA,5483
|
|
28
|
+
codedebrief/analysis/languages/java.py,sha256=tV0uoqSD6HyrcFF8oHrfyw-szWkji6wv-8PJz5ySko8,6072
|
|
29
|
+
codedebrief/analysis/languages/php.py,sha256=hzNcRhSQYoOaTofXM_XrCAAZj39wMS4LZhIbjK7A8bM,3260
|
|
30
|
+
codedebrief/analysis/languages/ruby.py,sha256=48axyjdg6e7U_488y9t6ePmKJx-3xRePJ4Lre2Qhk-E,2768
|
|
31
|
+
codedebrief/analysis/languages/rust.py,sha256=efn1rdCGofHuAUmTe40cbyXfVL5J9sENYQx7rXn5Zs4,3807
|
|
32
|
+
codedebrief/render/__init__.py,sha256=ghDW516vY7T-nWbYvj38Ns8GR40lAYEdzUfbM7yiJM8,208
|
|
33
|
+
codedebrief/render/html.py,sha256=sKUMF1UWSWkGdTtd3p_X-0LqK8gLwPENygQM2iB38FE,10640
|
|
34
|
+
codedebrief/render/markdown.py,sha256=3RbXAKi6PZfp6OvK1GqvHrS-AXvdEwHW-tL1YqEJJnk,5347
|
|
35
|
+
codedebrief/render/payload.py,sha256=k3u9LRDvrjXuWQ_RbnXX3cqKsS8UHzVc6lY5dWFABYE,14400
|
|
36
|
+
codedebrief/render/snapshot.py,sha256=AueLKF4axnHeRibGqiBXBsthu9m2BMWFLHnm4lvNGno,25548
|
|
37
|
+
codedebrief/render/assets/panels.js,sha256=nZ3PHIs0-JhyPopv126lo1OMVSVRtuSe7HiFtBe3VX4,17742
|
|
38
|
+
codedebrief/render/assets/shell.js,sha256=TLZ0IQzSzs51R6FSCgiRPgBOC2QwQdzF6hqpaog30ns,69483
|
|
39
|
+
codedebrief/render/assets/styles.css,sha256=kw877xa96kaUBD05yCQ1SX69KZRHhPnL3BTMCq_czX8,52278
|
|
40
|
+
codedebrief/render/assets/tree.js,sha256=WYx97jOQUt3e3hcy8RELKInnO-y4J4RZQU4AhD8cnV4,24180
|
|
41
|
+
codedebrief/render/assets/generated/codedebrief-viewer-runtime.iife.js,sha256=d2cmGiGqqTBgsgdQQvGV-rklXi-l2HjBh0EalZmfj1A,276745
|
|
42
|
+
codedebrief/schema/codedebrief.schema.json,sha256=CJTEgEcXvS09PYvciPkqjyLR9f4vzGHaCgvQ1gNFSoM,9760
|
|
43
|
+
codedebrief-0.11.0.dist-info/METADATA,sha256=ezkG6ADp0YAQHhIHEUH7pWJUaCFrbEhRFHLQPLkFynw,17493
|
|
44
|
+
codedebrief-0.11.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
|
|
45
|
+
codedebrief-0.11.0.dist-info/entry_points.txt,sha256=NLdCH2kxaZPfdGVhtzd1uhJ7xm36IlMqUAw9hXz_sk4,53
|
|
46
|
+
codedebrief-0.11.0.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
|
47
|
+
codedebrief-0.11.0.dist-info/licenses/NOTICE,sha256=1SKC2iM-7PF9gSHkpbqnxUW1dI8Pt6BKddq0-0BPSb4,365
|
|
48
|
+
codedebrief-0.11.0.dist-info/RECORD,,
|