fallow 3.39.0 → 3.41.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/schema.json CHANGED
@@ -35,7 +35,7 @@
35
35
  "writeOnly": true
36
36
  },
37
37
  "entry": {
38
- "description": "An array of project-root-relative glob patterns whose matching files are seeded as manual entry points, on top of the framework and package.json entries fallow discovers automatically, so their transitive imports are not reported as unused. Set it (e.g. `[\"src/main.ts\"]`) when a file is a real runtime root that no plugin or manifest declares; patterns are validated at load and matched against discovered files. For a script that does not run in production, use a `framework[]` entry with `entryPointRole: \"support\"` and leave its glob out of `entry`: a file that also matches `entry` stays a runtime root. A single `*` stays within one path segment; use `**` to match across directories.",
38
+ "description": "An array of project-root-relative glob patterns whose matching files are seeded as manual entry points, on top of the framework and package.json entries fallow discovers automatically, so their transitive imports are not reported as unused. Set it (e.g. `[\"src/main.ts\"]`) when a file is a real runtime root that no plugin or manifest declares; patterns are validated at load and matched against discovered files. For a script that does not run in production, use `supportEntry` and leave its glob out of `entry`: a file that also matches `entry` stays a runtime root. A single `*` stays within one path segment; use `**` to match across directories.",
39
39
  "type": "array",
40
40
  "items": {
41
41
  "type": "string"
@@ -50,6 +50,13 @@
50
50
  },
51
51
  "default": []
52
52
  },
53
+ "supportEntry": {
54
+ "description": "An array of project-root-relative glob patterns whose matching files are support entry points: dev scripts, tooling and setup files that run outside production. In default mode a support entry keeps its file and its imports reachable, the same as `entry`. In `--production` mode (or `production` for dead-code analysis), fallow leaves a file that only a support entry matches out of the analysis, so its imports credit no export, file or dependency. A file that also matches `entry`, a framework plugin or a package.json field stays an entry point, and a support file that production code imports stays a normal module. Use `entry` for the files that run in production. A single `*` stays within one path segment; use `**` to match across directories.",
55
+ "type": "array",
56
+ "items": {
57
+ "type": "string"
58
+ }
59
+ },
53
60
  "ignoreFindings": {
54
61
  "description": "An array of project-root-relative glob patterns whose source-owned dead-code findings are hidden after analysis without excluding matching files from discovery, parsing, resolution, or the module graph. Use `/` as the path separator on every platform. Positive patterns select paths to hide; `!`-prefixed patterns keep matching paths reportable, and a negated-only array reports only those exception paths. A finding with multiple source owners is hidden only when every owner matches, so a cycle, duplicate-export group, or unlisted dependency with any reportable location remains visible. Architecture, policy, suppression-hygiene, and framework-correctness findings remain visible even when a referenced path matches, as do manifest-owned findings that no source file owns: unused dependencies, unused dev and optional dependencies, catalog entries, and dependency overrides. Use `ignorePatterns` instead when a generated or vendored file must not be analyzed at all. A matching file that parses with errors reports no `source-parse-degraded` diagnostic, and its partial parse does not mark other findings as incomplete; use this only for files that are broken on purpose, such as syntax-error test fixtures. A single `*` stays within one path segment; use `**` to match across directories.",
55
62
  "type": "array",
@@ -85,6 +92,13 @@
85
92
  },
86
93
  "default": []
87
94
  },
95
+ "ignoreBinaries": {
96
+ "description": "A list of binary names or name globs that the `unlisted-binaries` rule does not report. Set it for a binary that the operating system, the CI image, or a tool outside `node_modules` provides (e.g. `[\"gnome-extensions\", \"tailscale\"]`). An entry without glob characters matches the binary name exactly; an entry with `*`, `?`, `[` or `{` is a glob matched against the binary name, so `xcrun*` covers every name that starts with `xcrun`. Fallow already skips shell builtins and a fixed list of common operating-system tools (such as `git`, `ssh-keygen`, `curl`, and `ffmpeg`).",
97
+ "type": "array",
98
+ "items": {
99
+ "type": "string"
100
+ }
101
+ },
88
102
  "ignoreCommandEntries": {
89
103
  "description": "A list of command names whose file arguments fallow does not make entry points. Fallow reads commands in package.json scripts (root and workspace packages), CI files (GitHub Actions and GitLab CI), Dockerfiles, Procfiles, and fly.toml files, and a file that a command names (such as `node scripts/seed.ts`) normally becomes an entry point. A listed command still counts as a used dependency, and its `--config` file is still tracked. Formatters and linters (ESLint, Prettier, Oxlint, Oxfmt, Biome, Stylelint, and similar tools) never make their targets entry points, so they do not need to be listed. Set it for a command whose file arguments are data, not code that runs (e.g. `[\"my-codegen\"]`), or use `[\"*\"]` to turn off entry points from all commands and declare real entries in `entry`. A name matches the command after environment, package-manager, and wrapper prefixes (`npx`, `pnpm exec`, `yarn run`, `varlock run --`), by exact file name; `*` is the only wildcard.",
90
104
  "type": "array",
@@ -228,6 +242,7 @@
228
242
  "unused-optional-dependencies": "warn",
229
243
  "unused-enum-members": "error",
230
244
  "unused-class-members": "error",
245
+ "unused-namespace-members": "warn",
231
246
  "unused-store-members": "warn",
232
247
  "unprovided-injects": "warn",
233
248
  "unrendered-components": "warn",
@@ -256,7 +271,9 @@
256
271
  "complexity-file-lines": "error",
257
272
  "unresolved-imports": "error",
258
273
  "unlisted-dependencies": "error",
274
+ "unlisted-binaries": "warn",
259
275
  "duplicate-exports": "error",
276
+ "duplicate-export-aliases": "warn",
260
277
  "type-only-dependencies": "warn",
261
278
  "test-only-dependencies": "warn",
262
279
  "dev-dependencies-in-production": "warn",
@@ -297,7 +314,7 @@
297
314
  "$ref": "#/$defs/CircularDependenciesConfig"
298
315
  },
299
316
  "effect": {
300
- "description": "Options for projects that use the Effect library, currently only `schemaExportsAsTypes`. Set `{ \"schemaExportsAsTypes\": true }` to report an unused exported Effect schema (a class that extends `Schema.Class`, `Schema.TaggedClass`, `Schema.TaggedError` and the other `Schema` class factories, or a const such as `Schema.Struct({...})` or `Schema.String.pipe(Schema.brand(\"Id\"))`) as an unused type under the `unused-types` rule, not as an unused export, so `\"unused-types\": \"off\"` hides it. `Schema` must come from `effect`, `effect/Schema` or `@effect/schema`. Default `false` leaves every report unchanged.",
317
+ "description": "Options for projects that use the Effect library, currently only `schemaExportsAsTypes`. Set `{ \"schemaExportsAsTypes\": true }` to report an unused exported Effect schema (a class that extends `Schema.Class`, `Schema.TaggedClass`, `Schema.TaggedError` and the other `Schema` class factories, or a const such as `Schema.Struct({...})` or `Schema.String.pipe(Schema.brand(\"Id\"))`) as an unused type under the `unused-types` rule, not as an unused export, so `\"unused-types\": \"off\"` hides it. `Schema` must come from `effect`, `effect/Schema` or `@effect/schema`. A re-export of a schema from another module also counts. In a module that imports Effect, a chain on an imported schema (`Imported.pipe(Schema.brand(\"Id\"))`, `Imported.annotations({...})`) and an alias (`export const Copy = Imported`) also count. Default `false` leaves every report unchanged.",
301
318
  "$ref": "#/$defs/EffectConfig"
302
319
  },
303
320
  "boundaries": {
@@ -370,7 +387,7 @@
370
387
  }
371
388
  },
372
389
  "overrides": {
373
- "description": "An ordered list of per-file rule-severity overrides: each entry re-severities specific analysis rules for files its globs match, layered on top of the top-level `rules` defaults. Set to relax or tighten a rule for a subset of paths (e.g. downgrade unused-exports to warn under a generated directory); each entry has `files` (glob-pattern array) and `rules` (a partial per-rule severity map of error/warn/off). Entries apply in list order and a file matched by several entries takes every matching entry's overrides (later entries win on conflict). For most rules, an override cannot start a detector for a rule that is off at top level, so set the top-level rule on and use an override to set `off` for the other paths. Project-level rules ignore overrides: unused-dependencies, unused-dev-dependencies, unused-optional-dependencies, unlisted-dependencies, type-only-dependencies, test-only-dependencies, dev-dependencies-in-production, duplicate-exports, re-export-cycle and unused-catalog-entries. Fallow reports each such entry as an `override-rule-ineffective` diagnostic that names the mechanism that works. A single `*` stays within one path segment; use `**` to match across directories.",
390
+ "description": "An ordered list of per-file rule-severity overrides: each entry re-severities specific analysis rules for files its globs match, layered on top of the top-level `rules` defaults. Set to relax or tighten a rule for a subset of paths (e.g. downgrade unused-exports to warn under a generated directory); each entry has `files` (glob-pattern array) and `rules` (a partial per-rule severity map of error/warn/off). Entries apply in list order and a file matched by several entries takes every matching entry's overrides (later entries win on conflict). For most rules, an override cannot start a detector for a rule that is off at top level, so set the top-level rule on and use an override to set `off` for the other paths. Project-level rules ignore overrides: unused-dependencies, unused-dev-dependencies, unused-optional-dependencies, unlisted-dependencies, unlisted-binaries, type-only-dependencies, test-only-dependencies, dev-dependencies-in-production, duplicate-exports, re-export-cycle and unused-catalog-entries. Fallow reports each such entry as an `override-rule-ineffective` diagnostic that names the mechanism that works. A single `*` stays within one path segment; use `**` to match across directories.",
374
391
  "type": "array",
375
392
  "items": {
376
393
  "$ref": "#/$defs/ConfigOverride"
@@ -825,9 +842,37 @@
825
842
  "additionalProperties": {
826
843
  "type": "string"
827
844
  }
845
+ },
846
+ "settings": {
847
+ "description": "Settings that apply only to the workspace packages that a key selects. A key is a workspace root relative to the project root, as `fallow list --workspaces` prints it, or a glob such as `packages/*`. A single `*` stays within one path segment. Each value can hold `ignoreDependencies` and `includeEntryExports`. A workspace gets the global `ignoreDependencies` plus the lists of every key that selects it. For `includeEntryExports`, an exact root wins over a glob, a glob with more literal segments wins over a shorter glob, and a workspace that no key sets uses the global value. The root package uses only the global keys. A key that selects no workspace gives a warning. An older fallow version ignores this map, so pair it with `minimumVersion`.",
848
+ "type": "object",
849
+ "additionalProperties": {
850
+ "$ref": "#/$defs/WorkspaceSettings"
851
+ }
828
852
  }
829
853
  }
830
854
  },
855
+ "WorkspaceSettings": {
856
+ "description": "The settings of one `workspaces.settings` key.",
857
+ "type": "object",
858
+ "properties": {
859
+ "ignoreDependencies": {
860
+ "description": "Package names or package-name globs that unused-dependency and unlisted-dependency detection ignore in the selected workspaces only, in addition to the global `ignoreDependencies`. An unused dependency uses the workspace of its `package.json`. An unlisted dependency uses the deepest workspace of the file that imports it. The syntax is the same as the global `ignoreDependencies`.",
861
+ "type": "array",
862
+ "items": {
863
+ "type": "string"
864
+ }
865
+ },
866
+ "includeEntryExports": {
867
+ "description": "When set, replaces the global `includeEntryExports` value for the files of the selected workspaces. A file belongs to its deepest workspace. The `--include-entry-exports` CLI flag turns the check on in every workspace and wins over this value.",
868
+ "type": [
869
+ "boolean",
870
+ "null"
871
+ ]
872
+ }
873
+ },
874
+ "additionalProperties": false
875
+ },
831
876
  "IgnoreExportRule": {
832
877
  "description": "Rule for ignoring specific exports.",
833
878
  "type": "object",
@@ -1656,6 +1701,11 @@
1656
1701
  "$ref": "#/$defs/Severity",
1657
1702
  "default": "error"
1658
1703
  },
1704
+ "unused-namespace-members": {
1705
+ "description": "Exported members of an exported TypeScript namespace that no code\nreads. Defaults to `warn`: a namespace often holds generated code,\nand a new rule must not fail the build of a project after an upgrade.\nA `warn` finding does not change the CLI exit code unless\n`--fail-on-issues` is set. The dead-code count gate of the GitHub\nAction counts it unless `fail-on-issues` is `false`.",
1706
+ "$ref": "#/$defs/Severity",
1707
+ "default": "warn"
1708
+ },
1659
1709
  "unused-store-members": {
1660
1710
  "description": "Store members (Pinia `state` / `getters` / `actions` key, or a\nsetup-store returned key) declared but never accessed by any consumer\nproject-wide. Defaults to `warn`, not `error` like the closed-set\nclass/enum member rules: a store has an OPEN declaration surface\n(plugins, `$onAction`, dynamic dispatch) so analyzer confidence is\ngenuinely lower. A `warn` finding does not change the CLI exit code\nunless `--fail-on-issues` is set. The dead-code count gate of the GitHub\nAction counts it unless `fail-on-issues` is `false`. Promotable to\n`error` once validated on a codebase.",
1661
1711
  "$ref": "#/$defs/Severity",
@@ -1796,11 +1846,21 @@
1796
1846
  "$ref": "#/$defs/Severity",
1797
1847
  "default": "error"
1798
1848
  },
1849
+ "unlisted-binaries": {
1850
+ "description": "A binary that a package.json script or a process call runs, but that\nno installed or listed package provides. Shell builtins and common\noperating-system tools are skipped; `ignoreBinaries` skips more.\nDefaults to `warn`.",
1851
+ "$ref": "#/$defs/Severity",
1852
+ "default": "warn"
1853
+ },
1799
1854
  "duplicate-exports": {
1800
1855
  "description": "The same export name provided by multiple modules; `ignoreExports`\nexcludes intentional barrel re-exports. Defaults to `error`.",
1801
1856
  "$ref": "#/$defs/Severity",
1802
1857
  "default": "error"
1803
1858
  },
1859
+ "duplicate-export-aliases": {
1860
+ "description": "One module that exports one binding under two or more names, for\nexample `export const a = 1; export default a;`. Defaults to `warn`.",
1861
+ "$ref": "#/$defs/Severity",
1862
+ "default": "warn"
1863
+ },
1804
1864
  "type-only-dependencies": {
1805
1865
  "description": "A production dependency imported only via type-only imports (a\n`devDependencies` candidate). Defaults to `warn`.",
1806
1866
  "$ref": "#/$defs/Severity",
@@ -2411,7 +2471,7 @@
2411
2471
  }
2412
2472
  },
2413
2473
  "rules": {
2414
- "description": "Partial per-rule severity map applied only to files matching this entry's `files` globs; each rule key takes `error`, `warn`, or `off`, and omitted rules keep their top-level severity. Set to change how specific rules (e.g. unused-exports, unused-files) behave for the scoped paths. Project-level rules ignore overrides: unused-dependencies, unused-dev-dependencies, unused-optional-dependencies, unlisted-dependencies, type-only-dependencies, test-only-dependencies, dev-dependencies-in-production, duplicate-exports, re-export-cycle and unused-catalog-entries. Fallow reports each such entry as an `override-rule-ineffective` diagnostic that names the mechanism that works. For most other rules, an override cannot start a detector for a rule that is off at top level.",
2474
+ "description": "Partial per-rule severity map applied only to files matching this entry's `files` globs; each rule key takes `error`, `warn`, or `off`, and omitted rules keep their top-level severity. Set to change how specific rules (e.g. unused-exports, unused-files) behave for the scoped paths. Project-level rules ignore overrides: unused-dependencies, unused-dev-dependencies, unused-optional-dependencies, unlisted-dependencies, unlisted-binaries, type-only-dependencies, test-only-dependencies, dev-dependencies-in-production, duplicate-exports, re-export-cycle and unused-catalog-entries. Fallow reports each such entry as an `override-rule-ineffective` diagnostic that names the mechanism that works. For most other rules, an override cannot start a detector for a rule that is off at top level.",
2415
2475
  "$ref": "#/$defs/PartialRulesConfig",
2416
2476
  "default": {}
2417
2477
  }
@@ -2535,6 +2595,17 @@
2535
2595
  }
2536
2596
  ]
2537
2597
  },
2598
+ "unused-namespace-members": {
2599
+ "description": "Optional override for [`RulesConfig::unused_namespace_members`].",
2600
+ "anyOf": [
2601
+ {
2602
+ "$ref": "#/$defs/Severity"
2603
+ },
2604
+ {
2605
+ "type": "null"
2606
+ }
2607
+ ]
2608
+ },
2538
2609
  "unused-store-members": {
2539
2610
  "description": "Optional override for [`RulesConfig::unused_store_members`].",
2540
2611
  "anyOf": [
@@ -2843,6 +2914,17 @@
2843
2914
  }
2844
2915
  ]
2845
2916
  },
2917
+ "unlisted-binaries": {
2918
+ "description": "Optional override for [`RulesConfig::unlisted_binaries`].",
2919
+ "anyOf": [
2920
+ {
2921
+ "$ref": "#/$defs/Severity"
2922
+ },
2923
+ {
2924
+ "type": "null"
2925
+ }
2926
+ ]
2927
+ },
2846
2928
  "duplicate-exports": {
2847
2929
  "description": "Optional override for [`RulesConfig::duplicate_exports`].",
2848
2930
  "anyOf": [
@@ -2854,6 +2936,17 @@
2854
2936
  }
2855
2937
  ]
2856
2938
  },
2939
+ "duplicate-export-aliases": {
2940
+ "description": "Optional override for [`RulesConfig::duplicate_export_aliases`].",
2941
+ "anyOf": [
2942
+ {
2943
+ "$ref": "#/$defs/Severity"
2944
+ },
2945
+ {
2946
+ "type": "null"
2947
+ }
2948
+ ]
2949
+ },
2857
2950
  "type-only-dependencies": {
2858
2951
  "description": "Optional override for [`RulesConfig::type_only_dependencies`].",
2859
2952
  "anyOf": [
@@ -3292,6 +3385,13 @@
3292
3385
  "minimum": 0,
3293
3386
  "default": 0
3294
3387
  },
3388
+ "unlistedBinaries": {
3389
+ "description": "Baseline count of `unlisted-binaries` findings.",
3390
+ "type": "integer",
3391
+ "format": "uint",
3392
+ "minimum": 0,
3393
+ "default": 0
3394
+ },
3295
3395
  "duplicateExports": {
3296
3396
  "description": "Baseline count of `duplicate-exports` findings.",
3297
3397
  "type": "integer",
@@ -56,6 +56,7 @@ cargo install fallow-cli # build from source
56
56
  13. **Use `fallow impact statusline` only for a user-facing status surface**. It intentionally emits one plain-text, path-free line and ignores `--format`. It starts no analysis, never enables Impact, and compares only whole-project scans. Do not parse this line as JSON.
57
57
  14. **Treat similar-code output as discovery only**. Never describe its score as a probability, finding, proof of equivalent behavior, or safe-refactor decision. Agents must not authorize setup. Inspect a candidate before judging it: save discovery as `similar-code.json`, inspect with `--candidates similar-code.json`, and pass the unchanged file to `fallow similar-code review`. Over MCP use `find_similar_code` with `paths:` and `inspect_similar_code` with a typed `snapshot`; it fails closed on stale source. Keep `candidate_worthy`, `behaviorally_equivalent`, and `refactor_safe` separate, use `needs-human-review`, and abstain when evidence is incomplete. Only `completion.status: "complete"` makes an empty result conclusive. Follow [the complete workflow to compare semantically similar functions](references/similar-code.md).
58
58
  15. **Check production runtime data before an edit or a delete, when Fallow Cloud is connected**. Prefer the scoped reads over the full `get_cloud_runtime_context` pull. Before an edit, run `fallow coverage review-packet --repo <owner/repo>` (MCP `get_cloud_review_packet`) for the changed files and read `hit_count`, `covered_by_test`, and the callers when present. Before a delete, require `period_tracking_state: "never_called"`, not only `tracking_state`, and read `evidence_window.observed_hours`: few observed hours or a low-traffic surface mean "not visited", not "dead". After a deploy, run `fallow coverage deployment-changes --repo <owner/repo>` (MCP `get_cloud_deployment_changes`) and, when `comparable` is `false`, report `reason` and claim no change. Open files by `repo_path`, not `file_path`. Production data is context, never a gate. Details: [references/mcp.md](references/mcp.md#scoped-cloud-reads).
59
+ 16. **Run `fallow doctor --format json --quiet` as a preflight**. Run it before the first analysis of a project, and again when a result looks wrong (an empty result, many unresolved imports, or missing workspaces). The doctor run reads the project setup and changes nothing. A required check with `status: "fail"` makes it exit 2. Fix each `fail` check before you trust the analysis. A `warn` message names the part of the analysis that degrades; a stale cache only makes the next run slower. Run each `remediation.command` from the project root (`cwd` is `.`). You may run it without asking when its `mutating` field is `false`; such a command can still write the Fallow cache. Ask the user before you run a remediation with `mutating: true`, such as a dependency install.
59
60
 
60
61
  ## Onboarding And Insight
61
62
  Offer setup after showing the findings from a human-requested analysis, only when all these conditions hold:
@@ -124,6 +125,8 @@ Fallow ships an MCP server (`fallow-mcp`) that exposes these same analyses as ag
124
125
 
125
126
  The server also serves read-only reference resources (no subprocess, no analysis run, cacheable by URI; your client reads them through its own resource tool): `fallow://tools`, `fallow://issue-types`, `fallow://explain/{issue_type}`, `fallow://task-matrix`, and the config, plugin, and rule-pack JSON Schemas. Every resource payload is JSON. Each content item carries the server version in `_meta.fallow_version`.
126
127
 
128
+ Fallow Cloud also runs a hosted MCP server at `POST https://api.fallow.cloud/mcp` (Bearer read-only or live API key). It serves production data with no local install, and has tools that `fallow-mcp` does not have, such as `get_file_context`, `verify_deployment`, and `list_errors`. Details: [references/mcp.md](references/mcp.md#hosted-fallow-cloud-mcp-server).
129
+
127
130
  Full tool catalogue, resource catalogue, key params, runtime source-map confidence tiers, shared timeouts, and the `next_steps` dispatch mapping: **[references/mcp.md](references/mcp.md)**.
128
131
 
129
132
  ## References
@@ -304,10 +307,12 @@ fallow dead-code --format json --quiet --save-regression-baseline
304
307
  # 2. In CI: fail only if issues increase beyond tolerance
305
308
  fallow dead-code --format json --quiet --fail-on-regression --tolerance 0
306
309
  # Identity-based baseline (fail only on NEW findings, not raw counts)
307
- fallow dead-code --format json --quiet --save-baseline .fallow/snapshot.json
308
- fallow dead-code --format json --quiet --baseline .fallow/snapshot.json
310
+ fallow dead-code --format json --quiet --save-baseline fallow-baselines/dead-code.json
311
+ fallow dead-code --format json --quiet --baseline fallow-baselines/dead-code.json
309
312
  ```
310
313
 
314
+ Commit the baseline file. Do not save it in `.fallow/`: fallow tells Git to ignore that cache directory, so the baseline is not committed and `fallow` prints a warning.
315
+
311
316
  `--save-regression-baseline` / `--regression-baseline` / `--fail-on-regression` / `--tolerance` are count-based gates for `dead-code`, `architecture`, bare combined mode, and `flags --retirement` (a flags baseline needs a PATH; without `--retirement` the options have no effect on `flags` and it warns). `--save-baseline` / `--baseline` are identity-based (track finding identity, fail on new). On bare `fallow` they hold the dead-code baseline only; pass health and duplication baselines with `--health-baseline` / `--dupes-baseline`. `audit` rejects the global baseline flags and uses `--dead-code-baseline` / `--health-baseline` / `--dupes-baseline` instead.
312
317
 
313
318
  With no path, `--save-regression-baseline` updates `regression.baseline` in the discovered fallow config, or creates `.fallowrc.json` when none exists. Pass a path only when a standalone baseline file is preferred.
@@ -136,6 +136,7 @@ Common global flags for this command: [`--format`](#global-flags), [`--quiet`](#
136
136
  | `--unused-enum-members` | Unused enum members |
137
137
  | `--unused-class-members` | Unused class members |
138
138
  | `--unused-store-members` | Unused Pinia store members |
139
+ | `--unused-namespace-members` | Namespace member is never referenced |
139
140
  | `--unprovided-injects` | inject() / getContext() reads a key that no provide() / setContext() supplies |
140
141
  | `--unrendered-components` | A Vue / Svelte component is reachable through a barrel but rendered nowhere |
141
142
  | `--unused-component-props` | A Vue defineProps prop or React component prop is referenced nowhere in its own component |
@@ -151,7 +152,9 @@ Common global flags for this command: [`--format`](#global-flags), [`--quiet`](#
151
152
  | `--unused-load-data-keys` | A SvelteKit load() return-object key is read by no consumer |
152
153
  | `--unresolved-imports` | Unresolved imports |
153
154
  | `--unlisted-deps` | Unlisted dependencies |
155
+ | `--unlisted-binaries` | Binary used but provided by no installed package |
154
156
  | `--duplicate-exports` | Duplicate exports |
157
+ | `--duplicate-export-aliases` | One module exports one binding under two or more names |
155
158
  | `--circular-deps` | Circular dependencies |
156
159
  | `--re-export-cycles` | Re-export cycles (`kind: multi-node` for barrel files re-exporting from each other in a loop, `kind: self-loop` for a barrel re-exporting from itself). File-scoped finding; chain propagation through the loop is a no-op so imports may silently come up empty. Distinct from `--circular-deps` (runtime cycles). |
157
160
  | `--package-cycles` | Two or more workspace packages import each other in a loop |
@@ -527,7 +530,7 @@ Human output groups paths under "Shared with your team (commit these)" and "Loca
527
530
  {
528
531
  "kind": "agent-install",
529
532
  "schema_version": 1,
530
- "fallow_version": "3.39.0",
533
+ "fallow_version": "3.41.0",
531
534
  "root": "/abs/path",
532
535
  "mode": "install",
533
536
  "dry_run": false,
@@ -739,7 +742,7 @@ fallow health --format json --quiet --trend
739
742
  {
740
743
  "kind": "health",
741
744
  "schema_version": 7,
742
- "version": "3.39.0",
745
+ "version": "3.41.0",
743
746
  "elapsed_ms": 32,
744
747
  "summary": {
745
748
  "files_analyzed": 482,
@@ -1214,7 +1217,7 @@ fallow audit \
1214
1217
  {
1215
1218
  "kind": "audit",
1216
1219
  "schema_version": 7,
1217
- "version": "3.39.0",
1220
+ "version": "3.41.0",
1218
1221
  "command": "audit",
1219
1222
  "verdict": "fail",
1220
1223
  "changed_files_count": 12,
@@ -1302,7 +1305,7 @@ fallow flags --format json --quiet --workspace my-package
1302
1305
  ```json
1303
1306
  {
1304
1307
  "schema_version": 7,
1305
- "version": "3.39.0",
1308
+ "version": "3.41.0",
1306
1309
  "elapsed_ms": 116,
1307
1310
  "feature_flags": [],
1308
1311
  "total_flags": 0
@@ -1403,7 +1406,7 @@ fallow security --gate newly-reachable --changed-since origin/main
1403
1406
  {
1404
1407
  "kind": "security",
1405
1408
  "schema_version": "4",
1406
- "version": "3.39.0",
1409
+ "version": "3.41.0",
1407
1410
  "elapsed_ms": 42,
1408
1411
  "config": {
1409
1412
  "rules": {
@@ -1432,7 +1435,7 @@ fallow security --gate newly-reachable --changed-since origin/main
1432
1435
  {
1433
1436
  "kind": "security",
1434
1437
  "schema_version": "4",
1435
- "version": "3.39.0",
1438
+ "version": "3.41.0",
1436
1439
  "elapsed_ms": 42,
1437
1440
  "config": {
1438
1441
  "rules": {
@@ -2241,7 +2244,7 @@ The `kill_matrix` object has these fields:
2241
2244
  | Field | Meaning |
2242
2245
  |---|---|
2243
2246
  | `status` | `complete`, `incomplete`, or `unavailable`, separate from mutation completion. |
2244
- | `reasons` | Evidence limitations, such as `kill-matrix-disabled`, `incomplete-mutant-results`, `baseline-failure`, `partial-mutation-run`, or `missing-test-file-metadata`. |
2247
+ | `reasons` | Evidence limitations, such as `kill-matrix-disabled`, `incomplete-mutant-results`, `baseline-failure`, `partial-mutation-run`, `missing-test-file-metadata`, or `unmatched-target`. |
2245
2248
  | `tests` | Entries with `test_id`, `file`, `kills`, `unique_kills`, `subsuming_tests`, and `notes`. |
2246
2249
  | `candidates` | Test IDs whose observed kill sets other tests cover. |
2247
2250
  | `coverage_without_kills` | Test IDs with runtime coverage and no observed kills. |
@@ -2250,6 +2253,22 @@ Each mutant and attempt records `killing_tests` and `kill_matrix_complete`. The
2250
2253
 
2251
2254
  Matrix mode does not add the other tests of the covering test files to the retry of a survivor. A survivor that normal mode kills in that retry can stay `survived` in matrix mode, so the two modes can give different scores.
2252
2255
 
2256
+ ### `mutation --kill-matrix-for`: Check named tests
2257
+
2258
+ ```bash
2259
+ fallow mutation src/math.ts --kill-matrix-for "test/math.test.ts::adds" --format json --quiet
2260
+ ```
2261
+
2262
+ Use this mode to check whether specific tests are redundant without a full kill matrix. Repeat the flag for each target. A target is a test file (each test in it) or a test ID (`file::name`). It is exclusive with `--kill-matrix`.
2263
+
2264
+ - Only the mutants that a target test covers run. The other mutants are `pruned` with `prune_reason: "no-target-coverage"`.
2265
+ - Each mutant runs its target tests with bail disabled, then its other covering tests with bail enabled, up to the first failure.
2266
+ - `kill_matrix.targets` lists each target with the `test_ids` that it selects. A target that selects no test exits `2` with `FALLOW_MUTATION_TARGET_UNMATCHED`.
2267
+ - Each target has its own `status` (`complete` or `incomplete`) and `reasons`. Only the tests of a complete target can be candidates. `candidates` can be nonempty while the top-level `status` is `incomplete`.
2268
+ - `kill_matrix.tests` has rows for target tests only. `unique_kills` are kills that no other test detects, target or not. `target_only_kills` lists kills that only other targets share, each with those `targets`. `subsuming_tests` is empty (note `subsumers-not-computed`).
2269
+ - A target with kills and no `unique_kills` is a candidate. With `target_only_kills`, it stays redundant only while one of the sharing targets stays. Do not remove all sharing targets together.
2270
+ - The evidence covers the planned scope only. A unique kill outside the scope is not visible.
2271
+
2253
2272
  ## `ci`: Provider-Aware Review Automation
2254
2273
 
2255
2274
  `fallow ci reconcile-review` reads a typed review envelope (`--format review-github` / `review-gitlab`), looks up existing fingerprints on the PR/MR, and resolves stale review threads when their finding is no longer present in the new envelope. Posts an idempotent "Resolved in `<sha>`" follow-up comment per stale finding (skipped if a marker for the same fingerprint at the current SHA already exists).
@@ -2312,7 +2331,7 @@ The HTTP layer mirrors the bash `gh_api_retry` / `curl_retry` helpers: `FALLOW_A
2312
2331
  {
2313
2332
  "kind": "dead-code",
2314
2333
  "schema_version": 7,
2315
- "version": "3.39.0",
2334
+ "version": "3.41.0",
2316
2335
  "elapsed_ms": 45,
2317
2336
  "total_issues": 12,
2318
2337
  "entry_points": {
@@ -2472,7 +2491,7 @@ When `--baseline` is used in combined output, the JSON includes a `baseline_delt
2472
2491
  {
2473
2492
  "kind": "dupes",
2474
2493
  "schema_version": 7,
2475
- "version": "3.39.0",
2494
+ "version": "3.41.0",
2476
2495
  "elapsed_ms": 82,
2477
2496
  "total_clones": 15,
2478
2497
  "total_lines_duplicated": 230,
@@ -2516,11 +2535,11 @@ When running `fallow` with no subcommand (all analyses), the JSON output combine
2516
2535
  {
2517
2536
  "kind": "combined",
2518
2537
  "schema_version": 7,
2519
- "version": "3.39.0",
2538
+ "version": "3.41.0",
2520
2539
  "elapsed_ms": 159,
2521
2540
  "check": {
2522
2541
  "schema_version": 7,
2523
- "version": "3.39.0",
2542
+ "version": "3.41.0",
2524
2543
  "elapsed_ms": 45,
2525
2544
  "total_issues": 12,
2526
2545
  "unused_files": [],
@@ -2740,7 +2759,7 @@ preset = "bulletproof"
2740
2759
  - `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"] } }`
2741
2760
  - `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": "^_" } }`
2742
2761
  - `circularDependencies.ignoreLazyImports`: opt-in boolean, default `false`. When `true`, `circular-dependencies` skips an import edge on which every import loads its target on demand or on another thread: an `import()` inside a function, a template `import()`, a lazy `import.meta.glob`, a worker URL, or a webpack worker loader request such as `worker-loader!./work.js`. A top-level `await import()`, `require()`, an eager `import.meta.glob`, and an edge that also has a static import stay. The filter runs before cycles are counted, so lazy cycles do not use the per-group cycle limit. Example: `{ "circularDependencies": { "ignoreLazyImports": true } }`
2743
- - `effect.schemaExportsAsTypes`: opt-in boolean, default `false`. When `true`, an unused exported Effect schema is reported under `unused-types`, not `unused-exports`, so `"unused-types": "off"` hides it. A schema is a class that extends a `Schema` class factory (`Schema.Class`, `Schema.TaggedClass`, `Schema.TaggedError`, `Schema.TaggedRequest`, `Schema.Error`, `Schema.Opaque`) or a const whose value is a `Schema` constructor, member or pipe chain (`Schema.Struct({...})`, `Schema.String.pipe(Schema.brand("Id"))`). `Schema` must be an import from `effect`, `effect/Schema` or `@effect/schema`. Each `pipe` argument must be a `Schema` transform such as `Schema.brand(...)`. Decoders such as `Schema.decodeUnknownSync(User)` and `pipe(Schema.decodeUnknownSync)` stay unused exports. Example: `{ "effect": { "schemaExportsAsTypes": true } }`
2762
+ - `effect.schemaExportsAsTypes`: opt-in boolean, default `false`. When `true`, an unused exported Effect schema is reported under `unused-types`, not `unused-exports`, so `"unused-types": "off"` hides it. A schema is a class that extends a `Schema` class factory (`Schema.Class`, `Schema.TaggedClass`, `Schema.TaggedError`, `Schema.TaggedRequest`, `Schema.Error`, `Schema.Opaque`) or a const whose value is a `Schema` constructor, member or pipe chain (`Schema.Struct({...})`, `Schema.String.pipe(Schema.brand("Id"))`). `Schema` must be an import from `effect`, `effect/Schema` or `@effect/schema`. Each `pipe` argument must be a `Schema` transform such as `Schema.brand(...)`. A re-export of a schema from another module (`export { User } from "./schemas"`, or an import that the module exports again) also counts. In a module that imports Effect, a chain on an imported schema (`User.pipe(Schema.brand("Id"))`, `User.annotations({...})`) and an alias (`export const Copy = User`) also count. A chain on a member of a namespace import (`S.User.pipe(...)`) does not count. Decoders such as `Schema.decodeUnknownSync(User)` and `pipe(Schema.decodeUnknownSync)` stay unused exports. Example: `{ "effect": { "schemaExportsAsTypes": true } }`
2744
2763
 
2745
2764
  ---
2746
2765
 
@@ -25,9 +25,12 @@ The `generated:issue-types` table below is regenerated from `fallow schema` by s
25
25
  | `unused-enum-member` | `--unused-enum-members` | yes | `// fallow-ignore-next-line unused-enum-member` | Enum values never referenced |
26
26
  | `unused-class-member` | `--unused-class-members` | - | `// fallow-ignore-next-line unused-class-member` | Methods and properties |
27
27
  | `unused-store-member` | `--unused-store-members` | - | `// fallow-ignore-next-line unused-store-member` | Pinia store state/getter/action (needs `pinia` dep) |
28
+ | `unused-namespace-member` | `--unused-namespace-members` | - | `// fallow-ignore-next-line unused-namespace-member` | Namespace member is never referenced |
28
29
  | `unresolved-import` | `--unresolved-imports` | - | `// fallow-ignore-next-line unresolved-import` | Imports that can't be resolved |
29
30
  | `unlisted-dependency` | `--unlisted-deps` | - | - | Used packages missing an applicable dependency declaration. This includes root code importing an npm workspace package: a workspace link or hoisted install makes the package resolvable but does not declare it. Add runtime imports to `dependencies`, or tooling/test imports to `devDependencies`, in the owning `package.json`. Private packages and tooling may inherit ancestor declarations. Self-references need no declaration. Use `ignoreDependencies` for a deliberate ambient-package opt-out. |
31
+ | `unlisted-binary` | `--unlisted-binaries` | - | - | Binary used but provided by no installed package; Needs installed dependencies; a project without a root node_modules reports none |
30
32
  | `duplicate-export` | `--duplicate-exports` | - | `// fallow-ignore-file duplicate-export` | Same symbol exported from multiple modules |
33
+ | `duplicate-export-alias` | `--duplicate-export-aliases` | - | `// fallow-ignore-file duplicate-export-alias` | One module exports one binding under two or more names |
31
34
  | `circular-dependency` | `--circular-deps` | - | `// fallow-ignore-next-line circular-dependency` | Import cycles in the module graph |
32
35
  | `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. |
33
36
  | `package-cycle` | `--package-cycles` | - | `// fallow-ignore-next-line package-cycle` | Two or more workspace packages import each other in a loop, so they cannot be built in dependency order. Edges are resolved imports, not declared `package.json` dependencies, so a package cycle can exist without a file-level cycle. Imports from test, spec, story, fixture and tooling config files do not count. Each finding lists `packages` in cycle order and one example import per hop in `edges`. Type-only imports count, and each hop has a `type_only` flag (a type-only hop still matters for declaration builds). Default `warn`. Requires a workspace with two or more packages. A suppression removes one import; the cycle goes away when every import on one hop is suppressed. `group_truncated: true` means the package group has more cycles than listed. `--changed-since` and diff scope use the example import of each hop (`edges[].path`). |
@@ -20,6 +20,7 @@ When using fallow via MCP (`fallow-mcp`), the following tools are available:
20
20
  | `inspect_similar_code` | trace | free | `fallow similar-code inspect <candidate-id> --candidates <report.json> --format json --quiet` | `candidate_id`, `snapshot` | Inspect one exact unverified candidate without rerunning provider retrieval or global ranking. Pass `candidate_id` plus a bounded typed snapshot containing the unchanged discovery `schema_version`, `generation`, selected `candidate`, `completion`, and `diagnostics`. Current source is re-extracted and both endpoint hashes must still match, so stale source fails closed. Keep candidate worthiness, behavioral equivalence, and refactor safety as separate verdicts, and abstain when evidence is incomplete. |
21
21
  | `mutation_plan` | analysis | free | `fallow mutation --plan --format json --quiet` | `changed_since`, `all`, `paths`, `max_mutants`, `operators` | Static mutation plan for changed code: mutant ids, operators, dispositions, and static test files; runs no tests |
22
22
  | `mutation_inspect` | trace | free | `fallow mutation inspect <mutant-id> [--report <report.json>] --format json --quiet` | `mutant_id`, `report` | Inspect one mutant of a saved mutation report (default: the last run report), with a stale status when its source changed; runs no tests |
23
+ | `mutation_tasks` | trace | free | `fallow mutation tasks [--report <report.json>] --format json --quiet` | `report` | The open tasks of a saved mutation report (default: the last run report) as one batch: each survived or uncovered mutant with its source lines before and after the change; runs no tests |
23
24
  | `inspect_target` | analysis | free | `fallow inspect --format json --quiet` | `target`, `production`, `include_churn`, `cloud` | Compose one evidence bundle for a file or exported symbol. File targets use `target: { type: "file", file }`; symbol targets use `target: { type: "symbol", file, export_name }`. Returns `kind: "inspect_target"`, normalized target identity, `trace_file`, optional `trace_export`, file-scoped dead-code actions, duplication groups filtered to the file, complexity findings filtered to the file, and security candidates scoped to the file. Set `include_churn: true` to add target-level git churn from the health hotspot subsystem. Churn is off by default, and unavailable git history or analysis failures remain explicit section states. Evidence sections carry `status` and `scope`; symbol targets warn when supporting evidence is file-scoped. Set `cloud: true` on a file target to add the `cloud` evidence section of `fallow inspect --cloud` (production data per local function). The CLI reads the key: `FALLOW_API_KEY` in the server environment, else the key that `fallow cloud login` stored; the key is never a parameter. `repo` (`owner/repo`) selects the repository and needs `cloud: true`. The section `status` is `ok`, `no_key`, `plan_required`, `unavailable` or `untracked`; a status other than `ok` never fails the call. `cloud: true` with a symbol target is refused. Set `format: "compact"` to get the plain text of `fallow inspect --format compact` (about 1 KB, no JSON) instead of the JSON bundle. Supports `root`, `config`, `production`, `workspace`, `include_churn`, `cloud`, `repo`, `format`, `no_cache`, and `threads`; `production` applies to trace, dead-code, and health evidence only. Raise `FALLOW_TIMEOUT_SECS` for large repos. |
24
25
  | `guard` | introspection | free | `fallow guard <file> --format json --quiet` | `files` | Report the architecture rules that apply to given files before editing them: boundary zone, allowed import zones, forbidden calls, and rule-pack policies |
25
26
  | `find_dupes` | analysis | free | `fallow dupes --format json --quiet` | `mode`, `near`, `min_tokens`, `min_occurrences`, `top`, `threshold` | Code duplication detection. Set `near: true` for function-level clones with small structural edits. Set `changed_since` to scope to changed files since a git ref. Set `min_occurrences` (≥ 2, default 2) to hide pair-only clones and focus on widespread copy-paste. Each `clone_groups[]` entry carries a normalized `fingerprint` and `spread`; near groups also carry `similarity`. `stats.clone_groups_ignored` reports reviewed groups hidden by config, while `stats.near_candidates_skipped` signals bounded near comparisons that were skipped. Pass the fingerprint to `trace_clone` to inspect the group |
@@ -134,6 +135,30 @@ An entry in `not_found` has no cloud data. Absence is not evidence that the code
134
135
 
135
136
  **Paths.** Open and edit files by `repo_path`. `file_path` is the path the runtime reported (for example `/app/src/x.ts` in a container) and often does not exist in the checkout.
136
137
 
138
+ ## Hosted Fallow Cloud MCP server
139
+
140
+ Fallow Cloud also runs a hosted MCP server. It serves the production data of one organization and needs no local fallow install and no checkout. Use the local `fallow-mcp` when you also need static analysis. Use the hosted server when fallow is not installed. Also use it for the tools that only the hosted server has.
141
+
142
+ - Endpoint: `POST https://api.fallow.cloud/mcp`, Streamable HTTP transport with JSON responses only, no session.
143
+ - Auth: `Authorization: Bearer <key>`. Use a read-only key (`fallow_read_k1_`). A live key (`fallow_live_k1_`) also works, but it can write through the REST API. The server refuses an ingest-only key (`fallow_pub_k1_`) and a dashboard session.
144
+ - Connect Claude Code: `claude mcp add --transport http fallow-cloud https://api.fallow.cloud/mcp --header "Authorization: Bearer $FALLOW_API_KEY"`.
145
+ - Shared tools: `get_cloud_runtime_context`, `get_cloud_review_packet` and `get_cloud_deployment_changes` have the same names and arguments as the local cloud tools. The server accepts and ignores CLI-only arguments such as `root`.
146
+ - The hosted server has no checkout, so it cannot use git defaults. Give `get_cloud_review_packet` explicit `files` or `functions`. Give `get_cloud_deployment_changes` a `sha`.
147
+ - `list_repos` lists the repositories of the organization that have production coverage.
148
+ - `tools/list` is the authority for the current tool set and the argument schemas.
149
+
150
+ | Hosted-only tool | Use it for |
151
+ |:-----------------|:-----------|
152
+ | `get_file_context` | One file before an edit: per function the usage, error groups, CPU time, never-run branches and production callers. `format: "text"` gives a short text form. |
153
+ | `verify_deployment` | After a deploy: did the listed `functions` or `files` run, do they have new error groups, are they slower or faster. Verdict `confirmed`, `attention`, `incomplete` or `awaiting_runtime`. |
154
+ | `list_errors` | Production error groups, newest first, with a symbolicated sample stack. Filter by `file`, `stable_id` or `sha`. |
155
+ | `get_branch_usage` | The source ranges of one file that never ran in production, for example an `if` arm or a `catch` block. |
156
+ | `get_runtime_dependencies` | The npm packages that loaded or ran in production for one deployment. A package without call data has `calls: null`. With `declared`, each package gets `loaded`, `not_loaded` or `untracked`. |
157
+ | `get_deployments` | The deployments of a repo, newest first. Use `git_sha` as `sha` in `get_cloud_deployment_changes` or `verify_deployment`. |
158
+ | `get_repo_activation` | The setup step that is missing when another tool gives `repo_not_found`, `untracked` rows or `awaiting_runtime`. |
159
+
160
+ The hosted data is context. It never proves that code is dead: the delete rule of "Scoped cloud reads" applies here too. `untracked` and `null` mean "no data", not zero. The server cuts a result above `max_output_bytes` (default 60000, for `get_file_context` 12000). A cut JSON result has a `truncation` object, and a paged tool gives the cursor of the first row that it did not show. When a result does not fit after every cut, the tool gives the error `output_too_large`: raise `max_output_bytes` or narrow the request.
161
+
137
162
  ## Runtime source-map confidence for cloud runtime tools
138
163
 
139
164
  | Values | Meaning | Agent action |