ts-reviewer 2.1.0 → 3.0.1
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.
- package/README.md +23 -18
- package/package.json +2 -2
- package/ts-reviewer/SKILL.md +99 -35
- package/ts-reviewer/references/architecture.md +65 -18
- package/ts-reviewer/references/fix-workflow.md +43 -35
- package/ts-reviewer/tools/classify-run.mjs +26 -0
- package/ts-reviewer/tools/co-change.mjs +116 -0
- package/ts-reviewer/tools/discover-projects.mjs +159 -0
- package/ts-reviewer/tools/run-cruise.mjs +226 -0
- package/ts-reviewer/tools/validate-report.mjs +324 -0
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ Three modes, one skill:
|
|
|
10
10
|
|
|
11
11
|
| Mode | What happens |
|
|
12
12
|
|---|---|
|
|
13
|
-
| **scan** | Analyzes the codebase and writes a prioritized report to `code-smells.md` |
|
|
13
|
+
| **scan** | Analyzes the codebase and writes a prioritized report to `code-smells/report.md` |
|
|
14
14
|
| **fix** | Reads the report and applies fixes file-by-file with tsc/lint/test verification |
|
|
15
15
|
| **auto** | Runs scan, asks you to confirm, fixes everything, deletes the report if clean |
|
|
16
16
|
|
|
@@ -81,7 +81,8 @@ Find issues in this project
|
|
|
81
81
|
Audit the codebase for security and type safety problems
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
Claude will analyze the project and write a report to `code-smells.md` in the project root.
|
|
84
|
+
Claude will analyze the project and write a report to `code-smells/report.md` in the project root.
|
|
85
|
+
With Architecture active, the same directory also holds project discovery, Knip, graph, metric, co-change, rule, and Mermaid artifacts.
|
|
85
86
|
|
|
86
87
|
#### Domain flags
|
|
87
88
|
|
|
@@ -114,7 +115,7 @@ After reviewing the scan report, ask Claude to fix the issues:
|
|
|
114
115
|
Fix the issues from the report
|
|
115
116
|
```
|
|
116
117
|
```
|
|
117
|
-
Apply fixes from code-smells.md
|
|
118
|
+
Apply fixes from code-smells/report.md
|
|
118
119
|
```
|
|
119
120
|
|
|
120
121
|
The fix workflow:
|
|
@@ -124,7 +125,7 @@ The fix workflow:
|
|
|
124
125
|
4. Runs linter, fixes lint errors
|
|
125
126
|
5. Runs full test suite, compares with baseline, fixes any regressions it caused
|
|
126
127
|
6. Repeats verification up to 5 iterations
|
|
127
|
-
7. Updates the report: if all fixed → deletes `code-smells.md`; if some remain → keeps it as an audit trail with BEFORE/AFTER diffs for every fix
|
|
128
|
+
7. Updates the report: if all fixed → deletes `code-smells/report.md`; if some remain → keeps it as an audit trail with BEFORE/AFTER diffs for every fix
|
|
128
129
|
|
|
129
130
|
**Important:** fix never commits or stages anything. You review the changes and decide what to keep.
|
|
130
131
|
|
|
@@ -227,7 +228,7 @@ A check line looks like this:
|
|
|
227
228
|
The format is enforced, not merely recommended:
|
|
228
229
|
|
|
229
230
|
```bash
|
|
230
|
-
npm test # typecheck +
|
|
231
|
+
npm test # typecheck + conformance and tool tests
|
|
231
232
|
```
|
|
232
233
|
|
|
233
234
|
The test catches a check line that lost its severity, a block the profile does not declare, blocks out of order, a banned vague word, and a line over the limit — each reported with its file and line number.
|
|
@@ -238,29 +239,33 @@ The test catches a check line that lost its severity, a block the profile does n
|
|
|
238
239
|
|
|
239
240
|
### Scan mode
|
|
240
241
|
|
|
241
|
-
1. **Discovery** — detects domain flags, maps the project, reads tsconfig.json, detects linter and test runner
|
|
242
|
+
1. **Discovery** — detects domain flags, maps the project, reads tsconfig.json, detects linter and test runner, and asks once before downloading a missing architecture tool.
|
|
242
243
|
2. **Diagnostics** — runs `tsc --noEmit`, linter, and LSP diagnostics (if available)
|
|
243
|
-
3. **
|
|
244
|
-
4. **
|
|
244
|
+
3. **Architecture pre-pass** — when active, writes bounded Knip, graph, metric, co-change, rule, and Mermaid artifacts under `code-smells/`, with project coverage and bounded failure diagnostics.
|
|
245
|
+
4. **Analysis** — specialized passes judge the candidates against the active checklists; tool output is never a finding by itself.
|
|
246
|
+
5. **Report** — deduplicates, applies severity boost (scoped modes), consolidates recurring patterns, enforces a noise budget, writes `code-smells/report.md`, and validates its contract before the scan succeeds. Architecture findings appear in a separate `## Architecture Opportunities` section at the end.
|
|
247
|
+
|
|
248
|
+
Validate a report directly with `node ts-reviewer/tools/validate-report.mjs --repo . --report code-smells/report.md`. It checks headings, counts, finding anchors, architecture fields, and linked artifacts without adding a dependency. An **error** is a defect of the report that rewriting it fixes; a **warning** names an outcome of the mechanical pre-pass — a graph with no diagram, say — that the report cannot fix, and warnings do not fail the run.
|
|
245
249
|
|
|
246
250
|
### Fix mode
|
|
247
251
|
|
|
248
|
-
1.
|
|
249
|
-
2.
|
|
250
|
-
3.
|
|
251
|
-
4.
|
|
252
|
-
5.
|
|
253
|
-
6.
|
|
254
|
-
7.
|
|
255
|
-
8.
|
|
252
|
+
1. Validates `code-smells/report.md` and stops before changing code when the report is invalid
|
|
253
|
+
2. Parses the report as the work plan
|
|
254
|
+
3. Captures test baseline (runs tests before changes)
|
|
255
|
+
4. Applies fixes bottom-to-top within each file (so line numbers don't shift)
|
|
256
|
+
5. Writes regression tests for each testable fix
|
|
257
|
+
6. Runs `tsc --noEmit` after each file
|
|
258
|
+
7. Runs the full verification loop: tsc + linter + test suite (max 5 iterations)
|
|
259
|
+
8. Compares test results with baseline — only fixes regressions it caused
|
|
260
|
+
9. Updates or deletes the report, keeps the remaining `code-smells/` artifacts, and asks before removing them
|
|
256
261
|
|
|
257
262
|
## Tips
|
|
258
263
|
|
|
259
|
-
- **Add `code-smells
|
|
264
|
+
- **Add `code-smells/` to `.gitignore`** — it contains review artifacts, not source code.
|
|
260
265
|
|
|
261
266
|
- **Commit before running fix** — so you can `git diff` to review changes and `git checkout -- .` to revert if needed.
|
|
262
267
|
|
|
263
|
-
- **Edit the report before fix** — since fix uses `code-smells.md` as its work plan, you can delete issues you don't want fixed, change severities, or add notes before running fix.
|
|
268
|
+
- **Edit the report before fix** — since fix uses `code-smells/report.md` as its work plan, you can delete issues you don't want fixed, change severities, or add notes before running fix.
|
|
264
269
|
|
|
265
270
|
- **Scoped review for PRs** — `"review my branch against main"` is the most practical mode for day-to-day use. Full codebase audits are better suited for periodic health checks.
|
|
266
271
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-reviewer",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "Install the TypeScript Code Reviewer skill for Claude Code, Codex, or Antigravity",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"build": "tsc -p tsconfig.json",
|
|
23
23
|
"prepublishOnly": "npm run build && npm test",
|
|
24
24
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
25
|
-
"test": "npm run typecheck && node --test cnlp/skill-format.test.js",
|
|
25
|
+
"test": "npm run typecheck && node --test cnlp/skill-format.test.js tools.test.mjs",
|
|
26
26
|
"dev": "npm run build && node --enable-source-maps dist/cli.js"
|
|
27
27
|
},
|
|
28
28
|
"keywords": [
|
package/ts-reviewer/SKILL.md
CHANGED
|
@@ -28,13 +28,15 @@ inputs:
|
|
|
28
28
|
- the reference checklists under `references/`
|
|
29
29
|
|
|
30
30
|
preconditions:
|
|
31
|
-
- `code-smells.md` exists before fix mode runs: it is the work plan, and fix stops with an error when it is absent
|
|
31
|
+
- `code-smells/report.md` exists before fix mode runs: it is the work plan, and fix stops with an error when it is absent
|
|
32
32
|
|
|
33
33
|
scope:
|
|
34
34
|
- `.ts`, `.mts`, and `.cts` files are reviewed alike
|
|
35
35
|
- `.d.ts` files are reviewed by the Type Safety and Config domains only: a declaration has no runtime behavior
|
|
36
36
|
- `.tsx` is out of scope
|
|
37
37
|
- the analysis scope in a scoped mode is the diff file list, and the reading scope is wider
|
|
38
|
+
- `--affected` widens Architecture evidence to modules reaching a changed module, and does not widen the analysis scope
|
|
39
|
+
- anchor each finding to 1 file, and set `in_diff: true` only when that file is in the diff list
|
|
38
40
|
- read as read-only context: `tsconfig.json`, the configs it extends, and `package.json`
|
|
39
41
|
- read as read-only context: the files the scoped files import 1 level deep, and the shared types in `types.ts`, `*.d.ts`, `interfaces/`, `shared/`
|
|
40
42
|
|
|
@@ -57,11 +59,16 @@ forbidden_behaviors:
|
|
|
57
59
|
- do not emit the same file and line twice
|
|
58
60
|
- do not boost severity in `full` scope mode: all code is treated alike
|
|
59
61
|
- do not flag a config issue in a scoped mode unless `tsconfig.json` is in the diff
|
|
62
|
+
- do not download and execute a missing analysis tool before the operator approves it once at discovery
|
|
63
|
+
- do not run `npm install` or `npm uninstall` for analysis: use an approved pinned-major `npx -y` command, or record the pre-pass as skipped
|
|
64
|
+
- do not rename a report section, field, severity, confidence, or domain: `report_format` and `domains` hold exact identifiers
|
|
60
65
|
|
|
61
66
|
outputs:
|
|
62
|
-
- `code-smells.md` in the project root: the scan report, and the work plan fix reads
|
|
63
|
-
-
|
|
64
|
-
-
|
|
67
|
+
- `code-smells/report.md` in the project root: the scan report, and the work plan fix reads
|
|
68
|
+
- `code-smells/knip.json`, `projects.json`, `co-change.md`, `cruise-summary.md`, `metrics.md`, and graph and diagram directories when Architecture is active
|
|
69
|
+
- `code-smells/suggested.dependency-cruiser.cjs` when prose declares dependency rules and no machine-readable declaration owns them
|
|
70
|
+
- the `## Architecture Opportunities` section of the report only when Architecture is active and at least 1 confirmed finding exists
|
|
71
|
+
- the audit trail in `code-smells/report.md` when any issue remains: BEFORE/AFTER for each fixed issue, a status tag for each failed, reverted, or skipped issue, the original entry for each untouched issue
|
|
65
72
|
- a regression test for each fix that is testable
|
|
66
73
|
|
|
67
74
|
run_modes:
|
|
@@ -119,40 +126,52 @@ workflow:
|
|
|
119
126
|
9. audit the config that governs the files in scope, and name that config in the summary
|
|
120
127
|
10. read the linter config: `eslint.config.*`, `.eslintrc.*`, `biome.json`, `deno.json`
|
|
121
128
|
11. read `package.json` for the dependencies and the module type, and verify the TypeScript version, `engines.node`, and `@types/node` against `target_stack`
|
|
122
|
-
12. identify
|
|
123
|
-
13.
|
|
124
|
-
14.
|
|
125
|
-
15.
|
|
126
|
-
16.
|
|
129
|
+
12. identify declared entry points from `package.json#exports`, `main`, `bin`, and the `start`, `dev`, and `serve` scripts
|
|
130
|
+
13. when Architecture is active, inspect local Knip and dependency-cruiser binaries and ask once before running either missing tool through pinned-major `npx -y`
|
|
131
|
+
14. collect the context files named in `scope:` when the scope mode is scoped
|
|
132
|
+
15. identify feature slices and public entry points when Architecture is active, leaving graph discovery to its mechanical pre-pass
|
|
133
|
+
16. collect machine-readable dependency rules and prose from ADR directories, `ARCHITECTURE.md`, README, and `CONTRIBUTING.md`
|
|
127
134
|
17. run `npx tsc --noEmit 2>&1 | head -200` over the full project, and report only the errors in the scoped files
|
|
128
135
|
18. run the linter: `npx eslint [files] --format json` or `npx biome check [files] --reporter json`
|
|
129
136
|
19. query the TypeScript LSP over MCP when it is reachable, then merge and deduplicate against the compiler output
|
|
130
137
|
20. triage every compiler and linter diagnostic through `severity_mapping`
|
|
131
138
|
21. read the reference file named in `domains` before each analysis pass
|
|
132
|
-
22. run
|
|
133
|
-
23.
|
|
134
|
-
24.
|
|
135
|
-
25.
|
|
136
|
-
26.
|
|
137
|
-
27.
|
|
138
|
-
28.
|
|
139
|
-
29.
|
|
140
|
-
30.
|
|
141
|
-
31.
|
|
142
|
-
32.
|
|
143
|
-
33.
|
|
144
|
-
34.
|
|
145
|
-
35.
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
139
|
+
22. run the mechanical pre-pass in `references/architecture.md` when Architecture is active, passing the approved tool decision and scoped base
|
|
140
|
+
23. report the discovery summary in the shape of `discovery_summary`, including skipped and clean mechanical results
|
|
141
|
+
24. run only the passes whose domain is in the active domain set, as sub-agents shaped by `subagent_template` or one domain at a time
|
|
142
|
+
25. give every agent all the scoped files when scoped files <= 20, and split by directory above that, with the shared types visible to every agent
|
|
143
|
+
26. re-read the exact lines in the current file state before a finding enters the report
|
|
144
|
+
27. read the callers to verify a data flow a finding rests on, or mark its problem statement with "if <condition>" and cap its severity at Medium
|
|
145
|
+
28. downgrade a flagged non-High pattern that appears 5+ times across the codebase by 1 level, and report it once as a Recurring Pattern
|
|
146
|
+
29. boost a finding carrying `in_diff: true` by 1 level in a scoped mode, and mark it `High [boosted, was Medium — new code]`
|
|
147
|
+
30. deduplicate the findings on the same file, line, and issue, keeping 1
|
|
148
|
+
31. merge the findings 2 domains raise on the same file and line into 1 entry attributing both categories, at the higher severity
|
|
149
|
+
32. consolidate 3+ identical issues into 1 Recurring Pattern entry
|
|
150
|
+
33. keep the top 15 by severity and impact when a single domain produces more than 25 Medium or Low findings, and consolidate the rest into Recurring Pattern entries with their counts
|
|
151
|
+
34. write `code-smells/report.md` in the shape of `report_format`
|
|
152
|
+
35. validate the report against `report_format` after writing it, and treat a `warning:` line as a pre-pass outcome the report cannot correct
|
|
153
|
+
```bash
|
|
154
|
+
# SKILL is the directory this file was loaded from.
|
|
155
|
+
SKILL=<the directory this file was loaded from>
|
|
156
|
+
node "$SKILL/tools/validate-report.mjs" --repo . --report code-smells/report.md
|
|
157
|
+
```
|
|
158
|
+
36. correct every named error and retry with report validation iterations <= 2
|
|
159
|
+
37. keep `code-smells/report.md` when the second validation fails, write `> unvalidated: <the first error>` under its title, and name the errors to the operator
|
|
160
|
+
38. sort by severity group, then category, then file path, and place `in_diff: true` before pre-existing in a scoped mode
|
|
161
|
+
39. show the top 10 and summarize the rest in a table when Medium and Low together hold more than 15 issues
|
|
162
|
+
40. recommend that the operator adds `code-smells/` to `.gitignore`: it holds review artifacts
|
|
163
|
+
41. read `references/fix-workflow.md` before fix mode executes: it holds the complete protocol
|
|
164
|
+
42. detect the test runner and run the baseline tests
|
|
165
|
+
43. fix the issues file by file, and run `tsc --noEmit` after each file
|
|
166
|
+
44. run the linter and fix the lint errors it reports
|
|
167
|
+
45. run the full test suite, compare it against the baseline, and fix the regressions
|
|
168
|
+
46. repeat the compiler, linter, and test verification with verification iterations <= 5
|
|
169
|
+
47. rerun the Architecture mechanical pre-pass on the fixed tree when Architecture is active
|
|
170
|
+
48. update `code-smells/report.md`: remove what is fixed, mark what failed
|
|
171
|
+
49. show the scan summary in auto mode, and ask the operator whether to proceed with the fix
|
|
172
|
+
50. re-scan after the fix in auto mode with full scan-fix cycles <= 2, and stop when issues persist after the second
|
|
173
|
+
51. delete `code-smells/report.md` and report success when every issue is fixed
|
|
174
|
+
52. retain the remaining `code-smells/` artifacts, state what they contain, and remove them only after the operator confirms
|
|
156
175
|
|
|
157
176
|
scope_commands:
|
|
158
177
|
```bash
|
|
@@ -161,6 +180,7 @@ npx glob '**/*.{ts,mts,cts}' --ignore '**/node_modules/**'
|
|
|
161
180
|
# or: git ls-files '*.ts' '*.mts' '*.cts'
|
|
162
181
|
|
|
163
182
|
# uncommitted — staged, unstaged, and untracked
|
|
183
|
+
BASE=HEAD
|
|
164
184
|
git diff --name-only HEAD -- '*.ts' '*.mts' '*.cts'
|
|
165
185
|
git ls-files --others --exclude-standard -- '*.ts' '*.mts' '*.cts'
|
|
166
186
|
|
|
@@ -170,6 +190,7 @@ git diff --name-only "$BASE"...HEAD -- '*.ts' '*.mts' '*.cts'
|
|
|
170
190
|
git diff --name-only HEAD -- '*.ts' '*.mts' '*.cts'
|
|
171
191
|
|
|
172
192
|
# commits:N — the last N commits
|
|
193
|
+
BASE=HEAD~N
|
|
173
194
|
git diff --name-only HEAD~N..HEAD -- '*.ts' '*.mts' '*.cts'
|
|
174
195
|
|
|
175
196
|
# the changed hunks, for the severity boost in a scoped mode
|
|
@@ -211,6 +232,16 @@ Strict mode: yes / partial / no
|
|
|
211
232
|
Linter: eslint / biome / none
|
|
212
233
|
Test runner: vitest / jest / mocha / node:test / none
|
|
213
234
|
Files in scope: <N> .ts files (+ <M> context files)
|
|
235
|
+
Architecture projects: <config and source roots, when active>
|
|
236
|
+
Architecture tools: <local or approved npx versions, when active>
|
|
237
|
+
Architecture coverage: <successful>/<selected>, when active
|
|
238
|
+
Mechanical results: <module and edge counts, cycles, orphans, and co-change pairs; name clean zeros>
|
|
239
|
+
Skipped pre-passes: <tool and reason, or none>
|
|
240
|
+
Speculative candidates: <names only, or none>
|
|
241
|
+
Declared dependency rules:
|
|
242
|
+
| Rule | Source file:line | Directories |
|
|
243
|
+
|---|---|---|
|
|
244
|
+
| <rule, or none> | <path:line> | <mapping> |
|
|
214
245
|
```
|
|
215
246
|
|
|
216
247
|
subagent_template:
|
|
@@ -239,6 +270,11 @@ Output JSONL, one object per line:
|
|
|
239
270
|
```
|
|
240
271
|
|
|
241
272
|
report_format:
|
|
273
|
+
- the `##` sections of the block below are the whole set, in that order, and a heading outside it is a renamed section
|
|
274
|
+
- Discovery, Pre-existing Issues, Architecture Opportunities, Verification, and Generated artifacts are optional, and the other 5 are always present
|
|
275
|
+
- `Total issues` counts the `###` findings, the summary-table rows, and the Architecture Opportunities entries, and the severity breakdown counts the same 3
|
|
276
|
+
- a `Recurring Patterns` row is a pattern rather than an issue, and no row of that table is counted
|
|
277
|
+
- a summary table is read by its `Category` and `Location` columns, and a pattern table by its `Pattern` and `Occurrences` columns
|
|
242
278
|
````markdown
|
|
243
279
|
# TypeScript Code Review Report
|
|
244
280
|
|
|
@@ -247,6 +283,7 @@ report_format:
|
|
|
247
283
|
**Stack:** TypeScript 5.9.x / ES2024 / Node 24 — matches / <deviation>
|
|
248
284
|
**Scope:** Full / Uncommitted / Branch `x` vs `y` / Last N commits
|
|
249
285
|
**Files analyzed:** N (+ M context)
|
|
286
|
+
**Architecture coverage:** N/M (when active)
|
|
250
287
|
**Total issues:** N (X highest, Y high, Z medium, W low)
|
|
251
288
|
**Severity-boosted:** N (scoped modes only)
|
|
252
289
|
|
|
@@ -254,6 +291,10 @@ report_format:
|
|
|
254
291
|
|
|
255
292
|
<2-3 sentences on codebase health and key patterns>
|
|
256
293
|
|
|
294
|
+
## Discovery
|
|
295
|
+
|
|
296
|
+
<optional; the `discovery_summary` block as it was reported>
|
|
297
|
+
|
|
257
298
|
## Highest + High Issues
|
|
258
299
|
|
|
259
300
|
### TITLE — Severity [boosted info if applicable]
|
|
@@ -261,7 +302,7 @@ report_format:
|
|
|
261
302
|
**Category:** cat | **File:** `path` | **Line:** N | **Auto-fixable:** Yes/No | **New code:** Yes/No
|
|
262
303
|
|
|
263
304
|
```typescript
|
|
264
|
-
// snippet
|
|
305
|
+
// snippet: 3-7 lines copied from the file, within its own length of the stated line
|
|
265
306
|
```
|
|
266
307
|
|
|
267
308
|
**Problem:** explanation
|
|
@@ -272,13 +313,36 @@ report_format:
|
|
|
272
313
|
|
|
273
314
|
## Medium Issues
|
|
274
315
|
## Low Issues
|
|
316
|
+
|
|
317
|
+
| Issue | Category | Location | Fix |
|
|
318
|
+
|---|---|---|---|
|
|
319
|
+
| title | cat | `path:N` | recommendation |
|
|
320
|
+
|
|
275
321
|
## Recurring Patterns
|
|
322
|
+
|
|
323
|
+
| Pattern | Occurrences | Severity treatment |
|
|
324
|
+
|---|---|---|
|
|
325
|
+
| name | N | what happened to its members |
|
|
326
|
+
|
|
276
327
|
## Config Issues
|
|
328
|
+
|
|
329
|
+
<findings in the shape above, or prose naming where the config findings already sit>
|
|
330
|
+
|
|
277
331
|
## Pre-existing Issues (scoped modes only)
|
|
278
332
|
|
|
279
333
|
## Architecture Opportunities
|
|
280
334
|
|
|
281
|
-
<1 entry per candidate, in the shape the `report_format` block of references/architecture.md gives>
|
|
335
|
+
<optional; 1 entry per candidate, in the shape the `report_format` block of references/architecture.md gives>
|
|
336
|
+
|
|
337
|
+
## Verification
|
|
338
|
+
|
|
339
|
+
| Check | Result |
|
|
340
|
+
|---|---|
|
|
341
|
+
| the command that ran | what it reported |
|
|
342
|
+
|
|
343
|
+
## Generated artifacts
|
|
344
|
+
|
|
345
|
+
- `<file under code-smells/>` — what it holds
|
|
282
346
|
|
|
283
347
|
---
|
|
284
348
|
````
|
|
@@ -23,8 +23,8 @@ confidence_scale:
|
|
|
23
23
|
|
|
24
24
|
| Confidence | Criteria |
|
|
25
25
|
|---|---|
|
|
26
|
-
| strong | the pain repeats
|
|
27
|
-
| worth-exploring | the problem is confirmed
|
|
26
|
+
| strong | the pain repeats and the owner is named, or a quoted dependency rule maps 1:1 onto directories |
|
|
27
|
+
| worth-exploring | the problem is confirmed but the interface, migration, inferred rule, or layer mapping needs its own design |
|
|
28
28
|
| speculative | a signal with no call, history, or test evidence behind it |
|
|
29
29
|
|
|
30
30
|
read_first:
|
|
@@ -35,23 +35,57 @@ read_first:
|
|
|
35
35
|
- dependency direction matters more than layer count: the domain owns the logic, and transport and storage are injected or isolated at the edge
|
|
36
36
|
- 1 adapter is a hypothetical seam and 2 adapters are a real seam: do not introduce a port until at least 2 adapters are justified, production and test at the minimum
|
|
37
37
|
- an architecture finding rests on evidence: named files and symbols, an import or call direction, a repeated change path in `git log`, a duplicated rule, or a test no correct seam can reach
|
|
38
|
-
- state the observation apart from the inference
|
|
38
|
+
- state the observation apart from the inference, and list an evidence-free candidate as speculative in `discovery_summary` rather than reporting it as a defect
|
|
39
39
|
- a defect no test can reach through a correct seam is an architecture finding, and not a reason to write a test past the interface
|
|
40
40
|
- before proposing a module, a port, or a container, check in order: drop the need, an existing module in the repository, the standard library, a platform feature, an installed dependency
|
|
41
41
|
- design a hard-to-reverse proposal twice: compare 2 different interfaces on caller knowledge, seam placement, and migration cost, then recommend 1
|
|
42
42
|
- a cycle is unclear ownership and not a bad graph: move the type or the rule to its owner, and `import type` or a lazy import hides the direction rather than fixing it
|
|
43
43
|
- a path alias shortens an import path and is not an architecture boundary: ownership and a controlled export list are
|
|
44
|
+
- under `--arch`, Knip narrows the observed interface and confirms orphans, while dead-code findings remain owned by Dependency Hygiene
|
|
45
|
+
- apply an exception stated with a dependency rule before reporting it, and cap a path the declaration marks legacy or deprecated at Low
|
|
44
46
|
- pick the simplest form a deepened module can take: a pure function for a transformation, a reducer for events over 1 state, a state machine when a command is valid only in some states, a class only when it owns long-lived state
|
|
45
47
|
|
|
46
48
|
workflow:
|
|
47
|
-
1.
|
|
48
|
-
2.
|
|
49
|
-
3. list
|
|
50
|
-
4.
|
|
51
|
-
5.
|
|
52
|
-
6.
|
|
53
|
-
7.
|
|
54
|
-
8.
|
|
49
|
+
1. locate machine-readable dependency rules first, then prose in ADRs, `ARCHITECTURE.md`, README, and `CONTRIBUTING.md`, in that order
|
|
50
|
+
2. resolve conflicting ADRs only through an explicit supersede, and ask when the conflict would produce a High finding
|
|
51
|
+
3. list each extracted rule, its source line, and its directory mapping in `discovery_summary` before using it
|
|
52
|
+
4. write prose-derived rules to `code-smells/suggested.dependency-cruiser.cjs`, and do not add them to the project during scan
|
|
53
|
+
5. when no declaration exists, report observed structure and offer a declaration rather than inventing layers
|
|
54
|
+
6. run the mechanical pre-pass with the commands below against 1 unchanged tree before the semantic pass
|
|
55
|
+
7. classify Knip and dependency-cruiser by parseable output rather than exit code, since both tools use non-zero and zero exits for reportable candidates
|
|
56
|
+
8. record a project with source files and `totalCruised == 0` as a skipped pre-pass, and do not report its mechanical zeros
|
|
57
|
+
9. state Architecture coverage as successful projects over selected projects, and list each failed config with its bounded diagnostic
|
|
58
|
+
10. give the semantic pass `code-smells/metrics.md` rather than a raw graph
|
|
59
|
+
11. cross each co-change pair with the graph: an edge is weak evidence, while no edge across directories is an implicit-contract candidate
|
|
60
|
+
12. read ESLint boundary rules from linter output without converting them, since the linter already executed those rules
|
|
61
|
+
13. consolidate all violating edges for 1 declared rule into 1 candidate, after removing declared exceptions
|
|
62
|
+
14. trace `min(declared entry points, 3)` scenarios, ranked by the number of modules each entry point reaches
|
|
63
|
+
15. grep for feature-module imports inside the `shared`, `common`, `core`, and `utils` directories, which is the inverted direction
|
|
64
|
+
16. apply the deletion test only to a module whose whole export set has 1 importer and that wraps or re-exports another module
|
|
65
|
+
17. treat an interface or type re-exported unchanged through 3+ files as a pass-through chain
|
|
66
|
+
18. inspect the top 20 modules and folders by fan-in for mixed concepts, and use folder instability only to rank layer checks
|
|
67
|
+
19. name the module owning the rule and the module owning the state for each candidate, and mark the candidate speculative when neither is identifiable
|
|
68
|
+
20. keep each collapsed project overview, then create 2..3 focused Mermaid diagrams tied to the top findings after triage
|
|
69
|
+
21. generate SVG only after `dot -V` succeeds, and keep Mermaid when Graphviz is unavailable
|
|
70
|
+
22. run these checks rather than reporting a cycle, hub, orphan, co-change pair, or Knip entry directly
|
|
71
|
+
```bash
|
|
72
|
+
# SKILL is the directory this file was loaded from; the main workflow approved missing tools before this pass.
|
|
73
|
+
SKILL=<the directory this file was loaded from>
|
|
74
|
+
KNIP=$([ -x node_modules/.bin/knip ] && echo node_modules/.bin/knip || echo "npx -y knip@6.31.0")
|
|
75
|
+
|
|
76
|
+
mkdir -p code-smells
|
|
77
|
+
|
|
78
|
+
node "$SKILL/tools/discover-projects.mjs" > code-smells/projects.json
|
|
79
|
+
$KNIP --reporter json > code-smells/knip.json
|
|
80
|
+
node "$SKILL/tools/co-change.mjs" --projects code-smells/projects.json --out code-smells/co-change.md
|
|
81
|
+
node "$SKILL/tools/run-cruise.mjs" --projects code-smells/projects.json --out code-smells
|
|
82
|
+
|
|
83
|
+
# In a scoped mode, BASE is the comparison ref computed by scope_commands.
|
|
84
|
+
node "$SKILL/tools/run-cruise.mjs" --projects code-smells/projects.json --out code-smells --base "$BASE"
|
|
85
|
+
|
|
86
|
+
# After triage, create one diagram for a top finding.
|
|
87
|
+
node "$SKILL/tools/run-cruise.mjs" --projects code-smells/projects.json --out code-smells --focus '<module regex>' --name <finding>
|
|
88
|
+
```
|
|
55
89
|
|
|
56
90
|
checks:
|
|
57
91
|
- shallow modules — understanding 1 concept requires bouncing across many tiny modules: Medium
|
|
@@ -76,6 +110,7 @@ checks:
|
|
|
76
110
|
- under-engineering — event or string-keyed indirection between 2 modules that only ever talk to each other: Low, a direct typed call is checkable
|
|
77
111
|
- dependency direction — a domain or computation module importing IO directly, `node:fs`, `node:http`, a DB client, or `fetch`, where the classification puts that IO behind a seam: Medium
|
|
78
112
|
- dependency direction — a shared or leaf module, `utils/`, `types/`, or `core/`, importing from a feature module: High, the inverted direction is how import cycles start
|
|
113
|
+
- dependency direction — an import edge contradicting a layer rule the project declares in an ADR or ARCHITECTURE.md: High, quote the rule with its source line and list the violating edges
|
|
79
114
|
- dependency direction — a wire or DTO type from an external API imported deep into a domain module instead of mapped at the seam that owns the external contract: Medium
|
|
80
115
|
- state ownership — 2+ modules mutating 1 entity, cache, or record with no single owning module: High, the write paths cannot be tested or reasoned about apart
|
|
81
116
|
- state ownership — fix: a shared mutable entity, by naming 1 owning module and turning each write into a named command on it
|
|
@@ -88,6 +123,7 @@ non_findings:
|
|
|
88
123
|
- a module with exactly 1 importer that hides an ordering, an invariant, or a decision: 1 importer starts the deletion test and is not a finding by itself
|
|
89
124
|
- a layer count: the direction of the dependencies is the finding, and a layer holding a real rule is not
|
|
90
125
|
- a port with 1 production adapter whose test double checks the same contract: the double is the second adapter
|
|
126
|
+
- duplicated trees whose intent is documented, excluded by tool policy, or maintained in lockstep: report at most the synchronized-edit cost at Low, not the decision
|
|
91
127
|
- formatting, import ordering, and file naming: `references/code-quality.md` owns them, and they are not architecture findings
|
|
92
128
|
|
|
93
129
|
forbidden_behaviors:
|
|
@@ -102,7 +138,9 @@ forbidden_behaviors:
|
|
|
102
138
|
- do not leave a new structure standing beside the old one: every proposal names the step deleting what it replaces
|
|
103
139
|
- do not propose a change contradicting a decision under `docs/adr/` silently: name the ADR and the conflict, and leave the decision to the operator
|
|
104
140
|
- do not report architecture candidates without naming 1 top recommendation and the reason it goes first
|
|
105
|
-
- do not
|
|
141
|
+
- do not claim the repository has no cycles, orphans, or coupling issues below 100% Architecture coverage: name the successful projects
|
|
142
|
+
- do not add a dependency as the fix for 1 import rule: use `package.json#exports`, the project's linter, or the workspace layout
|
|
143
|
+
- do not treat an approved `npx` graph tool used during review as a project dependency: it changes neither `package.json` nor the lockfile
|
|
106
144
|
|
|
107
145
|
dependency_classification:
|
|
108
146
|
|
|
@@ -115,6 +153,9 @@ dependency_classification:
|
|
|
115
153
|
|
|
116
154
|
severity_mapping:
|
|
117
155
|
|
|
156
|
+
- map a project-declared severity to the finding: `error` to High, `warn` to Medium, and `info` to Low
|
|
157
|
+
- copy the declared rule comment into Evidence, since it states the project's rationale and accepted debt
|
|
158
|
+
|
|
118
159
|
| Severity | Architecture criteria |
|
|
119
160
|
|---|---|
|
|
120
161
|
| Highest | an architecture issue directly causing a security vulnerability, data loss, or a production correctness bug |
|
|
@@ -124,6 +165,10 @@ severity_mapping:
|
|
|
124
165
|
|
|
125
166
|
fixability:
|
|
126
167
|
|
|
168
|
+
- an `enforce` change is `report-only`, since scan does not write a project config
|
|
169
|
+
- a `delete` change is `auto` only when no module imports the target
|
|
170
|
+
- a deepening, merge, or ownership move is `needs-confirm`
|
|
171
|
+
|
|
127
172
|
| Fixability | Meaning | Fix mode behaviour |
|
|
128
173
|
|---|---|---|
|
|
129
174
|
| `auto` | a local change: import path cleanup, a narrow circular-import break, a local module merge with co-located tests | applied in the normal fix loop |
|
|
@@ -134,17 +179,19 @@ report_format:
|
|
|
134
179
|
```md
|
|
135
180
|
### TITLE — Severity
|
|
136
181
|
|
|
137
|
-
- **Confidence:** strong | worth-exploring
|
|
182
|
+
- **Confidence:** strong | worth-exploring
|
|
138
183
|
- **Files:** relative/path/a.ts, relative/path/b.ts
|
|
139
184
|
- **Problem:** why this causes friction now (not just a pattern name)
|
|
140
185
|
- **Evidence:** the imports, callers, `git log` path, or test the finding rests on
|
|
141
|
-
- **
|
|
142
|
-
- **
|
|
143
|
-
- **
|
|
186
|
+
- **Change type:** deepening | ownership move | merge | delete | enforce
|
|
187
|
+
- **Proposed change:** plain-English description of what would change
|
|
188
|
+
- **Interface shape:** for deepening or merge only; rough sketch of the new interface and key invariants
|
|
189
|
+
- **Dependency category:** for deepening only; in-process | local-substitutable | remote-owned | true-external
|
|
190
|
+
- **Rule:** for enforce only; the exact rule text and the file where it would live
|
|
144
191
|
- **Test strategy:** how tests would improve (what tests survive, what gets deleted, what's new)
|
|
145
|
-
- **Migration:** prefactor | vertical slices | expand-contract, and the step
|
|
192
|
+
- **Migration:** for deepening, merge, ownership move, or delete; prefactor | vertical slices | expand-contract, and the deletion step
|
|
146
193
|
- **Benefits:** locality gained, leverage gained, test impact
|
|
147
194
|
- **Trade-offs:** what gets harder, what is genuinely uncertain
|
|
148
|
-
- **Fixability:** auto | needs-confirm | report-only
|
|
195
|
+
- **Fixability:** auto | needs-confirm | report-only, and report-only for enforce, since a new rule fails the build before the edges it names are gone
|
|
149
196
|
- **Top recommendation:** on exactly 1 entry in the report, the reason this candidate goes first
|
|
150
197
|
```
|