Uh oh!
There was an error while loading. Please reload this page.
cli: every documented os auth / os studio invocation now names a command that resolves - #11314
Conversation
…md>` in --help Fixes#11221 These three commands live at the root of packages/cli/src/commands/, so oclif's pattern-strategy loader registers them as `register` / `whoami` / `logout`. Their `static override examples` — printed verbatim by --help — spelled an `os auth <cmd>` shape that has never resolved, so a user copy-pasting out of --help hit `Error: Command auth:<cmd> not found.` Measured against the built CLI (packages/cli/bin/run.js) before the fix: `os auth whoami`, `os auth register`, `os auth logout` each exit 2 with `Error: Command auth:<cmd> not found.`; the bare `os whoami` / `os register` / `os logout` each exit 0 and print help. All seven examples entries now use the bare, registered spelling. Exported default classes are renamed to match their file-path-derived command id (AuthRegister -> Register, AuthWhoami -> Whoami, AuthLogout -> Logout). oclif derives ids from file paths, never from class names, so this changes no runtime resolution — re-verified against the rebuilt binary. It also brings these onto the package's measured convention: every other root-level command class is the PascalCase of its filename. packages/cli/test/remote-api-commands .test.ts imports two of them, but as DEFAULT imports, so the local binding is independent of the class name — that file is untouched and still passes. login.ts keeps AuthLogin: its examples were already correct (`$ os login`), putting it outside this card's file surface. The remaining holdout is reported rather than swept. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019siH5jDmk5hrayvfyojUqR
Fixes#11180 packages/cli/README.md's Development command table listed `| os studio [config] | Launch Studio UI with development server |`. The CLI ships no `studio` command. The oclif command set is pattern-derived from packages/cli/src/commands/**, and loading the built CLI's own Config enumerates 60 registered ids with zero matching `studio` — control: dev, serve, login, logout, register and whoami are all present in the same enumeration, so the check is not vacuous. From the outside, `os studio --help` exits 2 with `Error: Command studio not found.` The row is deleted rather than rewritten. Studio is not reached by a CLI command at all — the console serves it at /_console/studio after `os dev` or `os serve`, both of which this same table already lists. A replacement row would reintroduce the category error that made this one wrong: a Commands table lists commands, and a browser route is not one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019siH5jDmk5hrayvfyojUqR
… just fired Part of #11221 — the second half of the commit before it. environments.test.ts's #10967 pin carries a self-retiring EXCLUDED map. Its header states the design: register.ts / whoami.ts / logout.ts are carved out of the main assertion, and a second it.each re-runs the same predicate over exactly those files asserting an unresolved entry is still there — "when #11221's fix removes the last one, that assertion goes red on purpose, and the failure message says to delete the entry." Measured, with only the previous commit applied: 3 failed | 68 passed (71), each failure reading "register.ts no longer has an unresolved examples entry -- remove it from EXCLUDED above so it is scanned like every other command source." After retiring: 71 passed (71), all three now covered by the main assertion instead of exempted. Retirement shape follows the precedent this file names as its own (packages/create-objectstack/src/starter-comments-self-contained.test.ts, #11022): the map goes back to empty, the retiring assertion stays so the next entry is held to the same self-retirement, and the header records that it fired. See the PR body for the file-ownership check behind touching this file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019siH5jDmk5hrayvfyojUqR
📓 Docs Drift CheckThis PR changes 1 package(s): 2 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
What this run could not see
Coarse fallback — 23 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin d75d144077239f8f09118fdc77d89fd91b641c37 && git checkout d75d144077239f8f09118fdc77d89fd91b641c37
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin ab23c67abc2c99db9b58e70d46c438cd2c47151c bc08f9bbc91579cf6379a04d90d9b6153d6bbfd1 && git checkout -B drift-repro ab23c67abc2c99db9b58e70d46c438cd2c47151c && git merge --no-ff bc08f9bbc91579cf6379a04d90d9b6153d6bbfd1
node scripts/docs-audit/affected-docs.mjs --json ab23c67abc2c99db9b58e70d46c438cd2c47151c
|
os auth <cmd> / os studio invocation now names a command that resolvesos auth / os studio invocation now names a command that resolvesUh oh!
There was an error while loading. Please reload this page.
Fixes#11221
Fixes#11180
A family fold: two cards, one defect form — a documented CLI invocation that does not resolve — corrected to the real spelling, or removed. One commit per card, plus a third for the pin retirement the first commit fires. Verified against the built CLI, not by reading source.
The two cards
#11221 —
register/whoami/logoutexamples saidos auth …These three live at the root of
packages/cli/src/commands/, so oclif's pattern-strategy loader registers them asregister/whoami/logout. Theirstatic override examples— which oclif prints verbatim in--help— spelled anos auth …shape that has never resolved.Pre-fix, against
packages/cli/bin/run.js:…while the bare
os whoami/os register/os logouteach exited 0 and printed help. The examples named the one spelling that could not work.All seven
examplesentries now use the bare, registered spelling. The check that closes this card extracts the example lines from the rebuilt binary's own--helpoutput and resolves each against the rebuilt binary's own registry:(
TOKENon the sixth line is an angle-brackettokenplaceholder in the real example string and in the real output — respelled here per the note above.)The anti-vacuity block is the part that makes the seven
RESOLVESmean something: the same predicate still rejects the spellings this PR removed.Class renames.
AuthRegister→Register,AuthWhoami→Whoami,AuthLogout→Logout. oclif derives a command's id purely from its file path, never from the class name, so this changes no runtime resolution — re-verified by rebuilding and re-running--helpon all three. It also brings them onto this package's measured convention: surveying every root-level command source, each class is exactly the PascalCase of its filename, with theAuth*quartet the sole exception.login.tskeepsAuthLogin. Itsexampleswere already correct ($ os login), which puts it outside this card's file surface; that lone remaining holdout is reported, not swept.#11180 — the README listed
os studio, a command the CLI does not shippackages/cli/README.md's Development table carried a row readingos studio [config]— "Launch Studio UI with development server". Two independent readings, because "confirmed absent from the command registry" deserves better than a grep:Configenumerates 60 registered ids, of which zero matchstudio(and zero matchauth, and there is noauthtopic). Control, same enumeration:dev,serve,login,logout,register,whoamiall present. The control is what makes the zero evidence rather than a broken probe.os studio --helpexits 2 withError: Command studio not found.The row is deleted rather than rewritten. Studio is not reached by a CLI command at all — the console serves it at
/_console/studioafteros devoros serve, both of which this same table already lists. A replacement row would reintroduce the category error that made this one wrong: a Commands table lists commands, and a browser route is not one.The third commit: a pin that retired itself, exactly as designed
packages/cli/src/commands/environments/environments.test.ts(landed by #11227 for #10967) carries a deliberately self-retiringEXCLUDEDmap. Its header states the contract:That is measured here, not predicted. With only the first commit applied:
So #11221 could not land green without this edit, and the failing test names this card as the owner of the remedy. After retiring: 71 passed (71), with all three files now covered by the main assertion instead of exempted — the pin got stronger, not weaker.
Retirement shape follows the precedent the file names as its own (
packages/create-objectstack/src/starter-comments-self-contained.test.ts, retired the same way in #11022): the map goes back to empty, the retiring assertion stays so the next entry added is held to the same self-retirement, and the header records that it fired.On file ownership, since this path was on the dispatch's read-only list: that fence was attributed to #10967, which is closed (
completed, 2026-08-23T05:11:28Z) with PR #11227merged at 04:58 — roughly 3.5h before dispatch. No open PR or branch touches the file. The one genuinely live hold, #11268, touchesserve.ts,test/serve-node-env-production-default.e2e.test.ts,vitest.config.tsand its changeset — checked against its file list, zero overlap. Both genuinely-held surfaces (serve.ts,packages/cli/test/**) are untouched by this branch. Kept as its own commit so it can be dropped independently. Confirmed by the dispatching PM before this PR was opened.Out of scope, filed not swept
os auth login— that command does not resolve #11313 —packages/cli/src/utils/auth-config.ts:60throws "No stored credentials found. Please runos auth loginfirst.", andos auth loginis dead too (exit 2, measured). Deliberately not fixed here: it is a user-facing thrown error rather than anexamplesstring, so it is a different surface and belongs to a graded card of its own rather than being slipped into this one. Worth noting the existing pin cannot see this class at all — it readsexamplesarrays via AST.Verification
All at final head
bc08f9bb, each verdict quoted from what the gate itself printed.pnpm --filter @objectstack/cli test—Test Files 160 passed (160)/Tests 1822 passed (1822),VERDICT command-exit 0. Includesremote-api-commands.test.ts, which default-imports two of the renamed classes (default imports are rename-proof, so that held file needed no edit and still passes) andenvironments.test.ts.pnpm --filter @objectstack/cli typecheck(tsc --noEmit) —VERDICT command-exit 0.pnpm lint(repo-wideeslint . --no-inline-config) —VERDICT command-exit 0in 81s. Run in full; no narrowing taken.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(change set read by the script itself, three-dot, 7 paths). All 14 path-matched families run and green:check:changeset-gate-self-tests,check:cross-package-test-inputs,check:objectui-changeset,check:published-files,check:slot-lookup,check:test-source-alias,check:type-source-resolution,check-adr-0087-registration,check-changeset-no-major,check-ci-filter-parity,check-cross-package-test-inputs,check-empty-changeset,check-plugin-teardown-shape,check-affected-docs.check:query-options-erasure,check:type-check-coverage,check:engine-double-contract,check:where-matcher, pluscheck:nul-bytes.check:type-check-debt— first attempt refused (--re-measure cannot run: 1 workspace dependenc(ies) … have no built type entry point on disk -- @objectstack/service-knowledge), which means not measured, not passed. Built that closure and re-ran:OK — 33 ledger entr(ies) re-measured in 248.9s, 1897 raw tsc error(s) total, none above its recorded number. The--lowersurplus it reports sits inplugin-approvals/runtime/plugin-auth/trigger-record-change— all pre-existing and untouched by this diff.Two changesets, one per card, both
patchon@objectstack/cli, matching the precedent of both sibling fixes (#11227 for the help-text class, #10968 for the README-prose class). Noskip-changeset.Generated by Claude Code