ts-reviewer 3.6.1 → 3.7.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
@@ -17,6 +17,8 @@ Four modes, one skill:
17
17
 
18
18
  ## What's New
19
19
 
20
+ **3.7.0 — 3 questions before a scan.** A scan you start asks, in this order: which domains (2 pages, nothing pre-ticked — page 1 the 4 cheap groups, page 2 Security and Architecture), whether to run the skill lint, and which model runs the passes (every run, your last answer first). A flag answers its own question, a resumed scan asks nothing, and `--defaults` asks nothing at all — for an agent that starts the scan for you. The default set drops Security: 8 domains. `--pick` is gone: the menu now shows without it.
21
+
20
22
  **3.6.1 — the agent menu waits.** On Windows, after you picked the install scope, the agent menu took no keys: it confirmed both agents unasked or quit without installing. It now waits for your choice.
21
23
 
22
24
  **3.6.0 — install once for every project.** `npx ts-reviewer@latest install` asks whether to install globally or into the project, and `update` brings every install to the latest version without questions. Antigravity is no longer a target.
@@ -31,12 +33,12 @@ Four modes, one skill:
31
33
 
32
34
  Both are optional: a project with no `@hotpath` markers, no tests, and no history gets today's behaviour plus 1 verdict line per finding.
33
35
 
34
- The review covers nine domains by default, each with its own detailed checklist. Add `--arch` or `--full` to include architecture analysis:
36
+ The review has ten domains, each with its own detailed checklist. A scan asks which to run; the default set, for `--defaults` or no answer, is the eight below without Security and Architecture:
35
37
 
36
38
  | Domain | Examples | Default |
37
39
  |---|---|---|
38
40
  | **Type Safety** | `any` abuse, unsafe casts, non-null assertions, `unknown` discipline, missing exhaustive checks | ✓ |
39
- | **Security** | Injection, SSRF, prototype pollution, ReDoS, path traversal, hardcoded secrets | ✓ |
41
+ | **Security** | Injection, SSRF, prototype pollution, ReDoS, path traversal, hardcoded secrets | menu page 2 / `--full` |
40
42
  | **Async Patterns** | Floating promises, race conditions, missing timeouts, unbounded concurrency, `forEach(async...)` | ✓ |
41
43
  | **Modernization** | Numeric enums, `\|\|` vs `??`, mutating array methods, `satisfies`, `using` keyword | ✓ |
42
44
  | **Code Quality** | Dead code, complexity, duplication, debug artifacts, import-time side effects, testability | ✓ |
@@ -44,7 +46,7 @@ The review covers nine domains by default, each with its own detailed checklist.
44
46
  | **Boundary Validation** | `as T` on `JSON.parse`/`fetch`/env, DTO vs domain model separation, contract drift | ✓ |
45
47
  | **Error Handling** | Silent failures, throw hygiene, `cause` chaining, failure design at API seams | ✓ |
46
48
  | **Dependency Hygiene** | Lockfiles, wildcard versions, `npm audit`, duplicate-purpose and trivial deps | ✓ |
47
- | **Architecture** | Shallow modules, scattered concepts, tight coupling, dependency direction, layering | `--arch` / `--full` |
49
+ | **Architecture** | Shallow modules, scattered concepts, tight coupling, dependency direction, layering | menu page 2 / `--arch` / `--full` |
48
50
 
49
51
  ## Installation
50
52
 
@@ -127,18 +129,31 @@ The main agent writes its decisions, not the report: `tools/pass-prompts.mjs` fi
127
129
 
128
130
  The passes run in groups: Type Safety with Boundary Validation, Async Patterns with Error Handling, Config with Dependency Hygiene, Modernization with Code Quality, and Security and Architecture alone.
129
131
 
132
+ #### Start questions
133
+
134
+ A scan or auto run you start asks 3 questions before it reads the project, in this order:
135
+
136
+ 1. **Domains** — a multi-select in 2 pages, with nothing ticked in advance (a numbered list such as `1,3` on a host with no multi-select):
137
+ - page 1: Type Safety + Boundary Validation, Async Patterns + Error Handling, Config + Dependency Hygiene, Modernization + Code Quality — a usual scan ticks all 4;
138
+ - page 2: Security, Architecture — the expensive ones.
139
+ 2. **Skill lint** — whether to download and run the pinned ESLint config. Asked only when a picked domain has lint-owned lines; Knip and dependency-cruiser are approved in the same question when Architecture is picked and missing locally.
140
+ 3. **Pass model** — the model and effort for the analysis passes, your last answer first.
141
+
142
+ A resumed scan asks none of them: the queue holds the answers. Leaving a question unanswered takes the default, except the skill lint, which an unanswered approval declines.
143
+
130
144
  #### Domain flags
131
145
 
132
- By default, only the nine core domains run. Use flags to control which domains are active:
146
+ A flag answers its question, so the scan does not ask it:
133
147
 
134
- | Flag | What runs |
148
+ | Flag | What it answers |
135
149
  |---|---|
136
- | *(none)* | Type Safety, Security, Async, Modernization, Code Quality, Config, Boundary Validation, Error Handling, Dependency Hygiene |
150
+ | `--defaults` | All 3: the 8 default domains, the skill lint on, the model of the scout file (or the default sub-agent). For an agent that starts the scan for you; another flag next to it still wins for its own question |
151
+ | `--domains <slugs>` | Only the named domains, by slug (`security`, `type-safety`, `boundary-validation`, ...) or by pass group (`type-safety+boundary-validation`). `--no-arch` still removes Architecture |
137
152
  | `--arch` | Architecture only (shallow modules, coupling, dependency direction, seams) |
138
153
  | `--full` | All ten domains |
139
- | `--no-arch` | The nine core domains — overrides `--arch`, `--full`, and any phrase that would enable architecture |
140
- | `--domains <slugs>` | Only the named domains, by slug (`security`, `type-safety`, `boundary-validation`, ...) or by pass group (`type-safety+boundary-validation`). `--no-arch` still removes Architecture |
141
- | `--pick` | Asks which pass groups to run, in a multi-select (a numbered list on Codex). No answer runs the default set |
154
+ | `--no-arch` | Removes Architecture from the set the other flags give, or runs the default set alone |
155
+ | `--lint` / `--no-lint` | Runs or skips the skill lint |
156
+ | `--scout <model>` | The pass model, for 1 run |
142
157
 
143
158
  Examples:
144
159
 
@@ -338,7 +353,7 @@ The test catches a check line that lost its severity, a block the profile does n
338
353
 
339
354
  ### Scan mode
340
355
 
341
- 1. **Discovery** — detects domain flags, maps the project, reads tsconfig.json, detects linter and test runner, asks the pass model once per project, and asks once before downloading the skill lint or a missing architecture tool.
356
+ 1. **Discovery** — detects domain flags, maps the project, reads tsconfig.json, detects linter and test runner, after the 3 start questions: domains, the skill lint and any missing architecture tool, and the pass model.
342
357
  2. **Diagnostics** — runs `tsc --noEmit`, the project linter, the skill lint, and LSP diagnostics (if available). The skill lint's findings become the pass `lint-skill`; compiler and linter output is cached under `code-smells/passes/` and reused on a resume of the same commit.
343
358
  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.
344
359
  4. **Analysis** — specialized passes, 1 per group of domains, judge the candidates against the active checklists, skipping the lines the skill lint owns, 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.
@@ -375,7 +390,7 @@ Validate a report directly with `node ts-reviewer/tools/validate-report.mjs --re
375
390
 
376
391
  - **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.
377
392
 
378
- - **Pick the pass model once** — the first scan asks which model and effort the analysis passes use, and writes the answer to `.claude/agents/ts-reviewer-scout.md` (Claude Code: `model`, `effort`) or `.codex/agents/ts-reviewer-scout.toml` (Codex: `model`, `model_reasoning_effort`). A smaller model there, for example Sonnet at `high`, costs less, while the main agent keeps verifying every finding. Delete the file to be asked again, or pass `--scout <model>` for 1 run. Architecture always runs on the main agent's model.
393
+ - **Pick the pass model** — every scan asks which model and effort the analysis passes use, offers your last answer first, and writes the answer to `.claude/agents/ts-reviewer-scout.md` (Claude Code: `model`, `effort`) or `.codex/agents/ts-reviewer-scout.toml` (Codex: `model`, `model_reasoning_effort`). A smaller model there, for example Sonnet at `high`, costs less, while the main agent keeps verifying every finding. Pass `--scout <model>` to skip the question for 1 run. Architecture always runs on the main agent's model.
379
394
 
380
395
  - **Commit before running fix** — so you can `git diff` to review changes and `git checkout -- .` to revert if needed.
381
396
 
@@ -7,7 +7,7 @@ description: >
7
7
  fix issues, fix the report, fix code smells, auto-fix, review and fix,
8
8
  clean up code, tech debt, code health, security audit, modernize, review my changes,
9
9
  review my PR, review last commit. Architecture review: --arch, --full, review architecture,
10
- find refactoring opportunities, full audit. Domain pick: --domains, --pick, pick domains,
10
+ find refactoring opportunities, full audit. Domain pick: --domains, --defaults, pick domains,
11
11
  choose domains. Pure TypeScript 5.9.x, ES2024, Node 24 only.
12
12
  ---
13
13
 
@@ -64,7 +64,7 @@ forbidden_behaviors:
64
64
  - do not emit the same file and line twice
65
65
  - do not boost severity in `full` scope mode: all code is treated alike
66
66
  - do not flag a config issue in a scoped mode unless `tsconfig.json` is in the diff
67
- - do not download and execute a missing analysis tool before the operator approves it once at discovery
67
+ - do not download and execute a missing analysis tool before the operator approves it in `start_questions`
68
68
  - 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
69
69
  - do not rename a report section, field, severity, confidence, or domain: `report_format` and `domains` hold exact identifiers
70
70
  - do not start a wave before every pass of the previous wave is marked `done`, `pending`, or `failed` in the queue
@@ -91,23 +91,39 @@ run_modes:
91
91
  | `auto` | review and fix, auto-fix, scan and fix, clean up | scan, then investigate, then fix, then a re-scan |
92
92
 
93
93
  domain_sets:
94
- - read `--domains` and `--pick` first, then the explicit `--arch`, `--full`, and `--no-arch` flags, then the phrases below, then fall back to the default set
95
- - Architecture is off in a default scan, and loads `references/architecture.md` only when it is active
94
+ - read `--domains` first, then the explicit `--arch`, `--full`, and `--no-arch` flags, then the phrases below, then ask the domain menu of `start_questions`
95
+ - Architecture and Security are off in the default set: both are expensive, and Architecture loads `references/architecture.md` only when it is active
96
96
  - `--domains` takes slugs joined by `,`: a domain name in lowercase with `-` for each space, or a `pass_groups` group id for every domain of the group
97
97
  - stop and list the valid slugs when `--domains` names a slug that is neither
98
- - the `--pick` options are the rows of `pass_groups` in row order, each naming its domains, and the operator picks 1 or more
99
- - ask the pick as a multi-select in questions of <= 4 options, or as a numbered list read from a reply such as `1,3` on a host with no multi-select
100
- - a pick with no operator answer runs the default set, and the discovery summary says so
101
- - a module joins `--domains` and `--pick` through its rows in `domains` and `pass_groups`, with no edit to this block
98
+ - a module joins `--domains` and the domain menu through its rows in `domains` and `pass_groups`, with no edit to this block
102
99
 
103
100
  | Flag or phrase | Active domains |
104
101
  |---|---|
105
- | none | the 9 default domains: Type Safety, Security, Async Patterns, Modernization, Code Quality, Config, Boundary Validation, Error Handling, Dependency Hygiene |
102
+ | `--defaults`, or no answer to the domain menu | the 8 default domains: Type Safety, Boundary Validation, Async Patterns, Error Handling, Config, Dependency Hygiene, Modernization, Code Quality |
103
+ | the domain menu | the domains of the picked groups |
106
104
  | `--arch`, review architecture, find refactoring opportunities, deepening review | Architecture only |
107
105
  | `--full`, full audit, full review, review everything | all 10 domains |
108
106
  | `--domains <slugs>` | the named domains, and every domain of a named group |
109
- | `--pick`, pick domains, choose domains | the domains of the picked groups |
110
- | `--no-arch` | the set the rows above give, without Architecture, and it wins over any flag or phrase above |
107
+ | `--no-arch` | the set the rows above give, without Architecture, and the default set when no row above answers |
108
+
109
+ start_questions:
110
+ - ask the 3 questions below in their order in a `scan` or `auto` run, after the resume ask of step 6 and before discovery
111
+ - skip a question its flag answers, and skip all 3 on a resume: the plan holds the answers
112
+ - `--defaults` answers all 3: the default set, the skill lint run, and the model of the scout file or the default sub-agent
113
+ - a flag next to `--defaults` wins for its own question
114
+ - a question with no operator answer takes the `--defaults` answer, except the skill lint: an unanswered approval is a decline
115
+ - the domain menu has 2 pages, each 1 multi-select question holding the `pass_groups` rows of its page in row order, each option naming its domains
116
+ - tick no option in advance, and say in the page 1 question that a usual scan ticks every option of page 1
117
+ - ask a page as a numbered list read from a reply such as `1,3` on a host with no multi-select
118
+ - ask the domain menu again when the operator ticks no option on either page: an empty scan is never the intent
119
+ - ask the skill lint only when an active domain owns a line carrying "lint-owned by", and approve Knip and dependency-cruiser in the same question when Architecture is active and missing locally
120
+ - ask the pass model as `pass_agent` states
121
+
122
+ | Question | Answered by |
123
+ |---|---|
124
+ | domains | `--domains`, `--arch`, `--full`, `--no-arch`, and the phrases of `domain_sets` |
125
+ | skill lint | `--lint` runs it, `--no-lint` declines it |
126
+ | pass model | `--scout <model>` |
111
127
 
112
128
  scope_modes:
113
129
 
@@ -135,11 +151,11 @@ domains:
135
151
 
136
152
  workflow:
137
153
  1. identify the run mode from `run_modes`
138
- 2. identify the active domain set from `domain_sets`
154
+ 2. identify the active domain set from `domain_sets`, and leave a question it does not answer to `start_questions`
139
155
  3. identify the scope mode from `scope_modes`, and default to `full` when the request names none
140
156
  4. build the file list with the command in `scope_commands` for that scope mode
141
157
  5. ask whether to fall back to `full` when a scoped mode yields 0 files
142
- 6. ask once whether to resume or restart when `code-smells/passes/queue.md` exists, and delete `code-smells/passes/` on restart
158
+ 6. ask once whether to resume or restart when `code-smells/passes/queue.md` exists, delete `code-smells/passes/` on restart, then ask `start_questions` unless resuming
143
159
  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
144
160
  8. map the project tree in full, whatever the scope mode
145
161
  9. read `tsconfig.json`, and when Config is active read `references/tsconfig.md` and audit the config flags
@@ -149,7 +165,7 @@ workflow:
149
165
  13. read `package.json` for the dependencies and the module type, and verify the TypeScript version, `engines.node`, and `@types/node` against `target_stack`
150
166
  14. identify declared entry points from `package.json#exports`, `main`, `bin`, and the `start`, `dev`, and `serve` scripts
151
167
  15. count the markers `hot_marker` in `references/stack-cost.md` defines across the files in scope, and name the count in the discovery summary
152
- 16. ask once before a pinned-major `npx -y` run: the skill lint when it runs, Knip and dependency-cruiser when Architecture is active and missing locally
168
+ 16. run a pinned-major `npx -y` tool only when `start_questions` approved it: the skill lint, Knip, and dependency-cruiser
153
169
  17. collect the context files named in `scope:` when the scope mode is scoped
154
170
  18. identify feature slices and public entry points when Architecture is active, leaving graph discovery to its mechanical pre-pass
155
171
  19. collect machine-readable dependency rules and prose from ADR directories, `ARCHITECTURE.md`, README, and `CONTRIBUTING.md`
@@ -279,7 +295,7 @@ Hot paths: <N> marked / none: hot rests on loop bodies alone
279
295
  Files in scope: <N> .ts files (+ <M> context files)
280
296
  Excluded framework packages: <package names, or none>
281
297
  Agents per wave: <N>
282
- Domains: <the active domains> from the default set / a flag / --domains / the pick / an unanswered pick
298
+ Domains: <the active domains> from the domain menu / a flag / --domains / --defaults / an unanswered menu / the resumed plan
283
299
  Main agent: <model>
284
300
  Pass agent: ts-reviewer-scout <model> <effort> / the default sub-agent; Architecture on the main agent
285
301
  Skill lint: <N> findings / declined / failed: <reason>
@@ -342,10 +358,11 @@ pass_queue:
342
358
  - the pass id is the group id of `pass_groups`, or `<group id>.<directory slug>` for a split pass
343
359
  - the pass order is the row order of `pass_groups`, after the row `lint-skill` of `skill_lint`
344
360
  - the plan names every pass with its domains and files, and `lint-skill` with its files and no prompt
361
+ - the plan holds the start answers a resume reuses: `lint`, the domains of each pass, and the pass `model` and `effort`, or no `model` for the default sub-agent
345
362
  - `pass-prompts.mjs` fills `subagent_template` for each pass, and keeps the status, attempts, and findings of a pass the queue already holds: a resume writes the same plan
346
363
  ```json
347
364
  {
348
- "head": "<sha>", "scope": "full", "agents": 3, "lint": true,
365
+ "head": "<sha>", "scope": "full", "agents": 3, "lint": true, "model": "sonnet", "effort": "medium",
349
366
  "passes": [
350
367
  { "id": "security.src-auth", "domains": ["Security"], "files": ["src/auth/a.ts"], "context": ["src/types.ts"] }
351
368
  ]
@@ -362,6 +379,8 @@ pass_queue:
362
379
  HEAD: <sha>
363
380
  Scope: <mode>
364
381
  Agents per wave: <N>
382
+ Lint: yes / no
383
+ Pass model: <model> <effort> / default sub-agent
365
384
 
366
385
  | Pass | Domains | Files | Status | Attempts | Findings |
367
386
  |---|---|---|---|---|---|
@@ -376,24 +395,24 @@ pass_groups:
376
395
  - a filtered group takes the scoped files that the `workflow:` command of any of its references lists
377
396
  - a filtered group takes every scoped file when the skill lint did not run and the project linter enables no `no-floating-promises`
378
397
 
379
- | Group | Domains | Files |
380
- |---|---|---|
381
- | `security` | Security | every scoped file |
382
- | `type-safety+boundary-validation` | Type Safety, Boundary Validation | every scoped file |
383
- | `async-patterns+error-handling` | Async Patterns, Error Handling | filtered |
384
- | `config+dependency-hygiene` | Config, Dependency Hygiene | no `.ts` file: the project files each reference reads |
385
- | `modernization+code-quality` | Modernization, Code Quality | every scoped file |
386
- | `architecture` | Architecture | the inputs `references/architecture.md` names |
398
+ | Group | Domains | Files | Menu page |
399
+ |---|---|---|---|
400
+ | `security` | Security | every scoped file | 2 |
401
+ | `type-safety+boundary-validation` | Type Safety, Boundary Validation | every scoped file | 1 |
402
+ | `async-patterns+error-handling` | Async Patterns, Error Handling | filtered | 1 |
403
+ | `config+dependency-hygiene` | Config, Dependency Hygiene | no `.ts` file: the project files each reference reads | 1 |
404
+ | `modernization+code-quality` | Modernization, Code Quality | every scoped file | 1 |
405
+ | `architecture` | Architecture | the inputs `references/architecture.md` names | 2 |
387
406
 
388
407
  pass_agent:
389
408
  - every group runs as the `ts-reviewer-scout` agent when the scout file exists, except `architecture`, which runs as the default sub-agent on the main agent's model
390
409
  - the scout file is `.claude/agents/ts-reviewer-scout.md` on Claude Code and `.codex/agents/ts-reviewer-scout.toml` on Codex, in the project root
391
- - ask once for the scout model and effort when the scout file is absent, and write the answer to it
410
+ - ask the scout model and effort on every run, by `start_questions`, offering the model of the scout file first, and write the answer to the scout file
392
411
  - offer the models the host's agent call lists, or take the name the operator types when the host lists none
393
412
  - the answer "the main agent's model" writes `inherit` on Claude Code and leaves `model` out on Codex
394
413
  - pass the scout model, and the effort where the call takes one, in each agent call: a host can load a new agent file late
395
414
  - `--scout <model>` in the request wins for 1 run: every group but `architecture` runs as the default sub-agent on that model, no scout file is written, and no scout question is asked
396
- - a run with no operator answer writes no scout file and runs every group as the default sub-agent
415
+ - a run with no operator answer, or with `--defaults`, keeps the scout file, and runs every group as the default sub-agent when there is none
397
416
  - a host with no scout file format runs every group as the default sub-agent
398
417
  - start a new agent for every pass, and never send a second pass to an agent that ran one: a reused agent reads each pass with every earlier one in its context
399
418
  - close each agent once its `done` line is written
@@ -408,6 +427,7 @@ skill_lint:
408
427
  - add `--in-diff` to the `lint-pass.mjs` command in a scoped mode: the skill lint reads the scoped files only
409
428
  - run it after step 21, and write its findings as the pass `lint-skill` with `tools/lint-pass.mjs`, which takes category, severity, and fix from the owning line
410
429
  - a declined or failed run marks the pass `lint-skill` failed, and every analysis pass keeps the lint-owned lines
430
+ - `start_questions` asks the approval at the start of the run, and `--lint` or `--no-lint` answers it
411
431
  - an approval question with no operator answer is a decline
412
432
  - the skill lint replaces no project linter: step 21 runs the project config as before
413
433
  - leave the pass `lint-skill` out of the queue when no active domain owns a line carrying "lint-owned by": the lint has nothing to decide
@@ -64,7 +64,8 @@ export function passPrompts(plan, root) {
64
64
  writeFileSync(path.join(prompts, `${pass.id}.md`), head + filled + "\n");
65
65
  }
66
66
  writeFileSync(path.join(dir, "queue.md"), [
67
- "# Pass queue", "", `HEAD: ${plan.head}`, `Scope: ${plan.scope}`, `Agents per wave: ${plan.agents}`, "",
67
+ "# Pass queue", "", `HEAD: ${plan.head}`, `Scope: ${plan.scope}`, `Agents per wave: ${plan.agents}`,
68
+ `Lint: ${plan.lint ? "yes" : "no"}`, `Pass model: ${[plan.model ?? "default sub-agent", plan.effort].filter(Boolean).join(" ")}`, "",
68
69
  "| Pass | Domains | Files | Status | Attempts | Findings |", "|---|---|---|---|---|---|", ...rows, "",
69
70
  ].join("\n"));
70
71
  return rows.length;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-reviewer",
3
- "version": "3.6.1",
3
+ "version": "3.7.0",
4
4
  "description": "Install the TypeScript Code Reviewer skill for Claude Code or Codex, globally or per project",
5
5
  "license": "MIT",
6
6
  "type": "module",