fallow 3.5.0 → 3.6.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
@@ -2,98 +2,60 @@
2
2
 
3
3
  **Codebase intelligence for TypeScript and JavaScript.**
4
4
 
5
- Free static analysis of code and styles, optional paid runtime intelligence (Fallow Runtime). Quality, risk, architecture, dependencies, duplication, and design-system drift, for humans, CI, and the agents writing your code.
5
+ One binary finds unused code, circular dependencies, duplication, complexity hotspots, boundary violations, and design-system styling drift. An optional paid layer, Fallow Runtime, adds production execution evidence. No AI inside the analyzer, and no TypeScript compiler or Node.js runtime needed for static analysis: runs are deterministic, with typed output contracts and traceable explanations.
6
6
 
7
7
  [![CI](https://github.com/fallow-rs/fallow/actions/workflows/ci.yml/badge.svg)](https://github.com/fallow-rs/fallow/actions/workflows/ci.yml)
8
8
  [![npm](https://img.shields.io/npm/v/fallow.svg)](https://www.npmjs.com/package/fallow)
9
9
  [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/fallow-rs/fallow/blob/main/LICENSE)
10
10
 
11
- Fallow turns a frontend repository into a trusted quality report: health score, changed-code risk, hotspots, duplication, architecture issues, dependency hygiene, styling consistency, and cleanup opportunities.
12
-
13
- It helps you answer: what changed, what got riskier, what should be reviewed, what should be refactored, and what can be safely removed. No AI inside the analyzer. Fallow produces deterministic findings, typed output contracts, and traceable explanations that downstream tools can trust.
14
-
15
- Static analysis is open source. An optional runtime layer adds production execution evidence. Rust-native, sub-second, 123 framework plugins, no Node.js runtime dependency for analysis. fallow's edge is doing more in one pass: dead code, duplication, dependencies, complexity, architecture, styling consistency, and security candidates in a single tool. For head-to-head timings against [knip](https://knip.dev) and [jscpd](https://github.com/kucherenko/jscpd), see the [benchmarks](https://github.com/fallow-rs/fallow/tree/main/benchmarks): fallow is faster than knip on smaller projects, knip is faster on several larger repos, and jscpd's Rust rewrite is faster for raw duplication scanning.
16
-
17
- ## Installation
11
+ ## Install
18
12
 
19
13
  ```bash
20
- npm install --save-dev fallow # or: pnpm add -D fallow / yarn add -D fallow / bun add -d fallow
14
+ npm install --save-dev fallow # or: pnpm add -D fallow / yarn add -D fallow
21
15
  ```
22
16
 
23
- Installs the `fallow` CLI in your project, along with the `fallow-lsp` and `fallow-mcp` launchers that start the LSP and MCP servers from the same binary.
24
-
25
- The package also ships a version-matched Agent Skill under `skills/fallow`.
26
- For tools that need CLI and issue-surface metadata without spawning the binary,
27
- `fallow/capabilities.json` mirrors `fallow schema` for the installed version.
28
- TanStack Intent discovers it from `node_modules` automatically:
29
-
30
- ```bash
31
- npx @tanstack/intent list
32
- npx @tanstack/intent load fallow#fallow
33
- ```
34
-
35
- For one-off CLI use without project-local skill discovery, run `npx fallow`.
36
-
37
- Parsing fallow's JSON output in TypeScript? Import the typed shapes:
38
-
39
- ```ts
40
- import type { CheckOutput, FallowJsonOutput } from "fallow/types";
41
- ```
42
-
43
- The types are generated from the same schema as the VS Code extension and pin to the CLI version you install. See [docs.fallow.tools](https://docs.fallow.tools) for the full output contract.
17
+ This installs the `fallow` CLI plus the `fallow-lsp` and `fallow-mcp` launchers, so editor and agent integrations resolve the project-local binary instead of whatever happens to be on `PATH`. For one-off use, run `npx fallow` without installing. Other channels (cargo, Docker, prebuilt binaries) are covered in the [installation guide](https://docs.fallow.tools/installation).
44
18
 
45
19
  ## Quick start
46
20
 
47
21
  ```bash
48
- npx fallow audit # PR-style audit: verdict pass / warn / fail
49
- npx fallow audit --format json # Machine-readable audit (for CI and agents)
50
- npx fallow health --score # Quality score and grade
51
- npx fallow # Full codebase analysis: health + duplication + cleanup
52
- npx fallow dead-code # Cleanup-specific findings
22
+ npx fallow # Full pipeline: dead code + duplication + health
23
+ npx fallow audit # Gate only what a PR changed: verdict pass/warn/fail
24
+ npx fallow health --score # 0 to 100 health score with a letter grade
25
+ npx fallow dupes # Duplication; modes strict, mild (default), weak, semantic
53
26
  npx fallow fix --dry-run # Preview automatic cleanup
54
27
  ```
55
28
 
56
- ## What Fallow reports
57
-
58
- - **Quality score** -- compact health score with grade and trend delta when snapshot history is enabled
59
- - **PR risk** -- changed-code analysis with pass / warn / fail verdict and per-finding attribution
60
- - **Hotspots** -- functions, files, and packages combining complexity, churn, size, and coupling
61
- - **Duplication** -- clone families across four detection modes (strict, mild, weak, semantic)
62
- - **Design-system styling** -- CSS, Sass/Less, CSS Modules, Tailwind/shadcn/CVA, StyleX/PandaCSS, vanilla-extract, styled-components, and Emotion consistency signals
63
- - **Architecture** -- circular dependencies, boundary violations, re-export chains
64
- - **Dependency hygiene** -- unused, unlisted, unresolved, duplicate, and type-only deps; pnpm catalog and overrides
65
- - **Cleanup opportunities** -- unused files, exports, types, enum members, class members, stale suppressions
66
- - **Runtime intelligence (optional)** -- hot paths, cold code, runtime-weighted health, stale flags
29
+ ## Output and exit codes
67
30
 
68
- Cleanup opportunities are findings that look safe to review for removal because no graph evidence supports keeping them. Dead code is one category of cleanup, not the product identity.
31
+ Add `--format json --quiet` to any command for one typed JSON document on stdout. Exit code 1 means findings, not failure; 0 is clean (or an audit pass or warn verdict); 2 is a validation or runtime error, reported as a JSON error envelope rather than a stack trace.
69
32
 
70
- ## Code duplication
33
+ Parsing the output in TypeScript? Import the typed shapes, version-pinned to the CLI you install:
71
34
 
72
- ```bash
73
- fallow dupes # Default: mild mode
74
- fallow dupes --mode semantic # Catch clones with renamed variables
75
- fallow dupes --threshold 5 # Fail CI if duplication exceeds 5%
76
- fallow dupes --save-baseline # Save current duplication as baseline
35
+ ```ts
36
+ import type { CheckOutput, FallowJsonOutput } from "fallow/types";
77
37
  ```
78
38
 
79
- Four detection modes (strict, mild, weak, semantic), clone family grouping with refactoring suggestions, baseline tracking, and cross-language TS/JS matching.
39
+ Every issue carries an `actions[]` array with an `auto_fixable` flag, so scripts and agents know which findings they can hand to `fallow fix`. The full contract lives at [docs.fallow.tools](https://docs.fallow.tools).
80
40
 
81
- ## Built for agents
41
+ ## What fallow reports
82
42
 
83
- Fallow gives AI agents structured repo truth instead of forcing them to infer everything from grep. Agents call the CLI or the MCP server to answer:
43
+ - Unused files, exports, types, enum and class members, and dependencies
44
+ - Circular dependencies and re-export cycles
45
+ - Code duplication as clone families, across four detection modes
46
+ - Complexity hotspots and a 0 to 100 health score
47
+ - Architecture boundary violations, with zero-config presets
48
+ - Design-system styling drift for CSS and CSS-in-JS (Sass/Less, CSS Modules, Tailwind, styled-components, Emotion, and more)
49
+ - A changed-file PR gate with per-finding attribution (`fallow audit`)
50
+ - Optional runtime intelligence: hot paths, cold code, runtime-weighted health, stale flags (licensed Fallow Runtime; a single local coverage capture is free)
84
51
 
85
- - Who imports this symbol?
86
- - Why is this export considered used or unused?
87
- - What changed in this PR?
88
- - Which files are risky to touch?
89
- - What duplicate siblings exist?
90
- - What cleanup action is safest?
52
+ For head-to-head timings against [knip](https://knip.dev) and [jscpd](https://github.com/kucherenko/jscpd), see [BENCHMARKS.md](https://github.com/fallow-rs/fallow/blob/main/BENCHMARKS.md): fallow is faster than knip on smaller projects, knip is faster on several larger repos, and jscpd's Rust rewrite is faster at raw duplication scanning.
91
53
 
92
- Every issue in `--format json` carries a machine-actionable `actions` array with an `auto_fixable` flag so agents can self-correct.
54
+ ## Built for agents
93
55
 
94
- ### MCP server
56
+ Agents get structured repo truth instead of inferring everything from grep: who imports a symbol, why an export counts as used, what a PR changed, which cleanup action is safest.
95
57
 
96
- Agents that speak MCP can launch the bundled `fallow-mcp` server. Installed as a devDependency, the binary lives in `node_modules/.bin/` and is not on your `PATH`, so launch it through your package manager's runner:
58
+ The bundled `fallow-mcp` server lives in `node_modules/.bin/` when installed as a devDependency, so launch it through your package manager's runner:
97
59
 
98
60
  ```json
99
61
  {
@@ -106,15 +68,22 @@ Agents that speak MCP can launch the bundled `fallow-mcp` server. Installed as a
106
68
  }
107
69
  ```
108
70
 
109
- Swap `npx` for `pnpm exec` / `yarn` / `bunx` to match your package manager. If `fallow-mcp` is installed globally (on your `PATH`), `"command": "fallow-mcp"` works directly. See the [MCP integration guide](https://docs.fallow.tools/integrations/mcp).
71
+ Swap `npx` for `pnpm exec` or `yarn` to match your package manager; a globally installed `fallow-mcp` works as `"command": "fallow-mcp"` directly. See the [MCP integration guide](https://docs.fallow.tools/integrations/mcp).
72
+
73
+ The package also ships a version-matched agent skill under `skills/fallow`, and `fallow/capabilities.json` mirrors `fallow schema` for tools that need CLI and issue-surface metadata without spawning the binary. TanStack Intent discovers both from `node_modules`:
74
+
75
+ ```bash
76
+ npx @tanstack/intent list
77
+ npx @tanstack/intent load fallow#fallow
78
+ ```
110
79
 
111
80
  ## Framework support
112
81
 
113
- 123 built-in plugins covering Next.js, Nuxt, Remix, Qwik, SvelteKit, Gatsby, Astro, Angular, NestJS, AdonisJS, Ember, Expo Router, Vite, Webpack, Vitest, Jest, Playwright, Cypress, Storybook, ESLint, TypeScript, Tailwind, UnoCSS, Prisma, Drizzle, Convex, Turborepo, Hardhat, and many more. Auto-detected from your `package.json`.
82
+ Over 100 built-in framework plugins covering Next.js, Nuxt, Remix, Qwik, SvelteKit, Gatsby, Astro, Angular, NestJS, AdonisJS, Ember, Expo Router, Vite, Webpack, Vitest, Jest, Playwright, Cypress, Storybook, ESLint, TypeScript, Tailwind, UnoCSS, Prisma, Drizzle, Convex, Turborepo, Hardhat, and more. Entry points are auto-detected from `package.json`, so the first run needs no configuration.
114
83
 
115
84
  ## Configuration
116
85
 
117
- Create a config file in your project root, or run `fallow init`:
86
+ Works out of the box. To customize, let [`fallow recommend`](https://docs.fallow.tools/cli/recommend) propose a config from the detected stack (read-only; `--format json` returns the full decision set for agents), run `fallow init`, or create a config file in your project root:
118
87
 
119
88
  ```jsonc
120
89
  // .fallowrc.json
@@ -130,23 +99,13 @@ Create a config file in your project root, or run `fallow init`:
130
99
  }
131
100
  ```
132
101
 
133
- `$schema` gives editors autocomplete and validation and has no effect on
134
- analysis. As an npm package, `fallow` always ships a version-aligned schema at
135
- `./node_modules/fallow/schema.json`, which `fallow init` and
136
- `fallow recommend` point at by default: offline, no editor trust prompt. If
137
- you install fallow another way (cargo, homebrew, a bare binary) with no
138
- `node_modules/fallow` to point at, use the remote fallback instead:
139
- `https://raw.githubusercontent.com/fallow-rs/fallow/main/schema.json`. Some
140
- editors, including VS Code, refuse to load a remote schema URL until you
141
- explicitly trust the domain.
142
-
143
- Also supports TOML (`fallow init --toml` creates `fallow.toml`).
102
+ `$schema` gives editors autocomplete and validation and has no effect on analysis. The npm package ships a version-aligned schema at `./node_modules/fallow/schema.json`, so validation works offline with no editor trust prompt. TOML works too: `fallow init --toml` creates `fallow.toml`. Full reference: [configuration overview](https://docs.fallow.tools/configuration/overview).
144
103
 
145
104
  ## Documentation
146
105
 
147
- - [Full documentation](https://docs.fallow.tools)
106
+ - [docs.fallow.tools](https://docs.fallow.tools)
148
107
  - [GitHub repository](https://github.com/fallow-rs/fallow)
149
- - [Plugin Authoring Guide](https://github.com/fallow-rs/fallow/blob/main/docs/plugin-authoring.md)
108
+ - [Plugin authoring guide](https://github.com/fallow-rs/fallow/blob/main/docs/plugin-authoring.md)
150
109
 
151
110
  ## License
152
111
 
package/capabilities.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fallow",
3
- "version": "3.5.0",
3
+ "version": "3.6.0",
4
4
  "manifest_version": "1",
5
5
  "description": "Codebase analyzer for TypeScript/JavaScript: unused code, circular dependencies, code duplication, complexity hotspots, and architecture boundary violations",
6
6
  "global_flags": [
@@ -51,6 +51,16 @@
51
51
  "github-summary"
52
52
  ]
53
53
  },
54
+ {
55
+ "name": "--pretty",
56
+ "type": "bool",
57
+ "required": false,
58
+ "description": "Indent JSON output for manual inspection. Requires the final output format to be JSON",
59
+ "possible_values": [
60
+ "true",
61
+ "false"
62
+ ]
63
+ },
54
64
  {
55
65
  "name": "--quiet",
56
66
  "type": "bool",
@@ -311,7 +321,7 @@
311
321
  "name": "--save-regression-baseline",
312
322
  "type": "string",
313
323
  "required": false,
314
- "description": "Save the current issue counts as a regression baseline"
324
+ "description": "Save the current issue counts as a regression baseline. Omit PATH to update regression.baseline in the discovered fallow config, or create .fallowrc.json when none exists. Provide PATH to write a standalone file"
315
325
  },
316
326
  {
317
327
  "name": "--only",
@@ -1700,6 +1710,11 @@
1700
1710
  }
1701
1711
  ]
1702
1712
  },
1713
+ {
1714
+ "name": "audit-cache",
1715
+ "description": "Maintain reusable audit base-snapshot caches",
1716
+ "flags": []
1717
+ },
1703
1718
  {
1704
1719
  "name": "decision-surface",
1705
1720
  "description": "Surface the consequential structural DECISIONS a change embeds (the apex of the review brief), each framed as a judgment question with the routed expert to ask",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fallow",
3
- "version": "3.5.0",
3
+ "version": "3.6.0",
4
4
  "description": "Codebase intelligence for TypeScript and JavaScript. Free static analysis of code and styles, optional paid runtime intelligence (Fallow Runtime). Quality, risk, architecture, dependencies, duplication, and design-system drift for humans, CI, and the agents writing your code. Zero-config framework support.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -84,16 +84,16 @@
84
84
  "detect-libc": "2.1.2"
85
85
  },
86
86
  "devDependencies": {
87
- "@tanstack/intent": "0.3.2"
87
+ "@tanstack/intent": "0.3.5"
88
88
  },
89
89
  "optionalDependencies": {
90
- "@fallow-cli/darwin-arm64": "3.5.0",
91
- "@fallow-cli/darwin-x64": "3.5.0",
92
- "@fallow-cli/linux-x64-gnu": "3.5.0",
93
- "@fallow-cli/linux-arm64-gnu": "3.5.0",
94
- "@fallow-cli/linux-x64-musl": "3.5.0",
95
- "@fallow-cli/linux-arm64-musl": "3.5.0",
96
- "@fallow-cli/win32-arm64-msvc": "3.5.0",
97
- "@fallow-cli/win32-x64-msvc": "3.5.0"
90
+ "@fallow-cli/darwin-arm64": "3.6.0",
91
+ "@fallow-cli/darwin-x64": "3.6.0",
92
+ "@fallow-cli/linux-x64-gnu": "3.6.0",
93
+ "@fallow-cli/linux-arm64-gnu": "3.6.0",
94
+ "@fallow-cli/linux-x64-musl": "3.6.0",
95
+ "@fallow-cli/linux-arm64-musl": "3.6.0",
96
+ "@fallow-cli/win32-arm64-msvc": "3.6.0",
97
+ "@fallow-cli/win32-x64-msvc": "3.6.0"
98
98
  }
99
99
  }
@@ -1,10 +1,61 @@
1
1
  const test = require("node:test");
2
2
  const assert = require("node:assert/strict");
3
+ const fs = require("node:fs");
3
4
  const os = require("node:os");
4
5
  const { spawnSync } = require("node:child_process");
5
6
  const path = require("node:path");
6
7
 
7
8
  const RUN_BINARY = path.join(__dirname, "run-binary.js");
9
+ const BIN_DIR = path.join(__dirname, "..", "bin");
10
+
11
+ function currentPlatformPackage() {
12
+ const { getPlatformPackage } = require("./platform-package");
13
+ if (process.platform !== "linux") {
14
+ return getPlatformPackage(process.platform, process.arch);
15
+ }
16
+ let libcFamily;
17
+ try {
18
+ libcFamily = require("detect-libc").familySync();
19
+ } catch {
20
+ libcFamily = undefined;
21
+ }
22
+ return getPlatformPackage(process.platform, process.arch, libcFamily);
23
+ }
24
+
25
+ function runLauncher(t, launcher, args) {
26
+ const work = fs.mkdtempSync(path.join(os.tmpdir(), "fallow-launcher-"));
27
+ t.after(() => fs.rmSync(work, { recursive: true, force: true }));
28
+
29
+ const pkg = currentPlatformPackage();
30
+ assert.ok(pkg, "the test host must map to a supported platform package");
31
+ const pkgDir = path.join(work, "node_modules", ...pkg.split("/"));
32
+ fs.mkdirSync(pkgDir, { recursive: true });
33
+ fs.writeFileSync(
34
+ path.join(pkgDir, "package.json"),
35
+ JSON.stringify({ name: pkg, version: "3.5.0" }),
36
+ );
37
+
38
+ const binary = path.join(pkgDir, "fallow");
39
+ fs.writeFileSync(
40
+ binary,
41
+ "#!/usr/bin/env node\n" +
42
+ 'require("node:fs").writeFileSync(process.env.FALLOW_TEST_ARGS, JSON.stringify(process.argv.slice(2)));\n',
43
+ );
44
+ fs.chmodSync(binary, 0o755);
45
+
46
+ const argsFile = path.join(work, "args.json");
47
+ const result = spawnSync(process.execPath, [path.join(BIN_DIR, launcher), ...args], {
48
+ encoding: "utf8",
49
+ env: {
50
+ ...process.env,
51
+ NODE_PATH: path.join(work, "node_modules"),
52
+ FALLOW_SKIP_BINARY_VERIFY: "1",
53
+ FALLOW_TEST_ARGS: argsFile,
54
+ },
55
+ });
56
+ assert.equal(result.status, 0, result.stderr);
57
+ return JSON.parse(fs.readFileSync(argsFile, "utf8"));
58
+ }
8
59
 
9
60
  // Run a child that installs guardBrokenStdout, then emits a synthetic stdout
10
61
  // 'error' with the given code. Node delivers a broken-pipe failure as exactly
@@ -91,3 +142,23 @@ test("exitCodeForChildFailure preserves status codes and maps signal deaths", ()
91
142
  assert.equal(exitCodeForChildFailure({ status: null, signal: undefined }), 1);
92
143
  assert.equal(exitCodeForChildFailure({ status: null, signal: "NOT_A_SIGNAL" }), 1);
93
144
  });
145
+
146
+ test(
147
+ "fallow-lsp executes the multicall binary with the lsp-server subcommand",
148
+ { skip: process.platform === "win32" },
149
+ (t) => {
150
+ assert.deepEqual(runLauncher(t, "fallow-lsp", ["--stdio"]), ["lsp-server", "--stdio"]);
151
+ },
152
+ );
153
+
154
+ test(
155
+ "fallow-mcp executes the multicall binary with the mcp-server subcommand",
156
+ { skip: process.platform === "win32" },
157
+ (t) => {
158
+ assert.deepEqual(runLauncher(t, "fallow-mcp", ["--transport", "stdio"]), [
159
+ "mcp-server",
160
+ "--transport",
161
+ "stdio",
162
+ ]);
163
+ },
164
+ );
@@ -45,10 +45,10 @@ cargo install fallow-cli # build from source
45
45
 
46
46
  ## Agent Rules
47
47
 
48
- 1. **Always use `--format json --quiet 2>/dev/null`** for machine-readable output. The `2>/dev/null` discards stderr so progress messages and threshold warnings don't corrupt the JSON on stdout. Never use `2>&1`
48
+ 1. **Always use `--format json --quiet 2>/dev/null`** for machine-readable output and parse it as JSON. Compact JSON is the default; never depend on whitespace or add `--pretty` in agent pipelines. The `2>/dev/null` discards stderr so progress messages and threshold warnings don't corrupt the JSON on stdout. Never use `2>&1`
49
49
  2. **Always append `|| true`** to every fallow command. Exit code 1 means "issues found" (normal), not a runtime error. Without `|| true`, the Bash tool treats exit 1 as failure and cancels parallel commands. Only exit code 2 is a real error (invalid config, parse failure)
50
50
  3. **Use `--explain`** to include a `_meta` object in JSON output with metric definitions, ranges, and interpretation hints. In human format, `--explain` prints a `Description:` line under each section header.
51
- 4. **Use the root `kind` field** to identify typed JSON envelopes (`dead-code`, `dead-code-grouped`, `health`, `dupes`, `combined`, `audit`, etc.). `--legacy-envelope` exists only for one-cycle compatibility with older consumers.
51
+ 4. **Use the root `kind` field** to identify typed JSON envelopes (`dead-code`, `dead-code-grouped`, `health`, `dupes`, `combined`, `audit`, etc.).
52
52
  5. **Use issue type filters** (`--unused-exports`, `--unused-files`, etc.) to limit output scope
53
53
  6. **Always `--dry-run` before `fix`**, then `fix --yes` to apply
54
54
  7. **All output paths are relative** to the project root
@@ -109,6 +109,7 @@ Route by intent before reaching for the big analysis commands. Same matrix as `f
109
109
  | `suppressions` | List active fallow-ignore suppression markers (read-only inventory) | `--file` |
110
110
  | `explain` | Explain one issue type without running analysis | `<issue-type>`, `--format json` |
111
111
  | `audit` | Combined dead-code + complexity + duplication + styling for changed files, returns a verdict; `fallow review` is an alias for `fallow audit --brief` (advisory orientation brief, always exits 0) | `--base`, `--gate`, `--brief`, `--max-decisions`, `--walkthrough-guide`, `--walkthrough-file`, `--show-deprioritized`, `--production`, `--production-dead-code`, `--production-health`, `--production-dupes`, `--workspace`, `--changed-workspaces`, `--ci`, `--fail-on-issues`, `--explain`, `--explain-skipped`, `--dead-code-baseline`, `--health-baseline`, `--dupes-baseline`, `--max-crap`, `--coverage`, `--coverage-root`, `--no-css`, `--css-deep`, `--no-css-deep`, `--include-entry-exports` |
112
+ | `audit-cache` | Maintain reusable audit base-snapshot caches | |
112
113
  | `decision-surface` | Surface the consequential structural DECISIONS a change embeds (the apex of the review brief), each framed as a judgment question with the routed expert to ask | `--max-decisions` |
113
114
  | `impact` | Show what fallow has done for you: how many issues it is surfacing, the trend since the last recorded run, and how many commits it contained at the pre-commit gate | `--all`, `--sort`, `--limit` |
114
115
  | `security` | Surface opt-in local security candidates for agent verification (not confirmed vulnerabilities). Rule families include the graph rule `client-server-leak`, a data-driven `tainted-sink` catalogue, and the include-required `hardcoded-secret` category for provider-prefix credentials and high-entropy literals assigned to secret-shaped identifiers. Most catalogue rows require non-literal input; narrowly literal-aware rows flag deterministic unsafe literals. Rules default off; suppress a file with `// fallow-ignore-file security-sink`; scope categories with `security.categories`. Add project-local request object names with `security.requestReceivers`; it extends the built-in `req` / `request` / `ctx` / `context` / `event` allowlist for HTTP `query`, `params`, and `body` reads. `hardcoded-secret` runs only when listed in `security.categories.include`. | `--format human\|json\|sarif`, `--changed-since`, `--file`, `--diff-file`, `--workspace`, `--changed-workspaces`, `--surface`, `--ci`, `--fail-on-issues`, `--sarif-file`, `--summary` |
@@ -350,15 +351,17 @@ Adds a per-decision-point `contributions[]` array to every complexity finding (e
350
351
  ### Gate CI on regressions (baselines)
351
352
  ```bash
352
353
  # 1. Save the current issue counts as a regression baseline
353
- fallow dead-code --format json --quiet --save-regression-baseline .fallow/baseline.json
354
+ fallow dead-code --format json --quiet --save-regression-baseline
354
355
  # 2. In CI: fail only if issues increase beyond tolerance
355
- fallow dead-code --format json --quiet --regression-baseline .fallow/baseline.json --fail-on-regression --tolerance 0
356
+ fallow dead-code --format json --quiet --fail-on-regression --tolerance 0
356
357
  # Identity-based baseline (fail only on NEW findings, not raw counts)
357
358
  fallow dead-code --format json --quiet --save-baseline .fallow/snapshot.json
358
359
  fallow dead-code --format json --quiet --baseline .fallow/snapshot.json
359
360
  ```
360
361
 
361
- `--save-regression-baseline` / `--regression-baseline` / `--fail-on-regression` / `--tolerance` are count-based gates; `--save-baseline` / `--baseline` are identity-based (track finding identity, fail on new). All six are global flags, so they also work on `health` and `dupes`. `audit` rejects the global baseline flags and uses `--dead-code-baseline` / `--health-baseline` / `--dupes-baseline` instead.
362
+ `--save-regression-baseline` / `--regression-baseline` / `--fail-on-regression` / `--tolerance` are count-based gates for `dead-code` and bare combined mode. `--save-baseline` / `--baseline` are identity-based (track finding identity, fail on new). `audit` rejects the global baseline flags and uses `--dead-code-baseline` / `--health-baseline` / `--dupes-baseline` instead.
363
+
364
+ With no path, `--save-regression-baseline` updates `regression.baseline` in the discovered fallow config, or creates `.fallowrc.json` when none exists. Pass a path only when a standalone baseline file is preferred.
362
365
 
363
366
  ### Explain an issue type without running analysis
364
367
  ```bash
@@ -130,8 +130,9 @@ fallow dead-code --format json --quiet --trace src/utils.ts:myFunction
130
130
  fallow dead-code --format json --quiet --save-baseline fallow-baselines/dead-code.json
131
131
  fallow dead-code --format json --quiet --baseline fallow-baselines/dead-code.json --fail-on-issues
132
132
 
133
- # Regression detection: save baseline on main, compare on PRs
133
+ # Regression detection: update regression.baseline in the discovered config
134
134
  fallow dead-code --format json --quiet --save-regression-baseline
135
+ # Then compare on PRs
135
136
  fallow dead-code --format json --quiet --fail-on-regression --tolerance 2%
136
137
 
137
138
  # Scope to specific files (e.g., lint-staged)
@@ -509,7 +510,7 @@ fallow health --format json --quiet --trend
509
510
  {
510
511
  "kind": "health",
511
512
  "schema_version": 7,
512
- "version": "3.5.0",
513
+ "version": "3.6.0",
513
514
  "elapsed_ms": 32,
514
515
  "summary": {
515
516
  "files_analyzed": 482,
@@ -907,7 +908,7 @@ fallow audit \
907
908
  {
908
909
  "kind": "audit",
909
910
  "schema_version": 7,
910
- "version": "3.5.0",
911
+ "version": "3.6.0",
911
912
  "command": "audit",
912
913
  "verdict": "fail",
913
914
  "changed_files_count": 12,
@@ -982,7 +983,7 @@ fallow flags --format json --quiet --workspace my-package
982
983
  ```json
983
984
  {
984
985
  "schema_version": 7,
985
- "version": "3.5.0",
986
+ "version": "3.6.0",
986
987
  "elapsed_ms": 116,
987
988
  "feature_flags": [],
988
989
  "total_flags": 0
@@ -1083,7 +1084,7 @@ fallow security --gate newly-reachable --changed-since origin/main
1083
1084
  {
1084
1085
  "kind": "security",
1085
1086
  "schema_version": "4",
1086
- "version": "3.5.0",
1087
+ "version": "3.6.0",
1087
1088
  "elapsed_ms": 42,
1088
1089
  "config": {
1089
1090
  "rules": {
@@ -1112,7 +1113,7 @@ fallow security --gate newly-reachable --changed-since origin/main
1112
1113
  {
1113
1114
  "kind": "security",
1114
1115
  "schema_version": "4",
1115
- "version": "3.5.0",
1116
+ "version": "3.6.0",
1116
1117
  "elapsed_ms": 42,
1117
1118
  "config": {
1118
1119
  "rules": {
@@ -1637,6 +1638,7 @@ Available on all commands:
1637
1638
  | `-c, --config` | `string` | - | Config file path |
1638
1639
  | `--allow-remote-extends` | `bool` | `false` | Allow trusted config files to extend HTTPS URLs |
1639
1640
  | `-f, --format` | `human\|json\|sarif\|compact\|markdown\|codeclimate\|pr-comment-github\|pr-comment-gitlab\|review-github\|review-gitlab\|badge\|github-annotations\|github-summary` | `human` | Output format (alias: --output) |
1641
+ | `--pretty` | `bool` | `false` | Indent JSON output for manual inspection. Requires the final output format to be JSON |
1640
1642
  | `-q, --quiet` | `bool` | `false` | Suppress progress output |
1641
1643
  | `--no-cache` | `bool` | `false` | Disable incremental caching |
1642
1644
  | `--threads` | `string` | - | Number of parser threads |
@@ -1667,8 +1669,8 @@ Available on all commands:
1667
1669
  | `--report-path-prefix` | `string` | - | Prefix prepended to every path in the CI-facing formats (`github-annotations`, `github-summary`, `codeclimate`, `review-github`, `review-gitlab`). CI platforms address files by repository-root-relative path, so when the analyzed project lives in a subdirectory (e.g. `packages/app/`), paths need that offset. fallow detects the offset via the git toplevel automatically; this flag overrides the detection. Pass an empty string to disable rebasing and emit paths relative to `--root` |
1668
1670
  | `--fail-on-regression` | `bool` | `false` | Fail if issue count increased beyond tolerance vs a regression baseline |
1669
1671
  | `--tolerance` | `string` | `0` | Allowed increase: `"2%"` (percentage) or `"5"` (absolute). Default: `"0"` |
1670
- | `--regression-baseline` | `string` | - | Path to regression baseline file (default: `.fallow/regression-baseline.json`) |
1671
- | `--save-regression-baseline` | `string` | - | Save current issue counts as a regression baseline |
1672
+ | `--regression-baseline` | `string` | - | Path to a standalone regression baseline file. Without it, fallow uses `regression.baseline` from the config |
1673
+ | `--save-regression-baseline` | `string` | - | Save current issue counts. With no path, update `regression.baseline` in the discovered fallow config or create `.fallowrc.json`; with a path, write a standalone baseline file |
1672
1674
  | `--only` | `dead-code\|dupes\|health` | - | Run only specific analyses (e.g., `--only dead-code,dupes`). Values: `dead-code` (alias: `check`), `dupes`, `health` |
1673
1675
  | `--skip` | `dead-code\|dupes\|health` | - | Skip specific analyses (e.g., `--skip health`). Values: `dead-code` (alias: `check`), `dupes`, `health` |
1674
1676
  | `--dupes-mode` | `strict\|mild\|weak\|semantic` | - | Override duplication detection mode in combined mode |
@@ -1766,7 +1768,7 @@ Set `FALLOW_FORMAT=json` and `FALLOW_QUIET=1` in your agent environment to avoid
1766
1768
  | Format | Description | Use Case |
1767
1769
  |--------|-------------|----------|
1768
1770
  | `human` | Colored terminal output | Interactive use |
1769
- | `json` | Machine-readable JSON | Agent integration, CI pipelines |
1771
+ | `json` | Compact machine-readable JSON by default; add `--pretty` for indented manual inspection | Agent integration, CI pipelines |
1770
1772
  | `sarif` | Static Analysis Results Interchange Format | GitHub Code Scanning, SARIF-compatible tools |
1771
1773
  | `compact` | Grep-friendly: one issue per line. Dupes lines include `code-duplication:path:start-end:fingerprint=dup:<id>,...` | Quick filtering |
1772
1774
  | `markdown` | Markdown tables | Documentation, PR comments |
@@ -1836,7 +1838,7 @@ The HTTP layer mirrors the bash `gh_api_retry` / `curl_retry` helpers: `FALLOW_A
1836
1838
  {
1837
1839
  "kind": "dead-code",
1838
1840
  "schema_version": 7,
1839
- "version": "3.5.0",
1841
+ "version": "3.6.0",
1840
1842
  "elapsed_ms": 45,
1841
1843
  "total_issues": 12,
1842
1844
  "entry_points": {
@@ -1996,7 +1998,7 @@ When `--baseline` is used in combined output, the JSON includes a `baseline_delt
1996
1998
  {
1997
1999
  "kind": "dupes",
1998
2000
  "schema_version": 7,
1999
- "version": "3.5.0",
2001
+ "version": "3.6.0",
2000
2002
  "elapsed_ms": 82,
2001
2003
  "total_clones": 15,
2002
2004
  "total_lines_duplicated": 230,
@@ -2040,11 +2042,11 @@ When running `fallow` with no subcommand (all analyses), the JSON output combine
2040
2042
  {
2041
2043
  "kind": "combined",
2042
2044
  "schema_version": 7,
2043
- "version": "3.5.0",
2045
+ "version": "3.6.0",
2044
2046
  "elapsed_ms": 159,
2045
2047
  "check": {
2046
2048
  "schema_version": 7,
2047
- "version": "3.5.0",
2049
+ "version": "3.6.0",
2048
2050
  "elapsed_ms": 45,
2049
2051
  "total_issues": 12,
2050
2052
  "unused_files": [],
@@ -7,9 +7,9 @@
7
7
  * `npm/fallow/types/output-contract.d.ts` (published as `fallow/types`).
8
8
  *
9
9
  * To change a shape:
10
- * 1. Edit the Rust struct in `crates/types/src/results.rs` (or the
11
- * duplicates crate at `crates/core/src/duplicates/types.rs`). The Rust
12
- * side is the runtime source of truth for the JSON output.
10
+ * 1. Find the Rust owner through `derived_definition_names()` and its
11
+ * imports in `crates/cli/src/bin/schema_emit.rs`, then edit that type.
12
+ * Rust is the runtime source of truth for the JSON output.
13
13
  * 2. Regenerate `docs/output-schema.json` with
14
14
  * `cargo run -p fallow-cli --features schema-emit --bin fallow-schema-emit`.
15
15
  * The schema-emit drift tests compare the committed schema against the
@@ -10466,12 +10466,10 @@ export type RefactoringTarget = Omit<RefactoringTargetFinding, "actions">;
10466
10466
  // import the bare names from `fallow/types` would break at upgrade time
10467
10467
  // otherwise.
10468
10468
  //
10469
- // Stability commitment: these aliases ship as part of fallow's v2.x stable
10470
- // surface. They are scheduled for removal alongside the kind-tagged
10471
- // `FallowOutput` major bump (see https://github.com/fallow-rs/fallow/issues/413),
10472
- // with a one-minor-cycle deprecation window (`@deprecated` JSDoc +
10473
- // CHANGELOG headline) preceding the removal. New code should prefer the
10474
- // `*Finding` wrapper names. Full public-consumer policy:
10469
+ // Stability commitment: legacy output aliases remain supported throughout v3.
10470
+ // Removing them requires an explicit deprecation period and a future major
10471
+ // release. New code should prefer the `*Finding` wrapper names. Full
10472
+ // public-consumer policy:
10475
10473
  // https://github.com/fallow-rs/fallow/blob/main/docs/backwards-compatibility.md
10476
10474
  //
10477
10475