Skip to content

Commit 47d9b86

Browse files
committed
Harden per review: HTML-escape all model-derived strings (no innerHTML XSS), strict apply_audit validation (score-grade match, tag whitelist, clean/findings rules), add tests/ + CI, tone down README + honest 'what it is/isn't', SKILL.md capability/fallback mapping
1 parent 1522b36 commit 47d9b86

7 files changed

Lines changed: 468 additions & 86 deletions

File tree

.github/workflows/test.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: tests
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
8+
jobs:
9+
test:
10+
strategy:
11+
fail-fast: false
12+
matrix:
13+
os: [ubuntu-latest, windows-latest]
14+
python: ["3.9", "3.12"]
15+
runs-on: ${{ matrix.os }}
16+
steps:
17+
- uses: actions/checkout@v4
18+
- uses: actions/setup-python@v5
19+
with:
20+
python-version: ${{ matrix.python }}
21+
22+
- name: Compile scripts (syntax)
23+
run: python -m py_compile scripts/scan.py scripts/query.py scripts/apply_audit.py scripts/render.py
24+
25+
- name: Unit + golden tests
26+
run: python -m unittest discover -s tests -v
27+
28+
- name: Render the sample project (smoke)
29+
run: >
30+
python scripts/render.py
31+
--state examples/sample-project/modules.json
32+
--template assets/template.html
33+
--out-html /tmp/codemap.html --out-md /tmp/codemap.md
34+
shell: bash
35+
36+
template-js:
37+
runs-on: ubuntu-latest
38+
steps:
39+
- uses: actions/checkout@v4
40+
- uses: actions/setup-node@v4
41+
with:
42+
node-version: "20"
43+
- name: Syntax-check the template's inline JS
44+
run: |
45+
python - <<'PY'
46+
import re
47+
html = open("assets/template.html", encoding="utf-8").read()
48+
m = re.search(r"<script>(.*)</script>", html, re.S)
49+
open("/tmp/_t.js", "w", encoding="utf-8").write(m.group(1).replace("__ARCH_DATA__", "{}"))
50+
PY
51+
node --check /tmp/_t.js

README.md

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ helps you **pay down the cruft** — incrementally, one commit at a time.
99
![Python 3 · stdlib only](https://img.shields.io/badge/python-3%20·%20stdlib%20only-3776ab)
1010
![language agnostic](https://img.shields.io/badge/langs-Py%20·%20TS%20·%20Rust%20·%20C%23%20·%20C%2B%2B-555)
1111
![license MIT](https://img.shields.io/badge/license-MIT-blue)
12+
[![tests](https://github.com/Asixa/codemap-skill/actions/workflows/test.yml/badge.svg)](https://github.com/Asixa/codemap-skill/actions/workflows/test.yml)
1213

1314
> Every codebase accumulates cruft over time — monkeypatches, silent fallbacks, dead
1415
> "legacy" paths, half-finished stubs, copy-pasted duplication, god-files, and valueless
1516
> glue. **codemap surfaces that rot, ranks it, and hands an AI agent a clear punch-list to
16-
> fix it** — with a regression-gated fix loop so the cleanup never breaks your build.
17+
> fix it** — with a regression-gated fix loop: a change is accepted only when an
18+
> independent check shows your tests still pass.
1719
1820
![architecture map](examples/01-map.png)
1921

@@ -63,12 +65,24 @@ Most "architecture diagram" tools draw *files and imports*. codemap is different
6365
- **Incremental + git-aware.** A per-module content hash + the last-run commit mean re-runs
6466
only re-audit what changed, and `update` shows you the **commits since last time** and
6567
which modules they touched.
66-
- **Cleanup that can't regress.** `fix` runs a four-role loop — lock a test baseline →
67-
fix → an **independent acceptance check** proves the pre-fix tests still pass → re-score.
68+
- **Regression-gated cleanup.** `fix` runs a four-role loop — lock a test baseline →
69+
fix → an **independent acceptance check** must show the pre-fix tests still pass → re-score.
6870

6971
It's the maintenance pass you never have time to do, turned into something an agent can
7072
run on a schedule.
7173

74+
> **What it is (and isn't).** codemap is an agent-orchestration framework that makes the
75+
> map + audit *consistent and reviewable* — deterministic scripts handle LoC, hashing,
76+
> staleness, filtering and rendering, and a fixed rubric forces `file:line` evidence and
77+
> an independent audit per module. But the **module decomposition and the scores are model
78+
> judgments**, not the output of a deterministic static analyzer. Treat the map as a
79+
> high-quality, reviewable starting point — and commit `modules.json` so every score is
80+
> diffable in PRs.
81+
82+
Want to see it before installing? Open
83+
**[`examples/sample-project/codemap.html`](examples/sample-project/codemap.html)** — a
84+
fully rendered demo (the sample used for the screenshots).
85+
7286
## Screenshots
7387

7488
**Click any module** to highlight what it calls (downstream) and what depends on it
@@ -155,11 +169,15 @@ codemap/
155169
scripts/ # deterministic, stdlib-only Python
156170
scan.py # LoC + content hash + git diff + staleness
157171
query.py # filter modules (grade/tag/severity/…) → ids/paths/findings
158-
apply_audit.py # merge one subagent's audit into the state
172+
apply_audit.py # validate + merge one subagent's audit into the state
159173
render.py # modules.json → HTML + report
160174
assets/
161175
template.html # the interactive map shell (data injected at render time)
162-
examples/ # the screenshots above
176+
tests/ # stdlib unittest golden tests for the scripts
177+
examples/
178+
01-map.png … # the screenshots above
179+
sample-project/ # a fully rendered demo (modules.json + codemap.html/md)
180+
.github/workflows/test.yml # CI: py_compile + unittest + render + JS syntax check
163181
```
164182

165183
## License

SKILL.md

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,10 @@ per-module subagent loop — never load the full `modules.json` just to pick tar
9191

9292
## Hard rules
9393

94-
1. **Every module score comes from an independent subagent.** One subagent audits one
94+
1. **Every module score comes from an independent sub-task.** One sub-task audits one
9595
module against its `paths`, using the prompt in `reference/STANDARDS.md`. Never score
96-
inline in the main thread; never copy one module's score to another. Spawn them in
97-
parallel (one message, multiple Agent calls — Explore or general-purpose).
96+
inline in the main thread; never copy one module's score to another. Run them in
97+
parallel where the platform supports it (see *Capabilities & platform mapping*).
9898
2. **Scripts are deterministic; only decomposition, auditing, and theme-synthesis are
9999
model work.** `scan.py` / `render.py` / `apply_audit.py` never make quality judgments.
100100
3. **`modules.json` is the only thing you edit by hand** (structure/decomposition).
@@ -111,14 +111,29 @@ per-module subagent loop — never load the full `modules.json` just to pick tar
111111
build/typecheck is clean. A fixer may not write/edit its own tests or grade its own
112112
work — that defeats the gate.
113113

114+
## Capabilities & platform mapping
115+
116+
This workflow needs three capabilities. Each has a graceful fallback, so it runs on any
117+
agent — only the convenience changes, never the rules above.
118+
119+
| Capability | Native (Claude Code) | Codex / Cursor | Fallback if unavailable |
120+
|---|---|---|---|
121+
| **Independent sub-tasks** (one auditor/fixer per module) | `Agent` tool, many in parallel | their subagent/task tool | Audit modules **one at a time in the main thread** — still one module per pass against the rubric, never batch-scoring. Slower, fully valid. |
122+
| **Structured result** (the audit JSON) | `schema` on the Agent call | tool-specific schema, or just ask for JSON | Ask the sub-task to return **only** the JSON object; `apply_audit.py` validates it and rejects malformed/inconsistent results — no schema feature required. |
123+
| **Ask the user** (preferences on `init`) | `AskUserQuestion` | tool's prompt UI | Ask in plain text, or apply defaults (`lang=en`, output `.codemap/`, title = repo folder name) and tell the user how to change them in `.codemap/config.json`. |
124+
125+
The non-negotiables (independent per-module audit, deterministic scripts, the four-role
126+
fix gate) hold on every platform; the table only changes *how* you spawn the work.
127+
114128
---
115129

116130
## Command: `init` (first build)
117131

118132
Use when no `modules.json` exists yet. (Also accepts `generate` as an alias.)
119133

120-
0. **Ask the user for preferences first** (use the AskUserQuestion tool), then save them to
121-
`<project>/.codemap/config.json`:
134+
0. **Ask the user for preferences first** (use `AskUserQuestion` if available, else just ask
135+
in plain text; or apply the defaults from *Capabilities & platform mapping*), then save
136+
them to `<project>/.codemap/config.json`:
122137
- **UI language**`en` or `zh` (localizes the map chrome + report; module names are
123138
never translated). → `meta.lang`.
124139
- **Output location** — where the HTML/MD go. Default `.codemap/` (kept with the tool

0 commit comments

Comments
 (0)