Scope any file command to a path
Bare fallow, check, dupes, health, audit, security, fix, list and
similar-code now take an optional positional path:
npx fallow src/components
npx fallow health src/api/client.ts
npx fallow fix src/legacyThe whole-project graph is still built, so every cross-file fact stays sound.
Only the reported findings narrow, and fix plans and applies only the fixes
that touch scoped files.
Resolution is root-first for a bare relative path, ./ and ../ are honoured
as current-directory claims, and a missing or outside-root path is rejected with
an actionable exit-2 error rather than silently analysing the whole project. The
scope composes with --workspace as one more workspace root and intersects with
--changed-since and --diff-file. audit narrows its changed-file universe so
verdict and base attribution stay coherent, while its base pass stays unscoped
because it runs in another worktree.
Runtime coverage joins far more of your code
fallow coverage analyze --cloud joins cloud runtime rows against a static
index that was built from the health and complexity pass, which enumerates
declarations and bindings only. Everything else the runtime instrumenter names,
an arrow passed to a call and named after its callee (rows.map(...),
sqliteTable("t", {}, (table) => [...]), .references(() => ...)), an
object-literal method, a getter or setter, and a function assigned to a member,
had nothing to join against. Those rows landed in cloud_functions_unmatched
instead of reaching findings and hot_paths, and in a typical service those
are exactly the highest-traffic functions, so the hot-path list was led by
whichever declaration happened to be enumerated.
The index now carries every function the instrumenter would name, resolved
through the same walker the static inventory upload uses, so the identity
matches the stable_id the cloud stores. A function known only by the callee it
was passed to is flagged as a callback and its verdict copy names the call site
("Callback passed to map; ...") instead of pointing at a declaration that does
not exist.
The static function inventory was fixed on the same terms: an object-literal
method, a function-valued property, a getter or setter, a function assigned to a
member expression, and an anonymous export default were left at their
(anonymous_N) placeholder while the instrumenter names them run, execute,
get closed, rollback and default. Both sides now agree, so an uploaded
inventory entry and the runtime row for the same function share one identity.
The inventory blob reports its own size guard
fallow coverage upload-inventory --with-callers has always capped the
importer-edge map per callee so a pathological fan-in cannot bloat the upload,
but the cut was silent: a consumer could not tell a function that genuinely has
as many importers as the cap from one whose list was truncated.
The version 3 body now carries a callerEdgeLimits header next to callerEdges
with maxSitesPerFunction, maxSymbolsPerSite and truncatedFunctions, and the
command prints a warning naming how many functions lost importer sites. The
header is present only when callerEdges is, so version 1 and version 2 bodies
keep their exact wire shape.
Windows paths read correctly in check and health
Both human renderers printed the platform separator, so a Windows user was told
src\a.ts while dupes, list, fix and every JSON surface said src/a.ts.
The dimmed-directory and bold-filename split keys on /, so the whole path also
lost its emphasis. Every path those two renderers put on screen now normalises
the same way the rest of the CLI already did. On-disk path handling is untouched.
Install
npx fallow@3.25.0
npm install --save-dev fallow@3.25.0
cargo install fallow-cli@3.25.0Full Changelog: v3.24.1...v3.25.0