fallow 2.102.0 → 2.104.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 +2 -2
- package/package.json +10 -10
- package/schema.json +17 -0
- package/skills/fallow/SKILL.md +11 -10
- package/skills/fallow/references/cli-reference.md +60 -12
- package/skills/fallow/references/gotchas.md +13 -7
- package/skills/fallow/references/patterns.md +5 -5
- package/types/output-contract.d.ts +448 -122
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ Fallow turns a JS/TS repository into a trusted quality report: health score, cha
|
|
|
12
12
|
|
|
13
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
14
|
|
|
15
|
-
Static analysis is free and open source. An optional paid runtime layer (Fallow Runtime) adds production execution evidence. Rust-native, sub-second,
|
|
15
|
+
Static analysis is free and open source. An optional paid runtime layer (Fallow Runtime) 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, and security 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
16
|
|
|
17
17
|
## Installation
|
|
18
18
|
|
|
@@ -107,7 +107,7 @@ Swap `npx` for `pnpm exec` / `yarn` / `bunx` to match your package manager. If `
|
|
|
107
107
|
|
|
108
108
|
## Framework support
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
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`.
|
|
111
111
|
|
|
112
112
|
## Configuration
|
|
113
113
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fallow",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.104.0",
|
|
4
4
|
"description": "Deterministic codebase intelligence for TypeScript and JavaScript. Quality, risk, architecture, dependencies, duplication, and safe cleanup evidence for humans, CI, and agents. Optional runtime intelligence layer (Fallow Runtime) adds production execution evidence. Rust-native, sub-second, zero-config framework support.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -80,16 +80,16 @@
|
|
|
80
80
|
"detect-libc": "2.1.2"
|
|
81
81
|
},
|
|
82
82
|
"devDependencies": {
|
|
83
|
-
"@tanstack/intent": "0.
|
|
83
|
+
"@tanstack/intent": "0.3.2"
|
|
84
84
|
},
|
|
85
85
|
"optionalDependencies": {
|
|
86
|
-
"@fallow-cli/darwin-arm64": "2.
|
|
87
|
-
"@fallow-cli/darwin-x64": "2.
|
|
88
|
-
"@fallow-cli/linux-x64-gnu": "2.
|
|
89
|
-
"@fallow-cli/linux-arm64-gnu": "2.
|
|
90
|
-
"@fallow-cli/linux-x64-musl": "2.
|
|
91
|
-
"@fallow-cli/linux-arm64-musl": "2.
|
|
92
|
-
"@fallow-cli/win32-arm64-msvc": "2.
|
|
93
|
-
"@fallow-cli/win32-x64-msvc": "2.
|
|
86
|
+
"@fallow-cli/darwin-arm64": "2.104.0",
|
|
87
|
+
"@fallow-cli/darwin-x64": "2.104.0",
|
|
88
|
+
"@fallow-cli/linux-x64-gnu": "2.104.0",
|
|
89
|
+
"@fallow-cli/linux-arm64-gnu": "2.104.0",
|
|
90
|
+
"@fallow-cli/linux-x64-musl": "2.104.0",
|
|
91
|
+
"@fallow-cli/linux-arm64-musl": "2.104.0",
|
|
92
|
+
"@fallow-cli/win32-arm64-msvc": "2.104.0",
|
|
93
|
+
"@fallow-cli/win32-x64-msvc": "2.104.0"
|
|
94
94
|
}
|
|
95
95
|
}
|
package/schema.json
CHANGED
|
@@ -194,6 +194,9 @@
|
|
|
194
194
|
"dynamic-segment-name-conflict": "error"
|
|
195
195
|
}
|
|
196
196
|
},
|
|
197
|
+
"unusedComponentProps": {
|
|
198
|
+
"$ref": "#/$defs/UnusedComponentPropsConfig"
|
|
199
|
+
},
|
|
197
200
|
"boundaries": {
|
|
198
201
|
"$ref": "#/$defs/BoundaryConfig",
|
|
199
202
|
"default": {
|
|
@@ -1227,6 +1230,20 @@
|
|
|
1227
1230
|
}
|
|
1228
1231
|
]
|
|
1229
1232
|
},
|
|
1233
|
+
"UnusedComponentPropsConfig": {
|
|
1234
|
+
"description": "Options for the `unused-component-props` rule.\n\nLets a project exempt component props whose local destructure binding name\nmatches a regex from `unused-component-props`, honoring the\n\"accepted-but-intentionally-unused\" leading-underscore convention (Svelte 5\n`$props()`, React destructure) that mirrors TypeScript `noUnusedParameters`\nand ESLint `@typescript-eslint/no-unused-vars` `varsIgnorePattern` /\n`argsIgnorePattern`. Opt-in; an unset `ignorePattern` leaves the rule's\nbehavior unchanged.",
|
|
1235
|
+
"type": "object",
|
|
1236
|
+
"properties": {
|
|
1237
|
+
"ignorePattern": {
|
|
1238
|
+
"description": "Regex matched against each declared prop's LOCAL destructure binding name\n(e.g. `_stage` in `let { stage: _stage } = $props()`), which falls back\nto the public prop name when there is no alias. A prop whose local name\nmatches is treated as intentionally unused and never reported as\n`unused-component-props`. Matching is unanchored (substring), like\nESLint's `RegExp.test`, so anchor with `^_` to match a leading\nunderscore. Compiled and validated at config load (an invalid regex fails\nload). Applies to Vue, Svelte, Astro, and React/Preact props.",
|
|
1239
|
+
"type": [
|
|
1240
|
+
"string",
|
|
1241
|
+
"null"
|
|
1242
|
+
]
|
|
1243
|
+
}
|
|
1244
|
+
},
|
|
1245
|
+
"additionalProperties": false
|
|
1246
|
+
},
|
|
1230
1247
|
"BoundaryConfig": {
|
|
1231
1248
|
"description": "Architecture boundary configuration.",
|
|
1232
1249
|
"type": "object",
|
package/skills/fallow/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: fallow
|
|
3
|
-
description: Codebase intelligence for JavaScript and TypeScript. Free static layer reports quality, changed-code risk, cleanup opportunities (unused files, exports, types, dependencies), code duplication, circular dependencies, complexity hotspots, architecture boundary violations, feature flag patterns, and opt-in security candidates. Runtime coverage merges production execution data into the same health report for hot-path review, cold-path deletion confidence, and stale-flag evidence, with a single local capture available by default and continuous/cloud runtime monitoring available as an optional mode.
|
|
3
|
+
description: Codebase intelligence for JavaScript and TypeScript. Free static layer reports quality, changed-code risk, cleanup opportunities (unused files, exports, types, dependencies), code duplication, circular dependencies, complexity hotspots, architecture boundary violations, feature flag patterns, and opt-in security candidates. Runtime coverage merges production execution data into the same health report for hot-path review, cold-path deletion confidence, and stale-flag evidence, with a single local capture available by default and continuous/cloud runtime monitoring available as an optional mode. 123 framework plugins, zero configuration, sub-second static analysis. Use when asked to analyze code health, audit PR risk, find cleanup opportunities or unused code, detect duplicates, check circular dependencies, audit complexity, check architecture boundaries, detect feature flags, surface security candidates, clean up the codebase, auto-fix issues, merge runtime coverage, or run fallow.
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
6
|
author: Bart Waardenburg
|
|
@@ -10,7 +10,7 @@ metadata:
|
|
|
10
10
|
|
|
11
11
|
# Fallow: codebase intelligence for JavaScript and TypeScript
|
|
12
12
|
|
|
13
|
-
Codebase intelligence for JavaScript and TypeScript. The free static layer reports quality, changed-code risk, cleanup opportunities, circular dependencies, code duplication, complexity hotspots, architecture boundary violations, feature flag patterns, and opt-in security candidates. Runtime coverage merges production execution data into the same `fallow health` report for hot-path review, cold-path deletion confidence, and stale-flag evidence, with a single local capture available by default and continuous/cloud runtime monitoring available as an optional mode.
|
|
13
|
+
Codebase intelligence for JavaScript and TypeScript. The free static layer reports quality, changed-code risk, cleanup opportunities, circular dependencies, code duplication, complexity hotspots, architecture boundary violations, feature flag patterns, and opt-in security candidates. Runtime coverage merges production execution data into the same `fallow health` report for hot-path review, cold-path deletion confidence, and stale-flag evidence, with a single local capture available by default and continuous/cloud runtime monitoring available as an optional mode. 123 framework plugins, zero configuration, sub-second static analysis.
|
|
14
14
|
|
|
15
15
|
## When to Use
|
|
16
16
|
- Finding cleanup opportunities (unused files, exports, types, enum/class members)
|
|
@@ -66,7 +66,6 @@ cargo install fallow-cli # build from source
|
|
|
66
66
|
## Onboarding And Insight
|
|
67
67
|
Offer setup only after a human-requested analysis shows findings and all signals match: `fallow config --path` exits 3, not CI, not a pipeline format, `fallow impact --format json --quiet` has `onboarding_declined: false`, and no offer happened this session. Ask after showing value. Choices: guard commits and PRs, baseline the existing backlog and clean by category, add AGENTS.md guidance, or keep as-is. On decline, run `fallow init --decline --quiet` and stay silent for this project. Mutate only after consent. For guards, inspect `fallow hooks status --format json --quiet`, then use `fallow hooks install --target agent` and `fallow hooks install --target git`; for large backlogs, pair the gate with `--save-baseline` / new-only guidance. Offer `fallow impact enable` as local-only value tracking, never as telemetry; also offer it once on already-configured projects when `fallow impact status --format json` has `enabled: false` and `explicit_decision: false`, and record a no with `fallow impact disable --quiet`. Surface value on clear events: if the agent gate blocked a commit or push and a later retry succeeded, mention what was contained; when `next_steps` carries id `impact-report`, run its command and relay the non-zero numbers to the user in one line. On request, summarize non-zero Impact counts. Ask about telemetry only after such a win, only if `fallow telemetry status --format json` has `explicit_decision: false`, and never run `fallow telemetry enable`.
|
|
68
68
|
## Task Cheat Sheet
|
|
69
|
-
|
|
70
69
|
Route by intent before reaching for the big analysis commands. Same matrix as `fallow schema` (`task_matrix`) and the generated AGENTS.md section.
|
|
71
70
|
|
|
72
71
|
<!-- generated:task-matrix:start -->
|
|
@@ -107,10 +106,10 @@ Route by intent before reaching for the big analysis commands. Same matrix as `f
|
|
|
107
106
|
| `list` | Inspect project structure | `--files`, `--entry-points`, `--plugins`, `--boundaries`, `--workspaces` |
|
|
108
107
|
| `workspaces` | Inspect monorepo workspaces + discovery diagnostics (shorthand for `list --workspaces`) | (no flags) |
|
|
109
108
|
| `dupes` | Code duplication detection | `--mode`, `--threshold`, `--top`, `--changed-since`, `--workspace`, `--changed-workspaces`, `--skip-local`, `--cross-language`, `--ignore-imports`, `--no-ignore-imports`, `--explain-skipped`, `--fail-on-regression`, `--tolerance`, `--regression-baseline`, `--save-regression-baseline` |
|
|
110
|
-
| `health` | Function complexity analysis (also covers Angular templates as synthetic `<template>` findings: external `.html` files via `templateUrl` AND inline `@Component({ template: \`...\` })` literals; suppress external with `<!-- fallow-ignore-file complexity -->` at the top of the `.html` file, suppress inline with `// fallow-ignore-next-line complexity` directly above the `@Component` decorator) | `--complexity`, `--max-cyclomatic`, `--max-cognitive`, `--max-crap`, `--top`, `--sort`, `--file-scores`, `--hotspots`, `--ownership`, `--ownership-emails`, `--targets`, `--effort`, `--score`, `--min-score`, `--since`, `--min-commits`, `--save-snapshot`, `--trend`, `--coverage-gaps`, `--coverage`, `--coverage-root`, `--runtime-coverage`, `--min-invocations-hot`, `--min-observation-volume`, `--low-traffic-threshold`, `--workspace`, `--changed-workspaces`, `--baseline`, `--save-baseline` |
|
|
109
|
+
| `health` | Function complexity analysis (also covers Angular templates as synthetic `<template>` findings: external `.html` files via `templateUrl` AND inline `@Component({ template: \`...\` })` literals; suppress external with `<!-- fallow-ignore-file complexity -->` at the top of the `.html` file, suppress inline with `// fallow-ignore-next-line complexity` directly above the `@Component` decorator) | `--complexity`, `--max-cyclomatic`, `--max-cognitive`, `--max-crap`, `--top`, `--sort`, `--file-scores`, `--hotspots`, `--ownership`, `--ownership-emails`, `--targets`, `--effort`, `--score`, `--min-score`, `--since`, `--min-commits`, `--save-snapshot`, `--trend`, `--coverage-gaps`, `--coverage`, `--coverage-root`, `--runtime-coverage`, `--min-invocations-hot`, `--min-observation-volume`, `--low-traffic-threshold`, `--css`, `--complexity-breakdown`, `--min-severity`, `--report-only`, `--workspace`, `--changed-workspaces`, `--baseline`, `--save-baseline` |
|
|
111
110
|
| `flags` | Detect feature flag patterns (env vars, SDK calls, config objects) | `--top` |
|
|
112
111
|
| `explain` | Explain one issue type without running analysis | `<issue-type>`, `--format json` |
|
|
113
|
-
| `audit` | Combined dead-code + complexity + duplication for changed files | `--base`, `--gate`, `--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`, `--include-entry-exports` |
|
|
112
|
+
| `audit` | Combined dead-code + complexity + duplication 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`, `--include-entry-exports` |
|
|
114
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` |
|
|
115
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` |
|
|
116
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` |
|
|
@@ -149,10 +148,11 @@ Run `fallow <command> --help` for the full flag list per command (see also refer
|
|
|
149
148
|
| `circular-dependency` | `--circular-deps` | - | `// fallow-ignore-next-line circular-dependency` | Import cycles in the module graph |
|
|
150
149
|
| `re-export-cycle` | `--re-export-cycles` | - | `// fallow-ignore-file re-export-cycle` | Barrel files re-exporting from each other in a loop (`kind: "multi-node"`) or a barrel re-exporting from itself (`kind: "self-loop"`). Chain propagation through the loop is a structural no-op so imports through any member may silently come up empty. Default `warn`. Distinct from `circular-dependencies` (runtime cycles, sometimes intentional). File-scoped suppression only: `// fallow-ignore-file re-export-cycle` on any member breaks the cycle. |
|
|
151
150
|
| `boundary-violation` | `--boundary-violations` | - | `// fallow-ignore-next-line boundary-violation` | Imports crossing architecture zone boundaries. Presets: `layered`, `hexagonal`, `feature-sliced`, `bulletproof`; `autoDiscover` can create one zone per feature directory; per-rule `allowTypeOnly: [zones]` admits `import type` / `export type` crossings while still blocking value imports. Optional sections: `boundaries.coverage.requireAllFiles` reports unzoned source files (`allowUnmatched` globs exempt intentional ones), and `boundaries.calls.forbidden` bans callee patterns per zone (segment-aware and import-resolved, so `child_process.*` covers `node:child_process` named/namespace/default imports; direct callees only, zoned files only). The whole family shares the `boundary-violation` rule and suppression token (`boundary-call-violation` and `boundary-call-violations` accepted as aliases); start the rule at `warn` for a staged rollout |
|
|
152
|
-
| `boundary-coverage` | - | - | `// fallow-ignore-file boundary-violation` | Source file matches no configured architecture boundary zone; Requires boundaries.coverage.requireAllFiles |
|
|
153
|
-
| `boundary-call-violation` | - | - | `// fallow-ignore-next-line boundary-call-violation` | Zoned file calls a callee its zone forbids; Requires boundaries.calls.forbidden patterns |
|
|
151
|
+
| `boundary-coverage` | `--boundary-violations` | - | `// fallow-ignore-file boundary-violation` | Source file matches no configured architecture boundary zone; Requires boundaries.coverage.requireAllFiles |
|
|
152
|
+
| `boundary-call-violation` | `--boundary-violations` | - | `// fallow-ignore-next-line boundary-call-violation` | Zoned file calls a callee its zone forbids; Requires boundaries.calls.forbidden patterns |
|
|
154
153
|
| `policy-violation` | `--policy-violations` | - | `// fallow-ignore-next-line policy-violation` | Calls, imports, or catalogue-derived effects banned by a declarative rule pack (`rulePacks` config key lists standalone JSON/JSONC files of `banned-call`, `banned-import`, and `banned-effect` rules; pure data, no project code executes). Findings identified as `<pack>/<rule-id>`. Default `warn` master; per-rule `severity` overrides per finding and the exit gate reads the effective severity. Invalid or missing packs fail config load with exit 2. `fallow rule-pack-schema` prints the pack JSON Schema. Use the scoped token to suppress one rule; bare `policy-violation` still covers every pack rule on the line or file. |
|
|
155
154
|
| `stale-suppression` | `--stale-suppressions` | - | - | `fallow-ignore` comments or `@expected-unused` JSDoc tags that no longer match any issue |
|
|
155
|
+
| `missing-suppression-reason` | - | - | - | Suppression comment omits a required reason |
|
|
156
156
|
| `unused-catalog-entry` | `--unused-catalog-entries` | yes | - | `pnpm-workspace.yaml` entries no workspace package.json references via `catalog:` (default `warn`) |
|
|
157
157
|
| `empty-catalog-group` | `--empty-catalog-groups` | - | - | Named `catalogs.<name>:` groups in `pnpm-workspace.yaml` with no entries. Top-level `catalog:` placeholders are ignored. Default `warn`. |
|
|
158
158
|
| `unresolved-catalog-reference` | `--unresolved-catalog-references` | - | - | `package.json` references to `catalog:` / `catalog:<name>` whose catalog does not declare the package; `pnpm install` would fail. Default `error`. Suppress via `ignoreCatalogReferences: [{ package, catalog?, consumer? }]` in fallow config (package.json has no comment syntax). |
|
|
@@ -210,6 +210,7 @@ When using fallow via MCP (`fallow-mcp`), the following tools are available:
|
|
|
210
210
|
| `get_blast_radius` | runtime-coverage | freemium | `coverage`, `group_by` | Runtime-context slice for blast-radius review. Same params as `check_runtime_coverage`; read `runtime_coverage.blast_radius` for stable `fallow:blast:<hash>` IDs, caller counts, traffic-weighted caller reach, optional cloud deploy touch counts, and low/medium/high risk bands. |
|
|
211
211
|
| `get_importance` | runtime-coverage | freemium | `coverage`, `group_by` | Runtime-context slice for production-importance review. Same params as `check_runtime_coverage`; read `runtime_coverage.importance` for stable `fallow:importance:<hash>` IDs, invocations, cyclomatic complexity, owner count, 0-100 score, and templated reason. |
|
|
212
212
|
| `get_cleanup_candidates` | runtime-coverage | freemium | `coverage`, `group_by` | Runtime-context slice for cleanup review. Same params as `check_runtime_coverage`; read `runtime_coverage.findings` for `safe_to_delete`, `review_required`, `low_traffic`, and `coverage_unavailable`. |
|
|
213
|
+
| `get_token_blast_radius` | analysis | free | - | Design-token blast radius for Tailwind v4 @theme tokens AND CSS-in-JS defineVars/createTheme-family token definitions: per token, a consumer_count (static lower bound) and a capped located consumers[] sample tagged theme-var/css-var/utility/apply (Tailwind) or js-member (CSS-in-JS cross-module member access); descriptive context for sizing a token change, never a deletion gate |
|
|
213
214
|
| `audit` | analysis | free | `gate`, `base`, `max_crap`, `coverage`, `runtime_coverage` | Combined dead-code + complexity + duplication for changed files, returns verdict. Set `gate` to `"new-only"` or `"all"`. Optional `runtime_coverage` (V8 dir / V8 JSON / Istanbul JSON) folds runtime findings into the same call; `min_invocations_hot` tunes the hot-path threshold (default 100). Runtime evidence appears under the audit `complexity` sub-result, including `coverage_intelligence` when combined evidence yields actionable recommendations. |
|
|
214
215
|
| `decision_surface` | analysis | free | `base`, `max_decisions`, `workspace` | Surface the few consequential structural decisions a change embeds (coupling, public API, dependency), each as a judgment question with the routed expert; ranked, capped, and signal_id-anchored |
|
|
215
216
|
| `fallow_explain` | introspection | free | `issue_type` | Explain one issue type without running analysis. Required `issue_type`; returns rationale, examples, fix guidance, and docs URL |
|
|
@@ -296,7 +297,7 @@ fallow list --entry-points --format json --quiet
|
|
|
296
297
|
fallow list --plugins --format json --quiet
|
|
297
298
|
```
|
|
298
299
|
|
|
299
|
-
Shows detected entry points and active framework plugins (
|
|
300
|
+
Shows detected entry points and active framework plugins (123 built-in: Next.js, Vite, Ember, Wuchale, Jest, Storybook, Tailwind, PandaCSS, Contentlayer, tap, tsd, etc.).
|
|
300
301
|
|
|
301
302
|
### Production-only analysis
|
|
302
303
|
```bash
|
|
@@ -442,7 +443,7 @@ When `--format json` is active and exit code is 2, errors are emitted as JSON on
|
|
|
442
443
|
|
|
443
444
|
## Configuration
|
|
444
445
|
|
|
445
|
-
Fallow reads config from project root: `.fallowrc.json` > `.fallowrc.jsonc` > `fallow.toml` > `.fallow.toml`. Both `.fallowrc.json` and `.fallowrc.jsonc` accept JSON-with-comments syntax (same parser); the `.jsonc` extension lets editors auto-detect JSONC syntax highlighting. Most projects work with zero configuration thanks to
|
|
446
|
+
Fallow reads config from project root: `.fallowrc.json` > `.fallowrc.jsonc` > `fallow.toml` > `.fallow.toml`. Both `.fallowrc.json` and `.fallowrc.jsonc` accept JSON-with-comments syntax (same parser); the `.jsonc` extension lets editors auto-detect JSONC syntax highlighting. Most projects work with zero configuration thanks to 123 auto-detecting framework plugins.
|
|
446
447
|
|
|
447
448
|
```jsonc
|
|
448
449
|
{
|
|
@@ -479,7 +480,7 @@ export const deprecatedHelper = () => {};
|
|
|
479
480
|
## Key Gotchas
|
|
480
481
|
|
|
481
482
|
- **`fix --yes` is required** in non-TTY (agent) environments. Without it, `fix` exits with code 2
|
|
482
|
-
- **Zero config by default.**
|
|
483
|
+
- **Zero config by default.** 123 framework plugins auto-detect, including Wuchale config, Contentlayer content roots, tap and tsd test entry points. Don't create config unless customization is needed
|
|
483
484
|
- **Syntactic analysis only.** No TypeScript compiler, so fully dynamic `import(variable)` is not resolved
|
|
484
485
|
- **Function overloads are deduplicated.** TypeScript function overload signatures are merged into a single export (not reported as separate unused exports)
|
|
485
486
|
- **Re-export chains are resolved.** Exports through barrel files are tracked, not falsely flagged
|
|
@@ -17,6 +17,8 @@ Complete command and flag specifications for all fallow CLI commands.
|
|
|
17
17
|
- [`flags`: Feature Flag Detection](#flags-feature-flag-detection)
|
|
18
18
|
- [`security`: Security Candidate Detection](#security-security-candidate-detection)
|
|
19
19
|
- [`inspect`: Target Evidence Bundle](#inspect-target-evidence-bundle)
|
|
20
|
+
- [`trace`: Symbol Call Chains](#trace-symbol-call-chains)
|
|
21
|
+
- [`decision-surface`: Structural Decisions](#decision-surface-structural-decisions)
|
|
20
22
|
- [`explain`: Rule Explanation](#explain-rule-explanation)
|
|
21
23
|
- [`schema`: CLI Introspection](#schema-cli-introspection)
|
|
22
24
|
- [`config-schema`: Config JSON Schema](#config-schema-config-json-schema)
|
|
@@ -49,7 +51,7 @@ Analyzes the project for unused files, exports, dependencies, types, members, an
|
|
|
49
51
|
| `--top` | `string` | - | Show only the top N items per category |
|
|
50
52
|
| `--file` | `string` | - | Scope output to specific files. Only issues in the specified files are reported. Project-wide dependency issues are suppressed. Warns on non-existent paths. Useful for lint-staged |
|
|
51
53
|
|
|
52
|
-
Common global flags for this command: [`--format`](#global-flags), [`--quiet`](#global-flags), [`--output-file`](#global-flags), [`--
|
|
54
|
+
Common global flags for this command: [`--format`](#global-flags), [`--quiet`](#global-flags), [`--output-file`](#global-flags), [`--changed-since`](#global-flags), [`--max-file-size`](#global-flags), [`--production`](#global-flags), [`--no-production`](#global-flags), [`--production-dead-code`](#global-flags), [`--baseline`](#global-flags), [`--save-baseline`](#global-flags), [`--workspace`](#global-flags), [`--changed-workspaces`](#global-flags), [`--include-entry-exports`](#global-flags).
|
|
53
55
|
<!-- generated:flags:dead-code:end -->
|
|
54
56
|
### Issue Type Filters
|
|
55
57
|
|
|
@@ -396,7 +398,7 @@ Angular templates contribute synthetic `<template>` complexity findings whenever
|
|
|
396
398
|
| `--ownership` | `bool` | `false` | Attach ownership signals to hotspot entries: bus factor (Avelino truck factor), contributor count, top contributor with stale-days, recent contributors (top-3), `suggested_reviewers`, declared CODEOWNERS owner, `ownership_state`, ownership drift, unowned-hotspot detection. Human output gains a project-level summary line. JSON adds `low-bus-factor`, `unowned-hotspot`, `ownership-drift` action types. Test files get a `[test]` tag. Implies `--hotspots`. Requires git. |
|
|
397
399
|
| `--ownership-emails` | `raw\|handle\|anonymized\|hash` | - | Privacy mode for author emails. `handle` shows the local-part only (default, with GitHub noreply unwrap and deterministic same-handle disambiguation). `anonymized` emits stable `xxh3:` pseudonyms; `hash` remains accepted as the legacy spelling. `raw` shows full addresses. Use `anonymized` in regulated environments. Implies `--ownership`. Configure default via `health.ownership.emailMode`. |
|
|
398
400
|
| `--targets` | `bool` | `false` | Show only refactoring targets: ranked recommendations based on complexity, coupling, churn, and dead code signals. Categories: churn+complexity, circular dep, high impact, dead code, complexity, coupling. When no section flags are set, all sections are shown by default. Each target's JSON can include `direct_callers[]` (direct importers with the symbols they import) and `clone_siblings[]` (duplicate-code siblings with stable `dup:<8hex>` fingerprints for `fallow dupes --trace`); both omitted when empty. Human output adds `importers:` / `clones:` lines only when that evidence is present. |
|
|
399
|
-
| `--css` | `bool` | `false` | Add structural CSS analytics: specificity hotspots, !important density, over-complex selectors, deep nesting, and conservative cleanup candidates. Standard CSS is parsed structurally; preprocessor sources are scanned only where fallow can avoid expanding Sass/Less semantics. |
|
|
401
|
+
| `--css` | `bool` | `false` | Add structural CSS analytics: specificity hotspots, !important density, over-complex selectors, deep nesting, and conservative cleanup candidates. Standard CSS is parsed structurally; preprocessor sources are scanned only where fallow can avoid expanding Sass/Less semantics. Also derives `styling_health`, a descriptive A-F grade for CSS quality scored separately from the code `health_score` (never gates); it weights design-token drift (hardcoded value sprawl) over byte-identical repetition. |
|
|
400
402
|
| `--effort` | `low\|medium\|high` | - | Filter refactoring targets by effort level. Implies `--targets`. |
|
|
401
403
|
| `--score` | `bool` | `false` | Show only the project health score (0-100) with letter grade (A/B/C/D/F). The score is included by default when no section flags are set. JSON includes `health_score` object with `score`, `grade`, and `penalties` breakdown. As of v2.55.0, plain `--score` skips the churn-backed hotspot penalty so it does not run a `git log` shell-out per invocation; pass `--hotspots` (or `--targets` with `--score`) to include the hotspot penalty. Snapshot (`--save-snapshot`) and trend (`--trend`) flows still trigger hotspot vital signs so saved data stays complete. |
|
|
402
404
|
| `--min-score` | `string` | - | Fail (exit 1) only when the health score is below this threshold. Implies `--score`. Authoritative CI quality gate: when set, complexity findings are demoted to informational and the exit code is driven solely by the score, so `--min-score 0` always exits 0. Composes with `--min-severity`. |
|
|
@@ -506,7 +508,7 @@ fallow health --format json --quiet --trend
|
|
|
506
508
|
{
|
|
507
509
|
"kind": "health",
|
|
508
510
|
"schema_version": 7,
|
|
509
|
-
"version": "2.
|
|
511
|
+
"version": "2.104.0",
|
|
510
512
|
"elapsed_ms": 32,
|
|
511
513
|
"summary": {
|
|
512
514
|
"files_analyzed": 482,
|
|
@@ -833,6 +835,9 @@ Audits changed files for dead code, complexity, and duplication. Returns a verdi
|
|
|
833
835
|
| `--max-decisions` | `string` | `4` | Cap on the number of consequential structural decisions surfaced in the review brief's decision surface (the working-memory limit). Default 4; clamped to the 3-5 band (4 plus or minus 1). Only consulted on the brief path |
|
|
834
836
|
| `--walkthrough-guide` | `bool` | `false` | Emit the agent-contract WALKTHROUGH GUIDE: the current digest (brief + decision surface), the review direction, the JSON schema the agent must return, and a deterministic graph-snapshot hash pinned into the digest. The digest is built from the graph only (PR prose is never folded in, so it is injection-resistant). Implies the brief; always exits 0. A thin agent skill calls this to fetch the current guide, produces judgment JSON, then reopens with `--walkthrough-file` |
|
|
835
837
|
| `--walkthrough-file` | `string` | - | Ingest an agent's judgment JSON and POST-VALIDATE it against the LIVE graph. Rejects any judgment whose `signal_id` fallow did not emit (anti-hallucination); refuses the whole payload as stale when the echoed graph-snapshot hash no longer matches (the tree moved). The verifier is the graph, not a second model. Implies the brief; always exits 0. The agent's free-text framing is fenced as non-deterministic and never gates or auto-posts |
|
|
838
|
+
| `--walkthrough` | `bool` | `false` | Render the existing walkthrough guide as a staged HUMAN terminal tour (Stage 1 load-bearing / Stage 2 mechanical), or markdown with `--format markdown`. Implies the brief; always exits 0. `--format json --walkthrough` emits the same agent-contract JSON as `--walkthrough-guide` |
|
|
839
|
+
| `--mark-viewed` | `string` | - | Record one or more changed files as VIEWED in the local walkthrough viewed-state ledger (`.fallow/walkthrough-state.json`), then render the tour. Files already viewed (and still current) collapse into the Cleared panel. Repeatable. Stale marks (the tree moved) are ignored on render but never deleted. Only consulted on the `--walkthrough` path |
|
|
840
|
+
| `--show-cleared` | `bool` | `false` | Expand the Cleared panel in the human/markdown walkthrough tour: list each de-prioritized and already-viewed file instead of the collapsed one-line summary. Only consulted on the `--walkthrough` path |
|
|
836
841
|
| `--show-deprioritized` | `bool` | `false` | Expand the de-prioritized units in the review brief's weighted focus map ("show me what you de-prioritized"). The `deprioritized` escape-hatch list is ALWAYS present in `--format json` regardless; this flag only re-expands the collapse-by-default human focus render. Only consulted on the brief path |
|
|
837
842
|
|
|
838
843
|
Common global flags for this command: [`--format`](#global-flags), [`--quiet`](#global-flags), [`--changed-since`](#global-flags), [`--diff-file`](#global-flags), [`--diff-stdin`](#global-flags), [`--workspace`](#global-flags), [`--changed-workspaces`](#global-flags), [`--group-by`](#global-flags), [`--output-file`](#global-flags).
|
|
@@ -898,7 +903,7 @@ fallow audit \
|
|
|
898
903
|
{
|
|
899
904
|
"kind": "audit",
|
|
900
905
|
"schema_version": 7,
|
|
901
|
-
"version": "2.
|
|
906
|
+
"version": "2.104.0",
|
|
902
907
|
"command": "audit",
|
|
903
908
|
"verdict": "fail",
|
|
904
909
|
"changed_files_count": 12,
|
|
@@ -973,7 +978,7 @@ fallow flags --format json --quiet --workspace my-package
|
|
|
973
978
|
```json
|
|
974
979
|
{
|
|
975
980
|
"schema_version": 7,
|
|
976
|
-
"version": "2.
|
|
981
|
+
"version": "2.104.0",
|
|
977
982
|
"elapsed_ms": 116,
|
|
978
983
|
"feature_flags": [],
|
|
979
984
|
"total_flags": 0
|
|
@@ -1036,6 +1041,7 @@ The second rule family is a data-driven `tainted-sink` catalogue: syntactic dang
|
|
|
1036
1041
|
| `secret-pii-log` | 532 | source-backed secrets or request PII reaching logs |
|
|
1037
1042
|
| `hardcoded-secret` | 798 | provider-prefix credentials and high-entropy literals assigned to secret-shaped identifiers (include-required) |
|
|
1038
1043
|
| `secret-to-network` | 201 | a non-public `process.env` / `import.meta.env` secret reaching a network call body (`fetch` / `axios` / `got` / ...) via same-identifier flow (include-required) |
|
|
1044
|
+
| `llm-call-injection` | 1427 | an untrusted source reaching the prompt/messages argument of a known LLM-call sink (taint-path gated, pinned to distinctive LLM SDK call shapes) |
|
|
1039
1045
|
| `xpath-injection` | 643 | `xpath.select` / `select1` with a non-literal expression |
|
|
1040
1046
|
|
|
1041
1047
|
Build-config and test files are excluded from candidate generation. Security rule families default to `off` and are surfaced only by `fallow security`, never under bare `fallow` or the `audit` gate. Scope which catalogue categories run with `security.categories` include / exclude lists in config. 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. The setting is additive only and does not gate `*.searchParams`. `hardcoded-secret` and `secret-to-network` are intentionally include-required and only run when listed in `security.categories.include` (`secret-to-network` is opt-in because legitimate auth is also a secret reaching a network call). Public-by-convention env vars (`NEXT_PUBLIC_`, `VITE_`, ...) are never treated as secrets.
|
|
@@ -1073,7 +1079,7 @@ fallow security --gate newly-reachable --changed-since origin/main
|
|
|
1073
1079
|
{
|
|
1074
1080
|
"kind": "security",
|
|
1075
1081
|
"schema_version": "4",
|
|
1076
|
-
"version": "2.
|
|
1082
|
+
"version": "2.104.0",
|
|
1077
1083
|
"elapsed_ms": 42,
|
|
1078
1084
|
"config": {
|
|
1079
1085
|
"rules": {
|
|
@@ -1102,7 +1108,7 @@ fallow security --gate newly-reachable --changed-since origin/main
|
|
|
1102
1108
|
{
|
|
1103
1109
|
"kind": "security",
|
|
1104
1110
|
"schema_version": "4",
|
|
1105
|
-
"version": "2.
|
|
1111
|
+
"version": "2.104.0",
|
|
1106
1112
|
"elapsed_ms": 42,
|
|
1107
1113
|
"config": {
|
|
1108
1114
|
"rules": {
|
|
@@ -1215,6 +1221,48 @@ Each evidence section carries `status` and `scope`. Non-fatal child-analysis fai
|
|
|
1215
1221
|
|
|
1216
1222
|
---
|
|
1217
1223
|
|
|
1224
|
+
## `trace`: Symbol Call Chains
|
|
1225
|
+
|
|
1226
|
+
Walk the callers and callees of one exported symbol through the module graph. Callers are the modules that import the symbol (walked up); callees are the symbol's module's import-symbol edges plus its intra-module call sites (walked down). Best-effort and syntactic per ADR-001: resolved and unresolved callees are reported honestly, never silently dropped. This is its own surface, never folded into the ranked review brief.
|
|
1227
|
+
|
|
1228
|
+
The target is a positional argument, formatted as `FILE:SYMBOL` (for example `src/utils.ts:formatDate`). When neither `--callers` nor `--callees` is given, both directions are walked.
|
|
1229
|
+
|
|
1230
|
+
```bash
|
|
1231
|
+
fallow trace src/utils.ts:formatDate
|
|
1232
|
+
fallow trace src/utils.ts:formatDate --callers --depth 3
|
|
1233
|
+
```
|
|
1234
|
+
|
|
1235
|
+
<!-- generated:flags:trace:start -->
|
|
1236
|
+
| Flag | Type | Default | Description |
|
|
1237
|
+
|---|---|---|---|
|
|
1238
|
+
| `--callers` | `bool` | `false` | Walk UP to callers (modules that import the symbol). When neither `--callers` nor `--callees` is set, both directions are walked |
|
|
1239
|
+
| `--callees` | `bool` | `false` | Walk DOWN to callees (the symbol's module's import-symbol edges plus unresolved call sites). When neither flag is set, both are walked |
|
|
1240
|
+
| `--depth` | `string` | - | Chain depth bound for both directions (default 2). Symbol-level is best-effort, so a shallow bound keeps the trace legible |
|
|
1241
|
+
|
|
1242
|
+
Common global flags for this command: [`--format`](#global-flags), [`--quiet`](#global-flags), [`--root`](#global-flags), [`--config`](#global-flags).
|
|
1243
|
+
<!-- generated:flags:trace:end -->
|
|
1244
|
+
|
|
1245
|
+
---
|
|
1246
|
+
|
|
1247
|
+
## `decision-surface`: Structural Decisions
|
|
1248
|
+
|
|
1249
|
+
Surface only the consequential structural decisions a change embeds (the apex of the review brief): a ranked, capped (3 to 5, default 4) set of coupling/boundary, public-API/contract, and dependency decisions, each framed as a judgment question with the routed expert to ask, plus a trade-off clause and the count of in-repo consumers that already depend on the anchor. Runs the same changed-code analysis as `fallow review` but emits only the decisions, separable and cheap. Always exits 0 (advisory, never a gate); every decision is suppressible with `// fallow-ignore`. Use `--base` / `--changed-since` to pick the comparison point, exactly like `fallow audit`.
|
|
1250
|
+
|
|
1251
|
+
```bash
|
|
1252
|
+
fallow decision-surface --base main
|
|
1253
|
+
fallow decision-surface --base main --format json --quiet
|
|
1254
|
+
```
|
|
1255
|
+
|
|
1256
|
+
<!-- generated:flags:decision-surface:start -->
|
|
1257
|
+
| Flag | Type | Default | Description |
|
|
1258
|
+
|---|---|---|---|
|
|
1259
|
+
| `--max-decisions` | `string` | `4` | Cap on the number of surfaced decisions (the working-memory limit). Default 4; clamped to the 3-5 band (4 plus or minus 1) |
|
|
1260
|
+
|
|
1261
|
+
Common global flags for this command: [`--changed-since`](#global-flags), [`--format`](#global-flags), [`--quiet`](#global-flags), [`--workspace`](#global-flags), [`--root`](#global-flags), [`--config`](#global-flags).
|
|
1262
|
+
<!-- generated:flags:decision-surface:end -->
|
|
1263
|
+
|
|
1264
|
+
---
|
|
1265
|
+
|
|
1218
1266
|
## `explain`: Rule Explanation
|
|
1219
1267
|
|
|
1220
1268
|
Print rule rationale, examples, fix guidance, and docs URL for one issue type without running analysis.
|
|
@@ -1592,7 +1640,6 @@ Available on all commands:
|
|
|
1592
1640
|
| `--group-by` | `owner\|directory\|package\|section` | - | Group output by CODEOWNERS ownership (`owner`), first path component (`directory`), workspace package (`package`, aliases: `workspace`, `pkg`), or GitLab CODEOWNERS `[Section]` headers (`section`, alias: `gl-section`). All output formats partition issues into labeled groups. `section` mode attaches an `owners` array to each group in JSON output |
|
|
1593
1641
|
| `--performance` | `bool` | `false` | Show pipeline timing breakdown |
|
|
1594
1642
|
| `--explain` | `bool` | `false` | JSON: include metric definitions in `_meta`. Human: print a `Description:` line under each section header. Always on for MCP. |
|
|
1595
|
-
| `--legacy-envelope` | `bool` | `false` | Emit the previous typed JSON root envelope without top-level `kind` |
|
|
1596
1643
|
| `--explain-skipped` | `bool` | `false` | Show a per-pattern breakdown for default duplicate ignores |
|
|
1597
1644
|
| `--summary` | `bool` | `false` | Show only category counts without individual items. Useful for dashboards and quick overviews |
|
|
1598
1645
|
| `--ci` | `bool` | `false` | CI mode: `--format sarif --fail-on-issues --quiet` |
|
|
@@ -1768,7 +1815,7 @@ The HTTP layer mirrors the bash `gh_api_retry` / `curl_retry` helpers: `FALLOW_A
|
|
|
1768
1815
|
{
|
|
1769
1816
|
"kind": "dead-code",
|
|
1770
1817
|
"schema_version": 7,
|
|
1771
|
-
"version": "2.
|
|
1818
|
+
"version": "2.104.0",
|
|
1772
1819
|
"elapsed_ms": 45,
|
|
1773
1820
|
"total_issues": 12,
|
|
1774
1821
|
"entry_points": {
|
|
@@ -1928,7 +1975,7 @@ When `--baseline` is used in combined output, the JSON includes a `baseline_delt
|
|
|
1928
1975
|
{
|
|
1929
1976
|
"kind": "dupes",
|
|
1930
1977
|
"schema_version": 7,
|
|
1931
|
-
"version": "2.
|
|
1978
|
+
"version": "2.104.0",
|
|
1932
1979
|
"elapsed_ms": 82,
|
|
1933
1980
|
"total_clones": 15,
|
|
1934
1981
|
"total_lines_duplicated": 230,
|
|
@@ -1972,11 +2019,11 @@ When running `fallow` with no subcommand (all analyses), the JSON output combine
|
|
|
1972
2019
|
{
|
|
1973
2020
|
"kind": "combined",
|
|
1974
2021
|
"schema_version": 7,
|
|
1975
|
-
"version": "2.
|
|
2022
|
+
"version": "2.104.0",
|
|
1976
2023
|
"elapsed_ms": 159,
|
|
1977
2024
|
"check": {
|
|
1978
2025
|
"schema_version": 7,
|
|
1979
|
-
"version": "2.
|
|
2026
|
+
"version": "2.104.0",
|
|
1980
2027
|
"elapsed_ms": 45,
|
|
1981
2028
|
"total_issues": 12,
|
|
1982
2029
|
"unused_files": [],
|
|
@@ -2184,6 +2231,7 @@ preset = "bulletproof"
|
|
|
2184
2231
|
- `cache.maxSizeMb`: cap the serialized extraction cache size in megabytes. `FALLOW_CACHE_MAX_SIZE` wins over this config field
|
|
2185
2232
|
- `usedClassMembers`: class method/property names that extend the built-in Angular/React lifecycle allowlist with framework-invoked names. Each entry is a plain string (global suppression) or a scoped object `{ extends?, implements?, members }` matching only classes with the given heritage. Strings can be exact names (`"agInit"`) or glob patterns (`"*"` matches every member, `"enter*"` prefix, `"*Handler"` suffix, `"on*Event"` combined). Use scoped rules for common names like `refresh` or `execute` to avoid false negatives on unrelated classes; global strings for unique names like `agInit`. Example: `["agInit", { "implements": "ICellRendererAngularComp", "members": ["refresh"] }, { "extends": "BaseCommand", "members": ["execute"] }, { "extends": "GrammarBaseListener", "members": ["enter*", "exit*"] }]`. Glob patterns that match zero members emit a `WARN` so dead allowlist entries surface. An unconstrained scoped rule (no `extends` or `implements`) is rejected at load time. Use plugin-level `usedClassMembers` in a `.fallow/plugins/*.jsonc` file for library-specific allowlists
|
|
2186
2233
|
- `resolve.conditions`: additional package.json `exports` / `imports` condition names to honor during module resolution. Baseline conditions (`development`, `import`, `require`, `default`, `types`, `node`, plus `react-native` / `browser` under RN/Expo) are always included; user entries prepend ahead of them. Use for community conditions like `worker`, `edge-light`, `deno`, or custom bundler conditions. Example: `{ "resolve": { "conditions": ["worker", "edge-light"] } }`
|
|
2234
|
+
- `unusedComponentProps.ignorePattern`: opt-in regex that exempts a component prop from `unused-component-props` when the prop's LOCAL destructure binding name matches (the leading-underscore "accepted-but-intentionally-unused" convention, mirroring TS `noUnusedParameters` + ESLint `varsIgnorePattern` / `argsIgnorePattern`). Applies to Vue, Svelte, Astro, and React/Preact props. The match is on the local alias (`_stage` in `let { stage: _stage } = $props()`), not the public prop name the finding reports (`stage`); matching is unanchored like ESLint's `RegExp.test`, so anchor with `^_`. An invalid regex fails config load. Example: `{ "unusedComponentProps": { "ignorePattern": "^_" } }`
|
|
2187
2235
|
|
|
2188
2236
|
---
|
|
2189
2237
|
|
|
@@ -23,7 +23,7 @@ Always preview with `--dry-run` before applying. This is a destructive operation
|
|
|
23
23
|
|
|
24
24
|
## Don't Create Config Unless Needed
|
|
25
25
|
|
|
26
|
-
Fallow works with zero configuration for most projects thanks to
|
|
26
|
+
Fallow works with zero configuration for most projects thanks to 123 auto-detecting framework plugins. Creating an unnecessary config file can mask issues or override detection behavior.
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
29
|
# WRONG: creating config for a standard Next.js project
|
|
@@ -67,7 +67,7 @@ The `--changed-since` flag limits analysis to files modified since a git ref. It
|
|
|
67
67
|
# This only shows issues in files changed since main
|
|
68
68
|
fallow dead-code --format json --quiet --changed-since main
|
|
69
69
|
|
|
70
|
-
# Same for duplication
|
|
70
|
+
# Same for duplication, only clone groups involving changed files
|
|
71
71
|
fallow dupes --format json --quiet --changed-since main
|
|
72
72
|
|
|
73
73
|
# This shows ALL issues in the project
|
|
@@ -484,10 +484,16 @@ When `fallow health --css` reports `css_analytics.unused_theme_tokens`, treat th
|
|
|
484
484
|
|
|
485
485
|
The detector intentionally abstains when a Tailwind plugin or published CSS surface could consume tokens invisibly. Always run the row's `actions[].command` verification before deleting a token, and do not run `fallow fix` for these rows.
|
|
486
486
|
|
|
487
|
+
The same Tailwind v4 projects also get `css_analytics.token_consumers`, the reverse index: per `@theme` token, where it is consumed (a `consumer_count` plus a located `consumers[]` sample tagged `theme-var` / `css-var` / `utility` / `apply`), so you can read a token's blast radius before changing it. Treat `consumer_count` as a static lower bound: a computed class name such as `bg-${color}` is invisible to the scan, so a `0` here is the same "nothing fallow can see consumes this" population as `unused_theme_tokens`, not a deletion proof. `token_consumers` is descriptive context with no `actions[]`; drive any deletion off `unused_theme_tokens` and its verification command.
|
|
488
|
+
|
|
489
|
+
`token_consumers` also covers CSS-in-JS token DEFINITIONS (StyleX `defineVars`, vanilla-extract `createTheme` / `createThemeContract` / `createGlobalTheme`), disambiguated by the consumer `kind`: a CSS-in-JS entry has `kind` `js-member`, `token` is the binding-qualified dotted access path (`vars.color.primary`), and `namespace` is the defining binding (`vars`). The cross-file scan resolves only relative imports, so a token consumed through a path alias (`@/tokens`) or a bare-package import is not counted (a sharper lower bound), and unlike Tailwind there is no corroborating dead-token finding, so a CSS-in-JS `consumer_count` of `0` is a weaker signal. Gated on a declared CSS-in-JS library (`@stylexjs/stylex` / `@vanilla-extract/css`); Panda (`defineTokens` / `token('...')`) is a planned follow-on.
|
|
490
|
+
|
|
487
491
|
## CSS Health Candidates Are Advisory
|
|
488
492
|
|
|
489
493
|
`fallow health --css` also emits advisory cleanup and typo candidates in `css_analytics.unreferenced_css_classes` (a plain-CSS class defined but matched by no `class`/`className` in project markup), `css_analytics.unresolved_class_references` (the reverse: a markup class one edit away from a defined class, a likely typo), `css_analytics.unused_font_faces`, `css_analytics.undefined_keyframes`, and `css_analytics.font_size_unit_mix`. Treat them like review prompts, not confirmed defects. Run each row's `actions[].command` before changing CSS, because fonts, classes, animations, and type scales can be driven by inline styles, JavaScript, CMS templates, or preprocessor expansion that static analysis intentionally does not execute.
|
|
490
494
|
|
|
495
|
+
`fallow health --css` also derives `styling_health`, a descriptive A-F grade (and 0-100 `score`) for CSS quality, scored SEPARATELY from the code `health_score`. It is descriptive-only: it never gates an exit code, badge, or CI, and never affects the code score, so do NOT branch automation on it. Read it as a design-system credibility signal. It weights design-token DRIFT over byte-identical repetition: the `token_erosion` penalty includes a hardcoded-value-sprawl term over distinct `box-shadow` / `border-radius` / `line-height` values, but counts only HARDCODED literals: a system that references its scale via `var(--*)` scores 0 sprawl regardless of how many tokens it defines (so "tokenize repeated values" is the remedy the human output suggests). A grade from a thin CSS surface (or predominantly compile-time-atomic CSS-in-JS like StyleX/Panda) is marked `confidence: "low"` with a reason. `styling_health.formula_version` bumps when the rubric is recalibrated; if you diff the score/grade over time, gate on it and re-baseline at a bump rather than reading the step-change as a regression.
|
|
496
|
+
|
|
491
497
|
---
|
|
492
498
|
|
|
493
499
|
## Library Packages: Use `publicPackages` Instead of Visibility Tags
|
|
@@ -577,7 +583,7 @@ Fallow detects production dependencies that are only imported from test files (`
|
|
|
577
583
|
// src/handlers.test.ts
|
|
578
584
|
import { setupServer } from 'msw/node'; // Flagged as test-only dependency
|
|
579
585
|
|
|
580
|
-
// src/app.ts
|
|
586
|
+
// src/app.ts: no imports of "msw" here
|
|
581
587
|
```
|
|
582
588
|
|
|
583
589
|
```bash
|
|
@@ -596,8 +602,8 @@ The `test-only-dependencies` rule defaults to `warn`. Suppress with `"test-only-
|
|
|
596
602
|
|
|
597
603
|
These are separate features and can be used independently or together:
|
|
598
604
|
|
|
599
|
-
- **`FALLOW_COMMENT: "true"
|
|
600
|
-
- **`FALLOW_REVIEW: "true"
|
|
605
|
+
- **`FALLOW_COMMENT: "true"`**: posts a single summary comment on the MR with issue counts and a findings table
|
|
606
|
+
- **`FALLOW_REVIEW: "true"`**: posts inline code review comments on the exact MR diff lines where issues were found
|
|
601
607
|
|
|
602
608
|
```yaml
|
|
603
609
|
# WRONG: expecting inline review comments from FALLOW_COMMENT
|
|
@@ -658,7 +664,7 @@ variables:
|
|
|
658
664
|
FALLOW_CHANGED_SINCE: "origin/main"
|
|
659
665
|
|
|
660
666
|
# CORRECT: let the template auto-detect
|
|
661
|
-
# (no FALLOW_CHANGED_SINCE needed
|
|
667
|
+
# (no FALLOW_CHANGED_SINCE needed, it reads the MR target branch)
|
|
662
668
|
```
|
|
663
669
|
|
|
664
670
|
Override `FALLOW_CHANGED_SINCE` only when you need a specific ref (e.g., a release branch) or want to disable auto-detection by setting it to an empty string.
|
|
@@ -669,4 +675,4 @@ Override `FALLOW_CHANGED_SINCE` only when you need a specific ref (e.g., a relea
|
|
|
669
675
|
|
|
670
676
|
The GitLab CI template auto-detects the project's package manager from lockfiles (`package-lock.json` for npm, `pnpm-lock.yaml` for pnpm, `yarn.lock` for yarn). MR comments and review comments use the correct commands for the detected manager.
|
|
671
677
|
|
|
672
|
-
This means review comments will show `pnpm remove lodash` instead of `npm uninstall lodash` in a pnpm project. No configuration is needed
|
|
678
|
+
This means review comments will show `pnpm remove lodash` instead of `npm uninstall lodash` in a pnpm project. No configuration is needed; detection is automatic.
|
|
@@ -222,7 +222,7 @@ fallow:
|
|
|
222
222
|
FALLOW_FAIL_ON_ISSUES: "true"
|
|
223
223
|
```
|
|
224
224
|
|
|
225
|
-
Generates Code Quality reports (inline MR annotations) automatically. In MR pipelines, `--changed-since` is automatically set to the target branch
|
|
225
|
+
Generates Code Quality reports (inline MR annotations) automatically. In MR pipelines, `--changed-since` is automatically set to the target branch; no manual configuration needed.
|
|
226
226
|
|
|
227
227
|
If runners cannot reach `raw.githubusercontent.com`, run `fallow ci-template gitlab --vendor`, commit the generated `ci/` and `action/` files, and use GitLab's local include syntax:
|
|
228
228
|
|
|
@@ -494,9 +494,9 @@ fallow dupes --format json --quiet
|
|
|
494
494
|
| jscpd | fallow |
|
|
495
495
|
|-------|--------|
|
|
496
496
|
| Default (exact tokens) | `strict` |
|
|
497
|
-
|
|
|
498
|
-
|
|
|
499
|
-
|
|
|
497
|
+
| n/a | `mild` (fallow default, syntax normalized) |
|
|
498
|
+
| n/a | `weak` (literal normalization) |
|
|
499
|
+
| n/a | `semantic` (variable rename detection) |
|
|
500
500
|
|
|
501
501
|
---
|
|
502
502
|
|
|
@@ -640,7 +640,7 @@ Focus on findings that are BOTH dead code and duplicated:
|
|
|
640
640
|
|
|
641
641
|
## Custom Plugin Setup
|
|
642
642
|
|
|
643
|
-
For frameworks not covered by the
|
|
643
|
+
For frameworks not covered by the 123 built-in plugins.
|
|
644
644
|
|
|
645
645
|
### Option 1: Inline framework config
|
|
646
646
|
|