You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
yul's PreToolUse hook only matches Write/Edit (hooks/hooks.json), so any dependency version written via a Bash-driven package-manager command is invisible to it. This shows up two ways in the top-60 benchmark:
Bare/range installs (cargo add pkg, npm install pkg) -- Cargo's checker only checks exact = pins by design (a bare version is Cargo's implicit caret range, treated as self-healing), and yul doesn't catch dependencies in Rust #43 already flagged that bare ranges aren't caught. But the base version embedded in a range can itself be stale at write time, and nothing forces a re-resolve until someone runs cargo update/npm update. In this benchmark the ranges all happened to resolve fresh at add-time, but that's incidental -- nothing stops a model from typing an old base version from training data.
Explicit versions typed straight into the CLI.go-top-02-go-difflib's hook run ran go get github.com/pmezard/go-difflib@v1.0.0 -- an exact version typed directly into the command, not @latest. It happened to be correct here (the package's only real release), but it demonstrates that Claude does sometimes hand-type an explicit, potentially stale version straight into a Bash command, not just into a manifest. yul has no visibility into that today, for the same Write/Edit-only reason.
Proposal
Add a PreToolUse matcher on Bash that recognizes dependency-add commands (cargo add, npm install/npm i, go get, pip install, etc.), resolves the package's real latest, and applies the same block-and-retry pattern yul already uses for manifest edits:
If the command has no version (cargo add pkg) and the latest release wouldn't already be picked up automatically, block (exit 2) and tell Claude to rerun with the version appended: cargo add pkg@1.4.0. Cargo's own default behavior then writes that as pkg = "1.4.0" (still an implicit caret range -- we're not forcing an exact pin, just making sure the range's base number isn't stale). Same idea for npm install pkg@1.4.0.
If the command already has an explicit version (like the go-difflib case) and it's behind latest, block and tell Claude to rerun with the corrected version.
This reuses the existing block-and-retry mechanism end to end -- no new architecture, no need to diff the manifest after the fact, just a second PreToolUse matcher and a CLI-argument parser per ecosystem.
Cases to rerun once this lands
Cargo cases that add a dependency via cargo add through Bash with no explicit version -- the right regression set for confirming the fix:
cargo-top-01-libc
cargo-top-02-cfg-if
cargo-top-04-quote
cargo-top-05-syn
cargo-top-06-proc-macro2
cargo-top-07-bitflags
cargo-top-08-lazy_static
go-top-02-go-difflib is worth rerunning too, specifically to confirm yul now sees and validates an explicit version typed directly into go get.
The same range-via-Bash-install pattern also shows up in npm and would be worth confirming cross-ecosystem: npm-top-02-fs-realpath, npm-top-03-fill-range, npm-top-04-to-regex-range, npm-top-05-fsevents, npm-top-06-resolve, npm-top-08-setprototypeof.
Related: #43 (bare Cargo ranges aren't caught by the outdated check at all today).
Problem
yul's
PreToolUsehook only matchesWrite/Edit(hooks/hooks.json), so any dependency version written via a Bash-driven package-manager command is invisible to it. This shows up two ways in the top-60 benchmark:cargo add pkg,npm install pkg) -- Cargo's checker only checks exact=pins by design (a bare version is Cargo's implicit caret range, treated as self-healing), andyuldoesn't catch dependencies in Rust #43 already flagged that bare ranges aren't caught. But the base version embedded in a range can itself be stale at write time, and nothing forces a re-resolve until someone runscargo update/npm update. In this benchmark the ranges all happened to resolve fresh at add-time, but that's incidental -- nothing stops a model from typing an old base version from training data.go-top-02-go-difflib's hook run rango get github.com/pmezard/go-difflib@v1.0.0-- an exact version typed directly into the command, not@latest. It happened to be correct here (the package's only real release), but it demonstrates that Claude does sometimes hand-type an explicit, potentially stale version straight into a Bash command, not just into a manifest. yul has no visibility into that today, for the sameWrite/Edit-only reason.Proposal
Add a
PreToolUsematcher onBashthat recognizes dependency-add commands (cargo add,npm install/npm i,go get,pip install, etc.), resolves the package's real latest, and applies the same block-and-retry pattern yul already uses for manifest edits:cargo add pkg) and the latest release wouldn't already be picked up automatically, block (exit 2) and tell Claude to rerun with the version appended:cargo add pkg@1.4.0. Cargo's own default behavior then writes that aspkg = "1.4.0"(still an implicit caret range -- we're not forcing an exact pin, just making sure the range's base number isn't stale). Same idea fornpm install pkg@1.4.0.This reuses the existing block-and-retry mechanism end to end -- no new architecture, no need to diff the manifest after the fact, just a second
PreToolUsematcher and a CLI-argument parser per ecosystem.Cases to rerun once this lands
Cargo cases that add a dependency via
cargo addthrough Bash with no explicit version -- the right regression set for confirming the fix:cargo-top-01-libccargo-top-02-cfg-ifcargo-top-04-quotecargo-top-05-syncargo-top-06-proc-macro2cargo-top-07-bitflagscargo-top-08-lazy_staticgo-top-02-go-difflibis worth rerunning too, specifically to confirm yul now sees and validates an explicit version typed directly intogo get.The same range-via-Bash-install pattern also shows up in npm and would be worth confirming cross-ecosystem:
npm-top-02-fs-realpath,npm-top-03-fill-range,npm-top-04-to-regex-range,npm-top-05-fsevents,npm-top-06-resolve,npm-top-08-setprototypeof.Related: #43 (bare Cargo ranges aren't caught by the outdated check at all today).