Repository navigation
feat(cli): run only as the recorded version, on rules reconciled for its engines - #562
Conversation
…its engines A CLI that is not the version .taskless/taskless.json records for its package now refuses every command but init, info, auth and feedback (CLI_VERSION_MISMATCH), however it was started. check and verify refuse rules whose recorded rules.engines differ from the bundled ast-grep or Vale, for an engine the project has rules for (RULES_ENGINE_MISMATCH). --allow-version-mismatches, now also TASKLESS_ALLOW_VERSION_MISMATCHES, skips both; the repo's pnpm cli sets it.
The docs-npx-cli Vale rule now refuses an npx or dlx run of any subcommand but init, instead of rewriting docs toward npx @taskless/cli <command>.
init's upgrade trailer and the bare non-interactive notice sent readers to npx for update and agent, a CLI the version-pin gate refuses.
e46476f to
a879650
Compare
…any version A login is a per-repo token, not a version, so auth is exempt from the version-pin gate. docs-npx-cli now allows npx and dlx runs of auth.
|
@claude /review |
|
Claude finished @theCodeDrift's task in 3m 11s —— View job Review: feat(cli): run only as the recorded version, on rules reconciled for its enginesReview mode: incremental — read 0 prior review thread(s) before reviewing. Todo
AssessmentThis is a well-structured change with thorough unit and spawned-CLI test coverage (
One minor, non-blocking observation:
Nothing else stood out as a correctness, security, or test-adequacy gap — the gate's directional messaging (newer vs. older vs. other-channel), the "no manifest / unreadable manifest / self build / unknown version" exemptions, and the |
demo, help and test are not in commands/names.ts.
Pruned — AI Coding Agent |
Stack (root → tip):
Engine upgrades no longer carry backward-compatibility weight: rule migrations rewrite whatever an ast-grep or Vale release breaks. What still went wrong was running a CLI against rules reconciled for other engines. Until now the only version gate was the scaffold layout number, and rule migrations deliberately leave that alone. So nothing refused either of these cases:
type_synomymrename,checkreported no ast-grep findings at all.npx @taskless/cli@latest update --ruleshad already migrated past it.What changes
.taskless/taskless.jsonrecords for its package refuses every command exceptinit,info,authandfeedback, withCLI_VERSION_MISMATCH. This applies however the CLI was started: npx, dlx,node_modulesor the launcher. "Recorded" means what that package's launcher runs (recordedLauncherVersion), so the gate and the launcher can't disagree.initis the one command that moves the record, which makes it the way to upgrade.updateis gated, because it moves the rules' record, not the CLI's.checkandverifyrefuse withRULES_ENGINE_MISMATCHwhenrules.enginesdiffers from the bundled ast-grep or Vale. This only applies to an engine the project has rules for, and only when engines were recorded at all. When the rules are behind, the message namesupdatethenupdate --rules. When they are ahead, it names the recorded CLI.validateis not gated, because an agent runs it during the walk.--allow-version-mismatchesskips both gates, andTASKLESS_ALLOW_VERSION_MISMATCHES=1is its environment form. The rootpnpm cliscript sets it, since this repo's manifest pins 0.11.2 with engines recorded at 0.45.2/3.18.0, andpnpm lintwould otherwise refuse its own fresh build.updaterecipe (topic v19): the walk passes the override to any mid-walkcheck, and the pinned-CLI bump in step 4 is now required whether or not a migration ran. It also adds the new codes to the error table and a ledger note under 0.13.3.init). Everything else goes through./.taskless/bin/cli.mjs:docs-npx-cliVale rule used to rewrite docs towardnpx @taskless/cli <command>. It now refuses an npx/dlx/bunx run of any subcommand butinitandauth(a login is a per-repo token, andauthruns on any version) in READMEs anddotagents.md, and still banspnpm cliin READMEs. It lists subcommands explicitly so prose like "run npx @taskless/cli to install" passes..taskless/README.mdtemplate runscheckthrough the launcher too.init's upgrade trailer says./.taskless/bin/cli.mjs update, not the npx invocation that ran it. The bare non-interactive notice names the launcher for recipes when the project has one.authrecipe (topic v4) saysauthruns on any version, and that logging in does not clear aCLI_VERSION_MISMATCHfrom another command.Reviewer notes
CLIs already published don't carry the gate, so the engine gate's "ahead" branch only protects CLIs released from here on.
After an upgrade with
init, CI stays red oncheckuntil someone runsupdate --rules. That's intended, and the refusal names both commands.Two test fixtures leaked a recorded version.
reconcile-markercopied this repo's scaffold, andonboardhard-coded0.7.0. Both now record no version or the built CLI's version.Error remedies (
auth login,rule restore, …) still repeat however the CLI was started. Under the gate, an npx run that gets far enough to print one is already the recorded version, so the remedy works, and changing ~20 call sites would change nothing anyone sees.This repo's own
.taskless/(pinned 0.11.2) moves in a separate PR. Its README is outside the Vale rule's scope.OpenSpec:
openspec/changes/archive/2026-10-20-cli-version-pin-gate/andopenspec/changes/archive/2026-10-21-npx-install-only/(ADDED-only deltas tocli, both archived in this PR).