Nothing in this repo ever compares the installed CLI against what is published. No update-notifier dependency, no registry query, no warning. Grepping packages/** for registry.npmjs, dist-tags, npm view, outdated or checkForUpdate returns nothing.
That was survivable while generated agent instructions ran npx --yes n8nac@<distTag>: npx re-resolved the dist tag on every single call, so the agent silently ran the newest publish and the user never had to think about it. #657 makes the generated context name a locally installed n8nac instead, which is roughly eight times faster per call but pins the version. The invisible auto-update is gone and nothing replaces it.
The docs gained an Update section in #657, but a line in a doc is not a signal. A user who installs once now sits on that version indefinitely, with an AGENTS.md that keeps pointing at it.
Proposal
One fail-silent check in update-ai, which is exactly the moment the agent context is regenerated and is already the command that knows both the version and the dist tag.
- Query
https://registry.npmjs.org/-/package/n8nac/dist-tags. It returns about 80 bytes: {"latest":"2.6.0","next":"2.6.0-rc.7",…}. No packument fetch.
- Compare against
getCliVersion() for the tag getDistTag() already computes.
- On a difference, print one dim line to stderr, matching the existing notice at
update-ai.ts:267-269.
Constraints it must respect
- Never fail the command.
update-ai is documented as never throwing: checkAndRefreshIfStale at :156-161 says "Safe to call at the top of any command — never throws", and run() swallows in silent mode at :280. The check goes inside that posture, not beside it.
- stderr, never stdout. The reason is written down at
update-ai.ts:267-269: machine-readable stdout must stay clean. update-ai has no --json today, but around forty other commands do.
--silent suppresses it. That flag exists for the background refresh path.
- Honour the opt-outs that already exist, and invent none.
packages/telemetry/src/index.ts:207-218 already reads CI === 'true' and DO_NOT_TRACK === '1'. Add NO_UPDATE_NOTIFIER, the de-facto standard name, rather than a bespoke variable.
- Skip in a dev checkout.
inferFastCliCommand at :92-98 already detects one. A maintainer on a locally bumped version should not be told to update.
- Time-box it. House style is global
fetch with an AbortController, as at instance-mcp-client.ts:70-90. A few seconds, then give up quietly.
No semver dependency: string inequality against the dist tag is enough for a hint, and skipping dev checkouts removes the only case where it reads backwards.
Adjacent finding, not part of this
checkAndRefreshIfStale has no production caller. Repo-wide, outside dist and node_modules, the only references are its own definition and two tests. Nothing in packages/cli/src/index.ts invokes it, so only the explicit update-ai command path runs today. Worth its own issue.
Nothing in this repo ever compares the installed CLI against what is published. No
update-notifierdependency, no registry query, no warning. Greppingpackages/**forregistry.npmjs,dist-tags,npm view,outdatedorcheckForUpdatereturns nothing.That was survivable while generated agent instructions ran
npx --yes n8nac@<distTag>: npx re-resolved the dist tag on every single call, so the agent silently ran the newest publish and the user never had to think about it. #657 makes the generated context name a locally installed n8nac instead, which is roughly eight times faster per call but pins the version. The invisible auto-update is gone and nothing replaces it.The docs gained an Update section in #657, but a line in a doc is not a signal. A user who installs once now sits on that version indefinitely, with an
AGENTS.mdthat keeps pointing at it.Proposal
One fail-silent check in
update-ai, which is exactly the moment the agent context is regenerated and is already the command that knows both the version and the dist tag.https://registry.npmjs.org/-/package/n8nac/dist-tags. It returns about 80 bytes:{"latest":"2.6.0","next":"2.6.0-rc.7",…}. No packument fetch.getCliVersion()for the taggetDistTag()already computes.update-ai.ts:267-269.Constraints it must respect
update-aiis documented as never throwing:checkAndRefreshIfStaleat:156-161says "Safe to call at the top of any command — never throws", andrun()swallows in silent mode at:280. The check goes inside that posture, not beside it.update-ai.ts:267-269: machine-readable stdout must stay clean.update-aihas no--jsontoday, but around forty other commands do.--silentsuppresses it. That flag exists for the background refresh path.packages/telemetry/src/index.ts:207-218already readsCI === 'true'andDO_NOT_TRACK === '1'. AddNO_UPDATE_NOTIFIER, the de-facto standard name, rather than a bespoke variable.inferFastCliCommandat:92-98already detects one. A maintainer on a locally bumped version should not be told to update.fetchwith anAbortController, as atinstance-mcp-client.ts:70-90. A few seconds, then give up quietly.No
semverdependency: string inequality against the dist tag is enough for a hint, and skipping dev checkouts removes the only case where it reads backwards.Adjacent finding, not part of this
checkAndRefreshIfStalehas no production caller. Repo-wide, outsidedistandnode_modules, the only references are its own definition and two tests. Nothing inpackages/cli/src/index.tsinvokes it, so only the explicitupdate-aicommand path runs today. Worth its own issue.