ts-reviewer 3.0.1 → 3.1.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.
package/README.md CHANGED
@@ -84,6 +84,8 @@ Audit the codebase for security and type safety problems
84
84
  Claude will analyze the project and write a report to `code-smells/report.md` in the project root.
85
85
  With Architecture active, the same directory also holds project discovery, Knip, graph, metric, co-change, rule, and Mermaid artifacts.
86
86
 
87
+ The analysis passes run in waves. `--agents N` sets how many run at once (default 3; `--agents 1` runs them one at a time in the main agent). Each pass writes its own findings file under `code-smells/passes/`, and the queue in `code-smells/passes/queue.md` tracks which passes are done, so an interrupted scan does not lose finished work.
88
+
87
89
  #### Domain flags
88
90
 
89
91
  By default, only the nine core domains run. Use flags to control which domains are active:
@@ -197,6 +199,12 @@ cnlp/ # the CNL-P format the skill files are wri
197
199
 
198
200
  ts-reviewer/
199
201
  ├── SKILL.md # Main skill file — mode routing, workflow orchestration
202
+ ├── tools/ # Mechanical pre-pass and report validator — plain Node, no dependencies
203
+ │ ├── discover-projects.mjs # Finds the TypeScript projects and their source roots
204
+ │ ├── co-change.mjs # Git co-change pairs across directory boundaries
205
+ │ ├── run-cruise.mjs # dependency-cruiser graphs, metrics, and Mermaid diagrams per project
206
+ │ ├── classify-run.mjs # Reads a tool run by its output, not its exit code
207
+ │ └── validate-report.mjs # Checks code-smells/report.md against the report contract
200
208
  └── references/
201
209
  ├── type-safety.md # Checklist: any, unknown, casts, !, exhaustiveness, branded types
202
210
  ├── security.md # Checklist: trust boundaries, injection, SSRF, pollution, ReDoS
@@ -240,9 +248,9 @@ The test catches a check line that lost its severity, a block the profile does n
240
248
  ### Scan mode
241
249
 
242
250
  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.
243
- 2. **Diagnostics** — runs `tsc --noEmit`, linter, and LSP diagnostics (if available)
251
+ 2. **Diagnostics** — runs `tsc --noEmit`, linter, and LSP diagnostics (if available); compiler and linter output is cached under `code-smells/passes/` and reused on a resume of the same commit.
244
252
  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.
253
+ 4. **Analysis** — specialized passes judge the candidates against the active checklists, running in waves of `--agents` at a time; each pass writes its own `code-smells/passes/<id>.jsonl`, and `passes/queue.md` marks which are done, so a stopped run resumes from the last checkpoint. Tool output is never a finding by itself.
246
254
  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
255
 
248
256
  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.
@@ -263,6 +271,10 @@ Validate a report directly with `node ts-reviewer/tools/validate-report.mjs --re
263
271
 
264
272
  - **Add `code-smells/` to `.gitignore`** — it contains review artifacts, not source code.
265
273
 
274
+ - **Resume an interrupted scan** — run the same scan again. When `code-smells/passes/queue.md` exists, the skill asks whether to resume (finished passes are skipped, cached `tsc` and linter output is reused on the same commit) or restart from scratch.
275
+
276
+ - **Claude Code users** — `CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS` in `settings.json` under `env` caps sub-agents for every session on the host. It is independent of `--agents`, which caps one review run and works in every supported agent.
277
+
266
278
  - **Commit before running fix** — so you can `git diff` to review changes and `git checkout -- .` to revert if needed.
267
279
 
268
280
  - **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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-reviewer",
3
- "version": "3.0.1",
3
+ "version": "3.1.0",
4
4
  "description": "Install the TypeScript Code Reviewer skill for Claude Code, Codex, or Antigravity",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -23,7 +23,7 @@ target_stack:
23
23
  - a pattern below this stack is a finding, and a feature above it is never recommended
24
24
 
25
25
  inputs:
26
- - the request, which carries the run mode, the domain set, and the scope mode
26
+ - the request, which carries the run mode, the domain set, the scope mode, and the wave size
27
27
  - the project `tsconfig.json`, `package.json`, and linter config
28
28
  - the reference checklists under `references/`
29
29
 
@@ -62,9 +62,12 @@ forbidden_behaviors:
62
62
  - do not download and execute a missing analysis tool before the operator approves it once at discovery
63
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
64
  - do not rename a report section, field, severity, confidence, or domain: `report_format` and `domains` hold exact identifiers
65
+ - do not start a wave before every pass of the previous wave is marked `done`, `pending`, or `failed` in the queue
66
+ - do not read a finding from an agent reply: the `.jsonl` file under `code-smells/passes/` is the record, and a reply holds 1 line
65
67
 
66
68
  outputs:
67
69
  - `code-smells/report.md` in the project root: the scan report, and the work plan fix reads
70
+ - `code-smells/passes/`: the pass queue, the cached diagnostics, and 1 JSONL file per pass
68
71
  - `code-smells/knip.json`, `projects.json`, `co-change.md`, `cruise-summary.md`, `metrics.md`, and graph and diagram directories when Architecture is active
69
72
  - `code-smells/suggested.dependency-cruiser.cjs` when prose declares dependency rules and no machine-readable declaration owns them
70
73
  - the `## Architecture Opportunities` section of the report only when Architecture is active and at least 1 confirmed finding exists
@@ -120,58 +123,65 @@ workflow:
120
123
  3. identify the scope mode from `scope_modes`, and default to `full` when the request names none
121
124
  4. build the file list with the command in `scope_commands` for that scope mode
122
125
  5. ask whether to fall back to `full` when a scoped mode yields 0 files
123
- 6. map the project tree in full, whatever the scope mode
124
- 7. read `tsconfig.json` and `references/tsconfig.md`, then audit the config flags
125
- 8. detect monorepo workspaces in `package.json` and `pnpm-workspace.yaml`, and every further tsconfig
126
- 9. audit the config that governs the files in scope, and name that config in the summary
127
- 10. read the linter config: `eslint.config.*`, `.eslintrc.*`, `biome.json`, `deno.json`
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`
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`
134
- 17. run `npx tsc --noEmit 2>&1 | head -200` over the full project, and report only the errors in the scoped files
135
- 18. run the linter: `npx eslint [files] --format json` or `npx biome check [files] --reporter json`
136
- 19. query the TypeScript LSP over MCP when it is reachable, then merge and deduplicate against the compiler output
137
- 20. triage every compiler and linter diagnostic through `severity_mapping`
138
- 21. read the reference file named in `domains` before each analysis pass
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
126
+ 6. ask once whether to resume or restart when `code-smells/passes/queue.md` exists, and delete `code-smells/passes/` on restart
127
+ 7. warn when the `HEAD` in the queue header differs from the current `HEAD` on a resume: the line re-read below catches a stale line
128
+ 8. map the project tree in full, whatever the scope mode
129
+ 9. read `tsconfig.json` and `references/tsconfig.md`, then audit the config flags
130
+ 10. detect monorepo workspaces in `package.json` and `pnpm-workspace.yaml`, and every further tsconfig
131
+ 11. audit the config that governs the files in scope, and name that config in the summary
132
+ 12. read the linter config: `eslint.config.*`, `.eslintrc.*`, `biome.json`, `deno.json`
133
+ 13. read `package.json` for the dependencies and the module type, and verify the TypeScript version, `engines.node`, and `@types/node` against `target_stack`
134
+ 14. identify declared entry points from `package.json#exports`, `main`, `bin`, and the `start`, `dev`, and `serve` scripts
135
+ 15. when Architecture is active, inspect local Knip and dependency-cruiser binaries and ask once before running either missing tool through pinned-major `npx -y`
136
+ 16. collect the context files named in `scope:` when the scope mode is scoped
137
+ 17. identify feature slices and public entry points when Architecture is active, leaving graph discovery to its mechanical pre-pass
138
+ 18. collect machine-readable dependency rules and prose from ADR directories, `ARCHITECTURE.md`, README, and `CONTRIBUTING.md`
139
+ 19. run `npx tsc --noEmit 2>&1 | head -200` over the full project into `code-smells/passes/tsc.log`, and report only the errors in the scoped files
140
+ 20. run the linter into `code-smells/passes/lint.json`: `npx eslint [files] --format json` or `npx biome check [files] --reporter json`
141
+ 21. reuse `tsc.log` and `lint.json` on a resume when the queue `HEAD` matches and the tree is clean, and rerun both otherwise
142
+ 22. query the TypeScript LSP over MCP when it is reachable, then merge and deduplicate against the compiler output
143
+ 23. triage every compiler and linter diagnostic through `severity_mapping`
144
+ 24. read the reference file named in `domains` before each analysis pass
145
+ 25. run the mechanical pre-pass in `references/architecture.md` when Architecture is active, passing the approved tool decision and scoped base
146
+ 26. report the discovery summary in the shape of `discovery_summary`, including skipped and clean mechanical results
147
+ 27. build the pass list: 1 pass per active domain, split by directory when scoped files > 20, with the shared types visible to every pass
148
+ 28. write `code-smells/passes/queue.md` in the shape of `pass_queue`, in its domain order, and skip a pass marked `done` on a resume
149
+ 29. run the pending passes in waves of the wave size, as sub-agents shaped by `subagent_template`, or in the main agent when the wave size is 1
150
+ 30. wait for every agent of a wave, then mark each pass `done` when the last line of its file is the `done` line, and `pending` otherwise
151
+ 31. mark a pass `failed` after 2 attempts without a `done` line, name it in the discovery summary, and report its domain as not run
152
+ 32. read the findings of every `done` pass from its `.jsonl` file before the re-read below
153
+ 33. re-read the exact lines in the current file state before a finding enters the report
154
+ 34. 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
155
+ 35. downgrade a flagged non-High pattern that appears 5+ times across the codebase by 1 level, and report it once as a Recurring Pattern
156
+ 36. boost a finding carrying `in_diff: true` by 1 level in a scoped mode, and mark it `High [boosted, was Medium — new code]`
157
+ 37. deduplicate the findings on the same file, line, and issue, keeping 1
158
+ 38. merge the findings 2 domains raise on the same file and line into 1 entry attributing both categories, at the higher severity
159
+ 39. consolidate 3+ identical issues into 1 Recurring Pattern entry
160
+ 40. 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
161
+ 41. write `code-smells/report.md` in the shape of `report_format`
162
+ 42. validate the report against `report_format` after writing it, and treat a `warning:` line as a pre-pass outcome the report cannot correct
153
163
  ```bash
154
164
  # SKILL is the directory this file was loaded from.
155
165
  SKILL=<the directory this file was loaded from>
156
166
  node "$SKILL/tools/validate-report.mjs" --repo . --report code-smells/report.md
157
167
  ```
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
168
+ 43. correct every named error and retry with report validation iterations <= 2
169
+ 44. 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
170
+ 45. sort by severity group, then category, then file path, and place `in_diff: true` before pre-existing in a scoped mode
171
+ 46. show the top 10 and summarize the rest in a table when Medium and Low together hold more than 15 issues
172
+ 47. recommend that the operator adds `code-smells/` to `.gitignore`: it holds review artifacts
173
+ 48. read `references/fix-workflow.md` before fix mode executes: it holds the complete protocol
174
+ 49. detect the test runner and run the baseline tests
175
+ 50. fix the issues file by file, and run `tsc --noEmit` after each file
176
+ 51. run the linter and fix the lint errors it reports
177
+ 52. run the full test suite, compare it against the baseline, and fix the regressions
178
+ 53. repeat the compiler, linter, and test verification with verification iterations <= 5
179
+ 54. rerun the Architecture mechanical pre-pass on the fixed tree when Architecture is active
180
+ 55. update `code-smells/report.md`: remove what is fixed, mark what failed
181
+ 56. show the scan summary in auto mode, and ask the operator whether to proceed with the fix
182
+ 57. re-scan after the fix in auto mode with full scan-fix cycles <= 2, and stop when issues persist after the second
183
+ 58. delete `code-smells/report.md` and report success when every issue is fixed
184
+ 59. retain the remaining `code-smells/` artifacts, state what they contain, and remove them only after the operator confirms
175
185
 
176
186
  scope_commands:
177
187
  ```bash
@@ -232,6 +242,8 @@ Strict mode: yes / partial / no
232
242
  Linter: eslint / biome / none
233
243
  Test runner: vitest / jest / mocha / node:test / none
234
244
  Files in scope: <N> .ts files (+ <M> context files)
245
+ Agents per wave: <N>
246
+ Resumed: <done>/<total> passes from code-smells/passes/queue.md, or no
235
247
  Architecture projects: <config and source roots, when active>
236
248
  Architecture tools: <local or approved npx versions, when active>
237
249
  Architecture coverage: <successful>/<selected>, when active
@@ -252,6 +264,9 @@ Read the reference checklist: [REFERENCE_PATH]
252
264
  Review these files: [FILE_LIST]
253
265
  Context files (read-only, do NOT report issues): [CONTEXT_FILE_LIST]
254
266
  Scope mode: [full|uncommitted|branch|commits:N]
267
+ Write every finding as 1 JSONL line to: [OUTPUT_PATH]
268
+ Append 1 last line when every file is reviewed: {"done": true, "findings": N, "files": M}
269
+ Reply with 1 line: the pass id, the findings count, the files count. The file is the result; the reply is not.
255
270
 
256
271
  Output JSONL, one object per line:
257
272
  {
@@ -269,6 +284,25 @@ Output JSONL, one object per line:
269
284
  }
270
285
  ```
271
286
 
287
+ pass_queue:
288
+ - `--agents N` in the request sets the wave size, and the default is 3
289
+ - `--agents 1` runs 1 pass at a time in the main agent, with no sub-agent
290
+ - the pass id is the domain slug, or `<domain slug>.<directory slug>` for a split pass
291
+ - the domain order: Security, Type Safety, Async Patterns, Error Handling, Boundary Validation, Config, Dependency Hygiene, Modernization, Code Quality, Architecture
292
+ - a status is `pending`, `done`, or `failed`, and `Attempts` counts the waves the pass ran in
293
+ ```markdown
294
+ # Pass queue
295
+
296
+ HEAD: <sha>
297
+ Scope: <mode>
298
+ Agents per wave: <N>
299
+
300
+ | Pass | Domain | Files | Status | Attempts | Findings |
301
+ |---|---|---|---|---|---|
302
+ | security | Security | 42 | done | 1 | 7 |
303
+ | type-safety.src-auth | Type Safety | 12 | pending | 1 | |
304
+ ```
305
+
272
306
  report_format:
273
307
  - the `##` sections of the block below are the whole set, in that order, and a heading outside it is a renamed section
274
308
  - Discovery, Pre-existing Issues, Architecture Opportunities, Verification, and Generated artifacts are optional, and the other 5 are always present