fallow 3.35.0 → 3.36.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/capabilities.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fallow",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.36.0",
|
|
4
4
|
"manifest_version": "1",
|
|
5
5
|
"description": "Codebase analyzer for TypeScript/JavaScript: unused code, circular dependencies, code duplication, complexity hotspots, and architecture boundary violations",
|
|
6
6
|
"global_flags": [
|
|
@@ -301,7 +301,7 @@
|
|
|
301
301
|
"name": "--fail-on-issues",
|
|
302
302
|
"type": "bool",
|
|
303
303
|
"required": false,
|
|
304
|
-
"description": "Exit
|
|
304
|
+
"description": "Exit 1 on issues, also where the default is 0: bare json, sarif, codeclimate and dupes",
|
|
305
305
|
"possible_values": [
|
|
306
306
|
"true",
|
|
307
307
|
"false"
|
|
@@ -7034,6 +7034,7 @@
|
|
|
7034
7034
|
"FALLOW_MAX_FILE_SIZE": "Per-file size ceiling in megabytes for source discovery (default 5; 0 = no limit). CLI --max-file-size flag overrides this.",
|
|
7035
7035
|
"FALLOW_TYPE_AWARE": "Enable or disable TypeScript semantic (type-aware) analysis for the run (true/false/1/0/yes/no/on/off). Precedence: --type-aware/--no-type-aware CLI flags, then FALLOW_TYPE_AWARE, then the audit.typeAware config field, then typeAware.enabled.",
|
|
7036
7036
|
"FALLOW_TYPE_AWARE_TIMEOUT_SECS": "Wall clock in seconds allowed for one TypeScript semantic sidecar request (default 120; unset, 0, or a non-numeric value keeps the default). Raise it for very large TypeScript programs, where a semantic query scans the whole program.",
|
|
7037
|
+
"FALLOW_TYPE_AWARE_BACKEND": "Experimental. Type-checker backend for the TypeScript semantic sidecar: typescript-go (default) or tsrs. The tsrs backend needs the exact pinned tsrs npm package where fallow-type-aware can resolve it. An unknown value makes the type-aware pass unavailable.",
|
|
7037
7038
|
"FALLOW_TYPE_AWARE_BIN": "Trusted executable override for the TypeScript semantic refinement sidecar used by dead-code --type-aware. Relative paths resolve from the caller's working directory before --root is applied; project node_modules and PATH are intentionally not searched. Default: sibling of the active Fallow executable.",
|
|
7038
7039
|
"FALLOW_AUDIT_BASE": "Pins the fallow audit comparison base ref when no --base/--changed-since is passed (e.g. upstream/main).",
|
|
7039
7040
|
"FALLOW_AUDIT_CACHE_MAX_AGE_DAYS": "GC threshold in days for reusable audit base-snapshot caches (default 30; 0 disables the sweep).",
|
|
@@ -8280,7 +8281,7 @@
|
|
|
8280
8281
|
]
|
|
8281
8282
|
},
|
|
8282
8283
|
"plugins": {
|
|
8283
|
-
"count":
|
|
8284
|
+
"count": 149,
|
|
8284
8285
|
"note": "Built-in framework plugins, auto-activated when their enabler dependency is present; run fallow list --plugins for the set active in a specific project",
|
|
8285
8286
|
"names": [
|
|
8286
8287
|
"nextjs",
|
|
@@ -8421,6 +8422,7 @@
|
|
|
8421
8422
|
"nodemon",
|
|
8422
8423
|
"pm2",
|
|
8423
8424
|
"dependency-cruiser",
|
|
8425
|
+
"dotenv",
|
|
8424
8426
|
"wuchale",
|
|
8425
8427
|
"varlock",
|
|
8426
8428
|
"pnpm",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fallow",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.36.0",
|
|
4
4
|
"mcpName": "io.github.fallow-rs/fallow",
|
|
5
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",
|
|
@@ -89,14 +89,14 @@
|
|
|
89
89
|
"@tanstack/intent": "0.5.5"
|
|
90
90
|
},
|
|
91
91
|
"optionalDependencies": {
|
|
92
|
-
"@fallow-cli/darwin-arm64": "3.
|
|
93
|
-
"@fallow-cli/darwin-x64": "3.
|
|
94
|
-
"@fallow-cli/linux-x64-gnu": "3.
|
|
95
|
-
"@fallow-cli/linux-arm64-gnu": "3.
|
|
96
|
-
"@fallow-cli/linux-x64-musl": "3.
|
|
97
|
-
"@fallow-cli/linux-arm64-musl": "3.
|
|
98
|
-
"@fallow-cli/win32-arm64-msvc": "3.
|
|
99
|
-
"@fallow-cli/win32-x64-msvc": "3.
|
|
100
|
-
"fallow-type-aware": "3.
|
|
92
|
+
"@fallow-cli/darwin-arm64": "3.36.0",
|
|
93
|
+
"@fallow-cli/darwin-x64": "3.36.0",
|
|
94
|
+
"@fallow-cli/linux-x64-gnu": "3.36.0",
|
|
95
|
+
"@fallow-cli/linux-arm64-gnu": "3.36.0",
|
|
96
|
+
"@fallow-cli/linux-x64-musl": "3.36.0",
|
|
97
|
+
"@fallow-cli/linux-arm64-musl": "3.36.0",
|
|
98
|
+
"@fallow-cli/win32-arm64-msvc": "3.36.0",
|
|
99
|
+
"@fallow-cli/win32-x64-msvc": "3.36.0",
|
|
100
|
+
"fallow-type-aware": "3.36.0"
|
|
101
101
|
}
|
|
102
102
|
}
|
package/schema.json
CHANGED
|
@@ -416,7 +416,7 @@
|
|
|
416
416
|
"default": false
|
|
417
417
|
},
|
|
418
418
|
"failOnParseError": {
|
|
419
|
-
"description": "When true, the run fails with exit code 1 if fallow could not parse a source file cleanly (a `source-parse-degraded` entry in `workspace_diagnostics[]`), and the `parse-error` entry of `gate_outcomes` names each such file. Boolean, defaults to false, so a file the parser rejects only warns. Applies to `fallow dead-code`, `fallow health`, `fallow audit` and the bare `fallow` run; the CLI flag `--fail-on-parse-error` arms the same gate for one run. Older fallow versions reject this key as unknown, so pair it with `minimumVersion` set to the release that added it.",
|
|
419
|
+
"description": "When true, the run fails with exit code 1 if fallow could not parse a source file cleanly (a `source-parse-degraded` or `source-nesting-too-deep` entry in `workspace_diagnostics[]`), and the `parse-error` entry of `gate_outcomes` names each such file. Boolean, defaults to false, so a file the parser rejects only warns. Applies to `fallow dead-code`, `fallow health`, `fallow audit` and the bare `fallow` run; the CLI flag `--fail-on-parse-error` arms the same gate for one run. Older fallow versions reject this key as unknown, so pair it with `minimumVersion` set to the release that added it.",
|
|
420
420
|
"type": "boolean",
|
|
421
421
|
"default": false
|
|
422
422
|
},
|
|
@@ -538,13 +538,13 @@
|
|
|
538
538
|
"description": "Plugin detected if this package is in dependencies.",
|
|
539
539
|
"type": "object",
|
|
540
540
|
"properties": {
|
|
541
|
-
"package": {
|
|
542
|
-
"description": "Exact package name looked up in the project's declared dependencies.",
|
|
543
|
-
"type": "string"
|
|
544
|
-
},
|
|
545
541
|
"type": {
|
|
546
542
|
"type": "string",
|
|
547
543
|
"const": "dependency"
|
|
544
|
+
},
|
|
545
|
+
"package": {
|
|
546
|
+
"description": "Exact package name looked up in the project's declared dependencies.",
|
|
547
|
+
"type": "string"
|
|
548
548
|
}
|
|
549
549
|
},
|
|
550
550
|
"required": [
|
|
@@ -556,13 +556,13 @@
|
|
|
556
556
|
"description": "Plugin detected if this file pattern matches.",
|
|
557
557
|
"type": "object",
|
|
558
558
|
"properties": {
|
|
559
|
-
"pattern": {
|
|
560
|
-
"description": "Project-root-relative glob; the plugin activates when any\ndiscovered file matches it. Validated at load like other user\nglobs (no absolute paths or `..` segments).\nA single `*` stays within one path segment; use `**` to match across directories.",
|
|
561
|
-
"type": "string"
|
|
562
|
-
},
|
|
563
559
|
"type": {
|
|
564
560
|
"type": "string",
|
|
565
561
|
"const": "fileExists"
|
|
562
|
+
},
|
|
563
|
+
"pattern": {
|
|
564
|
+
"description": "Project-root-relative glob; the plugin activates when any\ndiscovered file matches it. Validated at load like other user\nglobs (no absolute paths or `..` segments).\nA single `*` stays within one path segment; use `**` to match across directories.",
|
|
565
|
+
"type": "string"
|
|
566
566
|
}
|
|
567
567
|
},
|
|
568
568
|
"required": [
|
|
@@ -574,16 +574,16 @@
|
|
|
574
574
|
"description": "All conditions must be true.",
|
|
575
575
|
"type": "object",
|
|
576
576
|
"properties": {
|
|
577
|
+
"type": {
|
|
578
|
+
"type": "string",
|
|
579
|
+
"const": "all"
|
|
580
|
+
},
|
|
577
581
|
"conditions": {
|
|
578
582
|
"description": "Sub-conditions combined with logical AND.",
|
|
579
583
|
"type": "array",
|
|
580
584
|
"items": {
|
|
581
585
|
"$ref": "#/$defs/PluginDetection"
|
|
582
586
|
}
|
|
583
|
-
},
|
|
584
|
-
"type": {
|
|
585
|
-
"type": "string",
|
|
586
|
-
"const": "all"
|
|
587
587
|
}
|
|
588
588
|
},
|
|
589
589
|
"required": [
|
|
@@ -595,16 +595,16 @@
|
|
|
595
595
|
"description": "Any condition must be true.",
|
|
596
596
|
"type": "object",
|
|
597
597
|
"properties": {
|
|
598
|
+
"type": {
|
|
599
|
+
"type": "string",
|
|
600
|
+
"const": "any"
|
|
601
|
+
},
|
|
598
602
|
"conditions": {
|
|
599
603
|
"description": "Sub-conditions combined with logical OR.",
|
|
600
604
|
"type": "array",
|
|
601
605
|
"items": {
|
|
602
606
|
"$ref": "#/$defs/PluginDetection"
|
|
603
607
|
}
|
|
604
|
-
},
|
|
605
|
-
"type": {
|
|
606
|
-
"type": "string",
|
|
607
|
-
"const": "any"
|
|
608
608
|
}
|
|
609
609
|
},
|
|
610
610
|
"required": [
|
|
@@ -1269,6 +1269,10 @@
|
|
|
1269
1269
|
"maximum": 65535,
|
|
1270
1270
|
"default": 20
|
|
1271
1271
|
},
|
|
1272
|
+
"cyclomaticPolicy": {
|
|
1273
|
+
"description": "How the cyclomatic gate counts complexity (default: `standard`).\n`literal-membership` counts a chain of strict equality checks of one\nidentifier against primitive literals (`kind === \"a\" || kind === \"b\"`)\nas one predicate. The policy applies to the `maxCyclomatic` gate and\nto every CRAP score, so the `maxCrap` gate reads the same value.\nFindings then report the standard value as `standard_cyclomatic`. The\nhealth score, complexity density, and hotspots keep the standard\ncount. Older fallow versions reject this key as unknown, so pair it\nwith `minimumVersion`.",
|
|
1274
|
+
"$ref": "#/$defs/CyclomaticPolicy"
|
|
1275
|
+
},
|
|
1272
1276
|
"maxCognitive": {
|
|
1273
1277
|
"description": "Maximum allowed cognitive complexity per function (default: 15).\nFunctions exceeding this threshold are reported. Governs findings\nonly, never the health score.",
|
|
1274
1278
|
"type": "integer",
|
|
@@ -1362,6 +1366,21 @@
|
|
|
1362
1366
|
},
|
|
1363
1367
|
"additionalProperties": false
|
|
1364
1368
|
},
|
|
1369
|
+
"CyclomaticPolicy": {
|
|
1370
|
+
"description": "How `fallow health` counts cyclomatic complexity for its gates.\n\nThe policy changes the cyclomatic value that the `maxCyclomatic` gate reads\nand the cyclomatic value in every CRAP score. It does not change the health\nscore, the complexity density, or the hotspot ranking: those keep the\nstandard count so that grades stay comparable across projects.",
|
|
1371
|
+
"oneOf": [
|
|
1372
|
+
{
|
|
1373
|
+
"description": "Count every decision point, `&&`, `||`, and `??` operator (`McCabe`).",
|
|
1374
|
+
"type": "string",
|
|
1375
|
+
"const": "standard"
|
|
1376
|
+
},
|
|
1377
|
+
{
|
|
1378
|
+
"description": "Count a literal membership chain as one predicate. A chain such as\n`kind === \"a\" || kind === \"b\" || kind === \"c\"` adds no cyclomatic\nincrements for its `||` operators. Only strict equality checks of one\nidentifier against string, number, bigint, boolean, or `null` literals\nqualify. Member access, calls, mixed operators, and different operands\nkeep the standard count.",
|
|
1379
|
+
"type": "string",
|
|
1380
|
+
"const": "literal-membership"
|
|
1381
|
+
}
|
|
1382
|
+
]
|
|
1383
|
+
},
|
|
1365
1384
|
"HealthThresholdOverride": {
|
|
1366
1385
|
"description": "Per-file or per-function health threshold override.",
|
|
1367
1386
|
"type": "object",
|
|
@@ -440,7 +440,7 @@ The `--entry-weight` JSON output carries `entry_weight.entries[]`, one row per r
|
|
|
440
440
|
|
|
441
441
|
To gate eager growth in CI, save a baseline file on the main branch with `fallow list --entry-weight --save-regression-baseline <PATH>`. A later run with `--regression-baseline <PATH>` adds `entry_weight.regression`: per-entry `baseline_eager_bytes`, `current_eager_bytes`, `new_eager_packages` and `exceeded`. The comparison is report-only until you add `--fail-on-regression`; then an entry that grew more than `--tolerance` (bytes, or a percentage such as `5%`) exits 1. A new entry never fails the gate.
|
|
442
442
|
|
|
443
|
-
The `--workspaces` JSON output carries `workspaces[]` (name, project-root-relative path, `is_internal_dependency` bool) plus `workspace_diagnostics[]`. Each diagnostic has a `kind` discriminator (for example `undeclared-workspace`, `malformed-package-json`, `glob-matched-no-package-json`, `workspace-glob-outside-root`, `workspace-pattern-dir-missing`, `nested-project-root`, `malformed-tsconfig`, `tsconfig-reference-dir-missing`, `malformed-pnpm-workspace-yaml`, `skipped-large-file`, `skipped-minified-file`, `skipped-source-dotdir`, `source-read-failure`, `npm-lock-override-resolution-skipped`) with a typed payload (`error`, `pattern`, or none), and a `path` that is project-root-relative with forward slashes on every envelope that carries the array. The same `workspace_diagnostics[]` array is also surfaced on the `fallow dead-code --format json`, `fallow dupes --format json`, and `fallow health --format json` envelopes, at the top level of the bare combined `fallow --format json` envelope, on `fallow audit --format json` under `dead_code`, and on the `audit-brief` envelope shared by `fallow review --format json` and `fallow audit --brief --format json`, also under `dead_code` (omitted when empty). The combined carrier is the envelope root, not a section, so `--skip check`, `--only health`, and `--only dupes` all still report what their analyses recorded. The combined root is the union of what every analysis in the run recorded, deduplicated on the whole `kind` (typed payload included) plus `path`, so two overlapping globs still report the same package-less directory once per `pattern` (a declared glob's no-op `./` prefix is normalised away, so one glob written `"./apps/**"` in `package.json` and `apps/**` in `pnpm-workspace.yaml` stays one entry): a combined run walks the project once per analysis, and a per-analysis `production` mode (`production: { deadCode, health, dupes }`, `--production-health`) can give those walks different file sets, so only the union reports what the run as a whole saw. Each analysis contributes the workspace-discovery list its own config load produced, the same list `fallow list --workspaces` reports, so the combined root can carry an `undeclared-workspace` or `glob-matched-no-package-json` entry that the standalone `dead-code`, `check`, `health`, and `dupes` envelopes, which read the process diagnostics registry instead, do not. `fallow audit --format json` and the `audit-brief` envelope are on the same broad side: they fold the dead-code analysis's own list into their `dead_code.workspace_diagnostics[]`, so they too report an `undeclared-workspace` entry the standalone envelopes miss. The CLI and the programmatic route (MCP code mode, NAPI, embedders) agree on everything an analysis records: both folds close with the same process-registry read, which covers what an analysis records after its section captured its list (a `source-read-failure`, or the analysis-stage kinds a health run's own dead-code precompute records) and skips `skipped-large-file`, `skipped-minified-file`, and `skipped-source-dotdir`, since those reach an envelope only from the walk that recorded them. The analysis-stage kinds (`malformed-pnpm-workspace-yaml`, `bun-lockb-override-resolution-skipped`, `bun-lock-override-resolution-skipped`, `pnpm-lock-override-resolution-skipped`, `npm-lock-override-resolution-skipped`, `bun-resolutions-shadowed-by-overrides`, `pnpm-workspace-overrides-ignored`, `boundaries-not-configured`, `rule-packs-not-configured`) are recorded by the dead-code analyze pass, so they only appear on runs that include it: `fallow dupes --format json` and `fallow --only dupes` report the workspace-discovery and source-discovery kinds alone. A malformed ROOT `package.json` exits 2 at config load; everything else warns and continues. The dead-code result adds two more kinds, each with a `pattern` payload and `path: "."`: `ignore-dependencies-glob-unmatched` (an `ignoreDependencies` glob matched no declared dependency; omitted when the run reports no dependency finding, for example with `--unused-files` or `--file`) and `ignore-findings-pattern-unmatched` (an `ignoreFindings` pattern matched no finding). SARIF carries the same entries under `invocations[0].toolConfigurationNotifications[]` of the dead-code run. Markdown, `github-summary`, `pr-comment-github`, `pr-comment-gitlab` and the summary `body` of `review-github` and `review-gitlab` add an `Unmatched config patterns` section. Human, compact, CodeClimate and `github-annotations` print a stderr note. `fallow report --from` uses the same place as the live run of that format.
|
|
443
|
+
The `--workspaces` JSON output carries `workspaces[]` (name, project-root-relative path, `is_internal_dependency` bool) plus `workspace_diagnostics[]`. Each diagnostic has a `kind` discriminator (for example `undeclared-workspace`, `malformed-package-json`, `glob-matched-no-package-json`, `workspace-glob-outside-root`, `workspace-pattern-dir-missing`, `nested-project-root`, `malformed-tsconfig`, `tsconfig-reference-dir-missing`, `malformed-pnpm-workspace-yaml`, `skipped-large-file`, `skipped-minified-file`, `skipped-source-dotdir`, `source-read-failure`, `npm-lock-override-resolution-skipped`) with a typed payload (`error`, `pattern`, or none), and a `path` that is project-root-relative with forward slashes on every envelope that carries the array. The same `workspace_diagnostics[]` array is also surfaced on the `fallow dead-code --format json`, `fallow dupes --format json`, and `fallow health --format json` envelopes, at the top level of the bare combined `fallow --format json` envelope, on `fallow audit --format json` under `dead_code`, and on the `audit-brief` envelope shared by `fallow review --format json` and `fallow audit --brief --format json`, also under `dead_code` (omitted when empty). The combined carrier is the envelope root, not a section, so `--skip check`, `--only health`, and `--only dupes` all still report what their analyses recorded. The combined root is the union of what every analysis in the run recorded, deduplicated on the whole `kind` (typed payload included) plus `path`, so two overlapping globs still report the same package-less directory once per `pattern` (a declared glob's no-op `./` prefix is normalised away, so one glob written `"./apps/**"` in `package.json` and `apps/**` in `pnpm-workspace.yaml` stays one entry): a combined run walks the project once per analysis, and a per-analysis `production` mode (`production: { deadCode, health, dupes }`, `--production-health`) can give those walks different file sets, so only the union reports what the run as a whole saw. Each analysis contributes the workspace-discovery list its own config load produced, the same list `fallow list --workspaces` reports, so the combined root can carry an `undeclared-workspace` or `glob-matched-no-package-json` entry that the standalone `dead-code`, `check`, `health`, and `dupes` envelopes, which read the process diagnostics registry instead, do not. `fallow audit --format json` and the `audit-brief` envelope are on the same broad side: they fold the dead-code analysis's own list into their `dead_code.workspace_diagnostics[]`, so they too report an `undeclared-workspace` entry the standalone envelopes miss. The CLI and the programmatic route (MCP code mode, NAPI, embedders) agree on everything an analysis records: both folds close with the same process-registry read, which covers what an analysis records after its section captured its list (a `source-read-failure`, or the analysis-stage kinds a health run's own dead-code precompute records) and skips `skipped-large-file`, `skipped-minified-file`, and `skipped-source-dotdir`, since those reach an envelope only from the walk that recorded them. The analysis-stage kinds (`malformed-pnpm-workspace-yaml`, `bun-lockb-override-resolution-skipped`, `bun-lock-override-resolution-skipped`, `pnpm-lock-override-resolution-skipped`, `npm-lock-override-resolution-skipped`, `bun-resolutions-shadowed-by-overrides`, `pnpm-workspace-overrides-ignored`, `boundaries-not-configured`, `rule-packs-not-configured`) are recorded by the dead-code analyze pass, so they only appear on runs that include it: `fallow dupes --format json` and `fallow --only dupes` report the workspace-discovery and source-discovery kinds alone. A malformed ROOT `package.json` exits 2 at config load; everything else warns and continues. The dead-code result adds two more kinds, each with a `pattern` payload and `path: "."`: `ignore-dependencies-glob-unmatched` (an `ignoreDependencies` glob matched no declared dependency; omitted when the run reports no dependency finding, for example with `--unused-files` or `--file`) and `ignore-findings-pattern-unmatched` (an `ignoreFindings` pattern matched no finding). It also adds three kinds for an entry that matched but changed nothing, with the same payload: `entry-pattern-redundant` (every file the `entry` pattern matches is already a runtime entry point from another source), `ignore-dependencies-entry-redundant` (the `ignoreDependencies` entry hid no dependency finding; same gate as the unmatched glob) and `ignore-patterns-entry-redundant` (the `ignorePatterns` glob excluded no file that a built-in ignore, `.gitignore` or the file type filter does not already skip; a glob for build output has an effect only after a build). A `--production` run reports none of the three. SARIF carries the same entries under `invocations[0].toolConfigurationNotifications[]` of the dead-code run. Markdown, `github-summary`, `pr-comment-github`, `pr-comment-gitlab` and the summary `body` of `review-github` and `review-gitlab` add an `Unmatched config patterns` section, and a `Redundant config entries` section for the three redundant kinds. Human, compact, CodeClimate and `github-annotations` print a stderr note. `fallow report --from` uses the same place as the live run of that format.
|
|
444
444
|
|
|
445
445
|
The `--boundaries` JSON output carries `boundaries.logical_groups[]` alongside the existing `zones[]` / `rules[]` arrays. Each logical-group entry surfaces a user-authored `autoDiscover` parent zone (which expansion otherwise flattens into per-child zones like `features/auth` / `features/billing`): `name`, `children`, `auto_discover` (verbatim user strings), `status` (`ok` / `empty` / `invalid_path`), `source_zone_index`, summed `file_count`, optional `authored_rule` (the pre-expansion `{ allow, allowTypeOnly }` keyed on the parent), optional `fallback_zone` cross-reference when the parent also kept its own `patterns` (Bulletproof case), optional `merged_from` (parent zone indices when the user declared the same parent name twice; surfaces the duplicate in JSON instead of only in `tracing::warn!`), optional `original_zone_root` (echo of the parent's `root` subtree scope for monorepo patchers), and optional `child_source_indices` (parallel to `children`, attributing each child to a specific `auto_discover` entry when multiple paths were authored). The full shape is documented in `docs/output-schema.json` under `ListBoundariesOutput`.
|
|
446
446
|
|
|
@@ -526,7 +526,7 @@ Human output groups paths under "Shared with your team (commit these)" and "Loca
|
|
|
526
526
|
{
|
|
527
527
|
"kind": "agent-install",
|
|
528
528
|
"schema_version": 1,
|
|
529
|
-
"fallow_version": "3.
|
|
529
|
+
"fallow_version": "3.36.0",
|
|
530
530
|
"root": "/abs/path",
|
|
531
531
|
"mode": "install",
|
|
532
532
|
"dry_run": false,
|
|
@@ -737,7 +737,7 @@ fallow health --format json --quiet --trend
|
|
|
737
737
|
{
|
|
738
738
|
"kind": "health",
|
|
739
739
|
"schema_version": 7,
|
|
740
|
-
"version": "3.
|
|
740
|
+
"version": "3.36.0",
|
|
741
741
|
"elapsed_ms": 32,
|
|
742
742
|
"summary": {
|
|
743
743
|
"files_analyzed": 482,
|
|
@@ -1148,7 +1148,7 @@ A complexity finding matches its base finding by file path and function name. Th
|
|
|
1148
1148
|
|
|
1149
1149
|
Growth of a metric that the base finding already exceeded, in the same severity tier, makes the finding `worsened`, not introduced.
|
|
1150
1150
|
|
|
1151
|
-
An unchanged or decreased metric keeps the finding inherited, also when the exceeded category changes (for example from `both` to `cyclomatic`). When one file has more than one finding with the same function name, each base finding matches at most one head finding. Head findings with unchanged metric values and an unchanged line count match first. Head findings with unchanged metric values match next. The other findings then match in line order.
|
|
1151
|
+
An unchanged or decreased metric keeps the finding inherited, also when the exceeded category changes (for example from `both` to `cyclomatic`). When one file has more than one finding with the same function name, each base finding matches at most one head finding. Head findings with unchanged metric values and an unchanged line count match first. Head findings with unchanged metric values match next. Then head findings with unchanged cyclomatic and cognitive values match, also when the CRAP score changed, because a change of the coverage input changes the CRAP score. The other findings then match in line order.
|
|
1152
1152
|
|
|
1153
1153
|
A matched finding that is not introduced is `worsened` when a measured value is higher than in the base finding. The measured values are cyclomatic, cognitive, CRAP (only when both sides have a score) and the line count of the function. The line count must grow by at least 5 lines. It includes comments and blank lines, so the minimum keeps a finding inherited after a short comment or a formatter rewrap. Each complexity finding carries `attribution` (`introduced`, `worsened` or `inherited`). When a value grew, it also carries `worsened_metrics` with the `metric`, the `base` value and the `head` value. An introduced finding that matched a base finding also carries `worsened_metrics`. `attribution.worsened` gives the active mode. `attribution.complexity_worsened` counts the worsened findings, which are also in `complexity_inherited`. `--worsened` (config `audit.worsened`) decides their effect on the verdict:
|
|
1154
1154
|
|
|
@@ -1212,7 +1212,7 @@ fallow audit \
|
|
|
1212
1212
|
{
|
|
1213
1213
|
"kind": "audit",
|
|
1214
1214
|
"schema_version": 7,
|
|
1215
|
-
"version": "3.
|
|
1215
|
+
"version": "3.36.0",
|
|
1216
1216
|
"command": "audit",
|
|
1217
1217
|
"verdict": "fail",
|
|
1218
1218
|
"changed_files_count": 12,
|
|
@@ -1300,7 +1300,7 @@ fallow flags --format json --quiet --workspace my-package
|
|
|
1300
1300
|
```json
|
|
1301
1301
|
{
|
|
1302
1302
|
"schema_version": 7,
|
|
1303
|
-
"version": "3.
|
|
1303
|
+
"version": "3.36.0",
|
|
1304
1304
|
"elapsed_ms": 116,
|
|
1305
1305
|
"feature_flags": [],
|
|
1306
1306
|
"total_flags": 0
|
|
@@ -1401,7 +1401,7 @@ fallow security --gate newly-reachable --changed-since origin/main
|
|
|
1401
1401
|
{
|
|
1402
1402
|
"kind": "security",
|
|
1403
1403
|
"schema_version": "4",
|
|
1404
|
-
"version": "3.
|
|
1404
|
+
"version": "3.36.0",
|
|
1405
1405
|
"elapsed_ms": 42,
|
|
1406
1406
|
"config": {
|
|
1407
1407
|
"rules": {
|
|
@@ -1430,7 +1430,7 @@ fallow security --gate newly-reachable --changed-since origin/main
|
|
|
1430
1430
|
{
|
|
1431
1431
|
"kind": "security",
|
|
1432
1432
|
"schema_version": "4",
|
|
1433
|
-
"version": "3.
|
|
1433
|
+
"version": "3.36.0",
|
|
1434
1434
|
"elapsed_ms": 42,
|
|
1435
1435
|
"config": {
|
|
1436
1436
|
"rules": {
|
|
@@ -2245,7 +2245,7 @@ The HTTP layer mirrors the bash `gh_api_retry` / `curl_retry` helpers: `FALLOW_A
|
|
|
2245
2245
|
{
|
|
2246
2246
|
"kind": "dead-code",
|
|
2247
2247
|
"schema_version": 7,
|
|
2248
|
-
"version": "3.
|
|
2248
|
+
"version": "3.36.0",
|
|
2249
2249
|
"elapsed_ms": 45,
|
|
2250
2250
|
"total_issues": 12,
|
|
2251
2251
|
"entry_points": {
|
|
@@ -2405,7 +2405,7 @@ When `--baseline` is used in combined output, the JSON includes a `baseline_delt
|
|
|
2405
2405
|
{
|
|
2406
2406
|
"kind": "dupes",
|
|
2407
2407
|
"schema_version": 7,
|
|
2408
|
-
"version": "3.
|
|
2408
|
+
"version": "3.36.0",
|
|
2409
2409
|
"elapsed_ms": 82,
|
|
2410
2410
|
"total_clones": 15,
|
|
2411
2411
|
"total_lines_duplicated": 230,
|
|
@@ -2449,11 +2449,11 @@ When running `fallow` with no subcommand (all analyses), the JSON output combine
|
|
|
2449
2449
|
{
|
|
2450
2450
|
"kind": "combined",
|
|
2451
2451
|
"schema_version": 7,
|
|
2452
|
-
"version": "3.
|
|
2452
|
+
"version": "3.36.0",
|
|
2453
2453
|
"elapsed_ms": 159,
|
|
2454
2454
|
"check": {
|
|
2455
2455
|
"schema_version": 7,
|
|
2456
|
-
"version": "3.
|
|
2456
|
+
"version": "3.36.0",
|
|
2457
2457
|
"elapsed_ms": 45,
|
|
2458
2458
|
"total_issues": 12,
|
|
2459
2459
|
"unused_files": [],
|
|
@@ -179,7 +179,7 @@ Error-severity findings can trigger exit code 1. Default severity varies by rule
|
|
|
179
179
|
}
|
|
180
180
|
```
|
|
181
181
|
|
|
182
|
-
Exit code 1 always means that an enforced gate failed. A load warning or a workspace diagnostic (for example `node-modules-missing` or a tsconfig `extends` that does not resolve) never changes the exit code. The only
|
|
182
|
+
Exit code 1 always means that an enforced gate failed. A load warning or a workspace diagnostic (for example `node-modules-missing` or a tsconfig `extends` that does not resolve) never changes the exit code. The only exceptions are `source-parse-degraded` and `source-nesting-too-deep` with `--fail-on-parse-error`. To find the gate, read `gate_outcomes` in the JSON output and look for an entry with `status: "fail"` and `enforced: true`. Under `--quiet` and in every machine format, fallow also prints one stderr line that names the failed gates, for example `[X] Exit code 1: gate health-findings (3 at or above error) failed.` On `health`, the `complexity-*` rules default to `error`, so each complexity finding fails the run. Set them to `warn` or pass `--report-only` to report without a failure.
|
|
183
183
|
|
|
184
184
|
---
|
|
185
185
|
|
|
@@ -784,11 +784,11 @@ Prefer `fallow hooks install --target agent` to install this file. The script is
|
|
|
784
784
|
Behavior you can rely on:
|
|
785
785
|
- The handler walks up from the session directory to the nearest directory that holds `.claude/hooks/fallow-gate.sh` and runs the audit there, so a session in a package directory audits the install root. The walk stops at the first `.git` entry. When it finds no script, the handler runs the script under `$CLAUDE_PROJECT_DIR` from the session directory.
|
|
786
786
|
- The hook process can start in a directory that is not the session directory, for example in the main checkout when the session works in a nested git worktree. The script reads the session directory from the `cwd` field of the hook input and finds the audit root from it with the same walk. When the walk finds no script, for example with the user-scope script in `$HOME`, the audit root is the directory of the hook process when it is in the git work tree of the session. Else it is the git top level of the session directory, or the session directory outside a git repository. The audit root is never `$HOME`. The script compares physical paths, so a symlink does not change the walk. When the hook input has no usable `cwd`, the audit runs in the directory of the hook process.
|
|
787
|
-
- A `git commit` or `git push` can name another work tree. The script audits only that target when the command has the strict form `[cd <dir> &&] git [-C <dir>]... commit|push [<option or name>]...` and git reports another work tree for the target (`git rev-parse --show-toplevel --absolute-git-dir` gives a different top level and a different git directory than for the session directory). For a push, the common git directory must differ too: linked worktrees share refs, so a push from another linked worktree of the session repository audits the session tree and the target. A target in the same work tree keeps the session audit, because `git commit` commits the whole index. Each word in the strict form must be inert: a `-C` directory resolves physically as in git, a `cd` directory starts with `/`, `./` or `../`, a double-quoted word holds no `$`, backquote or backslash, and only a short list of options such as `-m`, `--amend`, `-S` and `-u` is allowed. Any other command audits the session tree as before, plus each directory that it names in another work tree. The gate blocks when one audit fails.
|
|
787
|
+
- A `git commit` or `git push` can name another work tree. The script audits only that target when the command has the strict form `[cd <dir> &&] git [-C <dir>]... commit|push [<option or name>]...` and git reports another work tree for the target (`git rev-parse --show-toplevel --absolute-git-dir` gives a different top level and a different git directory than for the session directory). For a push, the common git directory must differ too: linked worktrees share refs, so a push from another linked worktree of the session repository audits the session tree and the target. The one exception is a push that cannot send the session branch: the options are only `-u`, `-q`, `--set-upstream`, `--force-with-lease` and `--force-if-includes`, `git rev-parse --symbolic-full-name` gives the checked-out branch of the target for each refspec source, that branch is not the session branch, and a push without a refspec has `push.default` unset or `simple`, `current`, `upstream` or `nothing` and no remote `push` or `mirror` setting. That push audits only the target. A git error during this check keeps the session audit. A target in the same work tree keeps the session audit, because `git commit` commits the whole index. Each word in the strict form must be inert: a `-C` directory resolves physically as in git, a `cd` directory starts with `/`, `./` or `../`, a double-quoted word holds no `$`, backquote or backslash, and only a short list of options such as `-m`, `--amend`, `-S` and `-u` is allowed. Any other command audits the session tree as before, plus each directory that it names in another work tree. The gate blocks when one audit fails.
|
|
788
788
|
- Runs only when the intercepted command is a `git commit` or `git push`, including invocations that pass git-level options before the subcommand (`git -c user.name=x commit`, `git --no-pager commit`, `git -C dir push`, `git --git-dir=/x push`); anything else exits 0. Set `FALLOW_GATE_DEBUG=1` to log skipped commands to stderr.
|
|
789
789
|
- Resolves `fallow` from PATH first, then `npx --no-install fallow` as a fallback. Skips with a stderr notice if neither is available or if `jq` is missing.
|
|
790
790
|
- Enforces a version floor via `FALLOW_GATE_MIN_VERSION`. The installed gate script holds the default floor (currently `2.85.0`). Fallow maintainers raise that default by hand; `fallow hooks install` does not set it to the installed version. Binaries below the floor are blocked with an upgrade hint. Set the env var to the empty string to disable the check.
|
|
791
|
-
- Runs `fallow audit --format json --quiet --explain --gate-marker agent
|
|
791
|
+
- Runs `fallow audit --format json --quiet --explain --gate-marker agent`. On verdict=`fail`, it writes a short block message to stderr: the line `fallow-gate: blocked by fallow <version> at <binary>`, the verdict, one line for each finding that caused the block (`<kind> <path>:<line> <name>`, at most 50 lines), and the path of the full JSON report. Under the default `gate = "new-only"` the listed findings are the ones with `introduced: true`; under `gate = "all"` they are all findings that are not warnings. The full report goes to `.fallow/gate-report.json` in the audited tree, or to `FALLOW_GATE_REPORT` when set (a relative path resolves against the audited tree). Set `FALLOW_GATE_OUTPUT=json` to write the full JSON envelope to stderr instead, preceded by `fallow-gate: blocked by fallow <version> at <binary>` so the responsible binary is always identifiable. The gate marker lets local Impact record blocked-then-cleared agent gate events when Impact is enabled.
|
|
792
792
|
- On runtime error (`{"error": true, ...}`) or unexpected non-zero exit, fails open with a one-line stderr notice; warn verdicts pass through silently.
|
|
793
793
|
|
|
794
794
|
### `.codex/hooks.json`
|
|
@@ -164,6 +164,10 @@ export type AuditWorsened = ("warn" | "error" | "off")
|
|
|
164
164
|
* is decided here.
|
|
165
165
|
*/
|
|
166
166
|
export type GateStatus = ("pass" | "warn" | "fail" | "skipped")
|
|
167
|
+
/**
|
|
168
|
+
* Why a file counts for the `parse-error` gate, other than a parser error.
|
|
169
|
+
*/
|
|
170
|
+
export type GateFileReason = "nesting-too-deep"
|
|
167
171
|
/**
|
|
168
172
|
* Analysis mode stored with baselines, snapshots, audit sides, and impact data.
|
|
169
173
|
*/
|
|
@@ -411,6 +415,7 @@ export type PolicyViolationSeverity = ("error" | "warn")
|
|
|
411
415
|
* The origin of a stale suppression: inline comment or JSDoc tag.
|
|
412
416
|
*/
|
|
413
417
|
export type SuppressionOrigin = ({
|
|
418
|
+
type: "comment"
|
|
414
419
|
/**
|
|
415
420
|
* The issue kind token from the comment (e.g., "unused-exports"), or None for blanket.
|
|
416
421
|
*/
|
|
@@ -432,8 +437,8 @@ is_file_level: boolean
|
|
|
432
437
|
* adopted the field stay byte-compatible. See issue #449.
|
|
433
438
|
*/
|
|
434
439
|
kind_known?: boolean
|
|
435
|
-
type: "comment"
|
|
436
440
|
} | {
|
|
441
|
+
type: "jsdoc_tag"
|
|
437
442
|
/**
|
|
438
443
|
* The name of the export that was tagged.
|
|
439
444
|
*/
|
|
@@ -442,7 +447,6 @@ export_name: string
|
|
|
442
447
|
* Human-authored reason after `--`, when present.
|
|
443
448
|
*/
|
|
444
449
|
reason?: (string | null)
|
|
445
|
-
type: "jsdoc_tag"
|
|
446
450
|
})
|
|
447
451
|
/**
|
|
448
452
|
* Where an override entry was declared. Serialized as the filename label
|
|
@@ -564,66 +568,67 @@ degrades_analysis?: boolean
|
|
|
564
568
|
export type WorkspaceDiagnostic1 = ({
|
|
565
569
|
kind: "undeclared-workspace"
|
|
566
570
|
} | {
|
|
571
|
+
kind: "malformed-package-json"
|
|
567
572
|
/**
|
|
568
573
|
* `serde_json` parse error text.
|
|
569
574
|
*/
|
|
570
575
|
error: string
|
|
571
|
-
kind: "malformed-package-json"
|
|
572
576
|
} | {
|
|
577
|
+
kind: "glob-matched-no-package-json"
|
|
573
578
|
/**
|
|
574
579
|
* The glob pattern that matched the directory.
|
|
575
580
|
*/
|
|
576
581
|
pattern: string
|
|
577
|
-
kind: "glob-matched-no-package-json"
|
|
578
582
|
} | {
|
|
583
|
+
kind: "workspace-glob-outside-root"
|
|
579
584
|
/**
|
|
580
585
|
* The workspace entry, as written in the file.
|
|
581
586
|
*/
|
|
582
587
|
pattern: string
|
|
583
|
-
kind: "workspace-glob-outside-root"
|
|
584
588
|
} | {
|
|
589
|
+
kind: "workspace-pattern-dir-missing"
|
|
585
590
|
/**
|
|
586
591
|
* The workspace pattern, as written in the file.
|
|
587
592
|
*/
|
|
588
593
|
pattern: string
|
|
589
|
-
kind: "workspace-pattern-dir-missing"
|
|
590
594
|
} | {
|
|
591
595
|
kind: "nested-project-root"
|
|
592
596
|
} | {
|
|
597
|
+
kind: "malformed-tsconfig"
|
|
593
598
|
/**
|
|
594
599
|
* JSONC parse error text.
|
|
595
600
|
*/
|
|
596
601
|
error: string
|
|
597
|
-
kind: "malformed-tsconfig"
|
|
598
602
|
} | {
|
|
599
603
|
kind: "tsconfig-reference-dir-missing"
|
|
600
604
|
} | {
|
|
605
|
+
kind: "malformed-pnpm-workspace-yaml"
|
|
601
606
|
/**
|
|
602
607
|
* YAML parse error text.
|
|
603
608
|
*/
|
|
604
609
|
error: string
|
|
605
|
-
kind: "malformed-pnpm-workspace-yaml"
|
|
606
610
|
} | {
|
|
611
|
+
kind: "skipped-large-file"
|
|
607
612
|
/**
|
|
608
613
|
* On-disk size of the skipped file in bytes.
|
|
609
614
|
*/
|
|
610
615
|
size_bytes: number
|
|
611
|
-
kind: "skipped-large-file"
|
|
612
616
|
} | {
|
|
617
|
+
kind: "skipped-minified-file"
|
|
613
618
|
/**
|
|
614
619
|
* On-disk size of the skipped file in bytes.
|
|
615
620
|
*/
|
|
616
621
|
size_bytes: number
|
|
617
|
-
kind: "skipped-minified-file"
|
|
618
622
|
} | {
|
|
619
623
|
kind: "skipped-source-dotdir"
|
|
620
624
|
} | {
|
|
625
|
+
kind: "source-read-failure"
|
|
621
626
|
/**
|
|
622
627
|
* Filesystem or UTF-8 decoding error from `read_to_string`.
|
|
623
628
|
*/
|
|
624
629
|
error: string
|
|
625
|
-
kind: "source-read-failure"
|
|
626
630
|
} | {
|
|
631
|
+
kind: "source-parse-degraded"
|
|
627
632
|
/**
|
|
628
633
|
* Number of parser diagnostics reported for the file.
|
|
629
634
|
*/
|
|
@@ -633,7 +638,12 @@ error_count: number
|
|
|
633
638
|
* the extracted module is a fragment at best.
|
|
634
639
|
*/
|
|
635
640
|
panicked: boolean
|
|
636
|
-
|
|
641
|
+
} | {
|
|
642
|
+
kind: "source-nesting-too-deep"
|
|
643
|
+
/**
|
|
644
|
+
* The bracket nesting cap of the pre-parse scan.
|
|
645
|
+
*/
|
|
646
|
+
limit: number
|
|
637
647
|
} | {
|
|
638
648
|
kind: "bun-lockb-override-resolution-skipped"
|
|
639
649
|
} | {
|
|
@@ -645,8 +655,8 @@ kind: "npm-lock-override-resolution-skipped"
|
|
|
645
655
|
} | {
|
|
646
656
|
kind: "bun-resolutions-shadowed-by-overrides"
|
|
647
657
|
} | {
|
|
648
|
-
cause: PnpmWorkspaceOverridesIgnoredCause
|
|
649
658
|
kind: "pnpm-workspace-overrides-ignored"
|
|
659
|
+
cause: PnpmWorkspaceOverridesIgnoredCause
|
|
650
660
|
} | {
|
|
651
661
|
kind: "node-modules-missing"
|
|
652
662
|
} | {
|
|
@@ -654,6 +664,7 @@ kind: "boundaries-not-configured"
|
|
|
654
664
|
} | {
|
|
655
665
|
kind: "rule-packs-not-configured"
|
|
656
666
|
} | {
|
|
667
|
+
kind: "excluded-by-default-ignore"
|
|
657
668
|
/**
|
|
658
669
|
* The built-in glob that matched, verbatim (for example
|
|
659
670
|
* `** /build/**`).
|
|
@@ -677,22 +688,22 @@ file_count: number
|
|
|
677
688
|
* one matched location out of several.
|
|
678
689
|
*/
|
|
679
690
|
directory_count: number
|
|
680
|
-
kind: "excluded-by-default-ignore"
|
|
681
691
|
} | {
|
|
692
|
+
kind: "no-source-files-analyzed"
|
|
682
693
|
/**
|
|
683
694
|
* Candidate source files the built-in ignore patterns removed from
|
|
684
695
|
* this walk, summed across every pattern. `0` when the walk found no
|
|
685
696
|
* candidate to exclude in the first place.
|
|
686
697
|
*/
|
|
687
698
|
excluded_file_count: number
|
|
688
|
-
kind: "no-source-files-analyzed"
|
|
689
699
|
} | {
|
|
700
|
+
kind: "file-scores-unavailable"
|
|
690
701
|
/**
|
|
691
702
|
* Scoring error text.
|
|
692
703
|
*/
|
|
693
704
|
error: string
|
|
694
|
-
kind: "file-scores-unavailable"
|
|
695
705
|
} | {
|
|
706
|
+
kind: "hotspots-skipped"
|
|
696
707
|
/**
|
|
697
708
|
* Which input stopped it, as a kebab-case token: `not-a-repository`,
|
|
698
709
|
* `no-commits`, `invalid-since` or `churn-file-unreadable`. The set is
|
|
@@ -706,25 +717,25 @@ kind: "file-scores-unavailable"
|
|
|
706
717
|
* remedy for all four.
|
|
707
718
|
*/
|
|
708
719
|
cause: string
|
|
709
|
-
kind: "hotspots-skipped"
|
|
710
720
|
} | {
|
|
721
|
+
kind: "change-coupling-skipped"
|
|
711
722
|
/**
|
|
712
723
|
* Kebab-case token: `shallow-clone` (the fetched history is
|
|
713
724
|
* incomplete) or `too-few-commits` (fewer analyzed commits than the
|
|
714
725
|
* minimum revisions of one file). The set is open.
|
|
715
726
|
*/
|
|
716
727
|
cause: string
|
|
717
|
-
kind: "change-coupling-skipped"
|
|
718
728
|
} | {
|
|
729
|
+
kind: "shallow-clone"
|
|
719
730
|
/**
|
|
720
731
|
* `true` when the run also asked for ownership attribution, which a
|
|
721
732
|
* shallow clone skews further by inflating single-author dominance.
|
|
722
733
|
*/
|
|
723
734
|
ownership_requested: boolean
|
|
724
|
-
kind: "shallow-clone"
|
|
725
735
|
} | {
|
|
726
736
|
kind: "unpinned-clock"
|
|
727
737
|
} | {
|
|
738
|
+
kind: "ownership-unavailable"
|
|
728
739
|
/**
|
|
729
740
|
* Which input failed, as a kebab-case token: `invalid-bot-pattern` or
|
|
730
741
|
* `codeowners-parse-failed`. The set is open.
|
|
@@ -734,21 +745,21 @@ cause: string
|
|
|
734
745
|
* Underlying error text.
|
|
735
746
|
*/
|
|
736
747
|
error: string
|
|
737
|
-
kind: "ownership-unavailable"
|
|
738
748
|
} | {
|
|
749
|
+
kind: "trend-snapshot-unreadable"
|
|
739
750
|
/**
|
|
740
751
|
* Filesystem or JSON error text.
|
|
741
752
|
*/
|
|
742
753
|
error: string
|
|
743
|
-
kind: "trend-snapshot-unreadable"
|
|
744
754
|
} | {
|
|
755
|
+
kind: "trend-group-baseline-unavailable"
|
|
745
756
|
/**
|
|
746
757
|
* Why the groups have no baseline, as a kebab-case token:
|
|
747
758
|
* `snapshot-has-no-groups` or `grouped-by-mismatch`. The set is open.
|
|
748
759
|
*/
|
|
749
760
|
cause: string
|
|
750
|
-
kind: "trend-group-baseline-unavailable"
|
|
751
761
|
} | {
|
|
762
|
+
kind: "plugin-config-unreadable"
|
|
752
763
|
/**
|
|
753
764
|
* The plugin that read the config, as it labels itself:
|
|
754
765
|
* `module-federation` for a standalone `module-federation.config.*`,
|
|
@@ -775,8 +786,8 @@ key: string
|
|
|
775
786
|
* option the message points at.
|
|
776
787
|
*/
|
|
777
788
|
reason: string
|
|
778
|
-
kind: "plugin-config-unreadable"
|
|
779
789
|
} | {
|
|
790
|
+
kind: "plugin-effect-not-modeled"
|
|
780
791
|
/**
|
|
781
792
|
* The plugin that read the config, as it labels itself (`nuxt`).
|
|
782
793
|
*/
|
|
@@ -795,34 +806,51 @@ key: string
|
|
|
795
806
|
* be classified at all. The set is open.
|
|
796
807
|
*/
|
|
797
808
|
reason: string
|
|
798
|
-
kind: "plugin-effect-not-modeled"
|
|
799
809
|
} | {
|
|
800
810
|
kind: "coverage-auto-detected"
|
|
801
811
|
} | {
|
|
802
812
|
kind: "flag-age-shallow-clone"
|
|
803
813
|
} | {
|
|
814
|
+
kind: "flag-age-unavailable"
|
|
804
815
|
/**
|
|
805
816
|
* Why no history is available, as a kebab-case token:
|
|
806
817
|
* `not-a-repository` or `no-commits`. The set is open.
|
|
807
818
|
*/
|
|
808
819
|
cause: string
|
|
809
|
-
kind: "flag-age-unavailable"
|
|
810
820
|
} | {
|
|
821
|
+
kind: "ignore-dependencies-glob-unmatched"
|
|
811
822
|
/**
|
|
812
823
|
* The `ignoreDependencies` entry, as written in the config.
|
|
813
824
|
*/
|
|
814
825
|
pattern: string
|
|
815
|
-
kind: "ignore-dependencies-glob-unmatched"
|
|
816
826
|
} | {
|
|
827
|
+
kind: "ignore-findings-pattern-unmatched"
|
|
817
828
|
/**
|
|
818
829
|
* The `ignoreFindings` entry, as written in the config.
|
|
819
830
|
*/
|
|
820
831
|
pattern: string
|
|
821
|
-
kind: "ignore-findings-pattern-unmatched"
|
|
822
832
|
} | {
|
|
833
|
+
kind: "entry-pattern-redundant"
|
|
834
|
+
/**
|
|
835
|
+
* The `entry` pattern, as written in the config.
|
|
836
|
+
*/
|
|
837
|
+
pattern: string
|
|
838
|
+
} | {
|
|
839
|
+
kind: "ignore-dependencies-entry-redundant"
|
|
840
|
+
/**
|
|
841
|
+
* The `ignoreDependencies` entry, as written in the config.
|
|
842
|
+
*/
|
|
843
|
+
pattern: string
|
|
844
|
+
} | {
|
|
845
|
+
kind: "ignore-patterns-entry-redundant"
|
|
846
|
+
/**
|
|
847
|
+
* The `ignorePatterns` glob, as written in the config.
|
|
848
|
+
*/
|
|
849
|
+
pattern: string
|
|
850
|
+
} | {
|
|
851
|
+
kind: "baseline-install-state-mismatch"
|
|
823
852
|
baseline_node_modules: NodeModulesState
|
|
824
853
|
run_node_modules: NodeModulesState
|
|
825
|
-
kind: "baseline-install-state-mismatch"
|
|
826
854
|
})
|
|
827
855
|
/**
|
|
828
856
|
* Why the declared pnpm version ignores the `overrides` section of
|
|
@@ -922,6 +950,15 @@ export type WorsenedMetricKind = ("cyclomatic" | "cognitive" | "crap" | "line_co
|
|
|
922
950
|
* Audit-mode reason why a complexity finding does not gate the verdict.
|
|
923
951
|
*/
|
|
924
952
|
export type AuditGateExemption = "test-file"
|
|
953
|
+
/**
|
|
954
|
+
* How `fallow health` counts cyclomatic complexity for its gates.
|
|
955
|
+
*
|
|
956
|
+
* The policy changes the cyclomatic value that the `maxCyclomatic` gate reads
|
|
957
|
+
* and the cyclomatic value in every CRAP score. It does not change the health
|
|
958
|
+
* score, the complexity density, or the hotspot ranking: those keep the
|
|
959
|
+
* standard count so that grades stay comparable across projects.
|
|
960
|
+
*/
|
|
961
|
+
export type CyclomaticPolicy = ("standard" | "literal-membership")
|
|
925
962
|
/**
|
|
926
963
|
* Coverage model used for CRAP score computation.
|
|
927
964
|
*/
|
|
@@ -1189,12 +1226,13 @@ export type DiffRiskActionType = ("suppress-line" | "suppress-file" | "suppress-
|
|
|
1189
1226
|
* `target` block of [`InspectOutput`], tagged by `type`.
|
|
1190
1227
|
*/
|
|
1191
1228
|
export type InspectTargetDescriptor = ({
|
|
1229
|
+
type: "file"
|
|
1192
1230
|
/**
|
|
1193
1231
|
* File path relative to the analysed root.
|
|
1194
1232
|
*/
|
|
1195
1233
|
file: string
|
|
1196
|
-
type: "file"
|
|
1197
1234
|
} | {
|
|
1235
|
+
type: "symbol"
|
|
1198
1236
|
/**
|
|
1199
1237
|
* File path relative to the analysed root.
|
|
1200
1238
|
*/
|
|
@@ -1203,7 +1241,6 @@ file: string
|
|
|
1203
1241
|
* Name of the inspected export.
|
|
1204
1242
|
*/
|
|
1205
1243
|
export_name: string
|
|
1206
|
-
type: "symbol"
|
|
1207
1244
|
})
|
|
1208
1245
|
/**
|
|
1209
1246
|
* `identity` block of [`InspectOutput`]; shape follows the target type.
|
|
@@ -2031,7 +2068,8 @@ files?: GateFile[]
|
|
|
2031
2068
|
*
|
|
2032
2069
|
* Today only `parse-error` emits it. The item carries the same facts as the
|
|
2033
2070
|
* `source-parse-degraded` entry in `workspace_diagnostics[]` for that file,
|
|
2034
|
-
* so a consumer can act on the gate without a join.
|
|
2071
|
+
* so a consumer can act on the gate without a join. With `reason` set, the
|
|
2072
|
+
* count and the parser outcome are placeholders.
|
|
2035
2073
|
*/
|
|
2036
2074
|
export interface GateFile {
|
|
2037
2075
|
/**
|
|
@@ -2039,14 +2077,19 @@ export interface GateFile {
|
|
|
2039
2077
|
*/
|
|
2040
2078
|
path: string
|
|
2041
2079
|
/**
|
|
2042
|
-
* The number of parser errors for the file.
|
|
2080
|
+
* The number of parser errors for the file. `1` when `reason` is set.
|
|
2043
2081
|
*/
|
|
2044
2082
|
error_count: number
|
|
2045
2083
|
/**
|
|
2046
2084
|
* True when the parser stopped in the file instead of recovering, so the
|
|
2047
|
-
* analysis saw only the part before the error.
|
|
2085
|
+
* analysis saw only the part before the error. `true` when `reason` is set.
|
|
2048
2086
|
*/
|
|
2049
2087
|
panicked: boolean
|
|
2088
|
+
/**
|
|
2089
|
+
* Why the file counts when it is not a parser error. Absent for a parser
|
|
2090
|
+
* error, the only reason before this field existed.
|
|
2091
|
+
*/
|
|
2092
|
+
reason?: (GateFileReason | null)
|
|
2050
2093
|
}
|
|
2051
2094
|
/**
|
|
2052
2095
|
* Metric and rule definitions emitted under `_meta` when `--explain` is
|
|
@@ -3431,7 +3474,7 @@ _meta?: (Meta | null)
|
|
|
3431
3474
|
* - source discovery, during the file walk: `skipped-large-file`,
|
|
3432
3475
|
* `skipped-minified-file`, `skipped-source-dotdir`,
|
|
3433
3476
|
* `excluded-by-default-ignore`, `source-read-failure`,
|
|
3434
|
-
* `source-parse-degraded`;
|
|
3477
|
+
* `source-parse-degraded`, `source-nesting-too-deep`;
|
|
3435
3478
|
* - dead-code analysis, from the dependency-catalog and override
|
|
3436
3479
|
* detectors: `malformed-pnpm-workspace-yaml`,
|
|
3437
3480
|
* `bun-lockb-override-resolution-skipped`;
|
|
@@ -3450,10 +3493,11 @@ _meta?: (Meta | null)
|
|
|
3450
3493
|
*
|
|
3451
3494
|
* A diagnostic here is advisory and never withholds a finding. Where an
|
|
3452
3495
|
* entry reports a source file this run never fully analyzed
|
|
3453
|
-
* (`source-parse-degraded`, `source-
|
|
3454
|
-
* `skipped-
|
|
3455
|
-
* verdict, so the affected
|
|
3456
|
-
*
|
|
3496
|
+
* (`source-parse-degraded`, `source-nesting-too-deep`,
|
|
3497
|
+
* `source-read-failure`, `skipped-large-file`, `skipped-minified-file`,
|
|
3498
|
+
* `skipped-source-dotdir`) it can distort a verdict, so the affected
|
|
3499
|
+
* `unused_files[]`, `unused_exports[]`, and dependency entries
|
|
3500
|
+
* additionally carry the caveat themselves in their own
|
|
3457
3501
|
* optional `reachability_caveats[]` array, and a reader who never scrolls
|
|
3458
3502
|
* back up to this list still sees it. `fallow fix` reads the same array
|
|
3459
3503
|
* and withholds the removal while a caveat stands.
|
|
@@ -7987,9 +8031,17 @@ line: number
|
|
|
7987
8031
|
*/
|
|
7988
8032
|
col: number
|
|
7989
8033
|
/**
|
|
7990
|
-
* Cyclomatic complexity of the function
|
|
8034
|
+
* Cyclomatic complexity of the function, as the cyclomatic gate and the
|
|
8035
|
+
* CRAP score read it. Under the `literal-membership` value of
|
|
8036
|
+
* `health.cyclomaticPolicy`, this is the value after literal membership
|
|
8037
|
+
* chains count as one predicate.
|
|
7991
8038
|
*/
|
|
7992
8039
|
cyclomatic: number
|
|
8040
|
+
/**
|
|
8041
|
+
* Standard `McCabe` cyclomatic complexity, present only when the
|
|
8042
|
+
* `health.cyclomaticPolicy` value gave `cyclomatic` a different value.
|
|
8043
|
+
*/
|
|
8044
|
+
standard_cyclomatic?: (number | null)
|
|
7993
8045
|
/**
|
|
7994
8046
|
* Cognitive complexity of the function.
|
|
7995
8047
|
*/
|
|
@@ -8305,6 +8357,15 @@ weight: number
|
|
|
8305
8357
|
* consumer explain a cognitive `+3` as "+1 base, +2 nesting".
|
|
8306
8358
|
*/
|
|
8307
8359
|
nesting: number
|
|
8360
|
+
/**
|
|
8361
|
+
* This cyclomatic `||` increment is part of a literal membership chain:
|
|
8362
|
+
* strict equality checks of one identifier against primitive literals
|
|
8363
|
+
* (`kind === "a" || kind === "b"`). The `literal-membership` value of
|
|
8364
|
+
* `health.cyclomaticPolicy` removes these increments from the effective
|
|
8365
|
+
* cyclomatic value. Omitted when `false`, and always `false` under the
|
|
8366
|
+
* default `standard` policy.
|
|
8367
|
+
*/
|
|
8368
|
+
literal_membership?: boolean
|
|
8308
8369
|
}
|
|
8309
8370
|
/**
|
|
8310
8371
|
* Resolved thresholds used to evaluate a health finding.
|
|
@@ -8435,6 +8496,11 @@ functions_above_threshold: number
|
|
|
8435
8496
|
* Global cyclomatic-complexity ceiling for this run.
|
|
8436
8497
|
*/
|
|
8437
8498
|
max_cyclomatic_threshold: number
|
|
8499
|
+
/**
|
|
8500
|
+
* Cyclomatic policy of the gates (`health.cyclomaticPolicy`). Absent
|
|
8501
|
+
* under the default `standard` policy.
|
|
8502
|
+
*/
|
|
8503
|
+
cyclomatic_policy?: (CyclomaticPolicy | null)
|
|
8438
8504
|
/**
|
|
8439
8505
|
* Global cognitive-complexity ceiling for this run.
|
|
8440
8506
|
*/
|
|
@@ -16769,7 +16835,7 @@ _meta?: (Meta | null)
|
|
|
16769
16835
|
* - source discovery, during the file walk: `skipped-large-file`,
|
|
16770
16836
|
* `skipped-minified-file`, `skipped-source-dotdir`,
|
|
16771
16837
|
* `excluded-by-default-ignore`, `source-read-failure`,
|
|
16772
|
-
* `source-parse-degraded`;
|
|
16838
|
+
* `source-parse-degraded`, `source-nesting-too-deep`;
|
|
16773
16839
|
* - dead-code analysis, from the dependency-catalog and override
|
|
16774
16840
|
* detectors: `malformed-pnpm-workspace-yaml`,
|
|
16775
16841
|
* `bun-lockb-override-resolution-skipped`;
|
|
@@ -16788,10 +16854,11 @@ _meta?: (Meta | null)
|
|
|
16788
16854
|
*
|
|
16789
16855
|
* A diagnostic here is advisory and never withholds a finding. Where an
|
|
16790
16856
|
* entry reports a source file this run never fully analyzed
|
|
16791
|
-
* (`source-parse-degraded`, `source-
|
|
16792
|
-
* `skipped-
|
|
16793
|
-
* verdict, so the affected
|
|
16794
|
-
*
|
|
16857
|
+
* (`source-parse-degraded`, `source-nesting-too-deep`,
|
|
16858
|
+
* `source-read-failure`, `skipped-large-file`, `skipped-minified-file`,
|
|
16859
|
+
* `skipped-source-dotdir`) it can distort a verdict, so the affected
|
|
16860
|
+
* `unused_files[]`, `unused_exports[]`, and dependency entries
|
|
16861
|
+
* additionally carry the caveat themselves in their own
|
|
16795
16862
|
* optional `reachability_caveats[]` array, and a reader who never scrolls
|
|
16796
16863
|
* back up to this list still sees it. `fallow fix` reads the same array
|
|
16797
16864
|
* and withholds the removal while a caveat stands.
|
|
@@ -16829,10 +16896,12 @@ elapsed_ms: ElapsedMs
|
|
|
16829
16896
|
/**
|
|
16830
16897
|
* The verdict of every gate this run evaluated, keyed by name. The CLI
|
|
16831
16898
|
* always emits it, with the default exit rule of each section that ran
|
|
16832
|
-
* (`error-severity-findings`, `health-findings`).
|
|
16899
|
+
* (`error-severity-findings`, `health-findings`). A `coverage-gaps` rule
|
|
16900
|
+
* at `error` adds `health-coverage-gaps`. Without
|
|
16833
16901
|
* `--fail-on-issues` or `--ci`, the machine formats of the combined run
|
|
16834
16902
|
* exit 0 for findings, so most entries have `enforced: false`. With one of
|
|
16835
|
-
* these flags, the findings rules
|
|
16903
|
+
* these flags, the findings rules, `health-coverage-gaps` and
|
|
16904
|
+
* `duplication-threshold` are
|
|
16836
16905
|
* `enforced`, the dupes section adds an enforced `duplication-findings`
|
|
16837
16906
|
* entry, and every format exits 1 when one fails. For the default
|
|
16838
16907
|
* exit rules (`error-severity-findings`,
|
|
@@ -16984,8 +17053,8 @@ total_flags: number
|
|
|
16984
17053
|
* A flags run walks and parses the project like every other analysis, so
|
|
16985
17054
|
* it records the same discovery kinds: a `skipped-large-file`,
|
|
16986
17055
|
* `skipped-minified-file`, or `source-read-failure` file was never
|
|
16987
|
-
* scanned for flags,
|
|
16988
|
-
* a
|
|
17056
|
+
* scanned for flags, a `source-parse-degraded` file was scanned from a
|
|
17057
|
+
* partial module, and a `source-nesting-too-deep` file was not scanned. Each is a reason a flag can be missing from
|
|
16989
17058
|
* `feature_flags[]`, which is exactly what a consumer reading a
|
|
16990
17059
|
* zero-result run needs to know. The analysis-stage kinds appear here
|
|
16991
17060
|
* too: the scan correlates flags with dead exports, so it runs the
|