mirror of
https://github.com/Asixa/codemap-skill.git
synced 2026-08-28 17:01:14 +00:00
Brand outputs as codemap.html/md, add MIT LICENSE, promotional README + sample-project example screenshots
This commit is contained in:
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Xingyu Chen
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -1,192 +1,188 @@
|
|||||||
# codemap
|
# 🧹 codemap
|
||||||
|
|
||||||
A [Claude Code](https://claude.com/claude-code) **Agent Skill** that builds and
|
**A code janitor for AI coding agents.** Point it at any repo and it draws an
|
||||||
incrementally maintains an **interactive architecture map + per-module code-quality
|
**interactive architecture map**, scores **every module 0–100** for technical debt, and
|
||||||
audit** for any codebase.
|
helps you **clean up the spaghetti** — incrementally, one commit at a time.
|
||||||
|
|
||||||
It decomposes a project into *functional* modules (not files), draws their dependency
|

|
||||||
graph as a layered, clickable HTML page, and scores each module 0–100 for code health —
|

|
||||||
hunting for monkeypatching, fallbacks, legacy/dead code, stubs, dual-format handling,
|

|
||||||
bloat, duplication, and glue. Every module's score comes from an **independent
|

|
||||||
subagent** against a fixed rubric. It's **incremental**: a per-module content hash means
|

|
||||||
re-runs only re-audit what changed.
|
|
||||||
|
|
||||||
## What you get
|
> Every codebase rots into a 屎山 (spaghetti / big ball of mud) eventually — monkeypatches,
|
||||||
|
> silent fallbacks, dead "legacy" paths, half-finished stubs, copy-pasted duplication,
|
||||||
|
> god-files, and valueless glue. **codemap finds that rot, ranks it, and hands an AI agent
|
||||||
|
> a clean punch-list to fix it** — with a regression-gated fix loop so cleanup never breaks
|
||||||
|
> your build.
|
||||||
|
|
||||||
Three coupled artifacts, kept in sync:
|

|
||||||
|
|
||||||
| File | What | Where (default) |
|
---
|
||||||
|
|
||||||
|
## Why codemap
|
||||||
|
|
||||||
|
Most "architecture diagram" tools draw *files and imports*. codemap is different:
|
||||||
|
|
||||||
|
- **Functional modules, not files.** It groups code into the capabilities that actually
|
||||||
|
matter (a store, a handler group, a feature, a plugin) and lays them out along the
|
||||||
|
real data-flow.
|
||||||
|
- **It grades the rot.** Every module gets a health **score (0–100) and grade (A–F)** plus
|
||||||
|
concrete `file:line` findings, hunting specifically for the smells that make code
|
||||||
|
unmaintainable: `monkeypatch`, `fallback`, `silent-except`, `legacy`/dead code, `stub`,
|
||||||
|
`fake-output`, `dual-format`, `bloat`, `duplication`, `glue`, `god-component`, …
|
||||||
|
- **Independent, honest scoring.** Each module is audited by a **separate AI subagent**
|
||||||
|
against a fixed rubric — no single pass rubber-stamping the whole repo.
|
||||||
|
- **Incremental + git-aware.** A per-module content hash + the last-run commit mean re-runs
|
||||||
|
only re-audit what changed, and `update` shows you the **commits since last time** and
|
||||||
|
which modules they touched.
|
||||||
|
- **Cleanup that can't regress.** `fix` runs a four-role loop — lock a test baseline →
|
||||||
|
fix → an **independent acceptance check** proves the pre-fix tests still pass → re-score.
|
||||||
|
|
||||||
|
It's the maintenance pass you never have time to do, turned into something an agent can
|
||||||
|
run on a schedule.
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|
| Select a module — dependencies + audit | Audit report | Editable standard |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `config.json` | your saved **preferences** (UI language, output location, title) | `<project>/.codemap/` |
|
|  |  |  |
|
||||||
| `modules.json` | the **source of truth** (modules, deps, coupling, LoC, hash, score, findings) | `<project>/.codemap/` |
|
|
||||||
| `architecture-map.html` | self-contained **interactive map** (health coloring, filters, dependency highlighting, audit report) | `<project>/.codemap/` |
|
|
||||||
| `architecture-audit.md` | the written **report** (per-layer scores, LoC table, worst offenders, themes) | `<project>/.codemap/` |
|
|
||||||
|
|
||||||
Everything lives in **`<project>/.codemap/`** by default. On first run (`generate`) the
|
- **Click any module** to highlight what it calls (downstream) and what depends on it
|
||||||
tool asks your preferences — UI language, output location (point it at `docs/` if you
|
(upstream), with its score, smell tags, and `file:line` findings.
|
||||||
want the HTML/MD committed/visible), project title — and saves them to
|
- **Health vs coupling** color modes — problems pop amber/red, healthy modules recede to a
|
||||||
`.codemap/config.json`. The HTML and MD are **generated** from `modules.json` and must
|
muted green (colorblind-friendly; the cue is saturation, not just hue).
|
||||||
never be hand-edited.
|
- **Filter** by grade (≤ B/C/D/F) or by issue tag; jump straight to the worst offenders.
|
||||||
|
- **Editable Standard page** — change descriptions, **add your own issue tags** to capture
|
||||||
### Interactive map features
|
*your* definition of a problem, and Export to `standard.json`; future audits use it.
|
||||||
- Layered bands top→bottom along the data-flow; click a module to highlight what it
|
- **i18n** — English or Chinese UI (`meta.lang`); module names are never translated.
|
||||||
**calls** (downstream) and what **depends on it** (upstream).
|
- **Copy-fix button** on each module — copies `/codemap fix <module>` to paste into your agent.
|
||||||
- Per-module **health score + grade (A–F)**, smell tags, and concrete `file:line` findings.
|
|
||||||
- Color modes: **coupling** or **health** (problems pop amber/red, healthy modules
|
|
||||||
recede to a muted green — colorblind-friendly, the cue is saturation not just hue).
|
|
||||||
- **Filters**: by grade level (≤ B/C/D/F) and by issue tag; live match count.
|
|
||||||
- **Audit report** view: averages, grade spread, worst offenders, cross-cutting themes.
|
|
||||||
- **Standard page**: a built-in "Standard" view explaining the score→grade rubric, the
|
|
||||||
finding severities, and every smell tag — so the scores are self-documenting.
|
|
||||||
- **i18n**: set `meta.lang` to `"en"` or `"zh"` (module names are never translated).
|
|
||||||
|
|
||||||
## Languages
|
## Languages
|
||||||
|
|
||||||
Language-agnostic. The scripts count LoC and hash bytes for **any** text source, and
|
Language-agnostic. LoC and hashing work on **any** text source and `paths` are plain globs,
|
||||||
`paths` are plain globs, so it works for Python, **TypeScript/JS, Rust, C#/.NET, C/C++**,
|
so it covers **Python, TypeScript/JS, Rust, C#/.NET, C/C++, Go, Java, Swift**, and more.
|
||||||
Go, Java, Swift, and more. Build/test/generated trees are excluded out of the box
|
Build/test/generated trees are excluded out of the box (`target/`, `bin/`, `obj/`,
|
||||||
(`target/`, `bin/`, `obj/`, `node_modules/`, `cmake-build*`, `__pycache__/`, `dist/`,
|
`node_modules/`, `cmake-build*`, `__pycache__/`, `dist/`, `*.d.ts`, `*.Designer.cs`, …).
|
||||||
`*.d.ts`, `*.Designer.cs`, …). The audit rubric names *behaviors*, not syntax —
|
The rubric names *behaviors*, not syntax — `reference/STANDARDS.md` maps each smell to its
|
||||||
`reference/STANDARDS.md` maps each smell to its per-language form (e.g. `any-escape` =
|
per-language form (e.g. `any-escape` = `as any` / `dynamic` / `void*` / `reinterpret_cast`
|
||||||
`as any` / `dynamic` / `void*` / `reinterpret_cast` / `unsafe`).
|
/ `unsafe`).
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- **Python 3** (standard library only — no `pip install`, no external packages).
|
- **Python 3** — standard library only. No `pip install`, no external packages.
|
||||||
- **An AI coding agent** to drive the audit/fix/test steps — **Claude Code** (native
|
- **An AI coding agent** to drive the audit/fix/test steps: **Claude Code** (native skill)
|
||||||
skill) or **any other agent that can read instructions and spawn sub-tasks**, e.g.
|
or **any agent that reads instructions and spawns sub-tasks**, e.g. OpenAI **Codex**
|
||||||
OpenAI **Codex** (see [Using with Codex / other agents](#using-with-codex--other-agents)).
|
(see [Using with Codex](#using-with-codex--other-agents)).
|
||||||
- A browser to open the generated HTML. That's it.
|
- A browser to open the generated HTML. That's it.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
A skill is just a folder under `~/.claude/skills/`. Clone this repo into it:
|
A Claude Code skill is just a folder under `~/.claude/skills/`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone <this-repo-url> ~/.claude/skills/codemap
|
git clone https://github.com/Asixa/codemap-skill ~/.claude/skills/codemap
|
||||||
```
|
```
|
||||||
|
|
||||||
(Windows PowerShell: `git clone <url> $env:USERPROFILE\.claude\skills\codemap`.)
|
(Windows PowerShell: `git clone https://github.com/Asixa/codemap-skill $env:USERPROFILE\.claude\skills\codemap`.)
|
||||||
|
|
||||||
Restart Claude Code (or start a new session). The skill appears as `/codemap`.
|
Restart Claude Code (or start a new session). The skill appears as **`/codemap`**.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Talk to Claude in natural language, or use the subcommands. Claude reads `SKILL.md`
|
Talk to Claude in plain language, or use the subcommands. On the first run, codemap asks
|
||||||
and runs the scripts; the **audit / fix / test** steps spawn independent subagents.
|
your preferences (UI language, output location, project title) and saves them to
|
||||||
|
`<project>/.codemap/config.json`. Everything it produces lives in `<project>/.codemap/`.
|
||||||
|
|
||||||
| Command | Does |
|
| Command | Does |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `/codemap generate` | first build: decompose → scan → audit every module → render |
|
| `/codemap generate` | first build: ask prefs → decompose into modules → scan → audit every module → render |
|
||||||
| `/codemap check` | read-only: is the map stale? lists drifted / new / deleted modules |
|
| `/codemap check` | read-only: is the map stale? shows commits since last run + drifted / new / deleted modules |
|
||||||
| `/codemap update` | incremental: re-audit only changed modules, re-render |
|
| `/codemap update` | incremental + git-aware: re-audit only changed modules, re-render |
|
||||||
| `/codemap test <module>` | generate tests (regression net) for a module |
|
| `/codemap test <module>` | generate a regression-net of tests for a module |
|
||||||
| `/codemap fix <module>` | regression-gated fix: lock baseline → fix → independent acceptance → re-score |
|
| `/codemap fix <module>` | regression-gated cleanup: lock baseline → fix → independent acceptance → re-score |
|
||||||
|
|
||||||
You can also run the deterministic scripts directly (no AI needed for these):
|
The deterministic scripts (no AI needed) can also be run by hand:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
S=~/.claude/skills/codemap
|
S=~/.claude/skills/codemap
|
||||||
# what changed since last audit — incl. a `git` block listing the commits since the
|
# what changed since last run — a `git` block lists commits + affected modules
|
||||||
# last codemap run (meta.rev) and which modules they touched
|
python3 $S/scripts/scan.py --root . --state .codemap/modules.json
|
||||||
python3 $S/scripts/scan.py --root . --state .codemap/modules.json
|
# cache the current HEAD as the new baseline (end of an update)
|
||||||
# after an update, cache the current HEAD as the new baseline for next time
|
python3 $S/scripts/scan.py --root . --state .codemap/modules.json --stamp-rev
|
||||||
python3 $S/scripts/scan.py --root . --state .codemap/modules.json --stamp-rev
|
# pick targets cheaply, without reading the whole state (for agents)
|
||||||
# find modules to act on without reading the whole state (token-cheap, for agents)
|
|
||||||
python3 $S/scripts/query.py --state .codemap/modules.json --max-grade C --format ids
|
python3 $S/scripts/query.py --state .codemap/modules.json --max-grade C --format ids
|
||||||
python3 $S/scripts/query.py --state .codemap/modules.json --tag dual-format
|
python3 $S/scripts/query.py --state .codemap/modules.json --tag dual-format
|
||||||
# regenerate the HTML + MD from the state
|
# regenerate the HTML + report from the state
|
||||||
python3 $S/scripts/render.py --state .codemap/modules.json \
|
python3 $S/scripts/render.py --state .codemap/modules.json --template $S/assets/template.html \
|
||||||
--template $S/assets/template.html \
|
--out-html .codemap/codemap.html --out-md .codemap/codemap.md
|
||||||
--out-html .codemap/architecture-map.html --out-md .codemap/architecture-audit.md
|
|
||||||
```
|
```
|
||||||
|
|
||||||
> On Windows use `python` instead of `python3`.
|
> On Windows use `python` instead of `python3`.
|
||||||
|
|
||||||
## Using with Codex / other agents
|
## Using with Codex / other agents
|
||||||
|
|
||||||
The skill mechanism is Claude-specific, but the **engine is tool-agnostic**: the four
|
The skill mechanism is Claude-specific, but the **engine is tool-agnostic** — four
|
||||||
scripts are deterministic stdlib Python, and the workflow + rubric are plain Markdown
|
deterministic stdlib-Python scripts plus a Markdown workflow and rubric. **OpenAI Codex**
|
||||||
(`SKILL.md`, `reference/STANDARDS.md`). Any capable agent can drive it.
|
auto-reads the shipped **`AGENTS.md`**. To use codemap from Codex (or Cursor, Aider, …):
|
||||||
|
|
||||||
**OpenAI Codex** auto-reads an `AGENTS.md` in the working directory — this repo ships one
|
1. Clone this repo somewhere the agent can read, e.g. `git clone <url> ~/.codemap`.
|
||||||
that points Codex at the workflow and rubric. To use codemap from Codex (or Cursor,
|
2. Tell the agent: *"Use the codemap tool at `<path>` to map/audit this project — follow
|
||||||
Aider, etc.):
|
its `SKILL.md`; score each module with a separate sub-task per `reference/STANDARDS.md`."*
|
||||||
|
3. It runs the same `scan → audit → apply_audit → render` loop, using `query.py` to target.
|
||||||
1. Make the tool available — clone this repo somewhere the agent can read it, e.g.
|
|
||||||
`git clone <url> ~/.codemap` (or vendor it into your project).
|
|
||||||
2. Tell the agent: *"Use the codemap tool at `<path>` to build/update the architecture
|
|
||||||
map for this project. Follow its `SKILL.md`; score each module with a separate
|
|
||||||
sub-task using `reference/STANDARDS.md`."*
|
|
||||||
3. The agent runs the same commands shown above (`scan.py` → per-module audit →
|
|
||||||
`apply_audit.py` → `render.py`), using `query.py` to pick targets cheaply.
|
|
||||||
|
|
||||||
The deterministic parts (scan / query / render / apply_audit) you can also run **by
|
|
||||||
hand** with no agent at all — only the *scoring*, *fixing*, and *test-writing* need a
|
|
||||||
model, and those just follow `reference/STANDARDS.md`.
|
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
```
|
```
|
||||||
modules.json ──scan.py──▶ + LoC & content hash per module (stale = hash != auditedHash)
|
modules.json ──scan.py──▶ + LoC, content hash & git diff (stale = hash != auditedHash)
|
||||||
│ (decomposition + descriptions are authored by the model)
|
│ (decomposition + module descriptions: authored by the agent)
|
||||||
│◀─apply_audit.py── one INDEPENDENT subagent's score per module (fixed rubric)
|
│◀─apply_audit.py── one INDEPENDENT subagent's score per module (fixed rubric)
|
||||||
│◀─query.py────────── token-cheap targeting (by grade / tag / severity / staleness)
|
│◀─query.py────────── token-cheap targeting (by grade / tag / severity / staleness)
|
||||||
└──render.py────────▶ architecture-map.html + architecture-audit.md
|
└──render.py────────▶ codemap.html + codemap.md
|
||||||
```
|
```
|
||||||
|
|
||||||
- **Four separate subagent roles, never merged**: *auditor* (scores), *test-author*
|
`modules.json` is the source of truth (commit it for an audit history); the HTML/MD are
|
||||||
(writes tests), *fixer* (changes code), *acceptance/verifier* (proves no regression).
|
pure projections, regenerated by `render.py`. **Four separate subagent roles, never
|
||||||
A `fix` is accepted only when an independent acceptance subagent shows the pre-fix
|
merged:** *auditor* (scores), *test-author* (writes tests), *fixer* (changes code),
|
||||||
green tests are still green and the build is clean.
|
*acceptance/verifier* (proves no regression). Tests are the regression net and are kept
|
||||||
- Tests are excluded from a module's audit scope (they're the regression net, tracked
|
out of a module's own audit scope.
|
||||||
separately in the module's `tests` field).
|
|
||||||
|
## Customizing the standard (capture *your* "屎山")
|
||||||
|
|
||||||
|
The scoring standard is **data, not code** (`reference/standard.json`: rubric, severities,
|
||||||
|
coupling, and issue tags with descriptions). Open the **Standard** page in the map → **Edit**
|
||||||
|
→ tweak descriptions, **add your own tags**, then **Export** to
|
||||||
|
`<project>/.codemap/standard.json`. Custom tags flow through the whole map and are used by
|
||||||
|
future audits. The prose version + the exact subagent prompt live in `reference/STANDARDS.md`.
|
||||||
|
|
||||||
## Repository layout
|
## Repository layout
|
||||||
|
|
||||||
```
|
```
|
||||||
codemap/
|
codemap/
|
||||||
SKILL.md # the orchestration instructions Claude reads
|
SKILL.md # the orchestration the agent reads
|
||||||
README.md # this file
|
AGENTS.md # entry point for Codex / other agents
|
||||||
|
README.md
|
||||||
|
LICENSE # MIT
|
||||||
reference/
|
reference/
|
||||||
STANDARDS.md # the scoring rubric, smell taxonomy, severity, subagent prompts
|
STANDARDS.md # scoring rubric, smell taxonomy, severities, subagent prompts
|
||||||
DATA_MODEL.md # the modules.json schema
|
DATA_MODEL.md # modules.json schema
|
||||||
scripts/ # deterministic, stdlib-only Python
|
standard.json # the machine-readable default standard (overridable per project)
|
||||||
scan.py # LoC + content hash + staleness report
|
scripts/ # deterministic, stdlib-only Python
|
||||||
query.py # filter modules (grade/tag/severity/...) → ids/paths/findings
|
scan.py # LoC + content hash + git diff + staleness
|
||||||
apply_audit.py # merge one subagent's audit result into the state
|
query.py # filter modules (grade/tag/severity/…) → ids/paths/findings
|
||||||
render.py # modules.json → HTML + MD
|
apply_audit.py # merge one subagent's audit into the state
|
||||||
|
render.py # modules.json → HTML + report
|
||||||
assets/
|
assets/
|
||||||
template.html # the interactive map shell (data injected at render time)
|
template.html # the interactive map shell (data injected at render time)
|
||||||
|
examples/ # the screenshots above
|
||||||
```
|
```
|
||||||
|
|
||||||
## Customizing the standard (capture your own "what's a problem")
|
## License
|
||||||
|
|
||||||
The standard is **data, not code** — it lives in `reference/standard.json` (rubric,
|
[MIT](LICENSE) © 2026 Xingyu Chen.
|
||||||
severities, coupling, and the issue tags with descriptions). Two ways to customize:
|
|
||||||
|
|
||||||
- **In the map**: open the **Standard** page (header button), click **Edit**, change any
|
---
|
||||||
description, add your own tags (`+ Tag`), then **Export** → save the downloaded
|
|
||||||
`standard.json` to `<project>/.codemap/standard.json`. Edits are kept in the
|
|
||||||
browser until you export. Custom tags flow through the whole map (cards, filters,
|
|
||||||
report) and are used by future audits.
|
|
||||||
- **By file**: copy `reference/standard.json` to `<project>/.codemap/standard.json`
|
|
||||||
and edit it. `render.py` prefers the project file over the skill default.
|
|
||||||
|
|
||||||
The prose version + the exact subagent audit prompt live in `reference/STANDARDS.md`
|
<sub>Keywords: code quality · technical debt · refactoring · code janitor · legacy code
|
||||||
(keep the two in sync when changing the shipped defaults).
|
cleanup · architecture visualization · dependency graph · static analysis · code audit ·
|
||||||
|
Claude Code skill · Codex · AI agents · spaghetti code · 屎山.</sub>
|
||||||
## "Fix this" buttons & automation
|
|
||||||
|
|
||||||
Each module's detail panel has a **Copy fix prompt** button — it copies `/codemap fix
|
|
||||||
<module>` to the clipboard for you to paste into Claude Code (or adapt for Codex). The
|
|
||||||
page intentionally does **not** auto-launch an agent: a generated static HTML has no
|
|
||||||
privileged channel to the Claude CLI/agent, and auto-launching the CLI is fragile and
|
|
||||||
increasingly restricted. Copy-to-clipboard is the robust, future-proof bridge.
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
- `modules.json` is meant to be **committed** with your project — it's the audit history
|
|
||||||
and what makes diffs/incrementality reviewable.
|
|
||||||
- The engine is **language-agnostic**: `paths` globs and LoC counting work for any stack;
|
|
||||||
the audit subagent reads whatever code the globs point at.
|
|
||||||
|
|||||||
@@ -12,15 +12,15 @@ description: >-
|
|||||||
"is the arch map current", "update the architecture diagram", "fix module X".
|
"is the arch map current", "update the architecture diagram", "fix module X".
|
||||||
---
|
---
|
||||||
|
|
||||||
# Architecture Audit & Map
|
# codemap — Architecture Map & Code-Quality Audit
|
||||||
|
|
||||||
Builds and maintains three coupled artifacts for a project:
|
Builds and maintains three coupled artifacts for a project:
|
||||||
|
|
||||||
1. **`modules.json`** — the source of truth: every *functional* module (not file) with
|
1. **`modules.json`** — the source of truth: every *functional* module (not file) with
|
||||||
its paths, dependencies, coupling, LoC, content hash, score, grade, tags, findings.
|
its paths, dependencies, coupling, LoC, content hash, score, grade, tags, findings.
|
||||||
2. **`architecture-map.html`** — a self-contained interactive map (layered modules,
|
2. **`codemap.html`** — a self-contained interactive map (layered modules,
|
||||||
dependency highlighting, health coloring, audit-report view).
|
dependency highlighting, health coloring, audit-report view).
|
||||||
3. **`architecture-audit.md`** — the written report (per-layer scores, per-module LoC
|
3. **`codemap.md`** — the written report (per-layer scores, per-module LoC
|
||||||
table, worst offenders, cross-cutting themes).
|
table, worst offenders, cross-cutting themes).
|
||||||
|
|
||||||
The HTML and MD are **always regenerated** from `modules.json` by `render.py`. Never
|
The HTML and MD are **always regenerated** from `modules.json` by `render.py`. Never
|
||||||
@@ -51,7 +51,7 @@ prompt) and `standard.json` (the machine copy) in sync if you change the default
|
|||||||
- `config.json` — the user's saved preferences (UI language, output location, title…).
|
- `config.json` — the user's saved preferences (UI language, output location, title…).
|
||||||
- `modules.json` — the state (source of truth).
|
- `modules.json` — the state (source of truth).
|
||||||
- `standard.json` — optional per-project custom audit standard.
|
- `standard.json` — optional per-project custom audit standard.
|
||||||
- `architecture-map.html` + `architecture-audit.md` — the generated outputs (default).
|
- `codemap.html` + `codemap.md` — the generated outputs (default).
|
||||||
|
|
||||||
The output location is a user preference: if they want the HTML/MD committed/visible,
|
The output location is a user preference: if they want the HTML/MD committed/visible,
|
||||||
let them point it at `docs/` instead (ask — see `generate` step 0). Set
|
let them point it at `docs/` instead (ask — see `generate` step 0). Set
|
||||||
@@ -129,7 +129,7 @@ Use when no `modules.json` exists yet (this is also "init").
|
|||||||
Write `config.json` like:
|
Write `config.json` like:
|
||||||
```json
|
```json
|
||||||
{"lang":"zh","project":"My App","subtitle":"…","outputDir":".codemap",
|
{"lang":"zh","project":"My App","subtitle":"…","outputDir":".codemap",
|
||||||
"htmlFile":"architecture-map.html","mdFile":"architecture-audit.md"}
|
"htmlFile":"codemap.html","mdFile":"codemap.md"}
|
||||||
```
|
```
|
||||||
and apply it to `meta` when you build `modules.json`. Re-read `config.json` on later
|
and apply it to `meta` when you build `modules.json`. Re-read `config.json` on later
|
||||||
runs so preferences persist.
|
runs so preferences persist.
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 445 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 453 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 487 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 554 KiB |
File diff suppressed because one or more lines are too long
@@ -0,0 +1,186 @@
|
|||||||
|
<!--
|
||||||
|
This file: .codemap/codemap.md (written report)
|
||||||
|
Interactive map: .codemap/codemap.html
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Acme Storefront — Functional Module Quality Audit
|
||||||
|
|
||||||
|
> **Interactive view:** [`.codemap/codemap.html`](codemap.html) — per-module scores, findings, LoC, and the dependency graph. This file is the written report.
|
||||||
|
|
||||||
|
**Generated:** 2026-01-01 · **Modules:** 49 · **Size:** ≈ 28,600 LoC · 214 files (sample)
|
||||||
|
|
||||||
|
## Health by layer
|
||||||
|
|
||||||
|
| Layer | Modules | Avg score |
|
||||||
|
|---|--:|--:|
|
||||||
|
| Frontend · Shell & Routing | 3 | 87 |
|
||||||
|
| Frontend · Pages | 7 | 73 |
|
||||||
|
| Frontend · State Stores | 6 | 79 |
|
||||||
|
| Frontend · Transport | 5 | 80 |
|
||||||
|
| Backend · API Routes | 6 | 77 |
|
||||||
|
| Backend · Services | 8 | 73 |
|
||||||
|
| Backend · Domain Core | 5 | 89 |
|
||||||
|
| Backend · Persistence | 3 | 82 |
|
||||||
|
| Backend · Workers & Jobs | 3 | 77 |
|
||||||
|
| Integrations | 3 | 74 |
|
||||||
|
|
||||||
|
## Per-module lines of code & score
|
||||||
|
|
||||||
|
_LoC is the representative file/folder per module; folder-level modules overlap and are not additive._
|
||||||
|
|
||||||
|
### Frontend · Shell & Routing
|
||||||
|
|
||||||
|
| Module | LoC | Score | Tags |
|
||||||
|
|---|--:|:--|:--|
|
||||||
|
| App Shell | 420 | 84 B | — |
|
||||||
|
| Navigation | 240 | 88 B | — |
|
||||||
|
| Router | 180 | 90 A | — |
|
||||||
|
|
||||||
|
### Frontend · Pages
|
||||||
|
|
||||||
|
| Module | LoC | Score | Tags |
|
||||||
|
|---|--:|:--|:--|
|
||||||
|
| Admin | 2,100 | 66 C | bloat, any-escape |
|
||||||
|
| Checkout | 1,860 | 58 D | god-component, dual-format, fallback |
|
||||||
|
| Cart | 1,420 | 70 C | god-component |
|
||||||
|
| Product | 1,240 | 72 C | bloat |
|
||||||
|
| Catalog | 980 | 78 B | — |
|
||||||
|
| Account | 760 | 82 B | — |
|
||||||
|
| Search | 540 | 84 B | — |
|
||||||
|
|
||||||
|
### Frontend · State Stores
|
||||||
|
|
||||||
|
| Module | LoC | Score | Tags |
|
||||||
|
|---|--:|:--|:--|
|
||||||
|
| checkoutStore | 480 | 62 C | dual-format, legacy |
|
||||||
|
| catalogStore | 410 | 86 B | — |
|
||||||
|
| cartStore | 360 | 74 C | duplication |
|
||||||
|
| authStore | 290 | 80 B | — |
|
||||||
|
| searchStore | 220 | 82 B | — |
|
||||||
|
| uiStore | 150 | 88 B | — |
|
||||||
|
|
||||||
|
### Frontend · Transport
|
||||||
|
|
||||||
|
| Module | LoC | Score | Tags |
|
||||||
|
|---|--:|:--|:--|
|
||||||
|
| apiClient | 690 | 68 C | glue, bloat |
|
||||||
|
| wsClient | 230 | 84 B | — |
|
||||||
|
| adminClient | 180 | 80 B | — |
|
||||||
|
| paymentsClient | 140 | 86 B | — |
|
||||||
|
| pricingClient | 110 | 84 B | — |
|
||||||
|
|
||||||
|
### Backend · API Routes
|
||||||
|
|
||||||
|
| Module | LoC | Score | Tags |
|
||||||
|
|---|--:|:--|:--|
|
||||||
|
| orders routes | 610 | 74 C | dual-format |
|
||||||
|
| API Gateway | 540 | 88 B | — |
|
||||||
|
| payments routes | 480 | 55 D | stub, fallback |
|
||||||
|
| auth routes | 420 | 78 B | silent-except |
|
||||||
|
| products routes | 360 | 84 B | — |
|
||||||
|
| search routes | 240 | 82 B | — |
|
||||||
|
|
||||||
|
### Backend · Services
|
||||||
|
|
||||||
|
| Module | LoC | Score | Tags |
|
||||||
|
|---|--:|:--|:--|
|
||||||
|
| OrderService | 1,480 | 64 C | duplication, bloat |
|
||||||
|
| PricingEngine | 880 | 70 C | over-fit |
|
||||||
|
| InventoryService | 540 | 78 B | — |
|
||||||
|
| AuthService | 520 | 80 B | — |
|
||||||
|
| SearchService | 470 | 76 B | fallback |
|
||||||
|
| CatalogService | 430 | 86 B | — |
|
||||||
|
| NotificationService | 300 | 84 B | — |
|
||||||
|
| PaymentService | 260 | 48 D | stub, fake-output |
|
||||||
|
|
||||||
|
### Backend · Domain Core
|
||||||
|
|
||||||
|
| Module | LoC | Score | Tags |
|
||||||
|
|---|--:|:--|:--|
|
||||||
|
| Order | 380 | 88 B | — |
|
||||||
|
| Product | 260 | 90 A | — |
|
||||||
|
| User | 210 | 88 B | — |
|
||||||
|
| Money | 120 | 92 A | — |
|
||||||
|
| TokenUtil | 90 | 86 B | — |
|
||||||
|
|
||||||
|
### Backend · Persistence
|
||||||
|
|
||||||
|
| Module | LoC | Score | Tags |
|
||||||
|
|---|--:|:--|:--|
|
||||||
|
| Repository | 640 | 72 C | duplication |
|
||||||
|
| Migrations | 220 | 85 B | — |
|
||||||
|
| DB Pool | 180 | 90 A | — |
|
||||||
|
|
||||||
|
### Backend · Workers & Jobs
|
||||||
|
|
||||||
|
| Module | LoC | Score | Tags |
|
||||||
|
|---|--:|:--|:--|
|
||||||
|
| WebhookDispatcher | 340 | 68 C | silent-except, legacy |
|
||||||
|
| EmailWorker | 260 | 80 B | — |
|
||||||
|
| Templates | 150 | 84 B | — |
|
||||||
|
|
||||||
|
### Integrations
|
||||||
|
|
||||||
|
| Module | LoC | Score | Tags |
|
||||||
|
|---|--:|:--|:--|
|
||||||
|
| Stripe Gateway | 280 | 78 B | — |
|
||||||
|
| Shipping Provider | 230 | 74 C | glue |
|
||||||
|
| Analytics | 190 | 70 C | silent-except |
|
||||||
|
|
||||||
|
## Worst offenders
|
||||||
|
|
||||||
|
- **PaymentService (48/D)** — services/payment.py:31: charge()/refund() return a canned `{status:'succeeded'}` — sandbox stub, no real gateway call.
|
||||||
|
- **payments routes (55/D)** — api/payments.py:44: webhook handler always returns 200 without verifying the signature (stub).
|
||||||
|
- **Checkout (58/D)** — src/pages/Checkout.tsx: 1860-line god-component mixing the address/shipping/payment steps, validation and direct API calls.
|
||||||
|
- **checkoutStore (62/C)** — src/stores/checkout.ts:40: reads both snake_case and camelCase address fields (dual-format).
|
||||||
|
- **OrderService (64/C)** — services/order.py: 1480-line service; the order state machine is duplicated between place() and fulfill().
|
||||||
|
- **Admin (66/C)** — src/pages/Admin.tsx: 2100-line page: reports, tables and editors all in one file.
|
||||||
|
- **apiClient (68/C)** — src/transport/apiClient.ts: ~50 one-line get/post wrappers that only forward args (glue) — generate or collapse to a typed client.
|
||||||
|
- **WebhookDispatcher (68/C)** — workers/webhooks.py:55: `except: pass` swallows delivery errors — failed webhooks vanish.
|
||||||
|
- **Cart (70/C)**
|
||||||
|
- **PricingEngine (70/C)** — services/pricing.py:120: discount rules hardcoded to the current promo set (over-fit).
|
||||||
|
|
||||||
|
## All findings
|
||||||
|
|
||||||
|
### HIGH (4)
|
||||||
|
|
||||||
|
- **Checkout** · `src/pages/Checkout.tsx` — 1860-line god-component mixing the address/shipping/payment steps, validation and direct API calls.
|
||||||
|
- **payments routes** · `api/payments.py:44` — webhook handler always returns 200 without verifying the signature (stub).
|
||||||
|
- **OrderService** · `services/order.py` — 1480-line service; the order state machine is duplicated between place() and fulfill().
|
||||||
|
- **PaymentService** · `services/payment.py:31` — charge()/refund() return a canned `{status:'succeeded'}` — sandbox stub, no real gateway call.
|
||||||
|
|
||||||
|
### MED (13)
|
||||||
|
|
||||||
|
- **Product** · `src/pages/Product.tsx` — 1240-line component: gallery, variant picker and reviews in one file.
|
||||||
|
- **Checkout** · `src/pages/Checkout.tsx:412` — reads both `postal_code` and `postalCode` from the address form (dual-format).
|
||||||
|
- **Admin** · `src/pages/Admin.tsx` — 2100-line page: reports, tables and editors all in one file.
|
||||||
|
- **cartStore** · `src/stores/cart.ts:90` — cart totals re-implemented here and in PricingEngine (duplication).
|
||||||
|
- **checkoutStore** · `src/stores/checkout.ts:40` — reads both snake_case and camelCase address fields (dual-format).
|
||||||
|
- **apiClient** · `src/transport/apiClient.ts` — ~50 one-line get/post wrappers that only forward args (glue) — generate or collapse to a typed client.
|
||||||
|
- **orders routes** · `api/orders.py:88` — accepts both the legacy and v2 cart payload shapes (dual-format).
|
||||||
|
- **payments routes** · `api/payments.py:70` — falls back to marking the order paid when the provider call times out.
|
||||||
|
- **OrderService** · `services/order.py:620` — inventory reservation logic copy-pasted from InventoryService.
|
||||||
|
- **PricingEngine** · `services/pricing.py:120` — discount rules hardcoded to the current promo set (over-fit).
|
||||||
|
- **PaymentService** · `services/payment.py:88` — 'TODO: wire the real provider before launch.'
|
||||||
|
- **Repository** · `data/repo.py` — per-entity CRUD copy-pasted across 9 repositories — extract a base.
|
||||||
|
- **WebhookDispatcher** · `workers/webhooks.py:55` — `except: pass` swallows delivery errors — failed webhooks vanish.
|
||||||
|
|
||||||
|
### LOW (9)
|
||||||
|
|
||||||
|
- **Checkout** · `src/pages/Checkout.tsx:980` — silent catch around the shipping-rate fetch falls back to a flat rate.
|
||||||
|
- **Admin** · `src/pages/Admin.tsx:300` — several `as any` casts around the chart library.
|
||||||
|
- **checkoutStore** · `src/stores/checkout.ts:8` — legacy single-step draft kept for old links.
|
||||||
|
- **apiClient** · `src/transport/apiClient.ts:1` — one 690-line file mixing transport with the whole endpoint surface.
|
||||||
|
- **auth routes** · `api/auth.py:140` — broad except around the OAuth token exchange logs but swallows the cause.
|
||||||
|
- **SearchService** · `services/search.py:80` — documented fallback to SQL LIKE when Elasticsearch is unreachable.
|
||||||
|
- **WebhookDispatcher** · `workers/webhooks.py:12` — legacy v1 payload path kept alongside v2.
|
||||||
|
- **Shipping Provider** · `integrations/shipping.py` — adapter forwards every field unchanged (glue).
|
||||||
|
- **Analytics** · `integrations/analytics.py:22` — fire-and-forget send swallows failures silently.
|
||||||
|
|
||||||
|
## Cross-cutting themes
|
||||||
|
|
||||||
|
- **Payments is the weakest area.** PaymentService and the payments routes are still sandbox stubs (fake-output / stub) — real provider integration is unfinished, yet it is already wired into checkout.
|
||||||
|
- **Checkout and Order carry the most debt.** checkout_page, cartStore and OrderService are god-components with duplicated state-machine logic; the multi-step checkout mixes UI, validation and API calls in one file.
|
||||||
|
- **Dual-format is creeping in at the order boundary.** orders routes, checkoutStore and the checkout page accept both legacy and v2 payload shapes — normalize once at the transport layer instead.
|
||||||
|
- **apiClient is mostly glue.** ~50 near-identical endpoint wrappers add no value; generate them or collapse to a single typed client.
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -15,8 +15,8 @@ subagents edit it) and re-render.
|
|||||||
"generatedAt": "2026-01-01",
|
"generatedAt": "2026-01-01",
|
||||||
"rev": "abc1234", // git HEAD at the last codemap run (the baseline
|
"rev": "abc1234", // git HEAD at the last codemap run (the baseline
|
||||||
// `update`/`check` diff from; set by scan.py --stamp-rev)
|
// `update`/`check` diff from; set by scan.py --stamp-rev)
|
||||||
"htmlPath": ".codemap/architecture-map.html", // output location (for reciprocal links)
|
"htmlPath": ".codemap/codemap.html", // output location (for reciprocal links)
|
||||||
"mdPath": ".codemap/architecture-audit.md",
|
"mdPath": ".codemap/codemap.md",
|
||||||
"spineDesc": "A user edits … → … → persistence.", // shown on the spine view
|
"spineDesc": "A user edits … → … → persistence.", // shown on the spine view
|
||||||
"tracked_loc": 184900, // filled by scan.py --write (union, de-duped)
|
"tracked_loc": 184900, // filled by scan.py --write (union, de-duped)
|
||||||
"tracked_files": 980,
|
"tracked_files": 980,
|
||||||
|
|||||||
+6
-6
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""render.py — regenerate architecture-map.html + architecture-audit.md from modules.json.
|
"""render.py — regenerate codemap.html + codemap.md from modules.json.
|
||||||
|
|
||||||
modules.json is the single source of truth. The HTML and MD are pure projections
|
modules.json is the single source of truth. The HTML and MD are pure projections
|
||||||
of it and must never be hand-edited. Run scan.py --write before rendering so LoC /
|
of it and must never be hand-edited. Run scan.py --write before rendering so LoC /
|
||||||
@@ -8,7 +8,7 @@ content hashes are current.
|
|||||||
Usage:
|
Usage:
|
||||||
python render.py --state modules.json \
|
python render.py --state modules.json \
|
||||||
--template assets/template.html \
|
--template assets/template.html \
|
||||||
--out-html architecture-map.html --out-md architecture-audit.md
|
--out-html codemap.html --out-md codemap.md
|
||||||
|
|
||||||
Stdlib only.
|
Stdlib only.
|
||||||
"""
|
"""
|
||||||
@@ -70,12 +70,12 @@ def render_md(state):
|
|||||||
out = []
|
out = []
|
||||||
proj = meta.get("project", "Project")
|
proj = meta.get("project", "Project")
|
||||||
out.append("<!--")
|
out.append("<!--")
|
||||||
out.append(f" This file: {meta.get('mdPath', 'architecture-audit.md')} (written report)")
|
out.append(f" This file: {meta.get('mdPath', 'codemap.md')} (written report)")
|
||||||
out.append(f" Interactive map: {meta.get('htmlPath', 'architecture-map.html')}")
|
out.append(f" Interactive map: {meta.get('htmlPath', 'codemap.html')}")
|
||||||
out.append("-->\n")
|
out.append("-->\n")
|
||||||
out.append(f"# {proj} — Functional Module Quality Audit\n")
|
out.append(f"# {proj} — Functional Module Quality Audit\n")
|
||||||
out.append(f"> **Interactive view:** [`{meta.get('htmlPath','architecture-map.html')}`]"
|
out.append(f"> **Interactive view:** [`{meta.get('htmlPath','codemap.html')}`]"
|
||||||
f"({os.path.basename(meta.get('htmlPath','architecture-map.html'))}) — "
|
f"({os.path.basename(meta.get('htmlPath','codemap.html'))}) — "
|
||||||
"per-module scores, findings, LoC, and the dependency graph. This file is the written report.\n")
|
"per-module scores, findings, LoC, and the dependency graph. This file is the written report.\n")
|
||||||
gen = meta.get("generatedAt", "")
|
gen = meta.get("generatedAt", "")
|
||||||
loc_line = meta.get("locLine") or (
|
loc_line = meta.get("locLine") or (
|
||||||
|
|||||||
Reference in New Issue
Block a user