fallow 2.47.1 → 2.48.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 +12 -2
- package/package.json +22 -10
- package/skills/fallow/SKILL.md +386 -0
- package/skills/fallow/references/cli-reference.md +1479 -0
- package/skills/fallow/references/gotchas.md +611 -0
- package/skills/fallow/references/patterns.md +817 -0
|
@@ -0,0 +1,1479 @@
|
|
|
1
|
+
# Fallow CLI Reference
|
|
2
|
+
|
|
3
|
+
Complete command and flag specifications for all fallow CLI commands.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [`dead-code`: Dead Code Analysis](#dead-code-dead-code-analysis)
|
|
10
|
+
- [`dupes`: Duplication Detection](#dupes-duplication-detection)
|
|
11
|
+
- [`fix`: Auto-Remove Unused Code](#fix-auto-remove-unused-code)
|
|
12
|
+
- [`list`: Project Introspection](#list-project-introspection)
|
|
13
|
+
- [`init`: Config Generation](#init-config-generation)
|
|
14
|
+
- [`migrate`: Config Migration](#migrate-config-migration)
|
|
15
|
+
- [`health`: Function Complexity Analysis](#health-function-complexity-analysis)
|
|
16
|
+
- [`audit`: Changed-File Quality Gate](#audit-changed-file-quality-gate)
|
|
17
|
+
- [`flags`: Feature Flag Detection](#flags-feature-flag-detection)
|
|
18
|
+
- [`schema`: CLI Introspection](#schema-cli-introspection)
|
|
19
|
+
- [`config-schema`: Config JSON Schema](#config-schema-config-json-schema)
|
|
20
|
+
- [`plugin-schema`: Plugin JSON Schema](#plugin-schema-plugin-json-schema)
|
|
21
|
+
- [`config`: Show Resolved Config](#config-show-resolved-config)
|
|
22
|
+
- [Global Flags](#global-flags)
|
|
23
|
+
- [Environment Variables](#environment-variables)
|
|
24
|
+
- [Output Formats](#output-formats)
|
|
25
|
+
- [JSON Output Structure](#json-output-structure)
|
|
26
|
+
- [Configuration File Format](#configuration-file-format)
|
|
27
|
+
- [Inline Suppression Comments](#inline-suppression-comments)
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## `dead-code`: Dead Code Analysis
|
|
32
|
+
|
|
33
|
+
Analyzes the project for unused files, exports, dependencies, types, members, and more. Running `fallow` with no subcommand runs all analyses (dead code + duplication + complexity). Use `fallow dead-code` for dead code only.
|
|
34
|
+
|
|
35
|
+
### Flags
|
|
36
|
+
|
|
37
|
+
| Flag | Type | Default | Description |
|
|
38
|
+
|------|------|---------|-------------|
|
|
39
|
+
| `--format` | `human\|json\|sarif\|compact\|markdown\|codeclimate` | `human` | Output format |
|
|
40
|
+
| `--quiet` | bool | `false` | Suppress progress bars and timing on stderr |
|
|
41
|
+
| `--changed-since` | string | — | Only analyze files changed since a git ref (e.g., `main`, `HEAD~3`) |
|
|
42
|
+
| `--production` | bool | `false` | Exclude test/dev files, only start/build scripts |
|
|
43
|
+
| `--baseline` | path | — | Compare against a saved baseline |
|
|
44
|
+
| `--save-baseline` | path | — | Save current results as a baseline |
|
|
45
|
+
| `--workspace` | string | — | Scope to one or more workspaces. Comma-separated values, globs (`apps/*`, `@scope/*`), and `!`-prefixed negation (`!apps/legacy`) supported. Matched against package name AND workspace path relative to repo root. |
|
|
46
|
+
| `--changed-workspaces` | string (git ref) | — | Git-derived monorepo CI scoping: scope to workspaces containing any file changed since `REF` (e.g. `origin/main`). Auto-derives the workspace set from `git diff`. Mutually exclusive with `--workspace`. Missing ref is a hard error (exit 2), not silent full-scope fallback. |
|
|
47
|
+
| `--include-dupes` | bool | `false` | Cross-reference with duplication findings |
|
|
48
|
+
| `--file` | path (multiple) | — | 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 |
|
|
49
|
+
| `--include-entry-exports` | bool | `false` | Report unused exports in entry files (package.json `main`/`exports`, framework pages). Catches typos like `meatdata` vs `metadata` |
|
|
50
|
+
| `--trace` | `FILE:EXPORT` | — | Trace export usage chain |
|
|
51
|
+
| `--trace-file` | path | — | Show all edges for a file |
|
|
52
|
+
| `--trace-dependency` | string | — | Trace where a dependency is used |
|
|
53
|
+
|
|
54
|
+
### Issue Type Filters
|
|
55
|
+
|
|
56
|
+
| Flag | Issue Type |
|
|
57
|
+
|------|------------|
|
|
58
|
+
| `--unused-files` | Unused files |
|
|
59
|
+
| `--unused-exports` | Unused exports |
|
|
60
|
+
| `--unused-types` | Unused types |
|
|
61
|
+
| `--unused-deps` | Unused dependencies, devDependencies, optionalDependencies, type-only production deps, and test-only production deps |
|
|
62
|
+
| `--unused-enum-members` | Unused enum members |
|
|
63
|
+
| `--unused-class-members` | Unused class members |
|
|
64
|
+
| `--unresolved-imports` | Unresolved imports |
|
|
65
|
+
| `--unlisted-deps` | Unlisted dependencies |
|
|
66
|
+
| `--duplicate-exports` | Duplicate exports |
|
|
67
|
+
| `--circular-deps` | Circular dependencies |
|
|
68
|
+
| `--boundary-violations` | Boundary violations (imports crossing architecture zone boundaries) |
|
|
69
|
+
| `--stale-suppressions` | Stale suppression comments or `@expected-unused` JSDoc tags |
|
|
70
|
+
|
|
71
|
+
### Examples
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# Full analysis with JSON output
|
|
75
|
+
fallow dead-code --format json --quiet
|
|
76
|
+
|
|
77
|
+
# Only unused exports
|
|
78
|
+
fallow dead-code --format json --quiet --unused-exports
|
|
79
|
+
|
|
80
|
+
# PR check: only changed files
|
|
81
|
+
fallow dead-code --format json --quiet --changed-since main --fail-on-issues
|
|
82
|
+
|
|
83
|
+
# CI mode with SARIF upload
|
|
84
|
+
fallow dead-code --ci
|
|
85
|
+
|
|
86
|
+
# Production-only analysis
|
|
87
|
+
fallow dead-code --format json --quiet --production
|
|
88
|
+
|
|
89
|
+
# Single workspace package
|
|
90
|
+
fallow dead-code --format json --quiet --workspace my-package
|
|
91
|
+
|
|
92
|
+
# Multiple workspaces: comma-separated
|
|
93
|
+
fallow dead-code --format json --quiet --workspace web,admin
|
|
94
|
+
|
|
95
|
+
# Glob (matches package name OR relative path)
|
|
96
|
+
fallow dead-code --format json --quiet --workspace 'apps/*'
|
|
97
|
+
|
|
98
|
+
# Exclude a workspace from the set
|
|
99
|
+
fallow dead-code --format json --quiet --workspace 'apps/*,!apps/legacy'
|
|
100
|
+
|
|
101
|
+
# Monorepo CI: auto-scope to workspaces containing any file changed since origin/main
|
|
102
|
+
fallow dead-code --format json --quiet --changed-workspaces origin/main
|
|
103
|
+
|
|
104
|
+
# Debug: trace an export
|
|
105
|
+
fallow dead-code --format json --quiet --trace src/utils.ts:myFunction
|
|
106
|
+
|
|
107
|
+
# Incremental adoption with baseline
|
|
108
|
+
fallow dead-code --format json --quiet --save-baseline fallow-baselines/dead-code.json
|
|
109
|
+
fallow dead-code --format json --quiet --baseline fallow-baselines/dead-code.json --fail-on-issues
|
|
110
|
+
|
|
111
|
+
# Regression detection: save baseline on main, compare on PRs
|
|
112
|
+
fallow dead-code --format json --quiet --save-regression-baseline
|
|
113
|
+
fallow dead-code --format json --quiet --fail-on-regression --tolerance 2%
|
|
114
|
+
|
|
115
|
+
# Scope to specific files (e.g., lint-staged)
|
|
116
|
+
fallow dead-code --format json --quiet --file src/utils.ts --file src/helpers.ts
|
|
117
|
+
|
|
118
|
+
# Catch typos in entry file exports
|
|
119
|
+
fallow dead-code --format json --quiet --include-entry-exports
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## `dupes`: Duplication Detection
|
|
125
|
+
|
|
126
|
+
Finds code duplication and clones across the project.
|
|
127
|
+
|
|
128
|
+
### Flags
|
|
129
|
+
|
|
130
|
+
| Flag | Type | Default | Description |
|
|
131
|
+
|------|------|---------|-------------|
|
|
132
|
+
| `--format` | `human\|json\|sarif\|compact\|markdown\|codeclimate` | `human` | Output format |
|
|
133
|
+
| `--quiet` | bool | `false` | Suppress progress bars |
|
|
134
|
+
| `--top` | number | — | Show only the N largest clone groups (sorted by line count descending). Summary stats reflect the full project. |
|
|
135
|
+
| `--mode` | `strict\|mild\|weak\|semantic` | `mild` | Detection mode |
|
|
136
|
+
| `--min-tokens` | number | `50` | Minimum token count for a clone |
|
|
137
|
+
| `--min-lines` | number | `5` | Minimum line count for a clone |
|
|
138
|
+
| `--threshold` | number | `0` | Fail if duplication exceeds this percentage |
|
|
139
|
+
| `--skip-local` | bool | `false` | Only report cross-directory duplicates |
|
|
140
|
+
| `--cross-language` | bool | `false` | Strip type annotations for TS↔JS matching |
|
|
141
|
+
| `--ignore-imports` | bool | `false` | Exclude import declarations from clone detection |
|
|
142
|
+
| `--trace` | `FILE:LINE` | — | Trace all clones at a specific location |
|
|
143
|
+
| `--changed-since` | string | — | Only report duplication in files changed since a git ref |
|
|
144
|
+
| `--baseline` | path | — | Compare against baseline |
|
|
145
|
+
| `--save-baseline` | path | — | Save results as baseline |
|
|
146
|
+
| `--workspace` | string | — | Scope to one or more workspaces. Comma-separated values, globs (`apps/*`, `@scope/*`), and `!`-prefixed negation (`!apps/legacy`) supported. Matched against package name AND workspace path relative to repo root. |
|
|
147
|
+
| `--changed-workspaces` | string (git ref) | — | Git-derived monorepo CI scoping: scope to workspaces containing any file changed since `REF`. Mutually exclusive with `--workspace`. Missing ref is a hard error. |
|
|
148
|
+
|
|
149
|
+
### Detection Modes
|
|
150
|
+
|
|
151
|
+
| Mode | Behavior |
|
|
152
|
+
|------|----------|
|
|
153
|
+
| `strict` | Exact token match (no normalization) |
|
|
154
|
+
| `mild` | Syntax normalized (whitespace, semicolons) |
|
|
155
|
+
| `weak` | Different literal values treated as equivalent |
|
|
156
|
+
| `semantic` | Renamed variables also treated as equivalent |
|
|
157
|
+
|
|
158
|
+
### Examples
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
# Default duplication scan
|
|
162
|
+
fallow dupes --format json --quiet
|
|
163
|
+
|
|
164
|
+
# Semantic mode (detects renames)
|
|
165
|
+
fallow dupes --format json --quiet --mode semantic
|
|
166
|
+
|
|
167
|
+
# Cross-directory only, fail at 5%
|
|
168
|
+
fallow dupes --format json --quiet --skip-local --threshold 5
|
|
169
|
+
|
|
170
|
+
# Trace clones at a specific location
|
|
171
|
+
fallow dupes --format json --quiet --trace src/utils.ts:42
|
|
172
|
+
|
|
173
|
+
# Only check duplication in changed files
|
|
174
|
+
fallow dupes --format json --quiet --changed-since main
|
|
175
|
+
|
|
176
|
+
# Incremental CI
|
|
177
|
+
fallow dupes --format json --quiet --save-baseline fallow-baselines/dupes.json
|
|
178
|
+
fallow dupes --format json --quiet --baseline fallow-baselines/dupes.json --threshold 5
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## `fix`: Auto-Remove Unused Code
|
|
184
|
+
|
|
185
|
+
Auto-removes unused exports and dependencies.
|
|
186
|
+
|
|
187
|
+
### Flags
|
|
188
|
+
|
|
189
|
+
| Flag | Type | Default | Description |
|
|
190
|
+
|------|------|---------|-------------|
|
|
191
|
+
| `--dry-run` | bool | `false` | Show what would be removed without modifying files |
|
|
192
|
+
| `--yes` | bool | `false` | Skip confirmation prompt (**required** in non-TTY) |
|
|
193
|
+
| `--force` | bool | `false` | Alias for `--yes` |
|
|
194
|
+
| `--format` | `human\|json` | `human` | Output format |
|
|
195
|
+
| `--quiet` | bool | `false` | Suppress progress bars |
|
|
196
|
+
|
|
197
|
+
### Examples
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
# Preview changes
|
|
201
|
+
fallow fix --dry-run --format json --quiet
|
|
202
|
+
|
|
203
|
+
# Apply changes (--yes required in agent/CI environments)
|
|
204
|
+
fallow fix --yes --format json --quiet
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## `list`: Project Introspection
|
|
210
|
+
|
|
211
|
+
Inspect discovered files, entry points, detected frameworks, and architecture boundary zones.
|
|
212
|
+
|
|
213
|
+
### Flags
|
|
214
|
+
|
|
215
|
+
| Flag | Type | Description |
|
|
216
|
+
|------|------|-------------|
|
|
217
|
+
| `--files` | bool | List all discovered files |
|
|
218
|
+
| `--entry-points` | bool | List detected entry points |
|
|
219
|
+
| `--plugins` | bool | List active framework plugins |
|
|
220
|
+
| `--boundaries` | bool | Show architecture boundary zones, rules, and per-zone file counts |
|
|
221
|
+
| `--format` | `human\|json` | Output format |
|
|
222
|
+
| `--quiet` | bool | Suppress progress bars |
|
|
223
|
+
|
|
224
|
+
### Examples
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
fallow list --files --format json --quiet
|
|
228
|
+
fallow list --entry-points --format json --quiet
|
|
229
|
+
fallow list --plugins --format json --quiet
|
|
230
|
+
fallow list --boundaries --format json --quiet
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## `init`: Config Generation
|
|
236
|
+
|
|
237
|
+
Creates a config file in the project root.
|
|
238
|
+
|
|
239
|
+
### Flags
|
|
240
|
+
|
|
241
|
+
| Flag | Type | Description |
|
|
242
|
+
|------|------|-------------|
|
|
243
|
+
| `--toml` | bool | Create `fallow.toml` instead of `.fallowrc.json` |
|
|
244
|
+
| `--hooks` | bool | Scaffold a pre-commit git hook that runs `fallow dead-code --changed-since` on staged files |
|
|
245
|
+
| `--branch` | string | Base branch for the pre-commit hook (default: auto-detected or `main`). Only used with `--hooks` |
|
|
246
|
+
|
|
247
|
+
### Examples
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
fallow init # creates .fallowrc.json with $schema
|
|
251
|
+
fallow init --toml # creates fallow.toml
|
|
252
|
+
fallow init --hooks # scaffold a pre-commit git hook (auto-detects base branch)
|
|
253
|
+
fallow init --hooks --branch develop # hook using custom base branch
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## `migrate`: Config Migration
|
|
259
|
+
|
|
260
|
+
Migrates configuration from knip and/or jscpd to fallow. Auto-detects config files.
|
|
261
|
+
|
|
262
|
+
### Flags
|
|
263
|
+
|
|
264
|
+
| Flag | Type | Description |
|
|
265
|
+
|------|------|-------------|
|
|
266
|
+
| `--toml` | bool | Output as TOML instead of JSON |
|
|
267
|
+
| `--dry-run` | bool | Preview without writing |
|
|
268
|
+
| `--from` | path | Specify source config file path |
|
|
269
|
+
|
|
270
|
+
### Detected Source Configs
|
|
271
|
+
|
|
272
|
+
- `knip.json`, `knip.jsonc`, `.knip.json`, `.knip.jsonc`
|
|
273
|
+
- `package.json` embedded `knip` field
|
|
274
|
+
- `.jscpd.json`
|
|
275
|
+
- `package.json` embedded `jscpd` field
|
|
276
|
+
|
|
277
|
+
### Examples
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
fallow migrate --dry-run # preview
|
|
281
|
+
fallow migrate # auto-detect and write .fallowrc.json
|
|
282
|
+
fallow migrate --toml # output as TOML
|
|
283
|
+
fallow migrate --from knip.json
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## `health`: Function Complexity & File Health Analysis
|
|
289
|
+
|
|
290
|
+
Analyzes function complexity across the project using cyclomatic and cognitive complexity metrics. By default all sections are included (health score, complexity findings, file scores, hotspots, and refactoring targets). Use `--complexity`, `--file-scores`, `--hotspots`, `--targets`, or `--score` to show only specific sections.
|
|
291
|
+
|
|
292
|
+
### Flags
|
|
293
|
+
|
|
294
|
+
| Flag | Type | Default | Description |
|
|
295
|
+
|------|------|---------|-------------|
|
|
296
|
+
| `--format` | `human\|json\|sarif\|compact\|markdown\|codeclimate\|badge` | `human` | Output format |
|
|
297
|
+
| `--quiet` | bool | `false` | Suppress progress bars |
|
|
298
|
+
| `--max-cyclomatic` | number | `20` | Fail if any function exceeds this cyclomatic complexity |
|
|
299
|
+
| `--max-cognitive` | number | `15` | Fail if any function exceeds this cognitive complexity |
|
|
300
|
+
| `--max-crap` | number | `30.0` | Fail if any function has CRAP score >= threshold. CRAP combines complexity with coverage (`CC^2 * (1 - cov/100)^3 + CC`). Pair with `--coverage` for accurate per-function CRAP; without Istanbul data fallow estimates coverage from the module graph. |
|
|
301
|
+
| `--top` | number | — | Only show the top N most complex functions (and file scores/hotspots/targets) |
|
|
302
|
+
| `--sort` | `cyclomatic\|cognitive\|lines` | `cyclomatic` | Sort order for complexity findings |
|
|
303
|
+
| `--complexity` | bool | `false` | Show only function complexity findings. When no section flags are set, all sections are shown by default. |
|
|
304
|
+
| `--file-scores` | bool | `false` | Show only per-file maintainability index (LOC, fan-in, fan-out, dead code ratio, complexity density). Runs the full analysis pipeline. When no section flags are set, all sections are shown by default. |
|
|
305
|
+
| `--hotspots` | bool | `false` | Show only hotspots: files that are both complex and frequently changing. Combines git churn history with complexity data. Requires a git repository. When no section flags are set, all sections are shown by default. |
|
|
306
|
+
| `--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. |
|
|
307
|
+
| `--effort` | `low\|medium\|high` | — | Filter refactoring targets by effort level. Implies `--targets`. |
|
|
308
|
+
| `--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. |
|
|
309
|
+
| `--min-score` | number | — | Fail if health score is below this threshold (exit code 1). Implies `--score`. CI quality gate. |
|
|
310
|
+
| `--since` | string | `6m` | Git history window for hotspot analysis. Accepts durations (`6m`, `90d`, `1y`, `2w`) or ISO dates (`2025-06-01`). |
|
|
311
|
+
| `--min-commits` | number | `3` | Minimum number of commits for a file to be included in hotspot ranking. |
|
|
312
|
+
| `--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 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. |
|
|
313
|
+
| `--ownership-emails` | `raw\|handle\|hash` | `handle` | Privacy mode for author emails. `handle` shows the local-part only (default, with GitHub noreply unwrap). `hash` emits stable `xxh3:` pseudonyms. `raw` shows full addresses. Use `hash` in regulated environments. Implies `--ownership`. Configure default via `health.ownership.emailMode`. |
|
|
314
|
+
| `--changed-since` | string | — | Only analyze files changed since a git ref |
|
|
315
|
+
| `--workspace` | string | — | Scope to one or more workspaces. Comma-separated values, globs (`apps/*`, `@scope/*`), and `!`-prefixed negation (`!apps/legacy`) supported. Matched against package name AND workspace path relative to repo root. |
|
|
316
|
+
| `--baseline` | path | — | Compare against a saved baseline |
|
|
317
|
+
| `--save-baseline` | path | — | Save current results as a baseline |
|
|
318
|
+
| `--save-snapshot` | path (optional) | `.fallow/snapshots/<timestamp>.json` | Save vital signs snapshot for trend tracking. Forces file-scores + hotspot computation. |
|
|
319
|
+
| `--trend` | bool | `false` | Compare current metrics against the most recent saved snapshot. Reads from `.fallow/snapshots/` and shows per-metric deltas with directional indicators (improving/declining/stable). Implies `--score`. |
|
|
320
|
+
| `--coverage-gaps` | bool | `false` | Show runtime files and exports that no test dependency path reaches. Opt-in (default off). Configure severity via the `coverage-gaps` rule (`error`/`warn`/`off`). |
|
|
321
|
+
| `--coverage` | path | none | Path to Istanbul-format coverage data (`coverage-final.json`) for accurate per-function CRAP scores. Uses `CC^2 * (1-cov/100)^3 + CC` instead of static binary model. |
|
|
322
|
+
| `--coverage-root` | path | none | Rebase file paths in coverage data by stripping this prefix and prepending the project root. For CI/Docker environments where coverage was generated with different absolute paths. |
|
|
323
|
+
| `--production-coverage` | path | none | Merge runtime production-coverage input into the health report (paid feature). Accepts a V8 coverage directory (`NODE_V8_COVERAGE=...`), a single V8 coverage JSON file, or an Istanbul `coverage-final.json`. Requires an active license; start one with `fallow license activate --trial --email <addr>`. JSON output gains a `production_coverage` object with a top-level report verdict, per-finding `verdict` (`safe_to_delete` / `review_required` / `low_traffic` / `coverage_unavailable` / `active`), stable content-hash IDs (`fallow:prod:<hash>`), evidence block, and percentile-ranked hot paths. On protocol-0.3+ sidecars the `summary` also carries an optional `capture_quality` block (`window_seconds`, `instances_observed`, `lazy_parse_warning`, `untracked_ratio_percent`) that flags short-window captures where lazy-parsed scripts may not appear. |
|
|
324
|
+
| `--min-invocations-hot` | number | `100` | Invocation threshold for hot-path classification. Takes effect only when `--production-coverage` is set. |
|
|
325
|
+
| `--min-observation-volume` | number | `5000` | Minimum total trace volume before the sidecar may emit high-confidence `safe_to_delete` / `review_required` verdicts. Below this, confidence is capped at `medium`. |
|
|
326
|
+
| `--low-traffic-threshold` | number | `0.001` | Fraction of total trace count below which an invoked function is classified `low_traffic` rather than `active`. Expressed as a decimal (0.001 = 0.1%). |
|
|
327
|
+
|
|
328
|
+
### Exit Codes
|
|
329
|
+
|
|
330
|
+
| Code | Meaning |
|
|
331
|
+
|------|---------|
|
|
332
|
+
| 0 | No functions exceed thresholds (and score above `--min-score` if set) |
|
|
333
|
+
| 1 | Functions exceed thresholds, or score below `--min-score` |
|
|
334
|
+
|
|
335
|
+
### Examples
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
# Full complexity analysis with JSON output
|
|
339
|
+
fallow health --format json --quiet
|
|
340
|
+
|
|
341
|
+
# Project health score with letter grade
|
|
342
|
+
fallow health --format json --quiet --score
|
|
343
|
+
|
|
344
|
+
# CI gate: fail if score below 70
|
|
345
|
+
fallow health --format json --quiet --min-score 70
|
|
346
|
+
|
|
347
|
+
# Top 10 most complex functions
|
|
348
|
+
fallow health --format json --quiet --top 10
|
|
349
|
+
|
|
350
|
+
# Sort by cognitive complexity
|
|
351
|
+
fallow health --format json --quiet --sort cognitive
|
|
352
|
+
|
|
353
|
+
# Custom thresholds
|
|
354
|
+
fallow health --format json --quiet --max-cyclomatic 15 --max-cognitive 10
|
|
355
|
+
|
|
356
|
+
# Per-file maintainability index
|
|
357
|
+
fallow health --format json --quiet --file-scores
|
|
358
|
+
|
|
359
|
+
# Worst 20 files by maintainability
|
|
360
|
+
fallow health --format json --quiet --file-scores --top 20
|
|
361
|
+
|
|
362
|
+
# Only analyze files changed since main
|
|
363
|
+
fallow health --format json --quiet --changed-since main
|
|
364
|
+
|
|
365
|
+
# Single workspace package
|
|
366
|
+
fallow health --format json --quiet --workspace my-package
|
|
367
|
+
|
|
368
|
+
# Incremental adoption with baseline
|
|
369
|
+
fallow health --format json --quiet --save-baseline fallow-baselines/health.json
|
|
370
|
+
fallow health --format json --quiet --baseline fallow-baselines/health.json
|
|
371
|
+
|
|
372
|
+
# CI: fail if any function is too complex
|
|
373
|
+
fallow health --max-cyclomatic 25 --max-cognitive 20 --quiet
|
|
374
|
+
|
|
375
|
+
# Hotspot analysis (complex + frequently changing files)
|
|
376
|
+
fallow health --format json --quiet --hotspots
|
|
377
|
+
|
|
378
|
+
# Hotspots from the last year
|
|
379
|
+
fallow health --format json --quiet --hotspots --since 1y
|
|
380
|
+
|
|
381
|
+
# Hotspots with at least 5 commits
|
|
382
|
+
fallow health --format json --quiet --hotspots --min-commits 5
|
|
383
|
+
|
|
384
|
+
# Top 10 hotspots from the last 90 days
|
|
385
|
+
fallow health --format json --quiet --hotspots --since 90d --top 10
|
|
386
|
+
|
|
387
|
+
# Ranked refactoring recommendations
|
|
388
|
+
fallow health --format json --quiet --targets
|
|
389
|
+
|
|
390
|
+
# Top 5 refactoring targets
|
|
391
|
+
fallow health --format json --quiet --targets --top 5
|
|
392
|
+
|
|
393
|
+
# Only low-effort refactoring targets (quick wins)
|
|
394
|
+
fallow health --format json --quiet --effort low
|
|
395
|
+
|
|
396
|
+
# Save a vital signs snapshot for trend tracking
|
|
397
|
+
fallow health --format json --quiet --save-snapshot
|
|
398
|
+
|
|
399
|
+
# Save snapshot to a custom path
|
|
400
|
+
fallow health --format json --quiet --save-snapshot .fallow/baseline-snapshot.json
|
|
401
|
+
|
|
402
|
+
# Compare current metrics against the most recent snapshot
|
|
403
|
+
fallow health --format json --quiet --trend
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### JSON Output Structure
|
|
407
|
+
|
|
408
|
+
```json
|
|
409
|
+
{
|
|
410
|
+
"schema_version": 3,
|
|
411
|
+
"version": "2.47.0",
|
|
412
|
+
"elapsed_ms": 32,
|
|
413
|
+
"summary": {
|
|
414
|
+
"files_analyzed": 482,
|
|
415
|
+
"functions_analyzed": 3200,
|
|
416
|
+
"functions_above_threshold": 3,
|
|
417
|
+
"max_cyclomatic_threshold": 20,
|
|
418
|
+
"max_cognitive_threshold": 15
|
|
419
|
+
},
|
|
420
|
+
"findings": [
|
|
421
|
+
{
|
|
422
|
+
"path": "src/parser.ts",
|
|
423
|
+
"name": "parseExpression",
|
|
424
|
+
"line": 42,
|
|
425
|
+
"col": 0,
|
|
426
|
+
"cyclomatic": 28,
|
|
427
|
+
"cognitive": 22,
|
|
428
|
+
"line_count": 95,
|
|
429
|
+
"exceeded": "both"
|
|
430
|
+
}
|
|
431
|
+
]
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
When the unit size very-high-risk percentage is >= 3%, the JSON output includes a `large_functions` array listing functions exceeding 60 lines of code:
|
|
436
|
+
|
|
437
|
+
```json
|
|
438
|
+
{
|
|
439
|
+
"large_functions": [
|
|
440
|
+
{
|
|
441
|
+
"path": "src/parser.ts",
|
|
442
|
+
"name": "parseExpression",
|
|
443
|
+
"line": 42,
|
|
444
|
+
"line_count": 95
|
|
445
|
+
}
|
|
446
|
+
]
|
|
447
|
+
}
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
This drill-down shows which specific functions are driving the unit size penalty in the health score, making it actionable without a separate analysis pass.
|
|
451
|
+
|
|
452
|
+
With `--file-scores`, the JSON output also includes `file_scores` array and `summary.files_scored` / `summary.average_maintainability`:
|
|
453
|
+
|
|
454
|
+
```json
|
|
455
|
+
{
|
|
456
|
+
"summary": {
|
|
457
|
+
"files_scored": 482,
|
|
458
|
+
"average_maintainability": 88.5,
|
|
459
|
+
"coverage_model": "static_estimated"
|
|
460
|
+
},
|
|
461
|
+
"file_scores": [
|
|
462
|
+
{
|
|
463
|
+
"path": "src/parser.ts",
|
|
464
|
+
"fan_in": 8,
|
|
465
|
+
"fan_out": 4,
|
|
466
|
+
"dead_code_ratio": 0.25,
|
|
467
|
+
"complexity_density": 0.22,
|
|
468
|
+
"maintainability_index": 75.1,
|
|
469
|
+
"total_cyclomatic": 42,
|
|
470
|
+
"total_cognitive": 35,
|
|
471
|
+
"function_count": 12,
|
|
472
|
+
"lines": 190,
|
|
473
|
+
"crap_max": 42.0,
|
|
474
|
+
"crap_above_threshold": 2
|
|
475
|
+
}
|
|
476
|
+
]
|
|
477
|
+
}
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
The `crap_max` field is the highest CRAP (Change Risk Anti-Patterns) score among functions in the file, using the canonical formula `CC^2 * (1 - cov/100)^3 + CC`. The default model (`static_estimated`) estimates per-function coverage from export references: directly test-referenced = 85%, indirectly test-reachable = 40%, untested = 0%. Provide `--coverage <path>` with Istanbul-format `coverage-final.json` for exact scores (`istanbul` model). The `crap_above_threshold` field counts functions with CRAP >= 30. When `--file-scores` is active, `summary.coverage_model` indicates the model used (`"static_estimated"` or `"istanbul"`).
|
|
481
|
+
|
|
482
|
+
Maintainability index formula: `100 - (complexity_density × 30) - (dead_code_ratio × 20) - min(ln(fan_out+1) × 4, 15)`, clamped to 0–100. Higher is better. Type-only exports are excluded from dead_code_ratio. Zero-function files (barrels) are excluded by default.
|
|
483
|
+
|
|
484
|
+
With `--hotspots`, the JSON output includes a `hotspots` array and `hotspot_summary`:
|
|
485
|
+
|
|
486
|
+
```json
|
|
487
|
+
{
|
|
488
|
+
"hotspot_summary": {
|
|
489
|
+
"since": "6m",
|
|
490
|
+
"min_commits": 3,
|
|
491
|
+
"files_analyzed": 482,
|
|
492
|
+
"files_excluded": 312,
|
|
493
|
+
"shallow_clone": false
|
|
494
|
+
},
|
|
495
|
+
"hotspots": [
|
|
496
|
+
{
|
|
497
|
+
"path": "src/parser.ts",
|
|
498
|
+
"score": 92,
|
|
499
|
+
"commits": 28,
|
|
500
|
+
"weighted_commits": 34.5,
|
|
501
|
+
"lines_added": 410,
|
|
502
|
+
"lines_deleted": 180,
|
|
503
|
+
"complexity_density": 0.22,
|
|
504
|
+
"fan_in": 8,
|
|
505
|
+
"trend": "Accelerating"
|
|
506
|
+
}
|
|
507
|
+
]
|
|
508
|
+
}
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
Hotspot score formula: `normalized_churn × normalized_complexity × 100`, scaled 0–100. Higher means more urgent to refactor. The `trend` field indicates recent change velocity: `Accelerating` (increasing churn), `Stable` (constant), or `Cooling` (decreasing). Files below `--min-commits` are excluded. The `shallow_clone` field warns when git history is truncated (shallow clone), which may undercount commits.
|
|
512
|
+
|
|
513
|
+
With `--targets`, the JSON output includes a `targets` array with ranked refactoring recommendations:
|
|
514
|
+
|
|
515
|
+
```json
|
|
516
|
+
{
|
|
517
|
+
"targets": [
|
|
518
|
+
{
|
|
519
|
+
"path": "src/parser.ts",
|
|
520
|
+
"priority": 82.5,
|
|
521
|
+
"efficiency": 27.5,
|
|
522
|
+
"recommendation": "Split high-impact file — 25 dependents amplify every change",
|
|
523
|
+
"category": "split_high_impact",
|
|
524
|
+
"effort": "high",
|
|
525
|
+
"confidence": "medium",
|
|
526
|
+
"factors": [
|
|
527
|
+
{
|
|
528
|
+
"metric": "complexity_density",
|
|
529
|
+
"value": 0.75,
|
|
530
|
+
"threshold": 0.3,
|
|
531
|
+
"detail": "density 0.75 exceeds 0.3"
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
"metric": "fan_in",
|
|
535
|
+
"value": 25.0,
|
|
536
|
+
"threshold": 10.0,
|
|
537
|
+
"detail": "25 files depend on this"
|
|
538
|
+
}
|
|
539
|
+
]
|
|
540
|
+
}
|
|
541
|
+
],
|
|
542
|
+
"target_thresholds": {
|
|
543
|
+
"fan_in_p95": 12.0,
|
|
544
|
+
"fan_in_p75": 5.0,
|
|
545
|
+
"fan_out_p95": 15.0,
|
|
546
|
+
"fan_out_p90": 8
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
Targets are sorted by `efficiency` (priority / effort_numeric) descending, surfacing quick wins first. The `target_thresholds` object exposes the adaptive percentile-based thresholds used for scoring. Priority formula: `min(complexity_density, 1) x 30 + hotspot_boost x 25 + dead_code_ratio x 20 + fan_in_norm x 15 + fan_out_norm x 10`, clamped to 0-100. Fan-in and fan-out normalization uses the project's p95 values (with floors). Categories: `urgent_churn_complexity`, `break_circular_dependency`, `split_high_impact`, `remove_dead_code`, `extract_complex_functions`, `extract_dependencies`, `add_test_coverage`. Each target includes `efficiency`, `effort` (low/medium/high), `confidence` (high/medium/low, data source reliability), and contributing `factors`.
|
|
552
|
+
|
|
553
|
+
The `add_test_coverage` category fires when a file has 2+ functions with CRAP scores >= 30 and complexity density > 0.3. The `crap_max` metric appears in contributing factors for these targets.
|
|
554
|
+
|
|
555
|
+
### Vital Signs
|
|
556
|
+
|
|
557
|
+
All `health` JSON output includes a `vital_signs` object with project-wide metrics:
|
|
558
|
+
|
|
559
|
+
```json
|
|
560
|
+
{
|
|
561
|
+
"vital_signs": {
|
|
562
|
+
"dead_file_pct": 3.2,
|
|
563
|
+
"dead_export_pct": 8.1,
|
|
564
|
+
"avg_cyclomatic": 4.5,
|
|
565
|
+
"p90_cyclomatic": 12,
|
|
566
|
+
"maintainability_avg": 88.5,
|
|
567
|
+
"hotspot_count": 7,
|
|
568
|
+
"circular_dep_count": 2,
|
|
569
|
+
"unused_dep_count": 3,
|
|
570
|
+
"unit_size_profile": {
|
|
571
|
+
"low_risk": 82.1,
|
|
572
|
+
"medium_risk": 11.4,
|
|
573
|
+
"high_risk": 4.3,
|
|
574
|
+
"very_high_risk": 2.2
|
|
575
|
+
},
|
|
576
|
+
"unit_interfacing_profile": {
|
|
577
|
+
"low_risk": 95.6,
|
|
578
|
+
"medium_risk": 3.8,
|
|
579
|
+
"high_risk": 0.5,
|
|
580
|
+
"very_high_risk": 0.1
|
|
581
|
+
},
|
|
582
|
+
"p95_fan_in": 8,
|
|
583
|
+
"coupling_high_pct": 2.3
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
Fields are `null` when the corresponding data source is not available (e.g., `hotspot_count` is null without `--hotspots` or when git is not available). The `unit_size_profile` and `unit_interfacing_profile` are risk distribution histograms (low risk / medium risk / high risk / very high risk as percentages). `p95_fan_in` is the 95th percentile of incoming dependencies. `coupling_high_pct` is the percentage of files above the effective coupling threshold.
|
|
589
|
+
|
|
590
|
+
With `--score`, the JSON output includes a `health_score` object:
|
|
591
|
+
|
|
592
|
+
```json
|
|
593
|
+
{
|
|
594
|
+
"health_score": {
|
|
595
|
+
"score": 76.9,
|
|
596
|
+
"grade": "B",
|
|
597
|
+
"penalties": {
|
|
598
|
+
"dead_files": 3.1,
|
|
599
|
+
"dead_exports": 6.0,
|
|
600
|
+
"complexity": 0.0,
|
|
601
|
+
"p90_complexity": 0.0,
|
|
602
|
+
"maintainability": 0.0,
|
|
603
|
+
"hotspots": 0.0,
|
|
604
|
+
"unused_deps": 10.0,
|
|
605
|
+
"circular_deps": 4.0,
|
|
606
|
+
"unit_size": 0.0,
|
|
607
|
+
"coupling": 0.0,
|
|
608
|
+
"duplication": 4.0
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
Score is reproducible: `100 - sum(penalties) == score`. Penalty fields are absent when the pipeline didn't run. `--score` automatically runs duplication analysis. Grades: A (>= 85), B (70-84), C (55-69), D (40-54), F (< 40).
|
|
615
|
+
|
|
616
|
+
### Health Trend
|
|
617
|
+
|
|
618
|
+
With `--trend`, the JSON output includes a `health_trend` object comparing current metrics against the most recent saved snapshot:
|
|
619
|
+
|
|
620
|
+
```json
|
|
621
|
+
{
|
|
622
|
+
"health_trend": {
|
|
623
|
+
"compared_to": {
|
|
624
|
+
"timestamp": "2026-03-25T14:30:00Z",
|
|
625
|
+
"git_sha": "a1b2c3d",
|
|
626
|
+
"score": 74.2,
|
|
627
|
+
"grade": "B"
|
|
628
|
+
},
|
|
629
|
+
"metrics": [
|
|
630
|
+
{
|
|
631
|
+
"name": "score",
|
|
632
|
+
"label": "Health Score",
|
|
633
|
+
"previous": 74.2,
|
|
634
|
+
"current": 76.9,
|
|
635
|
+
"delta": 2.7,
|
|
636
|
+
"direction": "improving",
|
|
637
|
+
"unit": ""
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
"name": "dead_file_pct",
|
|
641
|
+
"label": "Dead Files",
|
|
642
|
+
"previous": 5.1,
|
|
643
|
+
"current": 4.2,
|
|
644
|
+
"delta": -0.9,
|
|
645
|
+
"direction": "improving",
|
|
646
|
+
"unit": "%",
|
|
647
|
+
"previous_count": { "value": 13, "total": 255 },
|
|
648
|
+
"current_count": { "value": 11, "total": 262 }
|
|
649
|
+
}
|
|
650
|
+
],
|
|
651
|
+
"snapshots_loaded": 3,
|
|
652
|
+
"overall_direction": "improving"
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
Metrics tracked: `score`, `dead_file_pct`, `dead_export_pct`, `avg_cyclomatic`, `maintainability_avg`, `unused_dep_count`, `circular_dep_count`, `hotspot_count`, `unit_size_very_high_pct`, `p95_fan_in`, `duplication_pct`. Each metric includes `direction` (`improving`, `declining`, `stable`). Percentage metrics include `previous_count`/`current_count` with raw numerator/denominator. `--trend` requires at least one saved snapshot in `.fallow/snapshots/`. When comparing against a snapshot from an older schema version (current: v5), the trend output warns that score deltas may reflect formula changes.
|
|
658
|
+
|
|
659
|
+
### Vital Signs Snapshots
|
|
660
|
+
|
|
661
|
+
`--save-snapshot` persists a `VitalSignsSnapshot` JSON file for trend tracking across runs. Snapshots automatically include the health score and grade. The snapshot contains more detail than the inline `vital_signs` object:
|
|
662
|
+
|
|
663
|
+
```json
|
|
664
|
+
{
|
|
665
|
+
"schema_version": 5,
|
|
666
|
+
"timestamp": "2025-12-01T10:30:00Z",
|
|
667
|
+
"vital_signs": {
|
|
668
|
+
"dead_file_pct": 3.2,
|
|
669
|
+
"dead_export_pct": 8.1,
|
|
670
|
+
"avg_cyclomatic": 4.5,
|
|
671
|
+
"p90_cyclomatic": 12,
|
|
672
|
+
"maintainability_avg": 88.5,
|
|
673
|
+
"hotspot_count": 7,
|
|
674
|
+
"circular_dep_count": 2,
|
|
675
|
+
"unused_dep_count": 3
|
|
676
|
+
},
|
|
677
|
+
"counts": {
|
|
678
|
+
"total_files": 482,
|
|
679
|
+
"dead_files": 15,
|
|
680
|
+
"total_exports": 1200,
|
|
681
|
+
"dead_exports": 97,
|
|
682
|
+
"total_dependencies": 42,
|
|
683
|
+
"unused_dependencies": 3
|
|
684
|
+
},
|
|
685
|
+
"git_sha": "abc1234",
|
|
686
|
+
"git_branch": "main",
|
|
687
|
+
"shallow_clone": false
|
|
688
|
+
}
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
The snapshot `schema_version` is independent of the report `schema_version`. Default path: `.fallow/snapshots/<timestamp>.json`. The `--save-snapshot` flag forces file-scores and hotspot computation to populate all vital signs fields.
|
|
692
|
+
|
|
693
|
+
---
|
|
694
|
+
|
|
695
|
+
## `audit`: Changed-File Quality Gate
|
|
696
|
+
|
|
697
|
+
Audits changed files for dead code, complexity, and duplication. Returns a verdict (pass/warn/fail). Purpose-built for PR quality gates and reviewing AI-generated code. Auto-detects the base branch if `--base` is not set.
|
|
698
|
+
|
|
699
|
+
### Flags
|
|
700
|
+
|
|
701
|
+
| Flag | Type | Default | Description |
|
|
702
|
+
|------|------|---------|-------------|
|
|
703
|
+
| `--base` | string | auto-detect | Git ref to compare against (alias for `--changed-since`) |
|
|
704
|
+
| `--production` | bool | false | Exclude test/story/dev files |
|
|
705
|
+
| `-w, --workspace` | string | — | Scope to one or more workspaces. Comma-separated, globs, `!` negation. |
|
|
706
|
+
| `--explain` | bool | false | Include metric definitions in JSON output |
|
|
707
|
+
| `--ci` | bool | false | Equivalent to `--format sarif --fail-on-issues --quiet` |
|
|
708
|
+
| `--fail-on-issues` | bool | false | Exit with code 1 if issues are found |
|
|
709
|
+
| `--sarif-file` | path | — | Write SARIF output to a file alongside primary format |
|
|
710
|
+
| `--dead-code-baseline` | path | — | Baseline file (produced by `fallow dead-code --save-baseline`). Pre-existing dead-code issues are excluded from the verdict. |
|
|
711
|
+
| `--health-baseline` | path | — | Baseline file (produced by `fallow health --save-baseline`). Pre-existing complexity findings are excluded from the verdict. |
|
|
712
|
+
| `--dupes-baseline` | path | — | Baseline file (produced by `fallow dupes --save-baseline`). Pre-existing clone groups are excluded from the verdict. |
|
|
713
|
+
| `--max-crap` | number | `30.0` | Forwarded to the health sub-analysis. Functions meeting or exceeding this CRAP score cause audit to fail. Same formula as `health --max-crap`. Pair with coverage data for accurate per-function CRAP. |
|
|
714
|
+
| `--fail-on-regression` | bool | false | Fail if issues increased beyond tolerance vs regression baseline |
|
|
715
|
+
| `--tolerance` | string | `0` | Allowed increase before regression fails (`N` or `N%`) |
|
|
716
|
+
| `--regression-baseline` | path | `.fallow/regression-baseline.json` | Path to the regression baseline file |
|
|
717
|
+
| `--save-regression-baseline` | path | — | Save current issue counts as a regression baseline |
|
|
718
|
+
|
|
719
|
+
### Verdicts
|
|
720
|
+
|
|
721
|
+
| Verdict | Exit code | When |
|
|
722
|
+
|---------|-----------|------|
|
|
723
|
+
| pass | 0 | No issues in changed files |
|
|
724
|
+
| warn | 0 | Issues found, all warn-severity |
|
|
725
|
+
| fail | 1 | Error-severity issues found |
|
|
726
|
+
| error | 2 | Runtime error (invalid ref, not a git repo) |
|
|
727
|
+
|
|
728
|
+
### Examples
|
|
729
|
+
|
|
730
|
+
```bash
|
|
731
|
+
# Auto-detect base branch
|
|
732
|
+
fallow audit --format json --quiet
|
|
733
|
+
|
|
734
|
+
# Explicit base ref
|
|
735
|
+
fallow audit --format json --quiet --base main
|
|
736
|
+
|
|
737
|
+
# Audit last 3 commits
|
|
738
|
+
fallow audit --format json --quiet --base HEAD~3
|
|
739
|
+
|
|
740
|
+
# Production code only in a monorepo workspace
|
|
741
|
+
fallow audit --format json --quiet --production --workspace @app/api
|
|
742
|
+
|
|
743
|
+
# CI mode (SARIF + fail on issues + quiet)
|
|
744
|
+
fallow audit --ci
|
|
745
|
+
|
|
746
|
+
# Per-analysis baselines: only fail on genuinely new issues
|
|
747
|
+
fallow audit \
|
|
748
|
+
--dead-code-baseline fallow-baselines/dead-code.json \
|
|
749
|
+
--health-baseline fallow-baselines/health.json \
|
|
750
|
+
--dupes-baseline fallow-baselines/dupes.json
|
|
751
|
+
# Or set these under `audit.*Baseline` in .fallowrc.json so `fallow audit` picks them up with no flags.
|
|
752
|
+
# The global --baseline / --save-baseline flags are REJECTED on audit (exit 2) because each sub-analysis uses a different baseline format.
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
### JSON Output Structure
|
|
756
|
+
|
|
757
|
+
```json
|
|
758
|
+
{
|
|
759
|
+
"schema_version": 3,
|
|
760
|
+
"version": "2.47.0",
|
|
761
|
+
"command": "audit",
|
|
762
|
+
"verdict": "fail",
|
|
763
|
+
"changed_files_count": 12,
|
|
764
|
+
"base_ref": "main",
|
|
765
|
+
"head_sha": "d4a2f91",
|
|
766
|
+
"elapsed_ms": 2140,
|
|
767
|
+
"summary": {
|
|
768
|
+
"dead_code_issues": 2,
|
|
769
|
+
"dead_code_has_errors": true,
|
|
770
|
+
"complexity_findings": 1,
|
|
771
|
+
"max_cyclomatic": 28,
|
|
772
|
+
"duplication_clone_groups": 0
|
|
773
|
+
},
|
|
774
|
+
"dead_code": {
|
|
775
|
+
"schema_version": 3,
|
|
776
|
+
"total_issues": 2,
|
|
777
|
+
"unused_exports": [...]
|
|
778
|
+
},
|
|
779
|
+
"complexity": {
|
|
780
|
+
"findings": [...]
|
|
781
|
+
},
|
|
782
|
+
"duplication": {
|
|
783
|
+
"clone_groups": []
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
The `verdict` field is always present and is the primary decision signal. Dead code, complexity, and duplication sections follow their respective schemas from the individual commands. Thresholds for complexity are inherited from `fallow health` config (defaults: cyclomatic 20, cognitive 15).
|
|
789
|
+
|
|
790
|
+
---
|
|
791
|
+
|
|
792
|
+
## `flags`: Feature Flag Detection
|
|
793
|
+
|
|
794
|
+
Detects feature flag patterns in the codebase. Identifies environment variable flags (`process.env.FEATURE_*`), SDK calls (LaunchDarkly, Statsig, Unleash, GrowthBook), and config object patterns (opt-in). Reports flag locations, detection confidence, and cross-references with dead code findings.
|
|
795
|
+
|
|
796
|
+
### Flags
|
|
797
|
+
|
|
798
|
+
| Flag | Type | Default | Description |
|
|
799
|
+
|------|------|---------|-------------|
|
|
800
|
+
| `--format` | `human\|json\|sarif\|compact\|markdown\|codeclimate` | `human` | Output format |
|
|
801
|
+
| `--quiet` | bool | `false` | Suppress progress bars |
|
|
802
|
+
| `--top` | number | — | Show only the top N flags |
|
|
803
|
+
|
|
804
|
+
### Examples
|
|
805
|
+
|
|
806
|
+
```bash
|
|
807
|
+
# Detect all feature flags with JSON output
|
|
808
|
+
fallow flags --format json --quiet
|
|
809
|
+
|
|
810
|
+
# Top 10 flags
|
|
811
|
+
fallow flags --format json --quiet --top 10
|
|
812
|
+
|
|
813
|
+
# Single workspace package
|
|
814
|
+
fallow flags --format json --quiet --workspace my-package
|
|
815
|
+
```
|
|
816
|
+
|
|
817
|
+
### JSON Output Structure
|
|
818
|
+
|
|
819
|
+
```json
|
|
820
|
+
{
|
|
821
|
+
"schema_version": 3,
|
|
822
|
+
"version": "2.47.0",
|
|
823
|
+
"elapsed_ms": 116,
|
|
824
|
+
"feature_flags": [],
|
|
825
|
+
"total_flags": 0
|
|
826
|
+
}
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
---
|
|
830
|
+
|
|
831
|
+
## `schema`: CLI Introspection
|
|
832
|
+
|
|
833
|
+
Dumps the full CLI interface definition as machine-readable JSON.
|
|
834
|
+
|
|
835
|
+
```bash
|
|
836
|
+
fallow schema
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
---
|
|
840
|
+
|
|
841
|
+
## `config-schema`: Config JSON Schema
|
|
842
|
+
|
|
843
|
+
Prints the JSON Schema for fallow configuration files.
|
|
844
|
+
|
|
845
|
+
```bash
|
|
846
|
+
fallow config-schema > schema.json
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
---
|
|
850
|
+
|
|
851
|
+
## `plugin-schema`: Plugin JSON Schema
|
|
852
|
+
|
|
853
|
+
Prints the JSON Schema for external plugin definition files.
|
|
854
|
+
|
|
855
|
+
```bash
|
|
856
|
+
fallow plugin-schema > plugin-schema.json
|
|
857
|
+
```
|
|
858
|
+
|
|
859
|
+
---
|
|
860
|
+
|
|
861
|
+
## `license`: Manage Paid-Feature License
|
|
862
|
+
|
|
863
|
+
Manage the local JWT used to unlock paid features (Phase 2 production coverage). Verification is fully offline against an Ed25519 public key compiled into the binary. Only `--trial` and `refresh` hit the network (`api.fallow.cloud`, 5s connect / 10s total timeout).
|
|
864
|
+
|
|
865
|
+
```bash
|
|
866
|
+
fallow license activate --trial --email you@company.com
|
|
867
|
+
fallow license activate eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...
|
|
868
|
+
fallow license activate --from-file ./license.jwt
|
|
869
|
+
cat ./license.jwt | fallow license activate --stdin
|
|
870
|
+
fallow license status
|
|
871
|
+
fallow license refresh
|
|
872
|
+
fallow license deactivate
|
|
873
|
+
```
|
|
874
|
+
|
|
875
|
+
### Subcommands
|
|
876
|
+
|
|
877
|
+
| Subcommand | Purpose |
|
|
878
|
+
|------------|---------|
|
|
879
|
+
| `activate` | Install a JWT or start a 30-day trial. JWT input precedence: positional arg > `--from-file` > `--stdin`. |
|
|
880
|
+
| `status` | Print tier, seats, features, days-until-expiry, and (when `refresh_after` has passed) a proactive refresh hint. |
|
|
881
|
+
| `refresh` | Fetch a fresh JWT using the currently stored one as identity proof. Exit 7 on network failure. |
|
|
882
|
+
| `deactivate` | Remove the local license file. |
|
|
883
|
+
|
|
884
|
+
### `activate` flags
|
|
885
|
+
|
|
886
|
+
| Flag | Type | Description |
|
|
887
|
+
|------|------|-------------|
|
|
888
|
+
| `--trial` | bool | Start a 30-day email-gated trial. Requires `--email`. **Rate-limited to 5 requests per hour per IP** — in CI or behind a shared NAT, start the trial locally and set `FALLOW_LICENSE` on the runner. |
|
|
889
|
+
| `--email <ADDR>` | string | Email for the trial flow. On success, `trialEndsAt` is printed to stdout so you can see the trial window without decoding the JWT. |
|
|
890
|
+
| `--from-file <PATH>` | path | Read a JWT from a file. |
|
|
891
|
+
| `--stdin` | bool | Read a JWT from stdin. Conflicts with `--from-file` and positional JWT. |
|
|
892
|
+
|
|
893
|
+
### Storage precedence
|
|
894
|
+
|
|
895
|
+
1. `FALLOW_LICENSE` (env var holding the full JWT string)
|
|
896
|
+
2. `FALLOW_LICENSE_PATH` (env var pointing at a file)
|
|
897
|
+
3. `~/.fallow/license.jwt` (default; written `chmod 0600` on Unix)
|
|
898
|
+
|
|
899
|
+
### Grace ladder
|
|
900
|
+
|
|
901
|
+
| Days past `exp` | State | Behavior |
|
|
902
|
+
|-----------------|-------|----------|
|
|
903
|
+
| `<= 7` | ExpiredWarning | Analysis runs; CLI prints a refresh hint |
|
|
904
|
+
| `> 7, <= 30` | ExpiredWatermark | Analysis runs; output gains a visible watermark until refreshed |
|
|
905
|
+
| `> 30` | HardFail | Paid features blocked; run `fallow license refresh` or start a new trial |
|
|
906
|
+
|
|
907
|
+
### Actionable error messages
|
|
908
|
+
|
|
909
|
+
On HTTP error from `api.fallow.cloud`, fallow parses the `{error, message, code}` envelope and maps known codes to targeted hints:
|
|
910
|
+
|
|
911
|
+
| Operation + code | CLI message |
|
|
912
|
+
|------------------|-------------|
|
|
913
|
+
| `refresh` + `token_stale` | `your stored license is too stale to refresh. Reactivate with: fallow license activate --trial --email <addr>` |
|
|
914
|
+
| `refresh` + `invalid_token` | `your stored license token is missing required claims. Reactivate with: fallow license activate --trial --email <addr>` |
|
|
915
|
+
| `refresh` or `trial` + `unauthorized` | `authentication failed. Reactivate with: fallow license activate --trial --email <addr>` |
|
|
916
|
+
| `trial` + `rate_limit_exceeded` | `trial creation is rate-limited to 5 per hour per IP. Wait an hour or retry from a different network (in CI, start the trial locally and set FALLOW_LICENSE on the runner).` |
|
|
917
|
+
|
|
918
|
+
Unknown codes fall back to the backend's `message` field, or the raw body.
|
|
919
|
+
|
|
920
|
+
### Exit Codes
|
|
921
|
+
|
|
922
|
+
| Code | Meaning |
|
|
923
|
+
|------|---------|
|
|
924
|
+
| `0` | Valid license (or trial/refresh succeeded) |
|
|
925
|
+
| `2` | Bad invocation (missing email for `--trial`, unreadable file) |
|
|
926
|
+
| `3` | License missing, hard-fail expired, or malformed JWT |
|
|
927
|
+
| `7` | Network failure or non-success HTTP status from `api.fallow.cloud` |
|
|
928
|
+
|
|
929
|
+
---
|
|
930
|
+
|
|
931
|
+
## `coverage`: Production-Coverage Workflow
|
|
932
|
+
|
|
933
|
+
Helper subcommand for the paid production-coverage analyzer. Two subcommands today:
|
|
934
|
+
|
|
935
|
+
- `coverage setup` — resumable state machine that wires license activation, sidecar installation, framework-aware coverage recipe writing, and automatic handoff into `fallow health --production-coverage`.
|
|
936
|
+
- `coverage upload-inventory` — push a static function inventory to fallow cloud so the dashboard can surface `untracked` functions (those in the codebase but never called at runtime).
|
|
937
|
+
|
|
938
|
+
```bash
|
|
939
|
+
fallow coverage setup # interactive
|
|
940
|
+
fallow coverage setup --yes # accept all prompts
|
|
941
|
+
fallow coverage setup --non-interactive # print instructions, do not prompt
|
|
942
|
+
|
|
943
|
+
fallow coverage upload-inventory # infers project-id, git-sha, API key
|
|
944
|
+
fallow coverage upload-inventory --dry-run # print what would be uploaded, exit 0
|
|
945
|
+
```
|
|
946
|
+
|
|
947
|
+
### `setup` flow
|
|
948
|
+
|
|
949
|
+
1. **License check** — if missing or hard-fail, offers to start a trial.
|
|
950
|
+
2. **Sidecar discovery** — resolves `FALLOW_COV_BIN`, project-local `node_modules/.bin/fallow-cov`, package-manager bin, `~/.fallow/bin/fallow-cov`, and `PATH`. When `FALLOW_COV_BIN` is set but points to a non-existent file, setup errors fast instead of falling through.
|
|
951
|
+
3. **Coverage recipe** — detects framework (Next.js, Nuxt, Astro, SvelteKit, Remix, NestJS, plain Node) and package manager (npm, pnpm, yarn, bun), then writes `docs/collect-coverage.md` with the correct commands.
|
|
952
|
+
4. **Handoff** — if `./coverage/coverage-final.json` or a V8 coverage directory already exists, setup runs `fallow health --production-coverage <path>` directly.
|
|
953
|
+
|
|
954
|
+
### `upload-inventory` flags
|
|
955
|
+
|
|
956
|
+
| Flag | Type | Default | Description |
|
|
957
|
+
|------|------|---------|-------------|
|
|
958
|
+
| `--api-key <KEY>` | string | `$FALLOW_API_KEY` | Fallow cloud bearer token. Generate at `https://fallow.cloud/settings#api-keys`. **Prefer `$FALLOW_API_KEY` on shared CI runners**: `--api-key` on the command line may be visible to other processes via `ps`. |
|
|
959
|
+
| `--api-endpoint <URL>` | string | `$FALLOW_API_URL` or `https://api.fallow.cloud` | Override for staging / on-prem. |
|
|
960
|
+
| `--project-id <OWNER/REPO>` | string | `$GITHUB_REPOSITORY` → `$CI_PROJECT_PATH` → `git remote get-url origin` | Project identifier. |
|
|
961
|
+
| `--git-sha <SHA>` | string | `git rev-parse HEAD` | Commit SHA this inventory is keyed to. Max 64 chars; `[A-Za-z0-9._-]` only. |
|
|
962
|
+
| `--allow-dirty` | bool | `false` | Silence the warning when the working tree has uncommitted changes. |
|
|
963
|
+
| `--exclude-paths <GLOB>` | glob | none | Additional globs to skip (repeatable), applied after the configured fallow ignore rules. |
|
|
964
|
+
| `--path-prefix <PREFIX>` | string | none | Prefix prepended to every emitted `filePath` so inventory matches runtime paths. Required for containerized deployments (runtime reports `/app/src/*` while the walker emits `src/*`). Common values: `/app`, `/workspace`, `/usr/src/app`, `/var/task`, `/home/runner/work/<repo>/<repo>`. Must start with `/`. |
|
|
965
|
+
| `--dry-run` | bool | `false` | Print what would be uploaded and exit. No network call. |
|
|
966
|
+
| `--ignore-upload-errors` | bool | `false` | Treat upload failures as warnings (exit 0). Validation errors still fail hard. |
|
|
967
|
+
|
|
968
|
+
Only plain JS/TS/JSX/TSX sources are walked. Declaration files (`*.d.ts`, `*.d.mts`, `*.d.cts`, `*.d.tsx`) and bodyless function signatures (TS overloads, `abstract` methods, `declare function`) are intentionally skipped; they have no runtime footprint. Function names match `oxc-coverage-instrument` byte-for-byte so the join with runtime coverage succeeds.
|
|
969
|
+
|
|
970
|
+
### Environment
|
|
971
|
+
|
|
972
|
+
- `FALLOW_COV_BIN` — explicit override for the sidecar binary (for `setup`). Wins over all other discovery paths. Must point to an existing file.
|
|
973
|
+
- `FALLOW_API_KEY` — fallow cloud bearer token (for `upload-inventory`). Overridden by `--api-key`.
|
|
974
|
+
- `FALLOW_API_URL` — base URL for cloud calls. Overridden by `--api-endpoint`.
|
|
975
|
+
|
|
976
|
+
### Exit Codes
|
|
977
|
+
|
|
978
|
+
| Code | Meaning |
|
|
979
|
+
|------|---------|
|
|
980
|
+
| `0` | Setup complete / upload succeeded / dry-run printed |
|
|
981
|
+
| `2` | Bad invocation, unable to resolve sidecar via env override (`setup`) |
|
|
982
|
+
| `4` | Sidecar install failed (`setup`) |
|
|
983
|
+
| `5` | Coverage input could not be pre-processed (`setup`) |
|
|
984
|
+
| `7` | Network failure (trial activation for `setup`; upload DNS/TLS/connect for `upload-inventory`) |
|
|
985
|
+
| `10` | Validation error: missing API key, unresolvable project-id, zero functions (`upload-inventory`) |
|
|
986
|
+
| `11` | Payload too large: inventory exceeds the 200,000-function server cap (`upload-inventory`) |
|
|
987
|
+
| `12` | Auth rejected: 401 / 403 from the server (`upload-inventory`) |
|
|
988
|
+
| `13` | Server error: 5xx or other non-2xx status (`upload-inventory`) |
|
|
989
|
+
|
|
990
|
+
---
|
|
991
|
+
|
|
992
|
+
## `config`: Show Resolved Config
|
|
993
|
+
|
|
994
|
+
Prints the loaded config file path and the resolved config (with `extends` merged) as JSON. Useful for verifying which config fallow picked up, especially in monorepos.
|
|
995
|
+
|
|
996
|
+
```bash
|
|
997
|
+
fallow config # path on first line, JSON below
|
|
998
|
+
fallow config --path # only the path (scriptable)
|
|
999
|
+
```
|
|
1000
|
+
|
|
1001
|
+
### Flags
|
|
1002
|
+
|
|
1003
|
+
| Flag | Type | Description |
|
|
1004
|
+
|------|------|-------------|
|
|
1005
|
+
| `--path` | bool | Print only the config file path, no JSON |
|
|
1006
|
+
|
|
1007
|
+
### Exit Codes
|
|
1008
|
+
|
|
1009
|
+
| Code | Meaning |
|
|
1010
|
+
|------|---------|
|
|
1011
|
+
| `0` | Config file found and loaded |
|
|
1012
|
+
| `2` | Error (parse failure, explicit `--config` path missing) |
|
|
1013
|
+
| `3` | No config file found; defaults are in effect |
|
|
1014
|
+
|
|
1015
|
+
Honors the global `--config <path>` flag: if passed, that path is loaded directly instead of walking the directory tree.
|
|
1016
|
+
|
|
1017
|
+
The `loaded config: <path>` line is also emitted to stderr automatically at the start of every human-format CLI run (suppressed by `--quiet` and non-human formats).
|
|
1018
|
+
|
|
1019
|
+
---
|
|
1020
|
+
|
|
1021
|
+
## Global Flags
|
|
1022
|
+
|
|
1023
|
+
Available on all commands:
|
|
1024
|
+
|
|
1025
|
+
| Flag | Type | Description |
|
|
1026
|
+
|------|------|-------------|
|
|
1027
|
+
| `-r, --root` | path | Project root directory |
|
|
1028
|
+
| `-c, --config` | path | Config file path |
|
|
1029
|
+
| `-f, --format` (alias: `--output`) | string | Output format |
|
|
1030
|
+
| `-q, --quiet` | bool | Suppress progress output |
|
|
1031
|
+
| `--no-cache` | bool | Disable incremental caching |
|
|
1032
|
+
| `--threads` | number | Number of parser threads |
|
|
1033
|
+
| `--changed-since` (alias: `--base`) | string | Git-aware incremental analysis |
|
|
1034
|
+
| `--baseline` | path | Compare to baseline |
|
|
1035
|
+
| `--save-baseline` | path | Save results as baseline |
|
|
1036
|
+
| `--fail-on-regression` | bool | Fail if issue count increased beyond tolerance vs a regression baseline |
|
|
1037
|
+
| `--tolerance` | string | Allowed increase: `"2%"` (percentage) or `"5"` (absolute). Default: `"0"` |
|
|
1038
|
+
| `--regression-baseline` | path | Path to regression baseline file (default: `.fallow/regression-baseline.json`) |
|
|
1039
|
+
| `--save-regression-baseline` | path | Save current issue counts as a regression baseline |
|
|
1040
|
+
| `--production` | bool | Exclude test/dev files, only start/build scripts |
|
|
1041
|
+
| `--performance` | bool | Show pipeline timing breakdown |
|
|
1042
|
+
| `-w, --workspace` | string | Scope to one or more workspaces (comma-separated, globs, `!` negation) |
|
|
1043
|
+
| `--changed-workspaces` | string (git ref) | Git-derived monorepo CI scoping: scope to workspaces containing any file changed since `REF`. Mutually exclusive with `--workspace`. Missing ref is a hard error. |
|
|
1044
|
+
| `--explain` | bool | Include metric definitions in JSON output (`_meta` object). Always on for MCP |
|
|
1045
|
+
| `--only` | string | Run only specific analyses (e.g., `--only dead-code,dupes`). Values: `dead-code` (alias: `check`), `dupes`, `health` |
|
|
1046
|
+
| `--skip` | string | Skip specific analyses (e.g., `--skip health`). Values: `dead-code` (alias: `check`), `dupes`, `health` |
|
|
1047
|
+
| `--ci` | bool | CI mode: `--format sarif --fail-on-issues --quiet` |
|
|
1048
|
+
| `--fail-on-issues` | bool | Exit 1 if any issues found (promotes `warn` to `error`) |
|
|
1049
|
+
| `--sarif-file` | path | Write SARIF output to a file instead of stdout |
|
|
1050
|
+
| `--summary` | bool | Show only category counts without individual items. Useful for dashboards and quick overviews |
|
|
1051
|
+
| `--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 |
|
|
1052
|
+
| `--score` | bool | Compute health score (0-100 with letter grade) in combined mode. Enables the health delta header in PR comments. JSON includes `health_score` object with `score`, `grade`, and `penalties` breakdown |
|
|
1053
|
+
| `--trend` | bool | Compare current health metrics against saved snapshot. Implies `--score`. Shows per-metric deltas with directional indicators. Requires at least one saved snapshot in `.fallow/snapshots/` |
|
|
1054
|
+
| `--save-snapshot` | path (optional) | Save vital signs snapshot for trend tracking. Default path: `.fallow/snapshots/<timestamp>.json`. Forces file-scores + hotspot computation |
|
|
1055
|
+
|
|
1056
|
+
---
|
|
1057
|
+
|
|
1058
|
+
## Environment Variables
|
|
1059
|
+
|
|
1060
|
+
| Variable | Description |
|
|
1061
|
+
|----------|-------------|
|
|
1062
|
+
| `FALLOW_FORMAT` | Default output format. CLI `--format` overrides. |
|
|
1063
|
+
| `FALLOW_QUIET` | Set to `1` to suppress progress. CLI `--quiet` overrides. |
|
|
1064
|
+
| `FALLOW_BIN` | Path to fallow binary (used by the MCP server). |
|
|
1065
|
+
| `FALLOW_TIMEOUT_SECS` | MCP server subprocess timeout in seconds (default: `120`). Increase for very large codebases. |
|
|
1066
|
+
| `FALLOW_EXTENDS_TIMEOUT_SECS` | Timeout for fetching remote `extends` URLs in seconds (default: `5`). |
|
|
1067
|
+
| `FALLOW_COMMAND` | GitLab CI: command to run (default: `dead-code`). |
|
|
1068
|
+
| `FALLOW_FAIL_ON_ISSUES` | GitLab CI: set to `true` to exit 1 if issues found. |
|
|
1069
|
+
| `FALLOW_CHANGED_SINCE` | GitLab CI: git ref for incremental analysis. Auto-detected in MR pipelines. |
|
|
1070
|
+
| `FALLOW_COMMENT` | GitLab CI: set to `true` to post MR summary comments. |
|
|
1071
|
+
| `FALLOW_REVIEW` | GitLab CI: set to `true` to post inline code review comments on MR diffs. |
|
|
1072
|
+
| `FALLOW_SCORE` | GitLab CI: set to `true` to compute health score in combined mode. Enables health delta header in MR comments. |
|
|
1073
|
+
| `FALLOW_TREND` | GitLab CI: set to `true` to compare current health metrics against saved snapshot. Implies `FALLOW_SCORE`. |
|
|
1074
|
+
| `FALLOW_EXTRA_ARGS` | GitLab CI: additional CLI flags passed through to fallow. |
|
|
1075
|
+
| `GITLAB_TOKEN` | GitLab CI: project access token with `api` scope (for MR comments/reviews). |
|
|
1076
|
+
|
|
1077
|
+
Set `FALLOW_FORMAT=json` and `FALLOW_QUIET=1` in your agent environment to avoid passing flags on every invocation.
|
|
1078
|
+
|
|
1079
|
+
---
|
|
1080
|
+
|
|
1081
|
+
## Output Formats
|
|
1082
|
+
|
|
1083
|
+
| Format | Description | Use Case |
|
|
1084
|
+
|--------|-------------|----------|
|
|
1085
|
+
| `human` | Colored terminal output | Interactive use |
|
|
1086
|
+
| `json` | Machine-readable JSON | Agent integration, CI pipelines |
|
|
1087
|
+
| `sarif` | Static Analysis Results Interchange Format | GitHub Code Scanning, SARIF-compatible tools |
|
|
1088
|
+
| `compact` | Grep-friendly: `type:path:line:name` per line | Quick filtering |
|
|
1089
|
+
| `markdown` | Markdown tables | Documentation, PR comments |
|
|
1090
|
+
| `codeclimate` | CodeClimate JSON array | GitLab Code Quality, CodeClimate-compatible tools |
|
|
1091
|
+
|
|
1092
|
+
---
|
|
1093
|
+
|
|
1094
|
+
## CI Integration
|
|
1095
|
+
|
|
1096
|
+
- **GitHub Actions**: `uses: fallow-rs/fallow@v2` — supports SARIF upload to Code Scanning, inline PR annotations (`annotations: true`), PR comments, all commands. Annotations use workflow commands (no Advanced Security required); limit with `max-annotations` (default 50). Set `score: true` to compute health score and enable the health delta header in PR comments
|
|
1097
|
+
- **GitLab CI**: include `ci/gitlab-ci.yml` template and extend `.fallow` — generates Code Quality reports via `--format codeclimate` (inline MR annotations), rich MR comments, code review comments, all commands. Variables use `FALLOW_` prefix (e.g., `FALLOW_COMMAND`, `FALLOW_FAIL_ON_ISSUES`). Set `FALLOW_SCORE: "true"` to compute health score; `FALLOW_TREND: "true"` to compare against saved snapshots
|
|
1098
|
+
- **Any CI**: `npx fallow --ci` — equivalent to `--format sarif --fail-on-issues --quiet`
|
|
1099
|
+
|
|
1100
|
+
### GitLab CI Variables
|
|
1101
|
+
|
|
1102
|
+
| Variable | Default | Description |
|
|
1103
|
+
|----------|---------|-------------|
|
|
1104
|
+
| `FALLOW_COMMAND` | `dead-code` | Command to run (`dead-code`, `dupes`, `health`, or default combined) |
|
|
1105
|
+
| `FALLOW_FAIL_ON_ISSUES` | `false` | Exit 1 if issues found |
|
|
1106
|
+
| `FALLOW_CHANGED_SINCE` | auto | Git ref for incremental analysis. Auto-detected in MR pipelines (`origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME`) |
|
|
1107
|
+
| `FALLOW_COMMENT` | `false` | Post a summary comment on the MR with findings |
|
|
1108
|
+
| `FALLOW_REVIEW` | `false` | Post inline code review comments on MR diff lines where issues were found |
|
|
1109
|
+
| `FALLOW_SCORE` | `false` | Compute health score (0-100 with letter grade) in combined mode. Enables the health delta header in MR comments |
|
|
1110
|
+
| `FALLOW_TREND` | `false` | Compare current health metrics against saved snapshot. Implies `FALLOW_SCORE`. Shows per-metric deltas |
|
|
1111
|
+
| `FALLOW_EXTRA_ARGS` | — | Additional CLI flags passed through to fallow |
|
|
1112
|
+
| `GITLAB_TOKEN` | — | Project access token with `api` scope (required for `FALLOW_COMMENT` and `FALLOW_REVIEW`). Alternatively, enable job token API access |
|
|
1113
|
+
|
|
1114
|
+
**Package manager detection**: The GitLab template auto-detects the project's package manager (npm, pnpm, or yarn) from lockfiles. MR comments and review comments show the correct install/run commands for the detected manager (e.g., `pnpm add -D` vs `npm install --save-dev`).
|
|
1115
|
+
|
|
1116
|
+
**Auto `--changed-since` in MR pipelines**: When running in a merge request pipeline, the template automatically sets `--changed-since origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME` unless `FALLOW_CHANGED_SINCE` is explicitly set. This scopes analysis to files changed in the MR without manual configuration.
|
|
1117
|
+
|
|
1118
|
+
---
|
|
1119
|
+
|
|
1120
|
+
## JSON Output Structure
|
|
1121
|
+
|
|
1122
|
+
### `dead-code` output
|
|
1123
|
+
|
|
1124
|
+
```json
|
|
1125
|
+
{
|
|
1126
|
+
"schema_version": 3,
|
|
1127
|
+
"version": "2.47.0",
|
|
1128
|
+
"elapsed_ms": 45,
|
|
1129
|
+
"total_issues": 12,
|
|
1130
|
+
"entry_points": {
|
|
1131
|
+
"total": 5,
|
|
1132
|
+
"sources": { "package_json_scripts": 2, "next_js": 3 }
|
|
1133
|
+
},
|
|
1134
|
+
"summary": {
|
|
1135
|
+
"total_issues": 12,
|
|
1136
|
+
"unused_files": 1,
|
|
1137
|
+
"unused_exports": 1,
|
|
1138
|
+
"unused_types": 1,
|
|
1139
|
+
"unused_dependencies": 1,
|
|
1140
|
+
"unused_enum_members": 0,
|
|
1141
|
+
"unused_class_members": 0,
|
|
1142
|
+
"unresolved_imports": 0,
|
|
1143
|
+
"unlisted_dependencies": 0,
|
|
1144
|
+
"duplicate_exports": 0,
|
|
1145
|
+
"type_only_dependencies": 0,
|
|
1146
|
+
"test_only_dependencies": 0,
|
|
1147
|
+
"circular_dependencies": 0,
|
|
1148
|
+
"boundary_violations": 0,
|
|
1149
|
+
"stale_suppressions": 0
|
|
1150
|
+
},
|
|
1151
|
+
"unused_files": [{ "path": "src/old.ts" }],
|
|
1152
|
+
"unused_exports": [{ "path": "src/utils.ts", "name": "unusedFn", "line": 42, "actions": [{"type": "remove-export", "auto_fixable": true, "description": "Remove the `export` keyword from the declaration"}, {"type": "suppress-line", "auto_fixable": false, "description": "Suppress with an inline comment above the line", "comment": "// fallow-ignore-next-line unused-export"}] }],
|
|
1153
|
+
"unused_types": [{ "path": "src/types.ts", "name": "OldType", "line": 10 }],
|
|
1154
|
+
"unused_dependencies": [{ "name": "lodash", "line": 5 }],
|
|
1155
|
+
"unused_dev_dependencies": [{ "name": "jest", "line": 8 }],
|
|
1156
|
+
"unused_enum_members": [{ "path": "src/enums.ts", "enum_name": "Status", "member": "Archived", "line": 5 }],
|
|
1157
|
+
"unused_class_members": [{ "path": "src/service.ts", "class_name": "Service", "member": "oldMethod", "line": 20 }],
|
|
1158
|
+
"unresolved_imports": [{ "path": "src/index.ts", "specifier": "./missing", "line": 3 }],
|
|
1159
|
+
"unlisted_dependencies": [{ "name": "chalk", "imported_from": [{ "path": "src/cli.ts", "line": 1, "col": 0 }] }],
|
|
1160
|
+
"duplicate_exports": [{ "name": "Config", "locations": ["src/config.ts:5", "src/types.ts:12"] }],
|
|
1161
|
+
"circular_dependencies": [{ "cycle": ["src/a.ts", "src/b.ts", "src/a.ts"], "line": 3, "col": 0, "is_cross_package": false }],
|
|
1162
|
+
"boundary_violations": [{ "from_path": "src/ui/Button.ts", "to_path": "src/data/db.ts", "from_zone": "ui", "to_zone": "data", "import_specifier": "../data/db", "line": 5, "col": 0 }],
|
|
1163
|
+
"unused_optional_dependencies": [{ "name": "fsevents" }],
|
|
1164
|
+
"type_only_dependencies": [{ "name": "zod", "used_in": ["src/schema.ts"], "line": 12 }],
|
|
1165
|
+
"test_only_dependencies": [{ "name": "msw", "path": "package.json", "line": 15 }],
|
|
1166
|
+
"stale_suppressions": [{ "path": "src/utils.ts", "line": 5, "col": 0, "origin": { "type": "inline_comment", "issue_type": "unused-export", "is_file_level": false } }]
|
|
1167
|
+
}
|
|
1168
|
+
```
|
|
1169
|
+
|
|
1170
|
+
#### `actions` Array
|
|
1171
|
+
|
|
1172
|
+
Every issue in `dead-code` JSON output includes an `actions` array with structured fix suggestions. Each action has:
|
|
1173
|
+
|
|
1174
|
+
| Field | Type | Required | Description |
|
|
1175
|
+
|-------|------|----------|-------------|
|
|
1176
|
+
| `type` | string | yes | Action type in kebab-case (14 types, e.g., `remove-export`, `remove-file`, `remove-dependency`, `suppress-line`, `add-to-config`) |
|
|
1177
|
+
| `auto_fixable` | bool | yes | `true` if `fallow fix` handles this action automatically |
|
|
1178
|
+
| `description` | string | yes | Human-readable description of the action |
|
|
1179
|
+
| `comment` | string | no | Suppression comment text (on `suppress-line` actions) |
|
|
1180
|
+
| `note` | string | no | Additional context on non-auto-fixable items |
|
|
1181
|
+
| `config_key` | string | no | Config field to update (on `add-to-config` actions) |
|
|
1182
|
+
| `value` | string | no | Value to add to the config field (on `add-to-config` actions) |
|
|
1183
|
+
|
|
1184
|
+
Example:
|
|
1185
|
+
|
|
1186
|
+
```json
|
|
1187
|
+
{
|
|
1188
|
+
"path": "src/utils.ts",
|
|
1189
|
+
"name": "helperFn",
|
|
1190
|
+
"line": 10,
|
|
1191
|
+
"actions": [
|
|
1192
|
+
{
|
|
1193
|
+
"type": "remove-export",
|
|
1194
|
+
"auto_fixable": true,
|
|
1195
|
+
"description": "Remove the `export` keyword from the declaration"
|
|
1196
|
+
},
|
|
1197
|
+
{
|
|
1198
|
+
"type": "suppress-line",
|
|
1199
|
+
"auto_fixable": false,
|
|
1200
|
+
"description": "Suppress with an inline comment above the line",
|
|
1201
|
+
"comment": "// fallow-ignore-next-line unused-export"
|
|
1202
|
+
}
|
|
1203
|
+
]
|
|
1204
|
+
}
|
|
1205
|
+
```
|
|
1206
|
+
|
|
1207
|
+
Dependency issues use `add-to-config` with `config_key` and `value`:
|
|
1208
|
+
|
|
1209
|
+
```json
|
|
1210
|
+
{
|
|
1211
|
+
"name": "autoprefixer",
|
|
1212
|
+
"line": 5,
|
|
1213
|
+
"actions": [
|
|
1214
|
+
{
|
|
1215
|
+
"type": "remove-dependency",
|
|
1216
|
+
"auto_fixable": true,
|
|
1217
|
+
"description": "Remove from package.json dependencies"
|
|
1218
|
+
},
|
|
1219
|
+
{
|
|
1220
|
+
"type": "add-to-config",
|
|
1221
|
+
"auto_fixable": false,
|
|
1222
|
+
"description": "Add to ignoreDependencies in fallow config",
|
|
1223
|
+
"config_key": "ignoreDependencies",
|
|
1224
|
+
"value": "autoprefixer"
|
|
1225
|
+
}
|
|
1226
|
+
]
|
|
1227
|
+
}
|
|
1228
|
+
```
|
|
1229
|
+
|
|
1230
|
+
#### `baseline_deltas` Object
|
|
1231
|
+
|
|
1232
|
+
When `--baseline` is used in combined output, the JSON includes a `baseline_deltas` object showing per-category changes since the baseline:
|
|
1233
|
+
|
|
1234
|
+
```json
|
|
1235
|
+
{
|
|
1236
|
+
"baseline_deltas": {
|
|
1237
|
+
"total_delta": -3,
|
|
1238
|
+
"per_category": {
|
|
1239
|
+
"unused_files": { "current": 5, "baseline": 7, "delta": -2 },
|
|
1240
|
+
"unused_exports": { "current": 10, "baseline": 11, "delta": -1 }
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
```
|
|
1245
|
+
|
|
1246
|
+
### `dupes` output
|
|
1247
|
+
|
|
1248
|
+
```json
|
|
1249
|
+
{
|
|
1250
|
+
"schema_version": 3,
|
|
1251
|
+
"version": "2.47.0",
|
|
1252
|
+
"elapsed_ms": 82,
|
|
1253
|
+
"total_clones": 15,
|
|
1254
|
+
"total_lines_duplicated": 230,
|
|
1255
|
+
"duplication_percentage": 4.2,
|
|
1256
|
+
"clone_groups": [
|
|
1257
|
+
{
|
|
1258
|
+
"instances": [
|
|
1259
|
+
{ "path": "src/a.ts", "start_line": 10, "end_line": 25 },
|
|
1260
|
+
{ "path": "src/b.ts", "start_line": 40, "end_line": 55 }
|
|
1261
|
+
],
|
|
1262
|
+
"tokens": 120,
|
|
1263
|
+
"lines": 16,
|
|
1264
|
+
"family": { "suggestion": "extract_function", "shared_files": ["src/a.ts", "src/b.ts"] }
|
|
1265
|
+
}
|
|
1266
|
+
],
|
|
1267
|
+
"mirrored_directories": [
|
|
1268
|
+
{ "dir_a": "src/components", "dir_b": "src/legacy/components", "shared_clones": 4 }
|
|
1269
|
+
]
|
|
1270
|
+
}
|
|
1271
|
+
```
|
|
1272
|
+
|
|
1273
|
+
The `mirrored_directories` array identifies directory pairs that share many clone groups, suggesting structural duplication (e.g., a copy-pasted module that was never cleaned up).
|
|
1274
|
+
|
|
1275
|
+
### `fix` output (dry-run)
|
|
1276
|
+
|
|
1277
|
+
```json
|
|
1278
|
+
{
|
|
1279
|
+
"changes": [
|
|
1280
|
+
{ "path": "src/utils.ts", "action": "remove_export", "name": "unusedFn", "line": 42 },
|
|
1281
|
+
{ "path": "package.json", "action": "remove_dependency", "name": "lodash" }
|
|
1282
|
+
],
|
|
1283
|
+
"total_changes": 2
|
|
1284
|
+
}
|
|
1285
|
+
```
|
|
1286
|
+
|
|
1287
|
+
### Combined output (`fallow` with no subcommand)
|
|
1288
|
+
|
|
1289
|
+
When running `fallow` with no subcommand (all analyses), the JSON output combines results from all enabled analyses:
|
|
1290
|
+
|
|
1291
|
+
```json
|
|
1292
|
+
{
|
|
1293
|
+
"check": {
|
|
1294
|
+
"schema_version": 3,
|
|
1295
|
+
"version": "2.47.0",
|
|
1296
|
+
"elapsed_ms": 45,
|
|
1297
|
+
"total_issues": 12,
|
|
1298
|
+
"unused_files": [],
|
|
1299
|
+
"unused_exports": [],
|
|
1300
|
+
"unused_types": [],
|
|
1301
|
+
"unused_dependencies": [],
|
|
1302
|
+
"unused_dev_dependencies": [],
|
|
1303
|
+
"unused_enum_members": [],
|
|
1304
|
+
"unused_class_members": [],
|
|
1305
|
+
"unresolved_imports": [],
|
|
1306
|
+
"unlisted_dependencies": [],
|
|
1307
|
+
"duplicate_exports": [],
|
|
1308
|
+
"circular_dependencies": [],
|
|
1309
|
+
"boundary_violations": [],
|
|
1310
|
+
"unused_optional_dependencies": [],
|
|
1311
|
+
"type_only_dependencies": [],
|
|
1312
|
+
"test_only_dependencies": [],
|
|
1313
|
+
"stale_suppressions": []
|
|
1314
|
+
},
|
|
1315
|
+
"dupes": {
|
|
1316
|
+
"schema_version": 3,
|
|
1317
|
+
"version": "2.47.0",
|
|
1318
|
+
"elapsed_ms": 82,
|
|
1319
|
+
"total_clones": 15,
|
|
1320
|
+
"total_lines_duplicated": 230,
|
|
1321
|
+
"duplication_percentage": 4.2,
|
|
1322
|
+
"clone_groups": []
|
|
1323
|
+
},
|
|
1324
|
+
"health": {
|
|
1325
|
+
"schema_version": 3,
|
|
1326
|
+
"version": "2.47.0",
|
|
1327
|
+
"elapsed_ms": 32,
|
|
1328
|
+
"summary": {},
|
|
1329
|
+
"findings": [],
|
|
1330
|
+
"vital_signs": {}
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
```
|
|
1334
|
+
|
|
1335
|
+
Use `--only` or `--skip` to control which analyses are included in the combined output.
|
|
1336
|
+
|
|
1337
|
+
With `--score`, the combined output's `health` section includes a `health_score` object (same schema as `health --score`). With `--trend`, it includes a `health_trend` object comparing against the most recent saved snapshot. With `--save-snapshot`, a vital signs snapshot is persisted for future trend comparisons.
|
|
1338
|
+
|
|
1339
|
+
### Error output (exit code 2)
|
|
1340
|
+
|
|
1341
|
+
```json
|
|
1342
|
+
{"error": true, "message": "invalid config: unknown field 'detect'", "exit_code": 2}
|
|
1343
|
+
```
|
|
1344
|
+
|
|
1345
|
+
---
|
|
1346
|
+
|
|
1347
|
+
## Configuration File Format
|
|
1348
|
+
|
|
1349
|
+
Config files are searched in priority order: `.fallowrc.json` > `fallow.toml` > `.fallow.toml`
|
|
1350
|
+
|
|
1351
|
+
### JSON Format (`.fallowrc.json`)
|
|
1352
|
+
|
|
1353
|
+
```jsonc
|
|
1354
|
+
{
|
|
1355
|
+
"$schema": "https://raw.githubusercontent.com/fallow-rs/fallow/main/schema.json",
|
|
1356
|
+
|
|
1357
|
+
// Entry points (glob patterns)
|
|
1358
|
+
"entry": ["src/index.ts", "scripts/*.ts"],
|
|
1359
|
+
|
|
1360
|
+
// Files to ignore (glob patterns)
|
|
1361
|
+
"ignorePatterns": ["**/*.generated.ts", "**/*.d.ts"],
|
|
1362
|
+
|
|
1363
|
+
// Dependencies to ignore
|
|
1364
|
+
"ignoreDependencies": ["autoprefixer"],
|
|
1365
|
+
|
|
1366
|
+
// Per-issue-type severity
|
|
1367
|
+
"rules": {
|
|
1368
|
+
"unused-files": "error",
|
|
1369
|
+
"unused-exports": "warn",
|
|
1370
|
+
"unused-types": "off",
|
|
1371
|
+
"unused-dependencies": "error",
|
|
1372
|
+
"unused-dev-dependencies": "warn",
|
|
1373
|
+
"unused-enum-members": "error",
|
|
1374
|
+
"unused-class-members": "warn",
|
|
1375
|
+
"unresolved-imports": "error",
|
|
1376
|
+
"unlisted-dependencies": "error",
|
|
1377
|
+
"duplicate-exports": "warn",
|
|
1378
|
+
"circular-dependencies": "warn",
|
|
1379
|
+
"boundary-violation": "error",
|
|
1380
|
+
"type-only-dependencies": "error",
|
|
1381
|
+
"test-only-dependencies": "warn",
|
|
1382
|
+
"stale-suppressions": "warn"
|
|
1383
|
+
},
|
|
1384
|
+
|
|
1385
|
+
// Per-path rule overrides
|
|
1386
|
+
"overrides": [
|
|
1387
|
+
{
|
|
1388
|
+
"files": ["*.test.ts", "*.spec.ts"],
|
|
1389
|
+
"rules": { "unused-exports": "off" }
|
|
1390
|
+
}
|
|
1391
|
+
],
|
|
1392
|
+
|
|
1393
|
+
// Duplication settings
|
|
1394
|
+
"duplicates": {
|
|
1395
|
+
"mode": "mild",
|
|
1396
|
+
"minTokens": 50,
|
|
1397
|
+
"minLines": 5,
|
|
1398
|
+
"threshold": 0,
|
|
1399
|
+
"skipLocal": false,
|
|
1400
|
+
"ignorePatterns": ["**/*.generated.ts"]
|
|
1401
|
+
},
|
|
1402
|
+
|
|
1403
|
+
// Architecture boundaries (preset or custom zones/rules)
|
|
1404
|
+
// Presets: "layered", "hexagonal", "feature-sliced", "bulletproof"
|
|
1405
|
+
"boundaries": {
|
|
1406
|
+
"preset": "bulletproof"
|
|
1407
|
+
},
|
|
1408
|
+
|
|
1409
|
+
// Production mode
|
|
1410
|
+
"production": false,
|
|
1411
|
+
|
|
1412
|
+
// Workspace packages that are public libraries.
|
|
1413
|
+
// Exports from these packages are not flagged as unused.
|
|
1414
|
+
"publicPackages": ["@myorg/shared-lib", "@myorg/utils"],
|
|
1415
|
+
|
|
1416
|
+
// Glob patterns for files that are dynamically loaded at runtime.
|
|
1417
|
+
// These files are treated as always-used and never flagged as unused.
|
|
1418
|
+
"dynamicallyLoaded": ["plugins/**/*.ts", "locales/**/*.json"],
|
|
1419
|
+
|
|
1420
|
+
// Inherit from base config (relative paths, npm: packages, or https:// URLs)
|
|
1421
|
+
"extends": ["./base-config.json", "npm:@my-org/fallow-config", "https://example.com/shared-config.json"],
|
|
1422
|
+
|
|
1423
|
+
// Custom external plugins
|
|
1424
|
+
"plugins": ["tools/plugins/"],
|
|
1425
|
+
|
|
1426
|
+
// Inline framework definitions
|
|
1427
|
+
"framework": [
|
|
1428
|
+
{
|
|
1429
|
+
"name": "my-framework",
|
|
1430
|
+
"enablers": ["my-framework"],
|
|
1431
|
+
"entryPoints": ["src/routes/**/*.ts"]
|
|
1432
|
+
}
|
|
1433
|
+
]
|
|
1434
|
+
}
|
|
1435
|
+
```
|
|
1436
|
+
|
|
1437
|
+
### TOML Format (`fallow.toml`)
|
|
1438
|
+
|
|
1439
|
+
```toml
|
|
1440
|
+
entry = ["src/index.ts", "scripts/*.ts"]
|
|
1441
|
+
ignorePatterns = ["**/*.generated.ts"]
|
|
1442
|
+
ignoreDependencies = ["autoprefixer"]
|
|
1443
|
+
production = false
|
|
1444
|
+
publicPackages = ["@myorg/shared-lib", "@myorg/utils"]
|
|
1445
|
+
dynamicallyLoaded = ["plugins/**/*.ts", "locales/**/*.json"]
|
|
1446
|
+
|
|
1447
|
+
[rules]
|
|
1448
|
+
unused-files = "error"
|
|
1449
|
+
unused-exports = "warn"
|
|
1450
|
+
unused-types = "off"
|
|
1451
|
+
|
|
1452
|
+
[duplicates]
|
|
1453
|
+
mode = "mild"
|
|
1454
|
+
minTokens = 50
|
|
1455
|
+
minLines = 5
|
|
1456
|
+
|
|
1457
|
+
[[overrides]]
|
|
1458
|
+
files = ["*.test.ts"]
|
|
1459
|
+
[overrides.rules]
|
|
1460
|
+
unused-exports = "off"
|
|
1461
|
+
|
|
1462
|
+
[boundaries]
|
|
1463
|
+
preset = "bulletproof"
|
|
1464
|
+
```
|
|
1465
|
+
|
|
1466
|
+
---
|
|
1467
|
+
|
|
1468
|
+
## Inline Suppression Comments
|
|
1469
|
+
|
|
1470
|
+
| Comment | Effect |
|
|
1471
|
+
|---------|--------|
|
|
1472
|
+
| `// fallow-ignore-next-line` | Suppress any issue on the next line |
|
|
1473
|
+
| `// fallow-ignore-next-line unused-export` | Suppress specific issue type |
|
|
1474
|
+
| `// fallow-ignore-file` | Suppress all issues in a file |
|
|
1475
|
+
| `// fallow-ignore-file unused-export` | Suppress specific issue type file-wide |
|
|
1476
|
+
|
|
1477
|
+
### Valid Issue Type Tokens
|
|
1478
|
+
|
|
1479
|
+
`unused-file`, `unused-export`, `unused-type`, `unused-dependency`, `unused-dev-dependency`, `unused-enum-member`, `unused-class-member`, `unresolved-import`, `unlisted-dependency`, `duplicate-export`, `circular-dependency`, `boundary-violation`, `unused-optional-dependency`, `type-only-dependency`, `test-only-dependency`, `code-duplication`
|