Back to Feed
article 2m read

A CLI that now installs itself before setup, then throws away the reason when it can't

Hooks start my agent-watching CLI on every tool call, so running it through npx was a slow default; setup now checks the PATH and installs the program globally first, but a failed install drops npm's error, and the check can't tell an old copy from the current one or notice an install that lands off the PATH.

Article DepthPractice

Flow

The setup check, step by step

  1. 1Look for the name

    Finds the program on the PATH. Any copy passes, even an old one.

  2. 2Install globally

    npm install with a spinner and a long timeout.

  3. 3Failure

    Prints the manual command and two tips. npm's own error is dropped.

  4. 4Success

    Setup goes on. Nothing looks for the program again first.

  5. 5Write hooks

    Agent config now runs the program by name.

Slowest way it can run is how I was telling people to start my CLI.

The CLI belongs to a small tool I'm building that watches coding agents. Setup adds hooks to each agent. A hook is a command the agent runs when something happens, like a tool call, so my program gets started many times in one session. Nobody sees those runs. They just feel a slow agent, and a slow hook gets deleted.

My onboarding page told people to run everything through npx. That's fine for trying a package once. But in a hook, every single call has to find the package and start it up before my code even begins. The change's notes call that a noticeable fraction of a second each time. I never timed it myself, but it adds up fast.

One check before setup starts

Now both setup commands start with the same check: is my program already on the PATH? If yes, keep going. If not, run a global npm install with a spinner and a long timeout. If the install works, setup continues. If it fails, setup prints the command to install by hand, the command to rerun, and two ways around a permissions error, then stops before writing any config.

The onboarding page changed too. It now says to install globally first, and the per-agent commands skip npx.

I'd guess that without this check, setup could look fine and still leave hooks that break later, when nobody is watching.

Where the reason goes missing

The global install is the step most likely to fail. And my install helper throws away npm's error. Its output goes into memory, and any failure just becomes false. A comment says the output is shown to the user, but it isn't. So the person is told it failed and gets two generic tips, never the real cause. What I want is closer to this:

return { ok: false, reason: lastLinesOf(npmError) };

The check also only looks for the name, so an old copy passes. And nothing looks again after installing, so a success message can still leave hooks pointing at a command that isn't there.

Keep reading

Pick up a connected idea or branch into a nearby one.

5 paths forward