fallow 2.98.0 → 2.100.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -88,6 +88,23 @@ Fallow gives AI agents structured repo truth instead of forcing them to infer ev
88
88
 
89
89
  Every issue in `--format json` carries a machine-actionable `actions` array with an `auto_fixable` flag so agents can self-correct.
90
90
 
91
+ ### MCP server
92
+
93
+ Agents that speak MCP can launch the bundled `fallow-mcp` server. Installed as a devDependency, the binary lives in `node_modules/.bin/` and is not on your `PATH`, so launch it through your package manager's runner:
94
+
95
+ ```json
96
+ {
97
+ "mcpServers": {
98
+ "fallow": {
99
+ "command": "npx",
100
+ "args": ["fallow-mcp"]
101
+ }
102
+ }
103
+ }
104
+ ```
105
+
106
+ Swap `npx` for `pnpm exec` / `yarn` / `bunx` to match your package manager. If `fallow-mcp` is installed globally (on your `PATH`), `"command": "fallow-mcp"` works directly. See the [MCP integration guide](https://docs.fallow.tools/integrations/mcp).
107
+
91
108
  ## Framework support
92
109
 
93
110
  122 built-in plugins covering Next.js, Nuxt, Remix, Qwik, SvelteKit, Gatsby, Astro, Angular, NestJS, AdonisJS, Ember, Expo Router, Vite, Webpack, Vitest, Jest, Playwright, Cypress, Storybook, ESLint, TypeScript, Tailwind, UnoCSS, Prisma, Drizzle, Convex, Turborepo, Hardhat, and many more. Auto-detected from your `package.json`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fallow",
3
- "version": "2.98.0",
3
+ "version": "2.100.0",
4
4
  "description": "Deterministic codebase intelligence for TypeScript and JavaScript. Quality, risk, architecture, dependencies, duplication, and safe cleanup evidence for humans, CI, and agents. Optional runtime intelligence layer (Fallow Runtime) adds production execution evidence. Rust-native, sub-second, zero-config framework support.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -83,13 +83,13 @@
83
83
  "@tanstack/intent": "0.0.42"
84
84
  },
85
85
  "optionalDependencies": {
86
- "@fallow-cli/darwin-arm64": "2.98.0",
87
- "@fallow-cli/darwin-x64": "2.98.0",
88
- "@fallow-cli/linux-x64-gnu": "2.98.0",
89
- "@fallow-cli/linux-arm64-gnu": "2.98.0",
90
- "@fallow-cli/linux-x64-musl": "2.98.0",
91
- "@fallow-cli/linux-arm64-musl": "2.98.0",
92
- "@fallow-cli/win32-arm64-msvc": "2.98.0",
93
- "@fallow-cli/win32-x64-msvc": "2.98.0"
86
+ "@fallow-cli/darwin-arm64": "2.100.0",
87
+ "@fallow-cli/darwin-x64": "2.100.0",
88
+ "@fallow-cli/linux-x64-gnu": "2.100.0",
89
+ "@fallow-cli/linux-arm64-gnu": "2.100.0",
90
+ "@fallow-cli/linux-x64-musl": "2.100.0",
91
+ "@fallow-cli/linux-arm64-musl": "2.100.0",
92
+ "@fallow-cli/win32-arm64-msvc": "2.100.0",
93
+ "@fallow-cli/win32-x64-msvc": "2.100.0"
94
94
  }
95
95
  }
package/schema.json CHANGED
@@ -178,6 +178,7 @@
178
178
  "coverage-gaps": "off",
179
179
  "feature-flags": "off",
180
180
  "stale-suppressions": "warn",
181
+ "require-suppression-reason": "off",
181
182
  "unused-catalog-entries": "warn",
182
183
  "empty-catalog-groups": "warn",
183
184
  "unresolved-catalog-references": "error",
@@ -234,7 +235,7 @@
234
235
  "default": []
235
236
  },
236
237
  "rulePacks": {
237
- "description": "Paths to declarative rule-pack files (JSON or JSONC), relative to the\nproject root. Each pack declares `banned-call` / `banned-import` rules\nthat report as `policy-violation` findings. Packs are pure data: no\nproject code is executed. Invalid or missing packs fail config load.",
238
+ "description": "Paths to declarative rule-pack files (JSON or JSONC), relative to the\nproject root. Each pack declares `banned-call`, `banned-import`, or\n`banned-effect` rules that report as `policy-violation` findings. Packs\nare pure data: no project code is executed. Invalid or missing packs\nfail config load.",
238
239
  "type": "array",
239
240
  "items": {
240
241
  "type": "string"
@@ -1046,7 +1047,7 @@
1046
1047
  "default": "error"
1047
1048
  },
1048
1049
  "unused-component-props": {
1049
- "description": "Vue `<script setup>` `defineProps` declared prop referenced nowhere\ninside its own single-file component (neither `<script>` nor\n`<template>`). The single-file dead-input direction. Defaults to `warn`,\nnot `error`: a prop can be part of a deliberately-stable public component\nAPI, so analyzer confidence is lower; warn encodes that without failing\nCI.",
1050
+ "description": "Vue `<script setup>` `defineProps`, Svelte 5 `$props()`, or React\ndeclared prop referenced nowhere inside its own component. The\nsingle-component dead-input direction. Defaults to `warn`, not `error`: a\nprop can be part of a deliberately-stable public component API, so\nanalyzer confidence is lower; warn encodes that without failing CI.",
1050
1051
  "$ref": "#/$defs/Severity",
1051
1052
  "default": "error"
1052
1053
  },
@@ -1139,6 +1140,11 @@
1139
1140
  "$ref": "#/$defs/Severity",
1140
1141
  "default": "warn"
1141
1142
  },
1143
+ "require-suppression-reason": {
1144
+ "description": "Opt-in suppression hygiene rule: when enabled, every `fallow-ignore-*`\ncomment and `@expected-unused` tag must carry a `-- <reason>` suffix.",
1145
+ "$ref": "#/$defs/Severity",
1146
+ "default": "off"
1147
+ },
1142
1148
  "unused-catalog-entries": {
1143
1149
  "$ref": "#/$defs/Severity",
1144
1150
  "default": "warn"
@@ -1939,6 +1945,16 @@
1939
1945
  }
1940
1946
  ]
1941
1947
  },
1948
+ "require-suppression-reason": {
1949
+ "anyOf": [
1950
+ {
1951
+ "$ref": "#/$defs/Severity"
1952
+ },
1953
+ {
1954
+ "type": "null"
1955
+ }
1956
+ ]
1957
+ },
1942
1958
  "unused-catalog-entries": {
1943
1959
  "anyOf": [
1944
1960
  {
@@ -95,6 +95,7 @@ Route by intent before reaching for the big analysis commands. Same matrix as `f
95
95
  | `fallow` | Run full codebase analysis: cleanup + duplication + health (default) | `--only`, `--skip`, `--production`, `--production-dead-code`, `--production-health`, `--production-dupes`, `--ci`, `--fail-on-issues`, `--group-by`, `--summary`, `--fail-on-regression`, `--tolerance`, `--regression-baseline`, `--save-regression-baseline`, `--score`, `--trend`, `--save-snapshot`, `--include-entry-exports` |
96
96
  | `dead-code` | Dead code analysis (`check` is an alias) | `--unused-exports`, `--changed-since`, `--changed-workspaces`, `--production`, `--file`, `--include-entry-exports`, `--stale-suppressions`, `--ci`, `--group-by`, `--summary`, `--fail-on-regression`, `--tolerance`, `--regression-baseline`, `--save-regression-baseline` |
97
97
  | `watch` | Watch for changes and re-run analysis | `--no-clear` |
98
+ | `inspect` | Compose one evidence bundle for a file or exported symbol | `--file <path>`, `--symbol <file>:<export>` |
98
99
  | `fix` | Auto-remove unused exports/deps | `--dry-run`, `--yes` (required in non-TTY) |
99
100
  | `init` | Generate config file, AGENTS.md agent guide, or pre-commit hook | `--toml`, `--agents`, `--hooks`, `--branch` |
100
101
  | `hooks` | Inspect, install, or remove fallow-managed Git and agent hooks | `status`, `install --target git`, `install --target agent`, `uninstall --target git`, `uninstall --target agent` |
@@ -150,7 +151,7 @@ Run `fallow <command> --help` for the full flag list per command (see also refer
150
151
  | `boundary-violation` | `--boundary-violations` | - | `// fallow-ignore-next-line boundary-violation` | Imports crossing architecture zone boundaries. Presets: `layered`, `hexagonal`, `feature-sliced`, `bulletproof`; `autoDiscover` can create one zone per feature directory; per-rule `allowTypeOnly: [zones]` admits `import type` / `export type` crossings while still blocking value imports. Optional sections: `boundaries.coverage.requireAllFiles` reports unzoned source files (`allowUnmatched` globs exempt intentional ones), and `boundaries.calls.forbidden` bans callee patterns per zone (segment-aware and import-resolved, so `child_process.*` covers `node:child_process` named/namespace/default imports; direct callees only, zoned files only). The whole family shares the `boundary-violation` rule and suppression token (`boundary-call-violation` and `boundary-call-violations` accepted as aliases); start the rule at `warn` for a staged rollout |
151
152
  | `boundary-coverage` | - | - | `// fallow-ignore-file boundary-violation` | Source file matches no configured architecture boundary zone; Requires boundaries.coverage.requireAllFiles |
152
153
  | `boundary-call-violation` | - | - | `// fallow-ignore-next-line boundary-call-violation` | Zoned file calls a callee its zone forbids; Requires boundaries.calls.forbidden patterns |
153
- | `policy-violation` | `--policy-violations` | - | `// fallow-ignore-next-line policy-violation` | Calls or imports banned by a declarative rule pack (`rulePacks` config key lists standalone JSON/JSONC files of `banned-call` / `banned-import` rules; pure data, no project code executes). Findings identified as `<pack>/<rule-id>`. Default `warn` master; per-rule `severity` overrides per finding and the exit gate reads the effective severity. Invalid or missing packs fail config load with exit 2. `fallow rule-pack-schema` prints the pack JSON Schema. Use the scoped token to suppress one rule; bare `policy-violation` still covers every pack rule on the line or file. |
154
+ | `policy-violation` | `--policy-violations` | - | `// fallow-ignore-next-line policy-violation` | Calls, imports, or catalogue-derived effects banned by a declarative rule pack (`rulePacks` config key lists standalone JSON/JSONC files of `banned-call`, `banned-import`, and `banned-effect` rules; pure data, no project code executes). Findings identified as `<pack>/<rule-id>`. Default `warn` master; per-rule `severity` overrides per finding and the exit gate reads the effective severity. Invalid or missing packs fail config load with exit 2. `fallow rule-pack-schema` prints the pack JSON Schema. Use the scoped token to suppress one rule; bare `policy-violation` still covers every pack rule on the line or file. |
154
155
  | `stale-suppression` | `--stale-suppressions` | - | - | `fallow-ignore` comments or `@expected-unused` JSDoc tags that no longer match any issue |
155
156
  | `unused-catalog-entry` | `--unused-catalog-entries` | yes | - | `pnpm-workspace.yaml` entries no workspace package.json references via `catalog:` (default `warn`) |
156
157
  | `empty-catalog-group` | `--empty-catalog-groups` | - | - | Named `catalogs.<name>:` groups in `pnpm-workspace.yaml` with no entries. Top-level `catalog:` placeholders are ignored. Default `warn`. |
@@ -172,8 +173,8 @@ Run `fallow <command> --help` for the full flag list per command (see also refer
172
173
  | `prop-drilling` | - | - | `// fallow-ignore-next-line prop-drilling` | A React/Preact prop is forwarded unchanged through 3+ pass-through components to a distant consumer; Opt-in: set rules.prop-drilling to warn or error to enable. Defaults to off. |
173
174
  | `thin-wrapper` | - | - | `// fallow-ignore-next-line thin-wrapper` | A React/Preact component whose whole body is a single spread-forwarded child render (a candidate for inlining); Opt-in: set rules.thin-wrapper to warn or error to enable. Defaults to off. |
174
175
  | `duplicate-prop-shape` | - | - | `// fallow-ignore-next-line duplicate-prop-shape` | Three or more React/Preact components across two or more files declare an identical prop-name set (a missing shared Props type); Opt-in: set rules.duplicate-prop-shape to warn or error to enable. Defaults to off. |
175
- | `route-collision` | - | - | - | Two or more Next.js App Router route files resolve to the same URL |
176
- | `dynamic-segment-name-conflict` | - | - | - | Sibling Next.js dynamic route segments use different slug names at the same position |
176
+ | `route-collision` | - | - | `// fallow-ignore-file route-collision` | Two or more Next.js App Router route files resolve to the same URL |
177
+ | `dynamic-segment-name-conflict` | - | - | `// fallow-ignore-file dynamic-segment-name-conflict` | Sibling Next.js dynamic route segments use different slug names at the same position |
177
178
  | `high-cyclomatic-complexity` | `--complexity` | - | `// fallow-ignore-next-line complexity` | Function has high cyclomatic complexity |
178
179
  | `high-cognitive-complexity` | `--complexity` | - | `// fallow-ignore-next-line complexity` | Function has high cognitive complexity |
179
180
  | `high-complexity` | `--complexity` | - | `// fallow-ignore-next-line complexity` | Function exceeds both complexity thresholds |
@@ -198,7 +199,7 @@ When using fallow via MCP (`fallow-mcp`), the following tools are available:
198
199
  | Tool | Kind | License | Key params | Description |
199
200
  |---|---|---|---|---|
200
201
  | `code_execute` | composition | free | `code`, `timeout_ms`, `max_output_bytes` | Bounded read-only Code Mode for composing multiple fallow analysis calls in one JavaScript snippet. The snippet receives `{ fallow, root }`, returns JSON-serializable data, and can call read-only helpers such as `fallow.projectInfo`, `fallow.audit`, `fallow.checkHealth`, and `fallow.run(tool, params)` for the same allowlist. Mutating fix tools are not exposed. The sandbox has no filesystem, network, imports, `eval`, `Function`, `process`, `require`, `Deno`, `Bun`, or shell access. Params: `code`, optional `root`, `timeout_ms` (capped at 30000), and `max_output_bytes` (capped at 4000000). |
201
- | `analyze` | analysis | free | `issue_types`, `production`, `workspace`, `baseline`, `group_by`, `file` | Full dead code analysis (unused files/exports/types/dependencies/members + circular dependencies + re-export cycles (barrel files that form a structural loop, silently breaking re-exports) + boundary violations + rule-pack policy violations (banned calls and banned imports declared via the `rulePacks` config key) + stale suppressions). Private type leaks are an opt-in API hygiene check via `issue_types: ["private-type-leaks"]`. Set `boundary_violations: true` as a convenience alias for `issue_types: ["boundary-violations"]`. Set `group_by` to `"owner"`, `"directory"`, `"package"`, or `"section"` to partition results. The `section` mode reads GitLab CODEOWNERS `[Section]` headers and emits `owners` metadata per group |
202
+ | `analyze` | analysis | free | `issue_types`, `production`, `workspace`, `baseline`, `group_by`, `file` | Full dead code analysis (unused files/exports/types/dependencies/members + circular dependencies + re-export cycles (barrel files that form a structural loop, silently breaking re-exports) + boundary violations + rule-pack policy violations (banned calls, imports, and catalogue-derived effects declared via the `rulePacks` config key) + stale suppressions). Private type leaks are an opt-in API hygiene check via `issue_types: ["private-type-leaks"]`. Set `boundary_violations: true` as a convenience alias for `issue_types: ["boundary-violations"]`. Set `group_by` to `"owner"`, `"directory"`, `"package"`, or `"section"` to partition results. The `section` mode reads GitLab CODEOWNERS `[Section]` headers and emits `owners` metadata per group |
202
203
  | `check_changed` | analysis | free | `since`, `baseline`, `fail_on_regression` | Incremental analysis of files changed since a git ref |
203
204
  | `security_candidates` | analysis | free | `gate`, `surface`, `changed_since`, `paths` | Unverified local security candidates, not confirmed vulnerabilities (`fallow security --format json`). Read `security_findings[]` for category, CWE, severity, evidence, trace, optional `reachability`, blind-spot counters, and optional `unresolved_callee_diagnostics` samples for dynamic callee follow-up. `severity` is a review-priority tier, not a verified vulnerability verdict. Each finding also carries an agent-actionable `candidate` (`source_kind`/`sink`/`boundary`), where URL-category sinks may include `url_shape` (`fixed-origin-dynamic-path` or `dynamic-origin`), an optional `taint_flow` source-to-sink triple, and a stable `finding_id` (equal to the SARIF fingerprint) for cross-run correlation; there is no `impact` field (deciding exploitability is the agent's job). Set `surface: true` to include top-level `attack_surface[]` entries with defensive-boundary prompts for a verifier. Set `gate` to `new` for changed-line candidates or `newly-reachable` for candidates that became reachable from entry points; `newly-reachable` requires `changed_since`. `reachability.untrusted_source_trace` is module-level import context only and does not prove value flow; `reachability.taint_confidence` tiers each reachable candidate as `arg-level` (sink argument traces to a same-module source read, strong) or `module-level` (only the module is import-reachable from a source, weak), so tier from this field instead of the evidence text. Verify trace, reachability context, severity, and evidence before editing code. Supports `root`, `config`, `workspace`, `paths`, `changed_since`, `changed_workspaces`, `surface`, `gate`, `no_cache`, and `threads`; `paths` forwards repeated `fallow security --file` filters for finding anchors, trace hops, untrusted-source reachability trace hops, and unresolved-callee diagnostics. See <https://docs.fallow.tools/cli/security-agent-verification> for the verifier packet and verdict recipe. Inherits `FALLOW_DIFF_FILE` from the server environment for line-level diff scoping; raise `FALLOW_TIMEOUT_SECS` for large repos. |
204
205
  | `inspect_target` | analysis | free | `target`, `production` | 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. Evidence sections carry `status` and `scope`; symbol targets warn when supporting evidence is file-scoped. Supports `root`, `config`, `production`, `workspace`, `no_cache`, and `threads`; `production` applies to trace, dead-code, and health evidence only. Raise `FALLOW_TIMEOUT_SECS` for large repos. |
@@ -16,6 +16,7 @@ Complete command and flag specifications for all fallow CLI commands.
16
16
  - [`audit`: Changed-File Quality Gate](#audit-changed-file-quality-gate)
17
17
  - [`flags`: Feature Flag Detection](#flags-feature-flag-detection)
18
18
  - [`security`: Security Candidate Detection](#security-security-candidate-detection)
19
+ - [`inspect`: Target Evidence Bundle](#inspect-target-evidence-bundle)
19
20
  - [`explain`: Rule Explanation](#explain-rule-explanation)
20
21
  - [`schema`: CLI Introspection](#schema-cli-introspection)
21
22
  - [`config-schema`: Config JSON Schema](#config-schema-config-json-schema)
@@ -77,7 +78,7 @@ Common global flags for this command: [`--format`](#global-flags), [`--quiet`](#
77
78
  | `--circular-deps` | Circular dependencies |
78
79
  | `--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). |
79
80
  | `--boundary-violations` | Boundary violations (imports crossing architecture zone boundaries, unzoned source files when `boundaries.coverage.requireAllFiles` is set, and forbidden calls from `boundaries.calls.forbidden`; suppression token `boundary-violation`, with `boundary-call-violation` and `boundary-call-violations` accepted as aliases for the whole family) |
80
- | `--policy-violations` | Rule-pack policy violations (banned calls and banned imports declared via the `rulePacks` config key) |
81
+ | `--policy-violations` | Rule-pack policy violations (banned calls, imports, and catalogue-derived effects declared via the `rulePacks` config key) |
81
82
  | `--stale-suppressions` | Stale suppression comments or `@expected-unused` JSDoc tags |
82
83
  | `--unused-catalog-entries` | Unused pnpm catalog entries |
83
84
  | `--empty-catalog-groups` | Empty named pnpm catalog groups |
@@ -504,7 +505,7 @@ fallow health --format json --quiet --trend
504
505
  {
505
506
  "kind": "health",
506
507
  "schema_version": 7,
507
- "version": "2.98.0",
508
+ "version": "2.100.0",
508
509
  "elapsed_ms": 32,
509
510
  "summary": {
510
511
  "files_analyzed": 482,
@@ -891,7 +892,7 @@ fallow audit \
891
892
  {
892
893
  "kind": "audit",
893
894
  "schema_version": 7,
894
- "version": "2.98.0",
895
+ "version": "2.100.0",
895
896
  "command": "audit",
896
897
  "verdict": "fail",
897
898
  "changed_files_count": 12,
@@ -966,7 +967,7 @@ fallow flags --format json --quiet --workspace my-package
966
967
  ```json
967
968
  {
968
969
  "schema_version": 7,
969
- "version": "2.98.0",
970
+ "version": "2.100.0",
970
971
  "elapsed_ms": 116,
971
972
  "feature_flags": [],
972
973
  "total_flags": 0
@@ -1066,7 +1067,7 @@ fallow security --gate newly-reachable --changed-since origin/main
1066
1067
  {
1067
1068
  "kind": "security",
1068
1069
  "schema_version": "4",
1069
- "version": "2.98.0",
1070
+ "version": "2.100.0",
1070
1071
  "elapsed_ms": 42,
1071
1072
  "config": {
1072
1073
  "rules": {
@@ -1095,7 +1096,7 @@ fallow security --gate newly-reachable --changed-since origin/main
1095
1096
  {
1096
1097
  "kind": "security",
1097
1098
  "schema_version": "4",
1098
- "version": "2.98.0",
1099
+ "version": "2.100.0",
1099
1100
  "elapsed_ms": 42,
1100
1101
  "config": {
1101
1102
  "rules": {
@@ -1159,6 +1160,55 @@ Every finding also carries an agent-actionable `candidate { source_kind, sink, b
1159
1160
 
1160
1161
  ---
1161
1162
 
1163
+ ## `inspect`: Target Evidence Bundle
1164
+
1165
+ Compose one evidence bundle before editing a file or exported symbol. This is the CLI equivalent of the MCP `inspect_target` tool.
1166
+
1167
+ ### Usage
1168
+
1169
+ ```bash
1170
+ fallow inspect --file src/api.ts --format json --quiet
1171
+ fallow inspect --symbol src/api.ts:fetchUser --format json --quiet
1172
+ ```
1173
+
1174
+ ### Target Flags
1175
+
1176
+ | Flag | Description |
1177
+ |------|-------------|
1178
+ | `--file <PATH>` | Inspect one project-relative file |
1179
+ | `--symbol <FILE:EXPORT>` | Inspect one exported symbol. Supporting dead-code, duplication, complexity, and security evidence is file-scoped in the first version |
1180
+
1181
+ Common global flags: `--format`, `--quiet`, `--root`, `--config`, `--workspace`, `--production`, `--no-cache`, `--threads`.
1182
+
1183
+ ### JSON Output Structure
1184
+
1185
+ ```json
1186
+ {
1187
+ "kind": "inspect_target",
1188
+ "target": { "type": "file", "file": "src/api.ts" },
1189
+ "identity": {
1190
+ "file": "src/api.ts",
1191
+ "is_reachable": true,
1192
+ "is_entry_point": false,
1193
+ "export_count": 3,
1194
+ "import_count": 2,
1195
+ "imported_by_count": 1
1196
+ },
1197
+ "evidence": {
1198
+ "trace_file": { "status": "ok", "scope": "file", "data": {} },
1199
+ "dead_code": { "status": "ok", "scope": "file", "data": {} },
1200
+ "duplication": { "status": "ok", "scope": "project_filtered_to_file", "data": {} },
1201
+ "complexity": { "status": "ok", "scope": "project_filtered_to_file", "data": {} },
1202
+ "security": { "status": "ok", "scope": "file", "data": {} }
1203
+ },
1204
+ "warnings": []
1205
+ }
1206
+ ```
1207
+
1208
+ Each evidence section carries `status` and `scope`. Non-fatal child-analysis failures become section-level errors and warnings, so callers can still use the remaining evidence.
1209
+
1210
+ ---
1211
+
1162
1212
  ## `explain`: Rule Explanation
1163
1213
 
1164
1214
  Print rule rationale, examples, fix guidance, and docs URL for one issue type without running analysis.
@@ -1645,7 +1695,7 @@ Set `FALLOW_FORMAT=json` and `FALLOW_QUIET=1` in your agent environment to avoid
1645
1695
  | `human` | Colored terminal output | Interactive use |
1646
1696
  | `json` | Machine-readable JSON | Agent integration, CI pipelines |
1647
1697
  | `sarif` | Static Analysis Results Interchange Format | GitHub Code Scanning, SARIF-compatible tools |
1648
- | `compact` | Grep-friendly: `type:path:line:name` per line | Quick filtering |
1698
+ | `compact` | Grep-friendly: one issue per line. Dupes lines include `code-duplication:path:start-end:fingerprint=dup:<id>,...` | Quick filtering |
1649
1699
  | `markdown` | Markdown tables | Documentation, PR comments |
1650
1700
  | `codeclimate` / `gitlab-codequality` | CodeClimate JSON array | GitLab Code Quality, CodeClimate-compatible tools |
1651
1701
  | `pr-comment-github` / `pr-comment-gitlab` | Sticky PR/MR comment markdown with HTML-comment marker for upsert | Posted by the action / template `comment.sh` scripts |
@@ -1712,7 +1762,7 @@ The HTTP layer mirrors the bash `gh_api_retry` / `curl_retry` helpers: `FALLOW_A
1712
1762
  {
1713
1763
  "kind": "dead-code",
1714
1764
  "schema_version": 7,
1715
- "version": "2.98.0",
1765
+ "version": "2.100.0",
1716
1766
  "elapsed_ms": 45,
1717
1767
  "total_issues": 12,
1718
1768
  "entry_points": {
@@ -1872,7 +1922,7 @@ When `--baseline` is used in combined output, the JSON includes a `baseline_delt
1872
1922
  {
1873
1923
  "kind": "dupes",
1874
1924
  "schema_version": 7,
1875
- "version": "2.98.0",
1925
+ "version": "2.100.0",
1876
1926
  "elapsed_ms": 82,
1877
1927
  "total_clones": 15,
1878
1928
  "total_lines_duplicated": 230,
@@ -1916,11 +1966,11 @@ When running `fallow` with no subcommand (all analyses), the JSON output combine
1916
1966
  {
1917
1967
  "kind": "combined",
1918
1968
  "schema_version": 7,
1919
- "version": "2.98.0",
1969
+ "version": "2.100.0",
1920
1970
  "elapsed_ms": 159,
1921
1971
  "check": {
1922
1972
  "schema_version": 7,
1923
- "version": "2.98.0",
1973
+ "version": "2.100.0",
1924
1974
  "elapsed_ms": 45,
1925
1975
  "total_issues": 12,
1926
1976
  "unused_files": [],
@@ -25,7 +25,7 @@
25
25
 
26
26
 
27
27
  /**
28
- * Schemas for the JSON output of fallow commands. Object-shaped envelopes covered by the `FallowOutput` contract carry a top-level `kind` discriminator (for example `dead-code`, `dead-code-grouped`, `health`, `dupes`, `combined`, `audit`, `explain`, `impact`, `security`, `coverage-setup`, `coverage-analyze`, `list-boundaries`, `review-envelope`, and `review-reconcile`). Consumers should branch on `kind` instead of probing for unique field presence. `--legacy-envelope` removes only the document-root `kind` for one compatibility cycle. `CodeClimateOutput` is a bare JSON array (per the Code Climate / GitLab Code Quality spec) and stays a sibling root branch discriminated by checking whether the document root is an array.
28
+ * Schemas for the JSON output of fallow commands. Object-shaped envelopes covered by the `FallowOutput` contract carry a top-level `kind` discriminator (for example `dead-code`, `dead-code-grouped`, `health`, `dupes`, `combined`, `audit`, `explain`, `inspect_target`, `impact`, `security`, `coverage-setup`, `coverage-analyze`, `list-boundaries`, `review-envelope`, and `review-reconcile`). Consumers should branch on `kind` instead of probing for unique field presence. `--legacy-envelope` removes only the document-root `kind` for one compatibility cycle. `CodeClimateOutput` is a bare JSON array (per the Code Climate / GitLab Code Quality spec) and stays a sibling root branch discriminated by checking whether the document root is an array.
29
29
  */
30
30
  export type FallowJsonOutput = (FallowOutput | CodeClimateOutput)
31
31
  /**
@@ -51,6 +51,8 @@ export type FallowOutput = ((AuditOutput & {
51
51
  kind: "audit"
52
52
  }) | (ExplainOutput & {
53
53
  kind: "explain"
54
+ }) | (InspectOutput & {
55
+ kind: "inspect_target"
54
56
  }) | (ReviewEnvelopeOutput & {
55
57
  kind: "review-envelope"
56
58
  }) | (ReviewReconcileOutput & {
@@ -75,6 +77,10 @@ kind: "impact"
75
77
  kind: "impact-cross-repo"
76
78
  }) | ((SecurityOutput | SecuritySummaryOutput) & {
77
79
  kind: "security"
80
+ }) | (SecuritySurvivorsOutput & {
81
+ kind: "security-survivors"
82
+ }) | (SecurityBlindSpotsOutput & {
83
+ kind: "security-blind-spots"
78
84
  }) | (CheckOutput & {
79
85
  kind: "dead-code"
80
86
  }) | (CombinedOutput & {
@@ -138,10 +144,12 @@ export type AuditGate = ("new-only" | "all")
138
144
  * Current per-instance flips:
139
145
  *
140
146
  * - `remove-catalog-entry` (`unused-catalog-entries`): `true` only when the
141
- * finding's `hardcoded_consumers` array is empty. When a workspace
142
- * package still pins a hardcoded version of the same package, `fallow fix`
143
- * skips the entry to avoid breaking `pnpm install`, and the action is
144
- * emitted with `auto_fixable: false`.
147
+ * finding's `hardcoded_consumers` array is empty and the source is
148
+ * `pnpm-workspace.yaml`. When a workspace package still pins a hardcoded
149
+ * version of the same package, `fallow fix` skips the entry to avoid
150
+ * breaking `pnpm install`. Bun `package.json` catalog entries are also
151
+ * emitted with `auto_fixable: false` because the current fixer is
152
+ * YAML-only.
145
153
  * - `remove-dependency` vs `move-dependency` (dependency findings): when the
146
154
  * finding's `used_in_workspaces` array is non-empty, the primary action
147
155
  * flips to `move-dependency` with `auto_fixable: false` (`fallow fix` will
@@ -172,7 +180,7 @@ export type IssueAction = (FixAction | SuppressLineAction | SuppressFileAction |
172
180
  * Discriminant string for [`FixAction`]. Kebab-case per the JSON output
173
181
  * contract.
174
182
  */
175
- export type FixActionType = ("remove-export" | "delete-file" | "remove-dependency" | "move-dependency" | "remove-enum-member" | "remove-class-member" | "resolve-import" | "install-dependency" | "remove-duplicate" | "move-to-dev" | "refactor-cycle" | "refactor-re-export-cycle" | "refactor-boundary" | "export-type" | "remove-catalog-entry" | "remove-empty-catalog-group" | "update-catalog-reference" | "add-catalog-entry" | "remove-catalog-reference" | "remove-dependency-override" | "fix-dependency-override" | "resolve-policy-violation" | "move-to-server-module" | "split-mixed-barrel" | "hoist-directive" | "wire-server-action" | "provide-inject" | "use-load-data" | "render-component" | "use-component-prop" | "emit-component-event" | "wire-svelte-event" | "resolve-route-collision" | "resolve-dynamic-segment-name-conflict")
183
+ export type FixActionType = ("remove-export" | "delete-file" | "remove-dependency" | "move-dependency" | "remove-enum-member" | "remove-class-member" | "resolve-import" | "install-dependency" | "remove-duplicate" | "move-to-dev" | "refactor-cycle" | "refactor-re-export-cycle" | "refactor-boundary" | "export-type" | "remove-catalog-entry" | "remove-empty-catalog-group" | "update-catalog-reference" | "add-catalog-entry" | "remove-catalog-reference" | "remove-dependency-override" | "fix-dependency-override" | "resolve-policy-violation" | "move-to-server-module" | "split-mixed-barrel" | "hoist-directive" | "wire-server-action" | "provide-inject" | "use-load-data" | "render-component" | "use-component-prop" | "emit-component-event" | "wire-svelte-event" | "resolve-route-collision" | "resolve-dynamic-segment-name-conflict" | "add-suppression-reason" | "remove-stale-suppression")
176
184
  /**
177
185
  * Singleton discriminant for [`SuppressLineAction`].
178
186
  */
@@ -237,7 +245,7 @@ export type ReExportCycleKind = ("multi-node" | "self-loop")
237
245
  /**
238
246
  * Which rule-pack rule kind produced a [`PolicyViolation`].
239
247
  */
240
- export type PolicyRuleKind = ("banned-call" | "banned-import")
248
+ export type PolicyRuleKind = ("banned-call" | "banned-import" | "banned-effect")
241
249
  /**
242
250
  * Effective severity of a single [`PolicyViolation`]. Per-rule `severity`
243
251
  * overrides the `rules."policy-violation"` master; `off` rules emit nothing,
@@ -253,6 +261,10 @@ export type SuppressionOrigin = ({
253
261
  * The issue kind token from the comment (e.g., "unused-exports"), or None for blanket.
254
262
  */
255
263
  issue_kind?: (string | null)
264
+ /**
265
+ * Human-authored reason after `--`, when present.
266
+ */
267
+ reason?: (string | null)
256
268
  /**
257
269
  * Whether this was a file-level suppression.
258
270
  */
@@ -272,6 +284,10 @@ type: "comment"
272
284
  * The name of the export that was tagged.
273
285
  */
274
286
  export_name: string
287
+ /**
288
+ * Human-authored reason after `--`, when present.
289
+ */
290
+ reason?: (string | null)
275
291
  type: "jsdoc_tag"
276
292
  })
277
293
  /**
@@ -563,6 +579,10 @@ export type RefactoringTargetActionType = ("apply-refactoring" | "suppress-line"
563
579
  * Direction of a metric's change, semantically (improving/declining/stable).
564
580
  */
565
581
  export type TrendDirection = ("improving" | "declining" | "stable")
582
+ /**
583
+ * Detector status codes for framework health observability.
584
+ */
585
+ export type FrameworkHealthDetectorStatus = ("active" | "disabled_by_config" | "abstained" | "not_checked")
566
586
  /**
567
587
  * Discriminant for [`CssCandidateAction::kind`].
568
588
  */
@@ -571,6 +591,17 @@ export type CssCandidateActionType = ("verify-unused" | "verify-undefined" | "co
571
591
  * Discriminant for [`UnusedAtRule::kind`].
572
592
  */
573
593
  export type UnusedAtRuleKind = ("property-registration" | "layer")
594
+ export type InspectTargetDescriptor = ({
595
+ file: string
596
+ type: "file"
597
+ } | {
598
+ file: string
599
+ export_name: string
600
+ type: "symbol"
601
+ })
602
+ export type InspectIdentity = (InspectFileIdentity | InspectSymbolIdentity)
603
+ export type InspectSectionStatus = ("ok" | "error")
604
+ export type InspectEvidenceScope = ("symbol" | "file" | "project_filtered_to_file")
574
605
  /**
575
606
  * Singleton GitHub review-event marker.
576
607
  */
@@ -720,6 +751,18 @@ export type SkippedSecurityCalleeReason = ("computed-member" | "dynamic-dispatch
720
751
  * Syntactic expression shape for a skipped security callee.
721
752
  */
722
753
  export type SkippedSecurityCalleeExpressionKind = ("static-member-expression" | "computed-member-expression" | "identifier" | "other")
754
+ /**
755
+ * The `fallow security survivors --format json` schema version.
756
+ */
757
+ export type SecuritySurvivorsSchemaVersion = "2"
758
+ /**
759
+ * Verifier verdict status accepted by `fallow security survivors`.
760
+ */
761
+ export type SecurityVerifierVerdictStatus = ("survivor" | "dismissed" | "needs-human-review")
762
+ /**
763
+ * The `fallow security blind-spots --format json` schema version.
764
+ */
765
+ export type SecurityBlindSpotsSchemaVersion = "1"
723
766
  /**
724
767
  * Discriminator value for [`CodeClimateIssue::kind`].
725
768
  */
@@ -1021,7 +1064,8 @@ boundary_coverage_violations?: BoundaryCoverageViolationFinding[]
1021
1064
  */
1022
1065
  boundary_call_violations?: BoundaryCallViolationFinding[]
1023
1066
  /**
1024
- * Banned calls and banned imports matched by declarative rule packs
1067
+ * Banned calls, imports, and catalogue-derived effects matched by
1068
+ * declarative rule packs
1025
1069
  * (`rulePacks` config). Wrapped in [`PolicyViolationFinding`] so each
1026
1070
  * entry carries a typed `actions` array natively. Each finding carries
1027
1071
  * its effective per-rule severity.
@@ -1032,24 +1076,25 @@ policy_violations?: PolicyViolationFinding[]
1032
1076
  */
1033
1077
  stale_suppressions?: StaleSuppression[]
1034
1078
  /**
1035
- * Entries in pnpm-workspace.yaml's catalog: or catalogs: sections not
1036
- * referenced by any workspace package via the catalog: protocol. Wrapped
1037
- * in [`UnusedCatalogEntryFinding`] so each entry carries a typed
1079
+ * Entries in package manager catalog sections not referenced by any
1080
+ * workspace package via the catalog: protocol. Supports
1081
+ * `pnpm-workspace.yaml` catalogs and Bun root `package.json` catalogs.
1082
+ * Wrapped in [`UnusedCatalogEntryFinding`] so each entry carries a typed
1038
1083
  * `actions` array natively, with per-instance `auto_fixable` derived
1039
- * from `hardcoded_consumers`.
1084
+ * from `hardcoded_consumers` and the catalog source file.
1040
1085
  */
1041
1086
  unused_catalog_entries?: UnusedCatalogEntryFinding[]
1042
1087
  /**
1043
- * Named groups under pnpm-workspace.yaml's catalogs: section that declare
1044
- * no package entries. The top-level catalog: map is not reported. Wrapped
1045
- * in [`EmptyCatalogGroupFinding`].
1088
+ * Named groups under package manager catalogs sections that declare no
1089
+ * package entries. The top-level catalog: map is not reported. Wrapped in
1090
+ * [`EmptyCatalogGroupFinding`].
1046
1091
  */
1047
1092
  empty_catalog_groups?: EmptyCatalogGroupFinding[]
1048
1093
  /**
1049
1094
  * Workspace package.json references to catalogs (`catalog:` or
1050
- * `catalog:<name>`) that do not declare the consumed package. pnpm install
1051
- * will error until the named catalog grows to include the package or the
1052
- * reference is switched / removed. Wrapped in
1095
+ * `catalog:<name>`) that do not declare the consumed package. The package
1096
+ * manager install will error until the named catalog grows to include the
1097
+ * package or the reference is switched / removed. Wrapped in
1053
1098
  * [`UnresolvedCatalogReferenceFinding`] with the discriminated
1054
1099
  * `add-catalog-entry` / `update-catalog-reference` primary at position 0.
1055
1100
  */
@@ -1121,8 +1166,8 @@ route_collisions?: RouteCollisionFinding[]
1121
1166
  */
1122
1167
  dynamic_segment_name_conflicts?: DynamicSegmentNameConflictFinding[]
1123
1168
  /**
1124
- * Vue `<script setup>` `defineProps` props referenced nowhere in their own
1125
- * SFC (neither `<script>` nor `<template>`). Wrapped in
1169
+ * Vue `<script setup>` `defineProps`, Svelte 5 `$props()`, and React props
1170
+ * referenced nowhere in their own component. Wrapped in
1126
1171
  * [`UnusedComponentPropFinding`] so each entry carries a typed `actions`
1127
1172
  * array natively. Default severity is `warn`.
1128
1173
  */
@@ -1292,7 +1337,7 @@ unprovided_injects?: number
1292
1337
  */
1293
1338
  unrendered_components?: number
1294
1339
  /**
1295
- * Vue `<script setup>` props referenced nowhere inside their own SFC.
1340
+ * Vue, Svelte, or React props referenced nowhere inside their own component.
1296
1341
  */
1297
1342
  unused_component_props?: number
1298
1343
  /**
@@ -1365,7 +1410,8 @@ boundary_coverage_violations?: number
1365
1410
  */
1366
1411
  boundary_call_violations?: number
1367
1412
  /**
1368
- * Banned calls and banned imports matched by declarative rule packs.
1413
+ * Banned calls, imports, and catalogue-derived effects matched by
1414
+ * declarative rule packs.
1369
1415
  */
1370
1416
  policy_violations?: number
1371
1417
  /**
@@ -1452,11 +1498,12 @@ type: FixActionType
1452
1498
  * FINDING, not per action type: the same `type` may carry
1453
1499
  * `auto_fixable: true` on one finding and `auto_fixable: false` on
1454
1500
  * another when per-instance guards in the applier discriminate (e.g.
1455
- * `remove-catalog-entry` flips on `hardcoded_consumers`, the primary
1456
- * dependency action flips between `remove-dependency` /
1457
- * `move-dependency` on `used_in_workspaces`). Filter on this bool of
1458
- * each individual action, not on `type`. See the [`IssueAction`]
1459
- * enum-level docs for the full list of per-instance flips.
1501
+ * `remove-catalog-entry` flips on `hardcoded_consumers` and catalog
1502
+ * source file, the primary dependency action flips between
1503
+ * `remove-dependency` / `move-dependency` on `used_in_workspaces`).
1504
+ * Filter on this bool of each individual action, not on `type`. See the
1505
+ * [`IssueAction`] enum-level docs for the full list of per-instance
1506
+ * flips.
1460
1507
  */
1461
1508
  auto_fixable: boolean
1462
1509
  /**
@@ -2122,7 +2169,7 @@ introduced?: (AuditIntroduced | null)
2122
2169
  */
2123
2170
  export interface TestOnlyDependencyFinding {
2124
2171
  /**
2125
- * Production dependency that is only imported by test files , consider
2172
+ * Production dependency that is only imported by test files, consider
2126
2173
  * moving to devDependencies.
2127
2174
  */
2128
2175
  package_name: string
@@ -2364,12 +2411,12 @@ introduced?: (AuditIntroduced | null)
2364
2411
  }
2365
2412
  /**
2366
2413
  * Wire-shape envelope for a [`PolicyViolation`] finding. Carries actions for
2367
- * replacing the banned call or import, or suppressing it with a scoped
2414
+ * replacing the banned call, import, or effect, or suppressing it with a scoped
2368
2415
  * `policy-violation:<pack>/<rule-id>` token.
2369
2416
  */
2370
2417
  export interface PolicyViolationFinding {
2371
2418
  /**
2372
- * The source file containing the banned call or import.
2419
+ * The source file containing the banned call, import, or effectful usage.
2373
2420
  */
2374
2421
  path: string
2375
2422
  /**
@@ -2392,8 +2439,8 @@ rule_id: string
2392
2439
  kind: PolicyRuleKind
2393
2440
  /**
2394
2441
  * What matched: the written callee path for `banned-call` (e.g.
2395
- * `cp.exec`), or the raw import specifier for `banned-import` (e.g.
2396
- * `moment/locale/nl`).
2442
+ * `cp.exec`), the raw import specifier for `banned-import` (e.g.
2443
+ * `moment/locale/nl`), or `<effect>: <callee>` for `banned-effect`.
2397
2444
  */
2398
2445
  matched: string
2399
2446
  severity: PolicyViolationSeverity
@@ -2428,12 +2475,20 @@ line: number
2428
2475
  */
2429
2476
  col: number
2430
2477
  origin: SuppressionOrigin
2478
+ /**
2479
+ * True when `rules.require-suppression-reason` reported a suppression
2480
+ * comment or tag that has no reason.
2481
+ */
2482
+ missing_reason?: boolean
2483
+ /**
2484
+ * Suggested next steps. Always emitted.
2485
+ */
2486
+ actions: IssueAction[]
2431
2487
  }
2432
2488
  /**
2433
2489
  * Wire-shape envelope for an [`UnusedCatalogEntry`] finding. Per-instance
2434
- * `auto_fixable` flips to `false` when `hardcoded_consumers` is non-empty:
2435
- * the entry cannot be removed safely while a workspace package still pins
2436
- * the same package via a hardcoded version range.
2490
+ * `auto_fixable` flips to `false` when `hardcoded_consumers` is non-empty or
2491
+ * the source is not `pnpm-workspace.yaml`.
2437
2492
  */
2438
2493
  export interface UnusedCatalogEntryFinding {
2439
2494
  /**
@@ -2441,16 +2496,16 @@ export interface UnusedCatalogEntryFinding {
2441
2496
  */
2442
2497
  entry_name: string
2443
2498
  /**
2444
- * Catalog group: `"default"` for the top-level `catalog:` map, or the
2445
- * named catalog key for entries declared under `catalogs.<name>:`.
2499
+ * Catalog group: `"default"` for the default catalog map, or the named
2500
+ * catalog key for entries declared under `catalogs.<name>`.
2446
2501
  */
2447
2502
  catalog_name: string
2448
2503
  /**
2449
- * Path to `pnpm-workspace.yaml`, relative to the analyzed root.
2504
+ * Path to the catalog source file, relative to the analyzed root.
2450
2505
  */
2451
2506
  path: string
2452
2507
  /**
2453
- * 1-based line number of the catalog entry within `pnpm-workspace.yaml`.
2508
+ * 1-based line number of the catalog entry within the source file.
2454
2509
  */
2455
2510
  line: number
2456
2511
  /**
@@ -2472,20 +2527,20 @@ introduced?: (AuditIntroduced | null)
2472
2527
  }
2473
2528
  /**
2474
2529
  * Wire-shape envelope for an [`EmptyCatalogGroup`] finding. Carries a
2475
- * straightforward `remove-empty-catalog-group` primary plus a YAML-comment
2476
- * suppress.
2530
+ * `remove-empty-catalog-group` primary. YAML-sourced findings also include a
2531
+ * YAML-comment suppress action.
2477
2532
  */
2478
2533
  export interface EmptyCatalogGroupFinding {
2479
2534
  /**
2480
- * Catalog group name declared under the top-level `catalogs:` map.
2535
+ * Catalog group name declared under the `catalogs` map.
2481
2536
  */
2482
2537
  catalog_name: string
2483
2538
  /**
2484
- * Path to `pnpm-workspace.yaml`, relative to the analyzed root.
2539
+ * Path to the catalog source file, relative to the analyzed root.
2485
2540
  */
2486
2541
  path: string
2487
2542
  /**
2488
- * 1-based line number of the empty group header within `pnpm-workspace.yaml`.
2543
+ * 1-based line number of the empty group header within the source file.
2489
2544
  */
2490
2545
  line: number
2491
2546
  /**
@@ -2531,10 +2586,10 @@ path: string
2531
2586
  */
2532
2587
  line: number
2533
2588
  /**
2534
- * Other catalogs (in the same `pnpm-workspace.yaml`) that DO declare this
2535
- * package. Empty when no catalog has the package. Sorted lexicographically.
2536
- * Lets agents and humans decide whether to switch the reference to a
2537
- * different catalog or to add the entry to the named catalog.
2589
+ * Other catalogs in the same catalog source that DO declare this package.
2590
+ * Empty when no catalog has the package. Sorted lexicographically. Lets
2591
+ * agents and humans decide whether to switch the reference to a different
2592
+ * catalog or to add the entry to the named catalog.
2538
2593
  */
2539
2594
  available_in_catalogs?: string[]
2540
2595
  /**
@@ -2956,11 +3011,11 @@ introduced?: (AuditIntroduced | null)
2956
3011
  */
2957
3012
  export interface UnusedComponentPropFinding {
2958
3013
  /**
2959
- * The `.vue` SFC declaring the unused prop.
3014
+ * The component file declaring the unused prop.
2960
3015
  */
2961
3016
  path: string
2962
3017
  /**
2963
- * The component name (the `.vue` file stem).
3018
+ * The component name.
2964
3019
  */
2965
3020
  component_name: string
2966
3021
  /**
@@ -3900,6 +3955,11 @@ health_trend?: (HealthTrend | null)
3900
3955
  * back to the report root.
3901
3956
  */
3902
3957
  actions_meta?: (HealthActionsMeta | null)
3958
+ /**
3959
+ * Optional framework-specific detector coverage. Present only when the
3960
+ * health run already needed the dead-code analysis output.
3961
+ */
3962
+ framework_health?: (FrameworkHealthDiagnostics | null)
3903
3963
  /**
3904
3964
  * Structural CSS analytics (specificity hotspots, `!important` density,
3905
3965
  * over-complex selectors, deep nesting). Present only with `--css`.
@@ -5537,6 +5597,37 @@ reason: string
5537
5597
  */
5538
5598
  scope: string
5539
5599
  }
5600
+ /**
5601
+ * Framework-specific health detector coverage surfaced for agent consumers.
5602
+ */
5603
+ export interface FrameworkHealthDiagnostics {
5604
+ /**
5605
+ * Detected framework IDs, sorted and deduplicated.
5606
+ */
5607
+ detected_frameworks: string[]
5608
+ /**
5609
+ * Detector coverage for the detected frameworks.
5610
+ */
5611
+ detectors: FrameworkHealthDetector[]
5612
+ }
5613
+ /**
5614
+ * Status for one framework-specific health detector.
5615
+ */
5616
+ export interface FrameworkHealthDetector {
5617
+ /**
5618
+ * Rule or detector ID, matching fallow's stable rule names where possible.
5619
+ */
5620
+ id: string
5621
+ /**
5622
+ * Framework ID that made this detector relevant.
5623
+ */
5624
+ framework: string
5625
+ status: FrameworkHealthDetectorStatus
5626
+ /**
5627
+ * Stable reason code for non-active statuses.
5628
+ */
5629
+ reason?: (string | null)
5630
+ }
5540
5631
  /**
5541
5632
  * Structural CSS analytics surfaced by `fallow health --css`.
5542
5633
  */
@@ -6330,6 +6421,45 @@ example: string
6330
6421
  how_to_fix: string
6331
6422
  docs: string
6332
6423
  }
6424
+ /**
6425
+ * Envelope emitted by `fallow inspect --format json`.
6426
+ */
6427
+ export interface InspectOutput {
6428
+ target: InspectTargetDescriptor
6429
+ identity: InspectIdentity
6430
+ evidence: InspectEvidence
6431
+ warnings: string[]
6432
+ }
6433
+ export interface InspectFileIdentity {
6434
+ file: string
6435
+ is_reachable?: unknown
6436
+ is_entry_point?: unknown
6437
+ export_count?: (number | null)
6438
+ import_count?: (number | null)
6439
+ imported_by_count?: (number | null)
6440
+ }
6441
+ export interface InspectSymbolIdentity {
6442
+ file: string
6443
+ export_name: string
6444
+ file_reachable?: unknown
6445
+ is_entry_point?: unknown
6446
+ is_used?: unknown
6447
+ reason?: unknown
6448
+ }
6449
+ export interface InspectEvidence {
6450
+ trace_file: InspectEvidenceSection
6451
+ trace_export?: (InspectEvidenceSection | null)
6452
+ dead_code: InspectEvidenceSection
6453
+ duplication: InspectEvidenceSection
6454
+ complexity: InspectEvidenceSection
6455
+ security: InspectEvidenceSection
6456
+ }
6457
+ export interface InspectEvidenceSection {
6458
+ status: InspectSectionStatus
6459
+ scope: InspectEvidenceScope
6460
+ message?: (string | null)
6461
+ data?: unknown
6462
+ }
6333
6463
  /**
6334
6464
  * Envelope emitted by `fallow --format review-github` / `review-gitlab`.
6335
6465
  */
@@ -6684,6 +6814,11 @@ health_trend?: (HealthTrend | null)
6684
6814
  * back to the report root.
6685
6815
  */
6686
6816
  actions_meta?: (HealthActionsMeta | null)
6817
+ /**
6818
+ * Optional framework-specific detector coverage. Present only when the
6819
+ * health run already needed the dead-code analysis output.
6820
+ */
6821
+ framework_health?: (FrameworkHealthDiagnostics | null)
6687
6822
  /**
6688
6823
  * Structural CSS analytics (specificity hotspots, `!important` density,
6689
6824
  * over-complex selectors, deep nesting). Present only with `--css`.
@@ -7106,7 +7241,8 @@ boundary_coverage_violations?: BoundaryCoverageViolationFinding[]
7106
7241
  */
7107
7242
  boundary_call_violations?: BoundaryCallViolationFinding[]
7108
7243
  /**
7109
- * Banned calls and banned imports matched by declarative rule packs
7244
+ * Banned calls, imports, and catalogue-derived effects matched by
7245
+ * declarative rule packs
7110
7246
  * (`rulePacks` config). Wrapped in [`PolicyViolationFinding`] so each
7111
7247
  * entry carries a typed `actions` array natively. Each finding carries
7112
7248
  * its effective per-rule severity.
@@ -7117,24 +7253,25 @@ policy_violations?: PolicyViolationFinding[]
7117
7253
  */
7118
7254
  stale_suppressions?: StaleSuppression[]
7119
7255
  /**
7120
- * Entries in pnpm-workspace.yaml's catalog: or catalogs: sections not
7121
- * referenced by any workspace package via the catalog: protocol. Wrapped
7122
- * in [`UnusedCatalogEntryFinding`] so each entry carries a typed
7256
+ * Entries in package manager catalog sections not referenced by any
7257
+ * workspace package via the catalog: protocol. Supports
7258
+ * `pnpm-workspace.yaml` catalogs and Bun root `package.json` catalogs.
7259
+ * Wrapped in [`UnusedCatalogEntryFinding`] so each entry carries a typed
7123
7260
  * `actions` array natively, with per-instance `auto_fixable` derived
7124
- * from `hardcoded_consumers`.
7261
+ * from `hardcoded_consumers` and the catalog source file.
7125
7262
  */
7126
7263
  unused_catalog_entries?: UnusedCatalogEntryFinding[]
7127
7264
  /**
7128
- * Named groups under pnpm-workspace.yaml's catalogs: section that declare
7129
- * no package entries. The top-level catalog: map is not reported. Wrapped
7130
- * in [`EmptyCatalogGroupFinding`].
7265
+ * Named groups under package manager catalogs sections that declare no
7266
+ * package entries. The top-level catalog: map is not reported. Wrapped in
7267
+ * [`EmptyCatalogGroupFinding`].
7131
7268
  */
7132
7269
  empty_catalog_groups?: EmptyCatalogGroupFinding[]
7133
7270
  /**
7134
7271
  * Workspace package.json references to catalogs (`catalog:` or
7135
- * `catalog:<name>`) that do not declare the consumed package. pnpm install
7136
- * will error until the named catalog grows to include the package or the
7137
- * reference is switched / removed. Wrapped in
7272
+ * `catalog:<name>`) that do not declare the consumed package. The package
7273
+ * manager install will error until the named catalog grows to include the
7274
+ * package or the reference is switched / removed. Wrapped in
7138
7275
  * [`UnresolvedCatalogReferenceFinding`] with the discriminated
7139
7276
  * `add-catalog-entry` / `update-catalog-reference` primary at position 0.
7140
7277
  */
@@ -7206,8 +7343,8 @@ route_collisions?: RouteCollisionFinding[]
7206
7343
  */
7207
7344
  dynamic_segment_name_conflicts?: DynamicSegmentNameConflictFinding[]
7208
7345
  /**
7209
- * Vue `<script setup>` `defineProps` props referenced nowhere in their own
7210
- * SFC (neither `<script>` nor `<template>`). Wrapped in
7346
+ * Vue `<script setup>` `defineProps`, Svelte 5 `$props()`, and React props
7347
+ * referenced nowhere in their own component. Wrapped in
7211
7348
  * [`UnusedComponentPropFinding`] so each entry carries a typed `actions`
7212
7349
  * array natively. Default severity is `warn`.
7213
7350
  */
@@ -8162,6 +8299,123 @@ coverage_unavailable: number
8162
8299
  runtime_unknown: number
8163
8300
  not_collected: number
8164
8301
  }
8302
+ /**
8303
+ * The `fallow security survivors --format json` envelope.
8304
+ */
8305
+ export interface SecuritySurvivorsOutput {
8306
+ schema_version: SecuritySurvivorsSchemaVersion
8307
+ version: ToolVersion
8308
+ elapsed_ms: ElapsedMs
8309
+ summary: SecuritySurvivorsSummary
8310
+ /**
8311
+ * Verifier-retained candidates keyed by finding id.
8312
+ */
8313
+ survivors: {
8314
+ [k: string]: SecuritySurvivor
8315
+ }
8316
+ /**
8317
+ * Ambiguous candidates keyed by finding id. These are not dismissed and are
8318
+ * kept explicit so queues can decide whether to include them.
8319
+ */
8320
+ needs_human_review: {
8321
+ [k: string]: SecuritySurvivor
8322
+ }
8323
+ }
8324
+ /**
8325
+ * Aggregate counts for survivor rendering.
8326
+ */
8327
+ export interface SecuritySurvivorsSummary {
8328
+ candidates: number
8329
+ verdicts: number
8330
+ survivors: number
8331
+ dismissed: number
8332
+ needs_human_review: number
8333
+ unverdicted: number
8334
+ }
8335
+ /**
8336
+ * One verifier-retained candidate row.
8337
+ */
8338
+ export interface SecuritySurvivor {
8339
+ /**
8340
+ * Stable candidate id from `security_findings[].finding_id`.
8341
+ */
8342
+ finding_id: string
8343
+ verdict: SecurityVerifierVerdictStatus
8344
+ /**
8345
+ * Short verifier reason.
8346
+ */
8347
+ reason?: (string | null)
8348
+ /**
8349
+ * Short verifier rationale.
8350
+ */
8351
+ rationale?: (string | null)
8352
+ /**
8353
+ * Optional verifier-provided confidence or review priority.
8354
+ */
8355
+ confidence?: (string | null)
8356
+ /**
8357
+ * Optional verifier-provided impact statement.
8358
+ */
8359
+ impact?: (string | null)
8360
+ /**
8361
+ * Optional verifier-owned remediation direction.
8362
+ */
8363
+ fix_direction?: (string | null)
8364
+ candidate: SecurityFinding
8365
+ }
8366
+ /**
8367
+ * The `fallow security blind-spots --format json` envelope.
8368
+ */
8369
+ export interface SecurityBlindSpotsOutput {
8370
+ schema_version: SecurityBlindSpotsSchemaVersion
8371
+ version: ToolVersion
8372
+ elapsed_ms: ElapsedMs
8373
+ summary: SecurityBlindSpotsSummary
8374
+ /**
8375
+ * Grouped unresolved callee diagnostics, derived from existing samples.
8376
+ */
8377
+ groups: SecurityBlindSpotGroup[]
8378
+ }
8379
+ /**
8380
+ * Aggregate counts for blind-spot output.
8381
+ */
8382
+ export interface SecurityBlindSpotsSummary {
8383
+ unresolved_edge_files: number
8384
+ unresolved_callee_sites: number
8385
+ sampled_callee_sites: number
8386
+ }
8387
+ /**
8388
+ * One actionable blind-spot group.
8389
+ */
8390
+ export interface SecurityBlindSpotGroup {
8391
+ reason: SkippedSecurityCalleeReason
8392
+ expression_kind: SkippedSecurityCalleeExpressionKind
8393
+ /**
8394
+ * Count in the bounded diagnostic sample.
8395
+ */
8396
+ sampled_count: number
8397
+ /**
8398
+ * Top files in this bounded diagnostic sample.
8399
+ */
8400
+ files: SecurityBlindSpotFile[]
8401
+ /**
8402
+ * Suggested next action for this group.
8403
+ */
8404
+ suggestion: string
8405
+ }
8406
+ /**
8407
+ * One file inside a blind-spot group.
8408
+ */
8409
+ export interface SecurityBlindSpotFile {
8410
+ /**
8411
+ * Project-relative source path.
8412
+ */
8413
+ path: string
8414
+ /**
8415
+ * Count in the bounded diagnostic sample.
8416
+ */
8417
+ sampled_count: number
8418
+ }
8165
8419
  /**
8166
8420
  * Bare `fallow --format json` envelope.
8167
8421
  */