docs(spec): cli-extension TSDoc step 2 "Discover" says what loads an oclif plugin into os - #21443
Conversation
…in into os The module TSDoc's step 2 said @objectstack/cli lists the plugin in its oclif.plugins array, or that users install it with `os plugins install`. @objectstack/cli declares no oclif.plugins and ships no plugin manager, so neither is true. The step now names the oclif rule (oclif.plugins plus dependencies of the CLI's own package.json) and the os-distribution route. Claude-Session: https://claude.ai/code/session_01UtnxvdiN376GF3sgXwAw4d Co-authored-by: Claude <noreply@anthropic.com>
Regenerated with `pnpm --filter @objectstack/spec gen:docs` after a spec build; the page lifts the module TSDoc, so only step 2 moves. Claude-Session: https://claude.ai/code/session_01UtnxvdiN376GF3sgXwAw4d Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check
What this run could not see
Coarse fallback — 138 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
Contract reviewServed-tier: Inputs: card #21286 (body; triage ① Derived judgmentsAccept set and public surface:
Each new sentence, read against the code at
Overstate or understate? The dev's probe finding is CONFIRMED from source. Is the new step a false exclusivity claim? No. The words are "oclif loads a plugin that the CLI's own Kept block spot-check, all TRUE at One reading, not a defect: neither the new step nor the README nor the plugins doc says how a distribution gets ② Semver level
Changeset prose, sentence by sentence: (1) "no longer tells plugin authors to run ③ Boundary flagsDev deviations:
Check-runs on this head at the final read (2026-10-02T17:32Z): 35 check-runs, 33 completed with conclusion success, 2 completed skipped ( Implemented-by: VERDICT: PASS |
Fixes #21286
Clause-②: no
What changes
packages/spec/src/kernel/cli-extension.zod.ts: the module TSDoc, "How It Works", step 2 "Discover" is rewritten. No schema, export, type or.describe()change.content/docs/references/kernel/cli-extension.mdx: regenerated with the repo's generator (pnpm --filter @objectstack/spec build, thengen:docs), not edited by hand. It moves by exactly the same five lines..changeset/21286-cli-extension-tsdoc-discover.md: an@objectstack/specpatch. The package'sfiles[]listssrc/**/*.zod.ts, so this source text ships in the tarball.Sentences changed (before, then after)
Only one sentence in the module TSDoc was false. It is step 2, "Discover".
Before (the placeholder
PKGstands for an angle-bracketed placeholder in the source):After:
Both halves of the old sentence were false.
@objectstack/clikeeps nooclif.pluginslist, andos plugins installis not a command. The new text matchespackages/cli/README.md("How Plugin Extension Works", step 3) and the callout incontent/docs/plugins/index.mdx, so all three surfaces say the same thing.Sentences measured and kept
Each sentence was checked against
@objectstack/cliand@oclif/core5.1.2 onorigin/main3a6d92f78b:oclifsection is what the loader reads.acme-helloin legs B, C, E and F).git grepfinds nocommanderand nocontributes.commandsread inpackages/cli/src, soobjectstack.config.tsplugins do not decide CLI commands.Measurements
What
packages/cli/package.jsondeclares.jq '.oclif.plugins'answersnull. Theoclifkeys arebin,dirname,commands,hooksandtopicSeparator, and no dependency field names an@oclif/plugin-*package. This confirms the PM's mechanism assumption 1.Loader probe. It calls
Config.load()from@oclif/core5.1.2, which is the callbin/run.js'srun()makes. A throwaway plugin@acme/os-extcarries one command,acme-hello.packages/cli/distwas not built, so the root's own command count is 0 in every leg. The probe reads the plugin list and whetheracme-helloregistered.OS_DATA_DIR)acme-hellopackages/cli@objectstack/clionlypackages/clipackage.jsonlists the plugin astype: user@objectstack/cli,@acme/os-ext(user)oclif.pluginsplusdependencies@acme/os-ext(core)oclif.pluginsplusdevDependenciesonly@objectstack/cliand the plugin@objectstack/cli,@acme/os-ext(all core)packages/clipackage.jsonlists the plugin astype: link@objectstack/cli,@acme/os-ext(link)Legs C and D are the rule the new step states, with its control. Leg E shows that a distribution loads
@objectstack/cliitself as a core plugin. That reading is at the plugin level only:@objectstack/cli's own commands are NOT MEASURED there, because itsdistwas not built.The reference page moves by exactly the changed sentences. These are the generator's own checks:
pnpm check:docsexits 1 and names one file,content/docs/references/kernel/cli-extension.mdx (out of date).HEAD, andgit hash-objectmatched theHEADblobdf95a843d9.pnpm --filter @objectstack/spec check:generated(15 artifacts) is green at that tree.Other mentions.
git grepoverpackages/spec/**andcontent/docs/**foros plugins,plugins install,plugin-pluginsandoclif.pluginsfound no other spec-surface hit. The remaining hits arecontent/docs/plugins/index.mdx:402-410, the callout, which is already correct. See the acceptance notes forobjectstack plugin install(singular).Acceptance notes (not changed here)
osalso loads plugins from its data directory. Legs B and F show this.@oclif/core's user-plugin loader runs whether or not a plugin manager is installed. It readspackage.jsonin the data directory ($OS_DATA_DIR, else$XDG_DATA_HOME/objectstack, else~/.local/share/objectstack) and loadstype: userandtype: linkentries. Nothingosships writes that file: it is the store@oclif/plugin-pluginsmaintains. The new step does not name it and does not claim the distribution is the only route. It also bears on the separateOclifPluginConfigenforce-or-remove question. One more consequence:packages/cli/bin/run.js's comment that a linked-plugin path "is not reachable today" holds only foros plugins link. A hand-writtentype: linkentry still loads (leg F). Carrier: none (domain:cli's file).content/docs/protocol/kernel/lifecycle.mdx(lines 194, 287, 357-403) documentsobjectstack plugin install,plugin enableandplugin test.packages/cli/src/commands/plugin/holds onlybuild,publishandsign, andpackages/cli/README.mdsays the group has noinstall. This was found by reading the files, not by running a built binary. It is a hand-written docs page outside this card's surface. Carrier: none.cli-extension.zod.ts(the retirement note) callsOclifPluginConfigSchema"that live surface". It is not part of the TSDoc block, and whether the surface is live is the maintainer's enforce-or-remove question, so it is left alone.Verification
Every reading below was taken at
52ece7d949, the PR's head.pnpm --filter @objectstack/spec buildexits 0 (the lock printedVERDICT command-exit 0). Thengen:docsexits 0 ("Generated 227 files"), andcheck:generatedexits 0 ("All 15 generated artifacts are up to date").pnpm --filter @objectstack/spec testexits 0: 600 test files, 17681 passed, 1 todo.pnpm --filter @objectstack/spec typecheckexits 0, withcheck:test-typecheck: OK.check:docsis described under Measurements above.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, with no paths, listed 104 commands for this change set. Each was run with its exit code captured before any pipe.PREREQUISITE NOT MET):check:doc-formula-expressions,check:doc-security-posture,check:skill-examples,check:docs-transcript-driftandcheck:lean-entry-closure. Each exits 0 after its prerequisite was built withturbo run build --filter=@objectstack/formula --filter=@objectstack/lint --filter=@objectstack/client-react --filter=@objectstack/objectql(exit 0).check:dual-build-cjs-loadsis NOT MEASURED. It needs every package'sdist(a fullpnpm build, 86 packages). This narrowing is declared: CI'sLint & Repo Gatesruns it on a full build.--ranreconciliation: "104 derived famil(ies) accounted for — 103 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3)".Generated by Claude Code