fallow 3.29.0 → 3.31.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.
@@ -746,6 +746,45 @@
746
746
  "license_note": null,
747
747
  "docs_url": "https://docs.fallow.tools/explanations/dead-code#re-export-cycles"
748
748
  },
749
+ {
750
+ "id": "package-cycle",
751
+ "rule_id": "fallow/package-cycle",
752
+ "command": "dead-code",
753
+ "category": "Architecture",
754
+ "description": "Two or more workspace packages import each other in a loop",
755
+ "label": "Package Cycles",
756
+ "config_key": "package-cycle",
757
+ "registry_index": 20,
758
+ "aliases": [
759
+ "package-cycles"
760
+ ],
761
+ "lsp": true,
762
+ "filter_flag": "--package-cycles",
763
+ "result_key": "package_cycles",
764
+ "summary_label": "Package cycles",
765
+ "summary_docs_anchor": "package-cycles",
766
+ "sarif_rule_ids": [
767
+ "fallow/package-cycle"
768
+ ],
769
+ "codeclimate_check_names": [
770
+ "fallow/package-cycle"
771
+ ],
772
+ "ts_alias": {
773
+ "name": "PackageCycle",
774
+ "parent": "PackageCycleFinding"
775
+ },
776
+ "counts_in_total": true,
777
+ "fixable": false,
778
+ "suppressible": true,
779
+ "suppress_comment": "// fallow-ignore-next-line package-cycle",
780
+ "default_severity": "warn",
781
+ "opt_in": false,
782
+ "frameworks": [],
783
+ "note": "Requires a workspace with two or more packages",
784
+ "license": "free",
785
+ "license_note": null,
786
+ "docs_url": "https://docs.fallow.tools/explanations/dead-code#package-cycles"
787
+ },
749
788
  {
750
789
  "id": "boundary-violation",
751
790
  "rule_id": "fallow/boundary-violation",
@@ -754,7 +793,7 @@
754
793
  "description": "Import crosses a configured architecture boundary",
755
794
  "label": "Boundary Violations",
756
795
  "config_key": "boundary-violation",
757
- "registry_index": 20,
796
+ "registry_index": 21,
758
797
  "aliases": [],
759
798
  "lsp": true,
760
799
  "filter_flag": "--boundary-violations",
@@ -791,7 +830,7 @@
791
830
  "description": "Source file matches no configured architecture boundary zone",
792
831
  "label": "Boundary Coverage",
793
832
  "config_key": "boundary-violation",
794
- "registry_index": 21,
833
+ "registry_index": 22,
795
834
  "aliases": [
796
835
  "boundary-coverage-violations"
797
836
  ],
@@ -827,7 +866,7 @@
827
866
  "description": "Zoned file calls a callee its zone forbids",
828
867
  "label": "Boundary Call Violations",
829
868
  "config_key": "boundary-violation",
830
- "registry_index": 22,
869
+ "registry_index": 23,
831
870
  "aliases": [
832
871
  "boundary-calls",
833
872
  "boundary-call-violations"
@@ -864,7 +903,7 @@
864
903
  "description": "Banned usage matched a rule-pack rule",
865
904
  "label": "Policy Violations",
866
905
  "config_key": "policy-violation",
867
- "registry_index": 23,
906
+ "registry_index": 24,
868
907
  "aliases": [
869
908
  "policy-violations"
870
909
  ],
@@ -900,7 +939,7 @@
900
939
  "description": "\"use client\" file exports a server-only / route-config name",
901
940
  "label": "Invalid Client Exports",
902
941
  "config_key": "invalid-client-export",
903
- "registry_index": 24,
942
+ "registry_index": 25,
904
943
  "aliases": [
905
944
  "invalid-client-exports"
906
945
  ],
@@ -938,7 +977,7 @@
938
977
  "description": "Barrel re-exports both a \"use client\" module and a server-only module",
939
978
  "label": "Mixed Client/Server Barrels",
940
979
  "config_key": "mixed-client-server-barrel",
941
- "registry_index": 25,
980
+ "registry_index": 26,
942
981
  "aliases": [
943
982
  "mixed-client-server-barrels"
944
983
  ],
@@ -974,7 +1013,7 @@
974
1013
  "description": "\"use client\" / \"use server\" directive is not in the leading position and is ignored",
975
1014
  "label": "Misplaced Directives",
976
1015
  "config_key": "misplaced-directive",
977
- "registry_index": 26,
1016
+ "registry_index": 27,
978
1017
  "aliases": [
979
1018
  "misplaced-directives"
980
1019
  ],
@@ -1010,7 +1049,7 @@
1010
1049
  "description": "inject() / getContext() reads a key that no provide() / setContext() supplies",
1011
1050
  "label": "Unprovided Injects",
1012
1051
  "config_key": "unprovided-injects",
1013
- "registry_index": 27,
1052
+ "registry_index": 28,
1014
1053
  "aliases": [
1015
1054
  "unprovided-injects"
1016
1055
  ],
@@ -1046,7 +1085,7 @@
1046
1085
  "description": "A Vue / Svelte component is reachable through a barrel but rendered nowhere",
1047
1086
  "label": "Unrendered Components",
1048
1087
  "config_key": "unrendered-components",
1049
- "registry_index": 28,
1088
+ "registry_index": 29,
1050
1089
  "aliases": [
1051
1090
  "unrendered-components"
1052
1091
  ],
@@ -1082,7 +1121,7 @@
1082
1121
  "description": "A Vue, Svelte, or React component prop is referenced nowhere in its own component",
1083
1122
  "label": "Unused Component Props",
1084
1123
  "config_key": "unused-component-props",
1085
- "registry_index": 29,
1124
+ "registry_index": 30,
1086
1125
  "aliases": [
1087
1126
  "unused-component-props"
1088
1127
  ],
@@ -1118,7 +1157,7 @@
1118
1157
  "description": "A Vue <script setup> defineEmits event is emitted nowhere in its own component",
1119
1158
  "label": "Unused Component Emits",
1120
1159
  "config_key": "unused-component-emits",
1121
- "registry_index": 30,
1160
+ "registry_index": 31,
1122
1161
  "aliases": [
1123
1162
  "unused-component-emits"
1124
1163
  ],
@@ -1154,7 +1193,7 @@
1154
1193
  "description": "An Angular @Input() / signal input() / model() input is read nowhere in its own component",
1155
1194
  "label": "Unused Component Inputs",
1156
1195
  "config_key": "unused-component-inputs",
1157
- "registry_index": 31,
1196
+ "registry_index": 32,
1158
1197
  "aliases": [
1159
1198
  "unused-component-inputs"
1160
1199
  ],
@@ -1190,7 +1229,7 @@
1190
1229
  "description": "An Angular @Output() / signal output() output is emitted nowhere in its own component",
1191
1230
  "label": "Unused Component Outputs",
1192
1231
  "config_key": "unused-component-outputs",
1193
- "registry_index": 32,
1232
+ "registry_index": 33,
1194
1233
  "aliases": [
1195
1234
  "unused-component-outputs"
1196
1235
  ],
@@ -1226,7 +1265,7 @@
1226
1265
  "description": "A Svelte component dispatches a createEventDispatcher event whose name is listened to nowhere in the project",
1227
1266
  "label": "Unused Svelte Events",
1228
1267
  "config_key": "unused-svelte-events",
1229
- "registry_index": 33,
1268
+ "registry_index": 34,
1230
1269
  "aliases": [
1231
1270
  "unused-svelte-events"
1232
1271
  ],
@@ -1262,7 +1301,7 @@
1262
1301
  "description": "A Next.js Server Action exported from a \"use server\" file is referenced by no code in the project",
1263
1302
  "label": "Unused Server Actions",
1264
1303
  "config_key": "unused-server-actions",
1265
- "registry_index": 34,
1304
+ "registry_index": 35,
1266
1305
  "aliases": [
1267
1306
  "unused-server-actions"
1268
1307
  ],
@@ -1298,7 +1337,7 @@
1298
1337
  "description": "A SvelteKit load() return-object key is read by no consumer",
1299
1338
  "label": "Unused Load Data Keys",
1300
1339
  "config_key": "unused-load-data-keys",
1301
- "registry_index": 35,
1340
+ "registry_index": 36,
1302
1341
  "aliases": [
1303
1342
  "unused-load-data-keys"
1304
1343
  ],
@@ -1334,7 +1373,7 @@
1334
1373
  "description": "Two or more Next.js App Router route files resolve to the same URL",
1335
1374
  "label": "Route Collisions",
1336
1375
  "config_key": "route-collision",
1337
- "registry_index": 36,
1376
+ "registry_index": 37,
1338
1377
  "aliases": [
1339
1378
  "route-collisions"
1340
1379
  ],
@@ -1372,7 +1411,7 @@
1372
1411
  "description": "Sibling Next.js dynamic route segments use different slug names at the same position",
1373
1412
  "label": "Dynamic Segment Conflicts",
1374
1413
  "config_key": "dynamic-segment-name-conflict",
1375
- "registry_index": 37,
1414
+ "registry_index": 38,
1376
1415
  "aliases": [
1377
1416
  "dynamic-segment-name-conflicts"
1378
1417
  ],
@@ -1410,7 +1449,7 @@
1410
1449
  "description": "Suppression comment or tag no longer matches any issue",
1411
1450
  "label": "Stale Suppressions",
1412
1451
  "config_key": "stale-suppressions",
1413
- "registry_index": 38,
1452
+ "registry_index": 39,
1414
1453
  "aliases": [],
1415
1454
  "lsp": true,
1416
1455
  "filter_flag": "--stale-suppressions",
@@ -1446,7 +1485,7 @@
1446
1485
  "description": "Suppression comment omits a required reason",
1447
1486
  "label": "Missing Suppression Reasons",
1448
1487
  "config_key": "require-suppression-reason",
1449
- "registry_index": 39,
1488
+ "registry_index": 40,
1450
1489
  "aliases": [
1451
1490
  "missing-suppression-reasons"
1452
1491
  ],
@@ -1478,7 +1517,7 @@
1478
1517
  "description": "Catalog entry not referenced by any workspace package",
1479
1518
  "label": "Unused Catalog Entries",
1480
1519
  "config_key": "unused-catalog-entries",
1481
- "registry_index": 40,
1520
+ "registry_index": 41,
1482
1521
  "aliases": [
1483
1522
  "catalog",
1484
1523
  "unused-catalog-entries"
@@ -1518,7 +1557,7 @@
1518
1557
  "description": "Named catalog group has no entries",
1519
1558
  "label": "Empty Catalog Groups",
1520
1559
  "config_key": "empty-catalog-groups",
1521
- "registry_index": 41,
1560
+ "registry_index": 42,
1522
1561
  "aliases": [
1523
1562
  "empty-catalog",
1524
1563
  "empty-catalog-groups"
@@ -1558,7 +1597,7 @@
1558
1597
  "description": "package.json references a catalog that does not declare the package",
1559
1598
  "label": "Unresolved Catalog References",
1560
1599
  "config_key": "unresolved-catalog-references",
1561
- "registry_index": 42,
1600
+ "registry_index": 43,
1562
1601
  "aliases": [
1563
1602
  "unresolved-catalog",
1564
1603
  "unresolved-catalog-references"
@@ -1598,7 +1637,7 @@
1598
1637
  "description": "Package-manager override target is not declared or resolved",
1599
1638
  "label": "Unused Dependency Overrides",
1600
1639
  "config_key": "unused-dependency-overrides",
1601
- "registry_index": 43,
1640
+ "registry_index": 44,
1602
1641
  "aliases": [
1603
1642
  "unused-dependency-overrides",
1604
1643
  "unused-override",
@@ -1639,7 +1678,7 @@
1639
1678
  "description": "Package-manager override has an unparsable key or value",
1640
1679
  "label": "Misconfigured Dependency Overrides",
1641
1680
  "config_key": "misconfigured-dependency-overrides",
1642
- "registry_index": 44,
1681
+ "registry_index": 45,
1643
1682
  "aliases": [
1644
1683
  "misconfigured-dependency-overrides",
1645
1684
  "misconfigured-override",
@@ -1680,7 +1719,7 @@
1680
1719
  "description": "Detected feature flag pattern",
1681
1720
  "label": "Feature Flags",
1682
1721
  "config_key": "feature-flags",
1683
- "registry_index": 48,
1722
+ "registry_index": 49,
1684
1723
  "aliases": [],
1685
1724
  "lsp": false,
1686
1725
  "filter_flag": null,
@@ -1710,9 +1749,9 @@
1710
1749
  "description": "A React/Preact prop is forwarded unchanged through 3+ pass-through components to a distant consumer",
1711
1750
  "label": "Prop Drilling",
1712
1751
  "config_key": "prop-drilling",
1713
- "registry_index": 50,
1752
+ "registry_index": 51,
1714
1753
  "aliases": [],
1715
- "lsp": false,
1754
+ "lsp": true,
1716
1755
  "filter_flag": null,
1717
1756
  "result_key": "prop_drilling_chains",
1718
1757
  "summary_label": "Prop drilling",
@@ -1742,11 +1781,11 @@
1742
1781
  "description": "A React/Preact component whose whole body is a single spread-forwarded child render (a candidate for inlining)",
1743
1782
  "label": "Thin Wrappers",
1744
1783
  "config_key": "thin-wrapper",
1745
- "registry_index": 51,
1784
+ "registry_index": 52,
1746
1785
  "aliases": [
1747
1786
  "thin-wrappers"
1748
1787
  ],
1749
- "lsp": false,
1788
+ "lsp": true,
1750
1789
  "filter_flag": null,
1751
1790
  "result_key": "thin_wrappers",
1752
1791
  "summary_label": "Thin wrappers",
@@ -1776,11 +1815,11 @@
1776
1815
  "description": "Three or more React/Preact components across two or more files declare an identical prop-name set (a missing shared Props type)",
1777
1816
  "label": "Duplicate Prop Shapes",
1778
1817
  "config_key": "duplicate-prop-shape",
1779
- "registry_index": 52,
1818
+ "registry_index": 53,
1780
1819
  "aliases": [
1781
1820
  "duplicate-prop-shapes"
1782
1821
  ],
1783
- "lsp": false,
1822
+ "lsp": true,
1784
1823
  "filter_flag": null,
1785
1824
  "result_key": "duplicate_prop_shapes",
1786
1825
  "summary_label": "Duplicate prop shapes",
@@ -1810,7 +1849,7 @@
1810
1849
  "description": "CSS or CSS-in-JS hardcoded styling value bypasses the design token system",
1811
1850
  "label": "CSS Token Drift",
1812
1851
  "config_key": "css-token-drift",
1813
- "registry_index": 53,
1852
+ "registry_index": 54,
1814
1853
  "aliases": [],
1815
1854
  "lsp": false,
1816
1855
  "filter_flag": null,
@@ -1840,7 +1879,7 @@
1840
1879
  "description": "CSS or CSS-in-JS declaration block is duplicated across rules",
1841
1880
  "label": "CSS Duplicate Block",
1842
1881
  "config_key": "css-duplicate-block",
1843
- "registry_index": 54,
1882
+ "registry_index": 55,
1844
1883
  "aliases": [],
1845
1884
  "lsp": false,
1846
1885
  "filter_flag": null,
@@ -1870,7 +1909,7 @@
1870
1909
  "description": "CSS selector, nesting, or important usage is structurally complex",
1871
1910
  "label": "CSS Selector Complexity",
1872
1911
  "config_key": "css-selector-complexity",
1873
- "registry_index": 55,
1912
+ "registry_index": 56,
1874
1913
  "aliases": [],
1875
1914
  "lsp": false,
1876
1915
  "filter_flag": null,
@@ -1900,7 +1939,7 @@
1900
1939
  "description": "CSS or CSS-in-JS surface appears unused",
1901
1940
  "label": "CSS Dead Surface",
1902
1941
  "config_key": "css-dead-surface",
1903
- "registry_index": 56,
1942
+ "registry_index": 57,
1904
1943
  "aliases": [],
1905
1944
  "lsp": false,
1906
1945
  "filter_flag": null,
@@ -1930,7 +1969,7 @@
1930
1969
  "description": "CSS or CSS-in-JS reference resolves to no stylesheet definition",
1931
1970
  "label": "CSS Broken Reference",
1932
1971
  "config_key": "css-broken-reference",
1933
- "registry_index": 57,
1972
+ "registry_index": 58,
1934
1973
  "aliases": [],
1935
1974
  "lsp": false,
1936
1975
  "filter_flag": null,
@@ -2402,6 +2441,36 @@
2402
2441
  "license_note": null,
2403
2442
  "docs_url": "https://docs.fallow.tools/cli/security"
2404
2443
  },
2444
+ {
2445
+ "id": "flag-retirement-candidate",
2446
+ "rule_id": "fallow/flag-retirement-candidate",
2447
+ "command": "flags",
2448
+ "category": "Flags",
2449
+ "description": "Feature flag is a retirement candidate",
2450
+ "label": null,
2451
+ "config_key": null,
2452
+ "registry_index": null,
2453
+ "aliases": [],
2454
+ "lsp": false,
2455
+ "filter_flag": null,
2456
+ "result_key": null,
2457
+ "summary_label": null,
2458
+ "summary_docs_anchor": null,
2459
+ "sarif_rule_ids": null,
2460
+ "codeclimate_check_names": null,
2461
+ "ts_alias": null,
2462
+ "counts_in_total": false,
2463
+ "fixable": false,
2464
+ "suppressible": false,
2465
+ "suppress_comment": null,
2466
+ "default_severity": null,
2467
+ "opt_in": null,
2468
+ "frameworks": [],
2469
+ "note": null,
2470
+ "license": "free",
2471
+ "license_note": null,
2472
+ "docs_url": "https://docs.fallow.tools/cli/flags#retirement-report"
2473
+ },
2405
2474
  {
2406
2475
  "id": "hardcoded-secret",
2407
2476
  "rule_id": "security/hardcoded-secret",
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "fallow",
3
- "version": "3.29.0",
3
+ "version": "3.31.0",
4
4
  "mcpName": "io.github.fallow-rs/fallow",
5
- "description": "Codebase intelligence for TypeScript and JavaScript. Free static analysis of code and styles, optional paid runtime intelligence (Fallow Runtime). Quality, risk, architecture, dependencies, duplication, and design-system drift for humans, CI, and the agents writing your code. Zero-config framework support.",
5
+ "description": "Codebase intelligence for TypeScript and JavaScript: health, complexity, duplication, architecture, styling drift, and unused code from one graph. CLI, LSP, and MCP server. Zero config for over 100 frameworks.",
6
6
  "license": "MIT",
7
7
  "repository": {
8
8
  "type": "git",
9
9
  "url": "git+https://github.com/fallow-rs/fallow.git"
10
10
  },
11
11
  "homepage": "https://docs.fallow.tools",
12
+ "funding": "https://github.com/sponsors/fallow-rs",
12
13
  "bugs": {
13
14
  "url": "https://github.com/fallow-rs/fallow/issues"
14
15
  },
@@ -88,14 +89,14 @@
88
89
  "@tanstack/intent": "0.4.0"
89
90
  },
90
91
  "optionalDependencies": {
91
- "@fallow-cli/darwin-arm64": "3.29.0",
92
- "@fallow-cli/darwin-x64": "3.29.0",
93
- "@fallow-cli/linux-x64-gnu": "3.29.0",
94
- "@fallow-cli/linux-arm64-gnu": "3.29.0",
95
- "@fallow-cli/linux-x64-musl": "3.29.0",
96
- "@fallow-cli/linux-arm64-musl": "3.29.0",
97
- "@fallow-cli/win32-arm64-msvc": "3.29.0",
98
- "@fallow-cli/win32-x64-msvc": "3.29.0",
99
- "fallow-type-aware": "3.29.0"
92
+ "@fallow-cli/darwin-arm64": "3.31.0",
93
+ "@fallow-cli/darwin-x64": "3.31.0",
94
+ "@fallow-cli/linux-x64-gnu": "3.31.0",
95
+ "@fallow-cli/linux-arm64-gnu": "3.31.0",
96
+ "@fallow-cli/linux-x64-musl": "3.31.0",
97
+ "@fallow-cli/linux-arm64-musl": "3.31.0",
98
+ "@fallow-cli/win32-arm64-msvc": "3.31.0",
99
+ "@fallow-cli/win32-x64-msvc": "3.31.0",
100
+ "fallow-type-aware": "3.31.0"
100
101
  }
101
102
  }
package/schema.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "title": "FallowConfig",
4
- "description": "The user-facing fallow configuration as authored in `.fallowrc.json` /\n`.fallowrc.jsonc` / `fallow.toml` (or the `fallow` key of `package.json`).\n\nEvery field documents its serialized meaning, default, and precedence\nagainst CLI flags and environment variables where they exist.\n`FallowConfig::resolve` compiles the loaded config (globs, regexes,\nplugin and rule-pack discovery) into a [`ResolvedConfig`] for analysis.\nUnknown keys are rejected at load so typos fail loud.",
4
+ "description": "The user-facing fallow configuration as authored in `.fallowrc.json` /\n`.fallowrc.jsonc` / `fallow.toml` / `.fallow.toml`.\n\nEvery field documents its serialized meaning, default, and precedence\nagainst CLI flags and environment variables where they exist.\n`FallowConfig::resolve` compiles the loaded config (globs, regexes,\nplugin and rule-pack discovery) into a [`ResolvedConfig`] for analysis.\nUnknown keys are rejected at load so typos fail loud.",
5
5
  "type": "object",
6
6
  "properties": {
7
7
  "$schema": {
@@ -36,7 +36,7 @@
36
36
  "default": []
37
37
  },
38
38
  "ignorePatterns": {
39
- "description": "An array of project-root-relative glob patterns for files to exclude from analysis entirely; entries are unioned with fallow's built-in defaults (**/node_modules/**, **/dist/**, **/build/**, **/.git/**, **/coverage/**, **/*.min.js, **/*.min.mjs, **/*.min.cjs, **/*.bundle.js), so custom globs add to rather than replace them. Set it (e.g. `[\"generated/**\"]`) to drop generated or vendored trees from every detector; patterns are validated at load.",
39
+ "description": "An array of project-root-relative glob patterns for files to exclude from analysis entirely; entries are unioned with fallow's built-in defaults (**/node_modules/**, **/dist/**, **/build/**, **/.git/**, **/coverage/**, **/*.min.js, **/*.min.mjs, **/*.min.cjs, **/*.bundle.js), so custom globs add to rather than replace them. Set it (e.g. `[\"generated/**\"]`) to drop generated or vendored trees from every detector; patterns are validated at load. A `!`-prefixed entry is an exception that applies after the defaults and the positive patterns: `\"!src/policy/coverage/**\"` brings back hand-written source under a built-in default such as `**/coverage/**`, and `\"!.config/**\"` adds a hidden directory to discovery. Paths under `node_modules` or `.git` can not be lifted, and a `!` entry that names one of these segments is a config error.",
40
40
  "type": "array",
41
41
  "items": {
42
42
  "type": "string"
@@ -59,7 +59,7 @@
59
59
  "default": []
60
60
  },
61
61
  "workspaces": {
62
- "description": "Monorepo workspace configuration whose sole sub-key patterns (array of globs) adds workspace package roots beyond those discovered from package.json workspaces, pnpm-workspace.yaml, and tsconfig references. Optional and absent by default (discovery uses the manifests alone); set it only when workspaces live in directories the standard manifests do not declare.",
62
+ "description": "Monorepo workspace configuration. `patterns` adds workspace package roots beyond manifest discovery; `changedSince` maps exact project-root-relative workspace roots to Git baseline refs. A global changed-since request overrides those per-package baselines.",
63
63
  "anyOf": [
64
64
  {
65
65
  "$ref": "#/$defs/WorkspaceConfig"
@@ -71,13 +71,20 @@
71
71
  "default": null
72
72
  },
73
73
  "ignoreDependencies": {
74
- "description": "A list of exact package names excluded from BOTH unused-dependency and unlisted-dependency detection, so a runtime-provided or otherwise-untracked package (e.g. `bun:sqlite`, a peer supplied at deploy time) is never flagged as unused when declared nor as unlisted when imported. Set it for packages fallow cannot observe being used and cannot observe being declared; matching is exact string equality against the package name, not a glob.",
74
+ "description": "A list of package names or package-name globs excluded from BOTH unused-dependency and unlisted-dependency detection, so a runtime-provided or otherwise-untracked package (e.g. `bun:sqlite`, a peer supplied at deploy time) is never flagged as unused when declared nor as unlisted when imported. Set it for packages fallow cannot observe being used and cannot observe being declared. An entry without glob characters matches the package name exactly; an entry with `*`, `?`, `[` or `{` is a glob in the `ignorePatterns` syntax matched against the package name, so `@acme/*` covers every package in the `@acme` scope.",
75
75
  "type": "array",
76
76
  "items": {
77
77
  "type": "string"
78
78
  },
79
79
  "default": []
80
80
  },
81
+ "ignoreCommandEntries": {
82
+ "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.",
83
+ "type": "array",
84
+ "items": {
85
+ "type": "string"
86
+ }
87
+ },
81
88
  "ignoreUnresolvedImports": {
82
89
  "description": "A list of glob patterns that suppress only `unresolved-import` findings whose raw import specifier matches; it does not change dependency usage accounting or resolver behavior. Patterns match the import string as written (not a filesystem path), so list both `@example/icons` and `@example/icons/**` to cover a bare package and its subpaths; parent-relative generated specifiers like `../generated/**` are valid, and broad values like `**` can hide real missing modules.",
83
90
  "type": "array",
@@ -232,6 +239,7 @@
232
239
  "dev-dependencies-in-production": "warn",
233
240
  "circular-dependencies": "error",
234
241
  "re-export-cycle": "warn",
242
+ "package-cycle": "warn",
235
243
  "boundary-violation": "error",
236
244
  "coverage-gaps": "off",
237
245
  "feature-flags": "off",
@@ -256,6 +264,10 @@
256
264
  "description": "Options for the `unused-component-props` rule, currently only `ignorePattern`: a regex matched against each declared prop's local destructure binding name (falling back to the public prop name when unaliased) to exempt intentionally-unused props such as the leading-underscore convention. Set `{ \"ignorePattern\": \"^_\" }` to skip props like `_stage`; matching is unanchored (substring, like ESLint's `RegExp.test`) so anchor with `^`, the pattern is validated at config load (invalid regex fails load), and it applies to Vue, Svelte, Astro, and React/Preact props (unset leaves the rule unchanged).",
257
265
  "$ref": "#/$defs/UnusedComponentPropsConfig"
258
266
  },
267
+ "circularDependencies": {
268
+ "description": "Options for the `circular-dependencies` rule, currently only `ignoreLazyImports`. Set `{ \"ignoreLazyImports\": true }` to skip import edges that load on demand or on another thread (an `import()` inside a function, a template `import()`, a lazy `import.meta.glob`, a worker URL, a webpack worker loader request such as `worker-loader!./work.js`) when fallow looks for cycles. A top-level `await import()`, `require()`, an eager glob, and an edge that also has a static import stay in the cycle graph. Default `false` leaves the rule unchanged.",
269
+ "$ref": "#/$defs/CircularDependenciesConfig"
270
+ },
259
271
  "boundaries": {
260
272
  "description": "Configures architecture boundary enforcement: which source directories belong to which named zone and which zones may import which others, reported as boundary-violation, boundary-coverage-violation, and boundary-call-violation findings (severity via rules.boundary-violation, default error). Set to enforce a layered/module architecture; the object holds `preset` (one of layered, hexagonal, feature-sliced, bulletproof, whose default zones/rules are merged in with the user-declared zones/rules taking precedence), `zones` (each with `name`, `patterns`, `autoDiscover`, optional `root`), `rules` (each with `from`, `allow`, `allowTypeOnly` target-zone lists), `coverage` (`requireAllFiles` plus `allowUnmatched` globs for files matching no zone), and `calls` (a `forbidden` list of `{from, callee}` banned-call rules per zone).",
261
273
  "$ref": "#/$defs/BoundaryConfig",
@@ -265,7 +277,7 @@
265
277
  }
266
278
  },
267
279
  "flags": {
268
- "description": "Configures feature-flag detection: `sdkPatterns` (custom flag-evaluating call signatures, each `{ function, nameArg (zero-based arg index of the flag name, default 0), provider? }`, merged with built-ins for LaunchDarkly, Statsig, Unleash, GrowthBook, Split, PostHog, Vercel Flags, ConfigCat, Flagsmith, Optimizely, and Eppo), `envPrefixes` (env-var prefixes marking `process.env.*` accesses as flags, merged with built-ins), and `configObjectHeuristics` (default false; when true, property accesses on objects whose name contains `feature`/`flag`/`toggle` are reported as low-confidence flags). Set `sdkPatterns`/`envPrefixes` to teach fallow a proprietary flag SDK or naming convention, or enable `configObjectHeuristics` for projects that read flags off config objects (higher false-positive rate). Feature-flag findings surface only when the `feature-flags` rule is enabled (default `off`).",
280
+ "description": "Configures feature-flag detection: `sdkPatterns` (custom flag-evaluating call signatures, each `{ function, nameArg (zero-based arg index of the flag name, default 0), provider? }`, merged with built-ins for LaunchDarkly, Statsig, Unleash, GrowthBook, Split, PostHog, Vercel Flags, ConfigCat, Flagsmith, Optimizely, and Eppo), `envPrefixes` (env-var prefixes marking `process.env.*` and `import.meta.env.*` accesses as flags, merged with built-ins), and `configObjectHeuristics` (default false; when true, property accesses on objects whose name contains `feature`/`flag`/`toggle` are reported as low-confidence flags). Set `sdkPatterns`/`envPrefixes` to teach fallow a proprietary flag SDK or naming convention, or enable `configObjectHeuristics` for projects that read flags off config objects (higher false-positive rate). Feature-flag findings surface only when the `feature-flags` rule is enabled (default `off`).",
269
281
  "$ref": "#/$defs/FlagsConfig",
270
282
  "default": {
271
283
  "configObjectHeuristics": false
@@ -754,6 +766,13 @@
754
766
  "type": "string"
755
767
  },
756
768
  "default": []
769
+ },
770
+ "changedSince": {
771
+ "description": "Git baseline refs keyed by workspace roots, written relative to the project root as `fallow list --workspaces` prints them. Scopes `check`, `dead-code`, `dupes` and editor diagnostics; `health`, `security` and `audit` ignore it. A global changed-since request takes precedence. Unlisted workspaces and root files remain in full scope. A key that names no workspace, or a ref that Git cannot resolve, leaves every package in full scope with a warning.",
772
+ "type": "object",
773
+ "additionalProperties": {
774
+ "type": "string"
775
+ }
757
776
  }
758
777
  }
759
778
  },
@@ -1494,6 +1513,11 @@
1494
1513
  "$ref": "#/$defs/Severity",
1495
1514
  "default": "warn"
1496
1515
  },
1516
+ "package-cycle": {
1517
+ "description": "A dependency cycle between workspace packages, built from resolved\ncross-package imports. Defaults to `warn`.",
1518
+ "$ref": "#/$defs/Severity",
1519
+ "default": "warn"
1520
+ },
1497
1521
  "boundary-violation": {
1498
1522
  "description": "An import crossing a forbidden architecture-boundary edge declared in\nthe `boundaries` config. Defaults to `error`.",
1499
1523
  "$ref": "#/$defs/Severity",
@@ -1620,6 +1644,17 @@
1620
1644
  },
1621
1645
  "additionalProperties": false
1622
1646
  },
1647
+ "CircularDependenciesConfig": {
1648
+ "description": "Options for the `circular-dependencies` rule.\n\nThe default leaves the rule unchanged: every runtime import edge takes\npart in cycle detection, and only type-only edges are skipped.",
1649
+ "type": "object",
1650
+ "properties": {
1651
+ "ignoreLazyImports": {
1652
+ "description": "Skip import edges that load their target on demand or on another\nthread when fallow looks for cycles. A literal `import()` inside a\nfunction, a template `import()`, a lazy `import.meta.glob`, a worker\nURL and a webpack worker loader request (`worker-loader!./work.js`)\nare lazy edges. A top-level `await import()`, `require()` and an\neager `import.meta.glob` load before the module finishes, so they stay.\nAn edge that also carries a static import stays. Default `false`.",
1653
+ "type": "boolean"
1654
+ }
1655
+ },
1656
+ "additionalProperties": false
1657
+ },
1623
1658
  "BoundaryConfig": {
1624
1659
  "description": "Architecture boundary configuration.",
1625
1660
  "type": "object",
@@ -1753,7 +1788,7 @@
1753
1788
  "type": "object",
1754
1789
  "properties": {
1755
1790
  "requireAllFiles": {
1756
- "description": "Report source files that do not match any boundary zone.",
1791
+ "description": "Report every analyzed source file that does not match any boundary\nzone, also a file that no entry point reaches.",
1757
1792
  "type": "boolean"
1758
1793
  },
1759
1794
  "allowUnmatched": {
@@ -1824,7 +1859,7 @@
1824
1859
  }
1825
1860
  },
1826
1861
  "envPrefixes": {
1827
- "description": "Environment variable prefixes that indicate feature flags.\nMerged with built-in prefixes. Only `process.env.*` accesses matching\nthese prefixes are reported as feature flags.",
1862
+ "description": "Environment variable prefixes that indicate feature flags.\nMerged with built-in prefixes. Only `process.env.*` and\n`import.meta.env.*` accesses matching these prefixes are reported as\nfeature flags.",
1828
1863
  "type": "array",
1829
1864
  "items": {
1830
1865
  "type": "string"
@@ -1834,6 +1869,13 @@
1834
1869
  "description": "Enable config object heuristic detection.\nWhen true, property accesses on objects whose name contains \"feature\",\n\"flag\", or \"toggle\" are reported as low-confidence feature flags.\nDefault: false (opt-in due to higher false positive rate).",
1835
1870
  "type": "boolean",
1836
1871
  "default": false
1872
+ },
1873
+ "vendorKeyPrefix": {
1874
+ "description": "Prefix to remove from each key of a `--flag-state` vendor export\nbefore the key is compared with the flag names in the code. For\nexample, `\"web.\"` makes the vendor key `web.new-checkout` match the\ncode flag `new-checkout`. A key without the prefix is compared as it\nis.",
1875
+ "type": [
1876
+ "string",
1877
+ "null"
1878
+ ]
1837
1879
  }
1838
1880
  }
1839
1881
  },
@@ -2463,6 +2505,17 @@
2463
2505
  }
2464
2506
  ]
2465
2507
  },
2508
+ "package-cycle": {
2509
+ "description": "Optional override for [`RulesConfig::package_cycle`].",
2510
+ "anyOf": [
2511
+ {
2512
+ "$ref": "#/$defs/Severity"
2513
+ },
2514
+ {
2515
+ "type": "null"
2516
+ }
2517
+ ]
2518
+ },
2466
2519
  "boundary-violation": {
2467
2520
  "description": "Optional override for [`RulesConfig::boundary_violation`].",
2468
2521
  "anyOf": [
@@ -2794,6 +2847,13 @@
2794
2847
  "minimum": 0,
2795
2848
  "default": 0
2796
2849
  },
2850
+ "packageCycles": {
2851
+ "description": "Baseline count of `package-cycle` findings.",
2852
+ "type": "integer",
2853
+ "format": "uint",
2854
+ "minimum": 0,
2855
+ "default": 0
2856
+ },
2797
2857
  "typeOnlyDependencies": {
2798
2858
  "description": "Baseline count of `type-only-dependencies` findings.",
2799
2859
  "type": "integer",