fallow 2.69.0 → 2.71.1
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 +8 -0
- package/package.json +27 -9
- package/schema.json +66 -1
- package/skills/fallow/SKILL.md +44 -47
- package/skills/fallow/references/cli-reference.md +235 -63
- package/skills/fallow/references/gotchas.md +21 -1
- package/skills/fallow/references/patterns.md +39 -78
- package/types/output-contract.d.ts +2545 -0
|
@@ -23,7 +23,7 @@ Always preview with `--dry-run` before applying. This is a destructive operation
|
|
|
23
23
|
|
|
24
24
|
## Don't Create Config Unless Needed
|
|
25
25
|
|
|
26
|
-
Fallow works with zero configuration for most projects thanks to
|
|
26
|
+
Fallow works with zero configuration for most projects thanks to 94 auto-detecting framework plugins. Creating an unnecessary config file can mask issues or override detection behavior.
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
29
|
# WRONG: creating config for a standard Next.js project
|
|
@@ -429,6 +429,26 @@ Fallow marks `static/style.css` and `static/app.js` as reachable. Root-relative
|
|
|
429
429
|
|
|
430
430
|
---
|
|
431
431
|
|
|
432
|
+
## GraphQL `#import` Documents Are Tracked
|
|
433
|
+
|
|
434
|
+
GraphQL `.graphql` and `.gql` files can keep nearby fragment documents reachable with relative `#import` comments. Fallow tracks `./` and `../` specifiers, including extensionless imports that resolve through `.graphql` and `.gql`; package-style specifiers are ignored.
|
|
435
|
+
|
|
436
|
+
```graphql
|
|
437
|
+
# src/query.graphql
|
|
438
|
+
|
|
439
|
+
#import "./fragments/user-fields"
|
|
440
|
+
|
|
441
|
+
query CurrentUser {
|
|
442
|
+
currentUser {
|
|
443
|
+
...UserFields
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
Fallow marks `src/fragments/user-fields.graphql` or `src/fragments/user-fields.gql` as reachable when either file exists. A typo in the relative path is reported as an unresolved import instead of silently dropping the edge.
|
|
449
|
+
|
|
450
|
+
---
|
|
451
|
+
|
|
432
452
|
## Library Packages: Use `publicPackages` Instead of Visibility Tags
|
|
433
453
|
|
|
434
454
|
In monorepos, shared library packages have exported APIs consumed by external consumers not visible to fallow. Instead of annotating every export with `/** @public */` (or `@internal`, `@beta`, `@alpha`), use the `publicPackages` config to mark entire workspace packages as public libraries. Exports and exported enum/class members from these packages are excluded from unused API detection.
|
|
@@ -129,6 +129,31 @@ Parse the JSON to list specific files and exports that became unused.
|
|
|
129
129
|
|
|
130
130
|
Computes a health score (0-100 with letter grade) in combined mode and enables the health delta header in PR comments.
|
|
131
131
|
|
|
132
|
+
### GitHub Actions: Severity-Aware PR Quality Gate (Audit)
|
|
133
|
+
|
|
134
|
+
```yaml
|
|
135
|
+
- uses: fallow-rs/fallow@v2
|
|
136
|
+
with:
|
|
137
|
+
command: audit
|
|
138
|
+
gate: new-only # default; fails only on findings introduced by this PR
|
|
139
|
+
fail-on-issues: true
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Runs `fallow audit` to combine dead-code + complexity + duplication scoped to changed files. The gate respects rule severity from `.fallowrc.json`, so `unused-exports: warn` projects do not fail when a PR touches a file with pre-existing warn-tier findings. Use `gate: all` to fail on every finding in changed files.
|
|
143
|
+
|
|
144
|
+
The action exposes `outputs.verdict` (`pass`/`warn`/`fail`) and `outputs.gate` for downstream conditionals; `outputs.issues` holds the introduced count under `gate: new-only` and the total count under `gate: all`.
|
|
145
|
+
|
|
146
|
+
```yaml
|
|
147
|
+
- uses: fallow-rs/fallow@v2
|
|
148
|
+
id: fallow
|
|
149
|
+
with:
|
|
150
|
+
command: audit
|
|
151
|
+
|
|
152
|
+
- name: Block release on regression
|
|
153
|
+
if: steps.fallow.outputs.verdict == 'fail'
|
|
154
|
+
run: exit 1
|
|
155
|
+
```
|
|
156
|
+
|
|
132
157
|
### GitHub Actions: Inline PR Annotations (No Advanced Security)
|
|
133
158
|
|
|
134
159
|
The official action supports inline PR annotations via GitHub workflow commands. This does not require Advanced Security (unlike SARIF upload) and works on any GitHub plan.
|
|
@@ -398,6 +423,7 @@ Creates `.fallowrc.json` with mapped settings:
|
|
|
398
423
|
- knip `rules`/`exclude`/`include` → fallow `rules` (error/warn/off)
|
|
399
424
|
- knip `ignore` → fallow `ignorePatterns`
|
|
400
425
|
- knip `ignoreDependencies` → fallow `ignoreDependencies`
|
|
426
|
+
- knip `ignoreExportsUsedInFile` → fallow `ignoreExportsUsedInFile` (boolean and `{ type, interface }` object form both supported; fallow groups type aliases and interfaces under one issue, so the two type-kind fields behave identically)
|
|
401
427
|
- Unmappable fields generate warnings with suggestions
|
|
402
428
|
|
|
403
429
|
### Step 3: Compare results
|
|
@@ -595,7 +621,7 @@ Focus on findings that are BOTH dead code and duplicated:
|
|
|
595
621
|
|
|
596
622
|
## Custom Plugin Setup
|
|
597
623
|
|
|
598
|
-
For frameworks not covered by the
|
|
624
|
+
For frameworks not covered by the 94 built-in plugins.
|
|
599
625
|
|
|
600
626
|
### Option 1: Inline framework config
|
|
601
627
|
|
|
@@ -693,13 +719,13 @@ Because Claude receives stderr as tool feedback on a blocked `PreToolUse` call,
|
|
|
693
719
|
Install it automatically:
|
|
694
720
|
|
|
695
721
|
```bash
|
|
696
|
-
fallow
|
|
722
|
+
fallow hooks install --target agent
|
|
697
723
|
```
|
|
698
724
|
|
|
699
725
|
Remove it later with:
|
|
700
726
|
|
|
701
727
|
```bash
|
|
702
|
-
fallow
|
|
728
|
+
fallow hooks uninstall --target agent
|
|
703
729
|
```
|
|
704
730
|
|
|
705
731
|
Manual files:
|
|
@@ -727,79 +753,14 @@ Manual files:
|
|
|
727
753
|
|
|
728
754
|
### `.claude/hooks/fallow-gate.sh`
|
|
729
755
|
|
|
730
|
-
|
|
731
|
-
#!/usr/bin/env bash
|
|
732
|
-
set -euo pipefail
|
|
733
|
-
|
|
734
|
-
# Generated by fallow setup-hooks.
|
|
735
|
-
# Requires bash and jq. On Windows run via git-bash or WSL.
|
|
736
|
-
# Blocks Claude Code git commit and git push when fallow audit returns verdict fail.
|
|
737
|
-
# Runtime errors fail open with a single stderr notice so skips stay visible.
|
|
738
|
-
|
|
739
|
-
if ! command -v jq >/dev/null 2>&1; then
|
|
740
|
-
echo "fallow-gate: jq not on PATH, skipping audit." >&2
|
|
741
|
-
exit 0
|
|
742
|
-
fi
|
|
756
|
+
Prefer `fallow hooks install --target agent` to install this file. The script is written and maintained by fallow itself; the canonical source is [`crates/cli/src/setup_hooks/fallow-gate.sh`](https://github.com/fallow-rs/fallow/blob/main/crates/cli/src/setup_hooks/fallow-gate.sh).
|
|
743
757
|
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
if command -v fallow >/dev/null 2>&1; then
|
|
752
|
-
RUNNER=(fallow)
|
|
753
|
-
elif command -v npx >/dev/null 2>&1 && VER="$(npx --no-install fallow --version 2>/dev/null || true)" && [[ "$VER" == fallow* ]]; then
|
|
754
|
-
RUNNER=(npx --no-install fallow)
|
|
755
|
-
else
|
|
756
|
-
echo "fallow-gate: fallow binary not found (tried PATH and npx --no-install), skipping audit." >&2
|
|
757
|
-
exit 0
|
|
758
|
-
fi
|
|
759
|
-
|
|
760
|
-
TMP_JSON="$(mktemp)"
|
|
761
|
-
TMP_ERR="$(mktemp)"
|
|
762
|
-
cleanup() {
|
|
763
|
-
rm -f "$TMP_JSON" "$TMP_ERR"
|
|
764
|
-
}
|
|
765
|
-
trap cleanup EXIT
|
|
766
|
-
|
|
767
|
-
if "${RUNNER[@]}" audit --format json --quiet --explain >"$TMP_JSON" 2>"$TMP_ERR"; then
|
|
768
|
-
STATUS=0
|
|
769
|
-
else
|
|
770
|
-
STATUS=$?
|
|
771
|
-
fi
|
|
772
|
-
|
|
773
|
-
VERDICT="$(jq -r '.verdict // empty' <"$TMP_JSON" 2>/dev/null || true)"
|
|
774
|
-
IS_ERROR="$(jq -r '.error // false' <"$TMP_JSON" 2>/dev/null || echo false)"
|
|
775
|
-
|
|
776
|
-
if [ "$VERDICT" = "fail" ]; then
|
|
777
|
-
cat "$TMP_JSON" >&2
|
|
778
|
-
exit 2
|
|
779
|
-
fi
|
|
780
|
-
|
|
781
|
-
if [ "$STATUS" -eq 2 ] || [ "$IS_ERROR" = "true" ]; then
|
|
782
|
-
MSG="$(jq -r '.message // empty' <"$TMP_JSON" 2>/dev/null || true)"
|
|
783
|
-
if [ -n "$MSG" ]; then
|
|
784
|
-
echo "fallow-gate: fallow audit runtime error ($MSG), skipping." >&2
|
|
785
|
-
else
|
|
786
|
-
echo "fallow-gate: fallow audit runtime error, skipping." >&2
|
|
787
|
-
fi
|
|
788
|
-
exit 0
|
|
789
|
-
fi
|
|
790
|
-
|
|
791
|
-
if [ "$STATUS" -ne 0 ]; then
|
|
792
|
-
ERR_LINE="$(sed -n '1p' "$TMP_ERR" 2>/dev/null || true)"
|
|
793
|
-
if [ -n "$ERR_LINE" ]; then
|
|
794
|
-
echo "fallow-gate: fallow audit exited $STATUS ($ERR_LINE), skipping." >&2
|
|
795
|
-
else
|
|
796
|
-
echo "fallow-gate: fallow audit exited $STATUS, skipping." >&2
|
|
797
|
-
fi
|
|
798
|
-
exit 0
|
|
799
|
-
fi
|
|
800
|
-
|
|
801
|
-
exit 0
|
|
802
|
-
```
|
|
758
|
+
Behavior you can rely on:
|
|
759
|
+
- Runs only when the intercepted command matches `git commit` or `git push`; otherwise exits 0.
|
|
760
|
+
- 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.
|
|
761
|
+
- Enforces a version floor via `FALLOW_GATE_MIN_VERSION` (default `2.46.0`). Binaries below the floor are blocked with an upgrade hint. Set the env var to the empty string to disable the check.
|
|
762
|
+
- Runs `fallow audit --format json --quiet --explain` and, on verdict=`fail`, writes the full JSON envelope to stderr preceded by `fallow-gate: blocked by fallow <version> at <binary>` so the responsible binary is always identifiable.
|
|
763
|
+
- On runtime error (`{"error": true, ...}`) or unexpected non-zero exit, fails open with a one-line stderr notice; warn verdicts pass through silently.
|
|
803
764
|
|
|
804
765
|
Codex fallback (add to repo root `AGENTS.md`):
|
|
805
766
|
|
|
@@ -812,13 +773,13 @@ Keep `fallow audit` in CI alongside this local gate. The hook only runs for Clau
|
|
|
812
773
|
### Remove the hook
|
|
813
774
|
|
|
814
775
|
```bash
|
|
815
|
-
fallow
|
|
776
|
+
fallow hooks uninstall --target agent
|
|
816
777
|
```
|
|
817
778
|
|
|
818
779
|
Removes the fallow-gate handler from `.claude/settings.json` (preserving any other handlers in the same matcher group), deletes `.claude/hooks/fallow-gate.sh` if it still carries the `# Generated by fallow setup-hooks.` marker, and strips the managed block from `AGENTS.md`. Idempotent: a second run reports `unchanged` / `not present` and exits 0.
|
|
819
780
|
|
|
820
781
|
Use `--force` to remove a hook script that the user has edited (the marker is no longer present). Use `--dry-run` to preview without touching files.
|
|
821
782
|
|
|
822
|
-
### Distinguish from `fallow
|
|
783
|
+
### Distinguish from `fallow hooks install --target git`
|
|
823
784
|
|
|
824
|
-
`fallow
|
|
785
|
+
`fallow hooks install --target git` is a different target: it scaffolds a shell-level Git pre-commit hook under `.git/hooks/` that runs `fallow` on changed files. That is the *human* enforcement path. `fallow hooks install --target agent` is the *agent* enforcement path, targeting `.claude/` and `AGENTS.md`. Both can live in the same repo: git hooks catch human commits, the agent gate catches agent commits.
|