Skip to content

Intercept Bash package-manager commands so yul can correct the version before it runs (Cargo/Go/npm) #45

Description

@algomaster99

Problem

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:

  1. 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.
  2. 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).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions