@ghostlygawd/codeweb 0.9.0

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.
Files changed (81) hide show
  1. package/.claude-plugin/plugin.json +30 -0
  2. package/CHANGELOG.md +480 -0
  3. package/LICENSE +21 -0
  4. package/README.md +573 -0
  5. package/agents/codeweb-dissector.md +56 -0
  6. package/agents/codeweb-domain-mapper.md +63 -0
  7. package/commands/codeweb.md +57 -0
  8. package/hooks/hooks.json +47 -0
  9. package/hooks/post-edit-diff.mjs +83 -0
  10. package/hooks/pre-edit-impact.mjs +94 -0
  11. package/hooks/session-brief.mjs +53 -0
  12. package/package.json +64 -0
  13. package/scripts/annotate.mjs +46 -0
  14. package/scripts/bench-ts-engine.mjs +59 -0
  15. package/scripts/bench.mjs +133 -0
  16. package/scripts/break-cycles.mjs +0 -0
  17. package/scripts/brief.mjs +28 -0
  18. package/scripts/build-report.mjs +182 -0
  19. package/scripts/campaign.mjs +61 -0
  20. package/scripts/check-consistency.mjs +45 -0
  21. package/scripts/ci-gate.mjs +86 -0
  22. package/scripts/cluster3.mjs +112 -0
  23. package/scripts/codemod.mjs +130 -0
  24. package/scripts/context-pack.mjs +118 -0
  25. package/scripts/deadcode.mjs +96 -0
  26. package/scripts/diff.mjs +0 -0
  27. package/scripts/explain.mjs +87 -0
  28. package/scripts/extract-symbols.mjs +1307 -0
  29. package/scripts/find-similar.mjs +86 -0
  30. package/scripts/find.mjs +50 -0
  31. package/scripts/fitness.mjs +90 -0
  32. package/scripts/grammars/PROVENANCE.md +36 -0
  33. package/scripts/grammars/tree-sitter-c-sharp.wasm +0 -0
  34. package/scripts/grammars/tree-sitter-go.wasm +0 -0
  35. package/scripts/grammars/tree-sitter-java.wasm +0 -0
  36. package/scripts/grammars/tree-sitter-python.wasm +0 -0
  37. package/scripts/grammars/tree-sitter-rust.wasm +0 -0
  38. package/scripts/grammars/tree-sitter-typescript.wasm +0 -0
  39. package/scripts/hotspots.mjs +53 -0
  40. package/scripts/lib/annotations.mjs +51 -0
  41. package/scripts/lib/bench-core.mjs +178 -0
  42. package/scripts/lib/brief-core.mjs +92 -0
  43. package/scripts/lib/campaign.mjs +73 -0
  44. package/scripts/lib/claims-check.mjs +44 -0
  45. package/scripts/lib/cli.mjs +140 -0
  46. package/scripts/lib/complexity.mjs +68 -0
  47. package/scripts/lib/dup-check.mjs +51 -0
  48. package/scripts/lib/find-core.mjs +85 -0
  49. package/scripts/lib/gate-md.mjs +50 -0
  50. package/scripts/lib/graph-ops.mjs +319 -0
  51. package/scripts/lib/hotspots.mjs +34 -0
  52. package/scripts/lib/query-core.mjs +85 -0
  53. package/scripts/lib/reading-order.mjs +53 -0
  54. package/scripts/lib/reliance.mjs +143 -0
  55. package/scripts/lib/risk.mjs +18 -0
  56. package/scripts/lib/shingles.mjs +39 -0
  57. package/scripts/lib/skeleton.mjs +41 -0
  58. package/scripts/lib/stats.mjs +92 -0
  59. package/scripts/lib/ts-engine.mjs +605 -0
  60. package/scripts/mcp-server.mjs +370 -0
  61. package/scripts/optimize.mjs +152 -0
  62. package/scripts/overlap.mjs +380 -0
  63. package/scripts/placement.mjs +93 -0
  64. package/scripts/query.mjs +94 -0
  65. package/scripts/reading-order.mjs +36 -0
  66. package/scripts/refresh.mjs +73 -0
  67. package/scripts/release-utils.mjs +158 -0
  68. package/scripts/release.mjs +62 -0
  69. package/scripts/report-template.html +730 -0
  70. package/scripts/review.mjs +112 -0
  71. package/scripts/risk.mjs +77 -0
  72. package/scripts/run.mjs +96 -0
  73. package/scripts/screenshot.mjs +104 -0
  74. package/scripts/simulate-edit.mjs +70 -0
  75. package/scripts/stats.mjs +31 -0
  76. package/scripts/trend.mjs +147 -0
  77. package/scripts/version-sync.mjs +19 -0
  78. package/skills/codebase-anatomy/SKILL.md +174 -0
  79. package/skills/codebase-anatomy/references/engine-detection.md +49 -0
  80. package/skills/codebase-anatomy/references/graph-schema.md +120 -0
  81. package/skills/codebase-anatomy/references/overlap-heuristics.md +52 -0
package/README.md ADDED
@@ -0,0 +1,573 @@
1
+ <div align="center">
2
+
3
+ <img src="assets/brand/hero.svg" alt="codeweb — the living map of your codebase" width="840">
4
+
5
+ [![Claude Code plugin](https://img.shields.io/badge/Claude_Code-plugin-c6f24e?style=flat-square)](#install)
6
+ [![zero dependencies](https://img.shields.io/badge/dependencies-zero-3fb950?style=flat-square)](#how-it-works)
7
+ [![deterministic engine](https://img.shields.io/badge/engine-deterministic-c6f24e?style=flat-square)](#how-it-works)
8
+ [![MCP server](https://img.shields.io/badge/MCP-server-a371f7?style=flat-square)](#use-it-as-an-mcp-tool)
9
+ [![version](https://img.shields.io/badge/version-0.9.0-c6f24e?style=flat-square)](CHANGELOG.md)
10
+ [![changelog](https://img.shields.io/badge/changelog-Keep_a_Changelog-ffb65c?style=flat-square)](CHANGELOG.md)
11
+
12
+ **Your coding agent greps. codeweb knows.**
13
+
14
+ Every serious change starts with the same questions: *who uses this? what breaks if I change it?
15
+ does this already exist? is this dead?* Today an agent answers them by grepping and reading whole
16
+ files — thousands of tokens per question, and it still guesses. codeweb maps the repo's call/import
17
+ graph once (~3 s for 3,000 symbols), then answers those questions **exactly, in milliseconds, for
18
+ about a kilobyte each** — as **24 deterministic MCP tools for your agent** (no LLM in the loop) and
19
+ a self-contained **interactive map for you**.
20
+
21
+ Measured on [vite](https://github.com/vitejs/vite) (3,000+ symbols), graded by the TypeScript
22
+ compiler as an independent referee ([`bench/results/oracle-ab.json`](bench/results/oracle-ab.json)):
23
+
24
+ | The question | codeweb | grep |
25
+ |---|---|---|
26
+ | *"Who depends on X?"* (30 symbols) | **100% of compiler-verified files, better precision than grep, 0.7 KB, one call** | 100% of files but 3× the tokens, as raw text lines the agent must still read |
27
+ | *"What breaks if I change X?"* | **one ~1 KB answer** | no transitive operator: ~5 recursive rounds, **126× the tokens** |
28
+ | *"Does this already exist? Is this dead? Did my edit break structure?"* | one call each (`find_similar` / `deadcode` / `diff` gate) | not answerable by search |
29
+
30
+ Don't take vite's word for it — **run the same referee on your own repo**:
31
+ `npm run bench -- <path>/.codeweb/graph.json` (context cost always; recall/precision graded by the
32
+ TypeScript compiler wherever `typescript` resolves — same engine as the published results).
33
+
34
+ In the frontier-agent A/B, the same channel lifted caller-discovery recall **+0.27** with
35
+ **~34% fewer tool calls and ~44% fewer tokens** than grep. And the byproduct is the part you can
36
+ see: the map also surfaces **duplication, dead code, hotspots, and tangled domains** — where your
37
+ codebase does the same work twice, which neither you nor the agent can see from inside a file.
38
+
39
+ **[Website](https://ghostlygawd.github.io/codeweb/)**&nbsp;·&nbsp;[See it in action](#see-it-in-action)&nbsp;·&nbsp;[Install](#install)&nbsp;·&nbsp;[Use](#use)&nbsp;·&nbsp;[For agents (MCP)](#use-it-as-an-mcp-tool)&nbsp;·&nbsp;[How it works](#how-it-works)&nbsp;·&nbsp;[Changelog](CHANGELOG.md)
40
+
41
+ </div>
42
+
43
+ ---
44
+
45
+ ## See it in action
46
+
47
+ One command runs the whole deterministic pipeline and drops an interactive map at
48
+ `<target>/.codeweb/report.html`. **Every screenshot below is that actual generated report**, codeweb
49
+ pointed read-only at **[axios](https://github.com/axios/axios)** — 334 product symbols across 11
50
+ areas (tests and tooling hidden by default). No mockups; regenerate them any time with
51
+ `node scripts/screenshot.mjs`.
52
+
53
+ > **▶ Read the full [axios case study](docs/case-study-axios.md):** on a library downloaded ~50M
54
+ > times a week, codeweb body-confirmed **3 real duplications** (two byte-identical across files),
55
+ > dismissed 12 false positives, and produced a cycle-safe merge plan for each. Or **[click around
56
+ > this exact map yourself](https://ghostlygawd.github.io/codeweb/demo/)** — it's live on GitHub Pages.
57
+
58
+ ### Know what an edit breaks — before you write
59
+
60
+ That's the whole point. Ask *if I change this function, what else moves?* — and codeweb answers from
61
+ structure, not a guess. Click any node in the [living map](https://ghostlygawd.github.io/codeweb/) and
62
+ its **blast radius** lights up: every function transitively affected, and the domains it crosses. It's
63
+ the `codeweb_impact` tool — the same answer an agent gets over MCP, before it writes a line.
64
+
65
+ <div align="center">
66
+ <img src="assets/screens/06-blast-radius.png" alt="codeweb blast radius: AxiosError selected in the axios graph — its area expanded in place, 58 users listed in the inspector, cross-area dependencies lit, neighboring areas highlighted" width="760">
67
+ <br><sub>Selecting <code>AxiosError</code> in axios lights up its <b>58 users across the areas that depend on it</b> — try it yourself in the <a href="https://ghostlygawd.github.io/codeweb/">living map</a>.</sub>
68
+ </div>
69
+
70
+ ### Navigate the whole system
71
+
72
+ A force-directed map of every symbol, collapsible to domains. Search, drag, zoom, and click any
73
+ node to trace what depends on it and what it reaches.
74
+
75
+ <img src="assets/screens/05-axios-graph.png" alt="codeweb Graph tab on axios: a force-directed domain map (adapters, helpers, core, cancel, defaults, platform) on a dark canvas" width="100%">
76
+
77
+ ### Findings — stop guessing what to refactor
78
+
79
+ Ranked **duplication** (the same function defined across many files), the most depended-on
80
+ **hotspots** to change with care, and likely-**dead code** — every row clickable to inspect what
81
+ calls it and what it calls.
82
+
83
+ <img src="assets/screens/05-axios-findings.png" alt="codeweb Findings tab on axios: ranked duplication, hotspots, and likely-dead code, with a clickable detail panel" width="100%">
84
+
85
+ ### See duplication density, and where areas tangle
86
+
87
+ <table>
88
+ <tr>
89
+ <td width="50%" valign="top">
90
+ <img src="assets/screens/05-axios-treemap.png" alt="codeweb Treemap on axios: every file sized by lines of code, duplication density carried by a slate-to-red lightness ramp">
91
+ <br><b>Treemap</b> — every file sized by lines of code; the brighter red a block, the more of it
92
+ is duplicated. The bright blocks are your consolidation targets, at a glance.
93
+ </td>
94
+ <td width="50%" valign="top">
95
+ <img src="assets/screens/05-axios-matrix.png" alt="codeweb Matrix on axios: a heatmap of call coupling between domains">
96
+ <br><b>Matrix</b> — area-to-area coupling. A big off-diagonal cell means two areas are tangled:
97
+ merge them, or put a clean interface between them.
98
+ </td>
99
+ </tr>
100
+ </table>
101
+
102
+ <div align="center">
103
+ <img src="assets/brand/demo.svg" alt="The codeweb pipeline: extract → cluster → overlap → render, looping" width="840">
104
+ <br><sub>The deterministic pipeline, looping: extract → cluster → overlap → render.</sub>
105
+ </div>
106
+
107
+ ---
108
+
109
+ codeweb is the missing **atomic-analysis + overlap-detective** layer. Where `repo-scan`
110
+ classifies *files* and flags duplicate *modules*, and `codebase-onboarding` writes high-level
111
+ architecture docs, codeweb works at **symbol resolution**: functions, classes, and methods, the
112
+ call/import edges between them, the semantic domain each belongs to, and the cross-domain
113
+ overlap graph.
114
+
115
+ ## Proven effective — measured, not just claimed
116
+
117
+ We didn't only assert codeweb works; we **pre-registered hypotheses and measured it**, applying the
118
+ same rigor codeweb brings to code: independent oracles, a pinned cross-language corpus, confidence
119
+ intervals, and adversarial review. **32 of 33 pre-registered checks pass** — and the testing was
120
+ rigorous enough to **find and fix two real bugs** the engine's own 286-test suite had missed.
121
+
122
+ - **Correctness held against independent oracles** — **zero observed disagreements across >490,000
123
+ comparisons** (cycles, impact, callers/callees, context-pack); 0 violations over 20,000 edit-safety trials.
124
+ - **Detection is accurate** — exact-clone **F1 1.0** (vs 0.67 name-match), renamed-clone recall **1.0
125
+ structural vs 0.0 lexical**, reuse-ranking **MRR 0.99**.
126
+ - **It scales** — runtime grows **sub-quadratically** (sub-linear in this corpus, b=0.33); structural
127
+ queries answer in **~95–120 ms** on a 3,201-symbol graph; zero runtime dependencies.
128
+ - **It's honest** — the one pass/fail miss (incremental speedup at high churn) is reported as a measured
129
+ curve; the agent A/B capstone returned a null (no headroom on clean tasks) and says so plainly.
130
+ - **And it measurably helps a frontier agent** — a post-hoc discovery pilot (Theme-5b, §3.8) found codeweb
131
+ lifts a frontier agent's caller-discovery **recall +0.27** while using **~34% fewer tool-calls** and
132
+ **~44% fewer tokens** than grep (all 8 engine-frozen reps positive); the harder edit-quality capstone
133
+ stays an honest null.
134
+
135
+ > **▶ Every number above is a receipt — see the [evidence ledger](https://ghostlygawd.github.io/codeweb/research.html).**
136
+ > The benchmark harnesses and raw results live in [`bench/`](bench/); every number regenerates with
137
+ > `node bench/run-all.mjs`, and `npm run bench:all -- --gate` re-measures the standing budgets
138
+ > **in CI on every PR** — a change that breaks a published number fails the build
139
+ > ([`bench/budgets.json`](bench/budgets.json) is the promise ledger). (The retired manuscript and
140
+ > pre-registration remain in git history, last at `v0.8.0`.)
141
+
142
+ And the value codeweb delivers during real work is counted where it accrues — the strictly-local
143
+ outcome ledger (`npm run stats`, surfaced in every session brief) prints a receipt shaped like:
144
+
145
+ ```
146
+ codeweb this month: 41 pre-edit card(s) · 5 card-named caller(s) followed · 2 regression(s) flagged · 120 queries served
147
+ ```
148
+
149
+ ## Two modes
150
+
151
+ - **Internal** — map your own codebase and find consolidation opportunities to restructure.
152
+ - **External** — clone a third-party repo *read-only* (e.g. a Claude Code plugin you found on
153
+ GitHub), fully map it, and get an adoption review before you commit to using it. codeweb
154
+ never executes target code.
155
+
156
+ ## Install
157
+
158
+ This is a self-contained Claude Code plugin — zero npm dependencies, just Node.js.
159
+
160
+ **As a Claude Code plugin:**
161
+ ```
162
+ /plugin marketplace add GhostlyGawd/codeweb
163
+ /plugin install codeweb
164
+ ```
165
+ Then restart Claude Code so the `/codeweb` command, agents, and skill register.
166
+
167
+ **Or run the engine directly — no plugin, no install:**
168
+ ```
169
+ git clone https://github.com/GhostlyGawd/codeweb.git
170
+ node codeweb/scripts/run.mjs /path/to/your/project --out-dir /path/to/your/project/.codeweb
171
+ # then open /path/to/your/project/.codeweb/report.html
172
+ ```
173
+
174
+ Requires Node.js — the whole deterministic pipeline (extract → cluster → overlap → render) runs
175
+ on Node, no external dependencies. Static-analysis tools (universal-ctags, ripgrep, madge, etc.)
176
+ are *optional* — they only sharpen the agent fallback path; the default engine reads the code
177
+ directly.
178
+
179
+ **In your editor:** [`editor/vscode-codeweb`](editor/vscode-codeweb/) is a zero-dependency VS Code
180
+ extension that shows **`N callers · blast M`** CodeLens above every mapped symbol (served from the
181
+ nearest `.codeweb/graph.json`, same numbers as `codeweb_callers`/`codeweb_impact`), with
182
+ click-through into the interactive report.
183
+
184
+ ## Use
185
+
186
+ ```
187
+ /codeweb # map the current project
188
+ /codeweb src/payments --depth symbol # deep-dive one subsystem
189
+ /codeweb https://github.com/owner/repo # external review before adopting
190
+ /codeweb owner/repo --open # clone, map, and open the report
191
+ ```
192
+
193
+ Flags: `--depth module|symbol|auto`, `--engine hybrid|read|tools`, `--focus <glob>`,
194
+ `--mode internal|external`, `--open`. See `commands/codeweb.md`.
195
+
196
+ ## Outputs (under `<target>/.codeweb/`)
197
+
198
+ | File | What it is |
199
+ |---|---|
200
+ | `graph.json` | The machine-readable web: `nodes`, `edges`, `domains`, `overlaps`, plus `meta` (target root, engine, languages, stats). |
201
+ | `report.html` | Self-contained interactive map — force-directed graph, domain tree, clickable node details, ranked overlap tab. No network/CDN required. |
202
+ | `report.md` | The same map as plain markdown — domains, top nodes, ranked overlaps. |
203
+ | `overlap.md` | The ranked consolidation opportunities in plain markdown. |
204
+ | `optimize.md` | The consolidation advisory — duplicate-logic findings tiered **ready / blocked / review**, each pre-flighted against the gate's cycle check (the `optimize.mjs` report). |
205
+ | `fragment.json` | The raw extractor output (atomic nodes + edges) before clustering — the pipeline's first stage. |
206
+
207
+ ## Query the graph (for agents & humans)
208
+
209
+ Once `graph.json` exists, `scripts/query.mjs` answers the structural questions an agent needs
210
+ before it edits — read-only, deterministic, no LLM in the loop:
211
+
212
+ ```
213
+ node scripts/query.mjs <graph.json> --impact <symbol> # blast radius: transitive callers + domains touched
214
+ node scripts/query.mjs <graph.json> --callers <symbol> # direct callers
215
+ node scripts/query.mjs <graph.json> --callees <symbol> # direct callees
216
+ node scripts/query.mjs <graph.json> --cycles # file-level dependency cycles (SCCs)
217
+ node scripts/query.mjs <graph.json> --orphans # uncalled & unexported (dead-code candidates)
218
+ ```
219
+
220
+ `<symbol>` is a node id (`file:label`) or a bare label (a label matching several nodes operates on
221
+ the union, reported in `matched`). Add `--json` for stable, machine-readable output. Exit codes:
222
+ `0` success (even when empty), `1` symbol not found, `2` usage/IO error. Example — *"what could I
223
+ break if I change the state store?"*:
224
+
225
+ ```
226
+ $ node scripts/query.mjs .codeweb/graph.json --impact lib/state-store/index.js:get
227
+ impact of lib/state-store/index.js:get: 120 functions across 12 domains
228
+ ```
229
+
230
+ > `--orphans` is a *candidate* list: extraction deliberately drops ambiguous call edges (precision
231
+ > over recall), so genuinely-called functions and entrypoints can surface — cross-check before deleting.
232
+
233
+ ## Guard agent edits (`diff`)
234
+
235
+ `scripts/diff.mjs` compares two `graph.json` snapshots (before vs after an edit) and flags
236
+ structural **regressions**, so it can run as a PostToolUse hook or CI gate:
237
+
238
+ ```
239
+ node scripts/diff.mjs <before.json> <after.json> [--json]
240
+ ```
241
+
242
+ It reports nodes/edges/overlaps/cycles/orphans added & removed plus the cross-domain coupling
243
+ delta, and **exits 1** (listing `regressions`) when an edit introduces a new dependency cycle, a
244
+ new duplication finding, or makes an existing symbol lose all its callers. It **exits 0** for pure
245
+ removals — deleting code/cycles/dups is an improvement, not a regression — and a brand-new uncalled
246
+ node is reported but does not trip the gate (agents add functions before wiring them).
247
+
248
+ ## Gate every PR (GitHub Action)
249
+
250
+ `scripts/ci-gate.mjs` turns the `diff` gate into CI: it builds the graph for the PR base and head and
251
+ **fails the build on a structural regression** (a new cycle, a new duplication, or a symbol that
252
+ loses all its callers). Drop it into any repo (full spec: [`docs/ci-gate.md`](docs/ci-gate.md)):
253
+
254
+ ```yaml
255
+ # .github/workflows/codeweb-gate.yml
256
+ on: pull_request
257
+ jobs:
258
+ gate:
259
+ runs-on: ubuntu-latest
260
+ steps:
261
+ - uses: actions/checkout@v4
262
+ with: { fetch-depth: 0 } # required — the gate diffs against the PR base
263
+ - uses: GhostlyGawd/codeweb/.github/actions/codeweb-gate@main
264
+ with: { target: src }
265
+ ```
266
+
267
+ Locally: `node scripts/ci-gate.mjs --base <ref> [--target <subdir>]`. Pure removals never trip the
268
+ gate; a brand-new uncalled function is reported but doesn't fail the build.
269
+
270
+ ## Advise consolidations (`optimize.mjs`)
271
+
272
+ Where `diff.mjs` *gates* (pass/fail on an edit), `optimize.mjs` *advises*: it reads a graph's
273
+ body-confirmed `overlaps[]` and ranks the `duplicate-logic` findings into consolidation
274
+ opportunities, **pre-flighting each proposed merge against the gate's own cycle check** — without
275
+ editing a line of source.
276
+
277
+ ```
278
+ node scripts/optimize.mjs <graph.json> [--json] # or set CODEWEB_WS
279
+ ```
280
+
281
+ Each opportunity is tiered: **ready** (body-confirmed ≥60%, not drifted, and the simulated merge
282
+ stays acyclic → the gate would pass, duplication −1), **blocked** (the naive merge would introduce a
283
+ new file cycle → the gate would reject it; needs a neutral home), or **review** (drifted copies,
284
+ merely-structural confidence, or non-`duplicate-logic` findings — human/agent judgement required).
285
+ Low/refuted findings are excluded outright. It picks a canonical survivor (most-called, tie-broken by
286
+ LOC then id) and reports the copies removed, callers rewired, blast radius, and LOC reclaimed. It is
287
+ **advisory only** — it never writes code and never exits non-zero on a clean read; the merge stays a
288
+ human + gate decision.
289
+
290
+ ## Track duplication over time (`trend.mjs`)
291
+
292
+ A one-shot map tells you where you are; `trend.mjs` tells you which way you're heading — is the
293
+ codebase consolidating or sprawling? It charts **body-confirmed duplication** and **cross-domain
294
+ coupling** across snapshots, with a sparkline and a rising/falling verdict:
295
+
296
+ ```
297
+ node scripts/trend.mjs --git <repo> --last 10 [--focus <subdir>] [--json] # snapshot the last N commits
298
+ node scripts/trend.mjs a.json b.json c.json [--labels …] [--json] # or chart pre-built snapshots
299
+ ```
300
+
301
+ The `--git` mode checks out each of the last N commits into an **ephemeral worktree** (read-only
302
+ over your working tree), runs the deterministic pipeline, and records the metrics — so you can watch
303
+ duplication trend down as you consolidate, or catch it creeping up in review.
304
+
305
+ ## Find the hotspots — where to refactor first (`hotspots.mjs`)
306
+
307
+ In a large repo the first question is *where do I even start?* `hotspots.mjs` answers it with the
308
+ **complexity × fan-in × churn** model — the riskiest, most-depended-on, most-churned symbols rank
309
+ first. Cyclomatic complexity and max nesting depth are computed during the body scan (every
310
+ `function`/`method` node carries `complexity` and `maxDepth`), so this needs no extra tooling; churn
311
+ is optional (`--git`, or `--churn <map.json>`).
312
+
313
+ ```
314
+ $ node scripts/hotspots.mjs <graph.json>
315
+ codeweb hotspots: axios/lib — 253 symbol(s) ranked by complexity x fan-in x churn
316
+ weights: complexity 0.5, fanIn 0.3, churn 0.2
317
+ 0.533 adapters/fetch.js:factory [cx 147 in 1 churn 0]
318
+ 0.347 adapters/http.js:httpAdapter [cx 102 in 0 churn 0]
319
+ 0.312 core/mergeConfig.js:mergeConfig [cx 33 in 6 churn 0]
320
+ 0.270 helpers/toFormData.js:toFormData [cx 50 in 3 churn 0]
321
+ ```
322
+
323
+ Every row shows its raw components, so the ranking is auditable rather than a black box. Add `--json`
324
+ for machine output; also surfaced as the `codeweb_hotspots` MCP tool.
325
+
326
+ ## Plan a whole optimization campaign (`campaign.mjs`)
327
+
328
+ `optimize` (ready merges), `deadcode` (safe deletes), and `break-cycles` (verified cuts) are three
329
+ separate advisors. `campaign.mjs` composes them into **one ordered, individually-gated, ROI-ranked
330
+ worklist** with cumulative projected deltas — "auto-optimize this codebase, at any scale." Crucially,
331
+ every step is pre-flighted so that applying the steps **in order** never introduces a cycle that
332
+ wasn't there before: a safe campaign is safe as a *sequence*, not merely per step. It is a read-only
333
+ plan — codeweb never writes source; the agent (+ the gate) executes each step.
334
+
335
+ ```
336
+ $ node scripts/campaign.mjs <graph.json>
337
+ codeweb campaign: axios/lib — 80 step(s): 2 cut, 77 delete, 1 merge
338
+ projected: -12 LOC, 2 cycle(s) broken (all steps stay gate-green in order)
339
+ [DELETE] adapters/fetch.js:duplex (roi 0; +0 LOC, +0 cycle; cumulative -0 LOC)
340
+ …each of 80 steps tagged [CUT|DELETE|MERGE] with its own gate verdict + cumulative delta
341
+ ```
342
+
343
+ `--budget N` keeps the top-N ROI prefix; `--json` emits per-step `{op, gate:{ok}, delta, cumulative,
344
+ roi}`. Also surfaced as `codeweb_campaign`.
345
+
346
+ ## Onboard in dependency order (`reading-order.mjs`)
347
+
348
+ To understand a codebase — or one domain — fast, `reading-order.mjs` emits a **foundations-first**
349
+ reading path: the depended-upon leaves before the orchestrators that call them, bounded to a budget.
350
+ A curated tour instead of blind grep.
351
+
352
+ ```
353
+ $ node scripts/reading-order.mjs <graph.json> --budget 6
354
+ codeweb reading-order: 6 symbol(s) — read top-down (foundations first):
355
+ 1. core/AxiosError.js:AxiosError
356
+ foundation — 18 in-scope caller(s)
357
+ 2. cancel/CanceledError.js:CanceledError
358
+ foundation — 5 in-scope caller(s)
359
+
360
+ ```
361
+
362
+ Scope it with `--scope domain|file|symbol <value>`; cycles degrade gracefully (members ordered by
363
+ fan-in, never a crash). Deterministic and read-only; also the `codeweb_reading_order` MCP tool.
364
+
365
+ ## Agent tools — context & pre-flight (`context-pack`, `simulate-edit`)
366
+
367
+ Two read-only tools that move work off the LLM and into the graph (full spec:
368
+ [`docs/agent-tools.md`](docs/agent-tools.md)):
369
+
370
+ ```
371
+ node scripts/context-pack.mjs <graph.json> <symbol> [--json] # minimal context to edit <symbol>
372
+ node scripts/simulate-edit.mjs <graph.json> --delete <sym> | --merge <a,b> [--into <id>] | --move <sym> --to <file>
373
+ ```
374
+
375
+ `context-pack` returns the **blast-radius-scoped** context for a symbol — its body, the direct
376
+ callers (call sites, with body), the direct callees (location-only), and the transitive impact set
377
+ (ids only) — so an agent edits with a small window instead of reading whole files. `simulate-edit`
378
+ predicts the regression gate's **structural verdict** (`{newCycles, lostCallers, ok}`) for a
379
+ hypothetical delete/merge/move **without performing it**, so doomed edits are discarded cheaply. Both
380
+ share the pure `applyEdit` primitive in `graph-ops.mjs` with `optimize.mjs` (one truth), and are
381
+ covered by property tests that pin the tool's output to an independent oracle.
382
+
383
+ ## Agent capability suite (write · review · optimize)
384
+
385
+ A set of read-only, deterministic tools that make an agent better at the three jobs — each pinned by
386
+ property tests against an independent oracle (full spec: [`docs/agent-tools-v2.md`](docs/agent-tools-v2.md)):
387
+
388
+ | Tool | Job | What it answers |
389
+ |---|---|---|
390
+ | `find-similar.mjs <graph> --body/--stdin/--signature [--structural]` | **write** | "Does code like this already exist?" — ranks existing bodies by token-shingle similarity (or, with `--structural`, by identifier-normalized *skeleton* similarity, catching renamed/Type-2 clones), so the agent reuses instead of re-implementing. |
391
+ | `placement.mjs <graph> --calls <ids>` | **write** | Where a new symbol belongs (domain + file by callee gravity) and whether it duplicates something. |
392
+ | `query.mjs <graph> --tests <symbol>` | **write** | The tests that exercise a symbol — run the right subset after an edit. |
393
+ | `review.mjs <graph> --changed <files> [--before g] [--gate]` | **review** | Maps a change to its changed symbols, blast radius, domains, and a fan-in-ranked review order; structural regression gate. |
394
+ | `fitness.mjs <graph> --rules codeweb.rules.json` | **review** | Checks architectural invariants (forbidden deps, layering, no-cycles, fan-in/loc caps); fails on violation. |
395
+ | `risk.mjs <graph> [--changed] [--churn/--git]` | **review** | Ranks symbols by change-risk (fan-in × fan-out × loc × blast × churn) for triage. |
396
+ | `codemod.mjs <graph> --merge <ids> --into <id> [--write]` | **optimize** | Plans a consolidation merge (deletions + caller rewrites + projected gate); `--write` applies it, gated + reversible. |
397
+ | `break-cycles.mjs <graph>` | **optimize** | For each dependency cycle, the cheapest edge to sever — *verified* to break it. |
398
+ | `deadcode.mjs <graph>` | **optimize** | Tiers orphans into safe-to-delete vs review-first (test-guarded / entrypoint-like). |
399
+ | `annotate.mjs --suppress <fingerprint> [--note …]` | **review** | Records a false-positive suppression in `.codeweb/annotations.json` (never touches source); `overlap`/`deadcode` then hide that finding and report a `suppressedCount`. Fingerprints are identity-based, so a genuinely *new* issue can't hide behind an old suppression. |
400
+
401
+ Plus **graph freshness**: `extract-symbols.mjs --cache <path>` re-scans only changed files **and
402
+ reuses per-file edges** (incremental edge derivation, guarded by a global symbol-set signature;
403
+ `--full` forces a from-scratch rebuild that is byte-identical to the incremental one), and
404
+ `refresh.mjs <graph>` re-extracts a graph's nodes+edges from disk so mid-edit queries stay accurate.
405
+ Nodes now carry a `signature` (params/returns) and, for functions/methods, `complexity` + `maxDepth`;
406
+ edges from test files are a distinct `test` kind (so production `--callers` exclude tests). All of the
407
+ above are also exposed over MCP (below).
408
+
409
+ ## Use it as an MCP tool
410
+
411
+ `scripts/mcp-server.mjs` is a zero-dependency MCP (Model Context Protocol) stdio server exposing all
412
+ **24** of codeweb's queries + the capability suite as tools any MCP client can call mid-task:
413
+ `codeweb_map` (build/rebuild the graph over MCP), `codeweb_brief` (the day-one repo page —
414
+ call it first), `codeweb_find` (concept search — free text like
415
+ *"retry backoff"* ranked into starting symbols, no name needed), `codeweb_callers/callees/impact/
416
+ cycles/orphans/diff`, the edit-loop tools `codeweb_context/refresh`, the intelligence tools
417
+ `codeweb_hotspots/campaign/reading_order`, plus `codeweb_tests/find_similar/placement/review/
418
+ fitness/risk/break_cycles/deadcode/codemod` (the last is plan-only — `--write` is not exposed).
419
+
420
+ **Installing the plugin registers the server automatically** (`.claude-plugin/plugin.json` carries
421
+ the `mcpServers` entry). Standalone — without the plugin — register it yourself:
422
+
423
+ ```
424
+ claude mcp add codeweb -- node /abs/path/to/codeweb/scripts/mcp-server.mjs
425
+ ```
426
+
427
+ or in an `.mcp.json`:
428
+
429
+ ```json
430
+ { "mcpServers": { "codeweb": { "command": "node", "args": ["/abs/path/to/codeweb/scripts/mcp-server.mjs"] } } }
431
+ ```
432
+
433
+ Built for agents, not just reachable by them:
434
+
435
+ - **`graph` is optional everywhere** — the server resolves the nearest `.codeweb/graph.json` above
436
+ its cwd (or `CODEWEB_WS`). No graph yet? The error names `codeweb_map`, which builds one (~3s for
437
+ a 3k-symbol repo) without leaving MCP.
438
+ - **Budgeted responses by default** — list-heavy tools answer with a one-line `summary`, the top-N
439
+ most relevant items, TRUE totals, and an explicit `more.remaining`; `full: true` (or
440
+ `limit`/`offset`) overrides. A `codeweb_context` that used to weigh ~300KB on a busy symbol now
441
+ answers in ~10KB of call-site windows.
442
+ - **Staleness awareness** — when the graph no longer matches disk, query results say so and point
443
+ at `codeweb_refresh`.
444
+ - The handshake carries `instructions` teaching the loop: *context → edit → refresh → diff-gate*.
445
+
446
+ ## How it works
447
+
448
+ For JavaScript, TypeScript, Python, Rust, Go, Java, C#, Ruby, PHP, Kotlin, and Swift the default is a **deterministic Node pipeline** — one
449
+ command, no LLM in the loop, reproducible byte-for-byte. `scripts/run.mjs` chains five stages
450
+ into a per-target workspace:
451
+
452
+ <div align="center">
453
+ <img src="assets/brand/pipeline.svg" alt="codeweb's four deterministic stages: extract, cluster, overlap, render" width="100%">
454
+ </div>
455
+
456
+ 1. **Extract** (`extract-symbols.mjs`) — parse every source file into atomic nodes (functions,
457
+ classes, methods) and call/import edges. Unresolved bare calls only wire to a global
458
+ definition when the name is unambiguous; multi-def names drop the edge rather than fabricate a
459
+ false hub. Each function/method node also gets a `signature`, cyclomatic `complexity`, and
460
+ `maxDepth`; edges are cached per file (incremental, byte-identical to a full rebuild) so refreshes scale.
461
+ 2. **Cluster** (`cluster3.mjs`) — strip genuine utility hubs, then group nodes into
462
+ directory-anchored semantic domains.
463
+ 3. **Overlap** (`overlap.mjs`) — detect duplicated logic and parallel implementations, then
464
+ confirm each candidate against the real function bodies (token-shingle similarity) so findings
465
+ are body-backed, not name coincidences. A structural pass over identifier-normalized *skeletons*
466
+ also catches renamed (Type-2) clones (`find-similar --structural`).
467
+ 4. **Render** (`build-report.mjs`) — turn `graph.json` into the self-contained `report.html`
468
+ (and `report.md`).
469
+
470
+ For languages the extractor can't parse (or with `--engine read`), codeweb **falls back** to the
471
+ agent path: parallel `codeweb-dissector` agents extract nodes + edges per subsystem, the
472
+ fragments merge into one graph by node id, and `codeweb-domain-mapper` tags domains and detects
473
+ overlaps. Both paths emit the same `graph.json` schema, so clustering, overlap, and rendering are
474
+ shared. In **external** mode, either path appends an adoption verdict (risk, deps, architecture).
475
+
476
+ ## Components
477
+
478
+ ```
479
+ codeweb/
480
+ ├── .claude-plugin/plugin.json
481
+ ├── commands/codeweb.md # /codeweb trigger
482
+ ├── scripts/ # the deterministic engine (default fast path)
483
+ │ ├── run.mjs # orchestrator — one command, runs all stages per target
484
+ │ ├── extract-symbols.mjs # stage 1: source -> atomic nodes + edges (JS/TS/Python/Rust/Go)
485
+ │ ├── cluster3.mjs # stage 2: hub-strip + directory-anchored domains
486
+ │ ├── overlap.mjs # stage 3: body-confirmed duplication/overlap detection
487
+ │ ├── build-report.mjs # stage 4: graph.json -> interactive report.html + report.md
488
+ │ ├── report-template.html # the renderer's self-contained HTML shell
489
+ │ ├── query.mjs # structural queries (callers/callees/tests/impact/cycles/orphans)
490
+ │ ├── diff.mjs # graph-delta / post-edit regression gate (before vs after)
491
+ │ ├── trend.mjs # duplication + coupling over snapshots / git history (dashboard)
492
+ │ ├── ci-gate.mjs # CI gate: before(base)-vs-after(working tree) diff, exits 1 on regression
493
+ │ ├── optimize.mjs # advise: rank body-confirmed dups into gated consolidation opportunities
494
+ │ ├── context-pack.mjs # agent context: blast-radius-scoped window to edit a symbol
495
+ │ ├── simulate-edit.mjs # agent pre-flight: predict the gate's verdict for delete/merge/move
496
+ │ ├── refresh.mjs # F0: re-extract a graph's nodes+edges from disk (cached, fast)
497
+ │ ├── find-similar.mjs # F1: rank existing bodies vs a candidate (reuse-at-write-time)
498
+ │ ├── placement.mjs # F2: suggest a new symbol's domain/file + reuse warnings
499
+ │ ├── review.mjs # F5: structural review of a change (blast radius, regressions)
500
+ │ ├── fitness.mjs # F6: architectural fitness-rule checker
501
+ │ ├── risk.mjs # F7: change-risk ranking for review triage
502
+ │ ├── codemod.mjs # F8: consolidation edit plan (+ gated/reversible --write)
503
+ │ ├── deadcode.mjs # F10: confidence-tiered dead-code workflow
504
+ │ ├── break-cycles.mjs # F9: cheapest verified cut per dependency cycle
505
+ │ ├── hotspots.mjs # rank symbols by complexity x fan-in x churn (where to refactor first)
506
+ │ ├── campaign.mjs # compose optimize+deadcode+break-cycles into one gated ROI worklist
507
+ │ ├── reading-order.mjs # foundations-first reading path for onboarding (bounded by budget)
508
+ │ ├── annotate.mjs # record false-positive suppressions in .codeweb/annotations.json
509
+ │ ├── mcp-server.mjs # MCP stdio server exposing all queries + the capability suite
510
+ │ └── lib/
511
+ │ ├── graph-ops.mjs # shared pure graph primitives (index, cycles, orphans, impact, reviewImpact, …)
512
+ │ ├── shingles.mjs # F1: shared token-shingle/jaccard (also used by overlap.mjs)
513
+ │ ├── skeleton.mjs # identifier-normalized skeleton for Type-2 (renamed) clone detection
514
+ │ ├── complexity.mjs # cyclomatic complexity + nesting depth (the hotspot inputs)
515
+ │ ├── dup-check.mjs # incremental duplication check over changed symbols (edit gate)
516
+ │ ├── annotations.mjs # finding fingerprints + false-positive suppression memory
517
+ │ ├── hotspots.mjs # the complexity x fan-in x churn blend (shared with tests)
518
+ │ ├── campaign.mjs # the ordered/gated/ROI campaign planner (pure)
519
+ │ ├── reading-order.mjs # foundations-first DAG linearization
520
+ │ └── risk.mjs # F7: the change-risk formula + weights (one truth)
521
+ ├── agents/ # fallback path (unparseable langs / --engine read)
522
+ │ ├── codeweb-dissector.md # atomic dissection (parallel, read-only)
523
+ │ └── codeweb-domain-mapper.md # domain tagging + overlap detection
524
+ ├── skills/codebase-anatomy/
525
+ │ ├── SKILL.md # orchestration brain (fast path default, agents fallback)
526
+ │ └── references/
527
+ │ ├── graph-schema.md
528
+ │ ├── overlap-heuristics.md
529
+ │ └── engine-detection.md
530
+ ├── assets/ # brand art (logo, hero, animated demo) + report screenshots
531
+ └── README.md
532
+ ```
533
+
534
+ ## Roadmap
535
+
536
+ - **More first-class languages** — eleven native today (JavaScript, TypeScript, Python, **Rust**,
537
+ **Go**, **Java**, **C#**, **Ruby**, **PHP**, **Kotlin**, **Swift**); anything else routes through
538
+ the agent fallback. Dynamic-dispatch AST tiers now cover JS/TS, Java, C#, Python, Go, and Rust —
539
+ Ruby/PHP/Kotlin/Swift dispatch is the next increment there.
540
+
541
+ _Recently shipped: an **agent-intelligence suite** — refactoring **hotspots** (complexity × fan-in ×
542
+ churn), a gated ROI-ranked optimization **campaign** planner, a foundations-first **reading-order**,
543
+ **Type-2 (renamed) clone** detection, false-positive **suppression memory**, and **5 new MCP tools
544
+ (20 total)** · a **[live interactive demo](https://ghostlygawd.github.io/codeweb/demo/)** on GitHub
545
+ Pages · Go and Rust on the fast path · duplication-over-time trend (`trend.mjs`) · a one-command CI
546
+ regression gate + GitHub Action._
547
+
548
+ ## Versioning & releases
549
+
550
+ codeweb follows [Semantic Versioning](https://semver.org/) and keeps a
551
+ [Keep a Changelog](https://keepachangelog.com/)-formatted [`CHANGELOG.md`](CHANGELOG.md). Every new
552
+ capability, benchmark, or fix is recorded there and shipped as a **tagged GitHub release** — product,
553
+ marketing, and research move as one front, never lost in commit history.
554
+
555
+ One source of truth keeps it honest. The version lives in `package.json`; the MCP tool count lives in
556
+ `scripts/mcp-server.mjs`. Everything else is derived and verified:
557
+
558
+ ```bash
559
+ npm run version-sync # propagate version + tool count -> plugin.json, SKILL.md, README badge
560
+ npm run check-consistency # fail if any public-facing surface has drifted
561
+ npm run build:site # regenerate the docs/ website (zero-dependency, deterministic)
562
+ npm run release -- --minor # roll the changelog, bump, sync, rebuild; prints the git/tag steps
563
+ ```
564
+
565
+ `check-consistency` runs in CI, applying codeweb's own "fail on regression" philosophy to its public
566
+ comms — the reason this README and the plugin manifest can't quietly disagree about how many tools
567
+ ship.
568
+
569
+ ## Handoffs
570
+
571
+ codeweb's domain map and overlap list feed naturally into `refactor-cleaner` (act on the
572
+ consolidation list), `codebase-onboarding` (use the domain map for a guide), and `code-tour`
573
+ (anchor a tour to the symbol index).
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: codeweb-dissector
3
+ description: Read-only atomic dissection pass for the codeweb plugin. Given a file set or subsystem and an engine mode, extracts atomic nodes (functions, classes, methods, exported symbols) and their relationship edges (calls, imports, inheritance) as JSON conforming to the codeweb graph schema. Used in parallel fan-out passes. Never executes target code.
4
+ tools: Read, Grep, Glob, Bash
5
+ model: sonnet
6
+ ---
7
+
8
+ # codeweb-dissector
9
+
10
+ You dissect one slice of a codebase into atomic graph fragments. You are spawned in parallel
11
+ with other dissectors, each owning a different subsystem. Your output is **data, not prose** —
12
+ return a single JSON object and nothing else.
13
+
14
+ ## Inputs you will be given
15
+
16
+ - A **scope**: a directory, a set of files, or a path glob you own.
17
+ - An **engine mode**: `hybrid` (default), `tools`, or `read`.
18
+ - The **graph schema** (nodes/edges shapes) — follow it exactly.
19
+ - The repo's detected **languages** and any **available analysis tools**.
20
+
21
+ ## Hard rules
22
+
23
+ - **Read-only.** Never run, build, install, or test the target. The only Bash you may run is
24
+ read-only static-analysis tooling (e.g. `ctags`, `madge`, `tree-sitter`, `go list`,
25
+ `rg`) against existing files. Never `npm install`, never run target entrypoints.
26
+ - **Stay in scope.** Only emit nodes for files inside your assigned scope. You may emit edges
27
+ that point *out* of your scope (to symbols other dissectors own) — the orchestrator merges
28
+ and reconciles them by `id`.
29
+ - **Deterministic ids.** Node `id` = `<repo-relative-path>:<symbol>` (e.g.
30
+ `src/auth/login.ts:loginUser`). For file/module nodes use the path alone.
31
+ - **No invention.** Every node and edge must correspond to real code you read or a tool
32
+ emitted. If unsure of an edge, omit it rather than guess.
33
+
34
+ ## Engine behaviour
35
+
36
+ - `hybrid` / `tools`: First try the available analysis tool for the language to get precise
37
+ symbols and edges (see the skill's engine-detection reference). Use the tool output as the
38
+ spine, then read the actual files to fill `summary`, `kind`, `exports`, and `loc`.
39
+ - `read` (or no tool available): Read each file and extract symbols and their call/import
40
+ edges by inspection. Prefer Grep to locate call sites quickly, then Read to confirm.
41
+
42
+ ## What to extract per node
43
+
44
+ `id`, `label`, `kind` (function|class|method|module|file), `file`, `line`, `loc`
45
+ (line count of the symbol body), `exports` (bool), and a one-sentence `summary` of what it
46
+ does. Leave `domain` empty — the domain-mapper assigns it.
47
+
48
+ ## Output
49
+
50
+ Return exactly one JSON object:
51
+
52
+ ```json
53
+ { "nodes": [ ... ], "edges": [ ... ] }
54
+ ```
55
+
56
+ No markdown fences, no commentary. If your scope is empty, return `{"nodes":[],"edges":[]}`.