Repository navigation
Commit 53fd35e
docs(spec): cli-extension TSDoc step 2 "Discover" says what loads an oclif plugin into
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`, then
`gen:docs`), not edited by hand. It moves by exactly the same five
lines.
- `.changeset/21286-cli-extension-tsdoc-discover.md`: an
`@objectstack/spec` `patch`. The package's `files[]` lists
`src/**/*.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 `PKG` stands for an angle-bracketed placeholder
in the source):
> 2. **Discover** — The main CLI (`@objectstack/cli`) lists the plugin
in its `oclif.plugins` array, or users install it via `os plugins
install PKG`.
After:
> 2. **Discover** — oclif loads a plugin that the CLI's own
`package.json` lists in both `oclif.plugins` and `dependencies`.
`@objectstack/cli` lists none and ships no plugin manager, so `os
plugins` is not a command. To add a plugin's commands to `os`, build an
`os` distribution: a package whose own `package.json` lists the plugin
in both places.
Both halves of the old sentence were false. `@objectstack/cli` keeps no
`oclif.plugins` list, and `os plugins install` is not a command. The new
text matches `packages/cli/README.md` ("How Plugin Extension Works",
step 3) and the callout in `content/docs/plugins/index.mdx`, so all
three surfaces say the same thing.
## Sentences measured and kept
Each sentence was checked against `@objectstack/cli` and `@oclif/core`
5.1.2 on `origin/main` `3a6d92f78b`:
- Intro: "This enables third-party packages … to register new CLI
commands via oclif's built-in plugin system." True. Probe legs C and E
(below) show a third-party plugin registering a command through oclif's
plugin loader.
- Step 1, "Declare": true. The plugin's own `oclif` section is what the
loader reads.
- Step 3, "Load": true. Once a plugin is loaded, its pattern-strategy
commands register (`acme-hello` in legs B, C, E and F).
- "Plugin Package Contract" and the two examples: true. They describe a
valid oclif plugin.
- "Migration from Commander.js": true. `git grep` finds no `commander`
and no `contributes.commands` read in `packages/cli/src`, so
`objectstack.config.ts` plugins do not decide CLI commands.
## Measurements
**What `packages/cli/package.json` declares.** `jq '.oclif.plugins'`
answers `null`. The `oclif` keys are `bin`, `dirname`, `commands`,
`hooks` and `topicSeparator`, 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/core` 5.1.2,
which is the call `bin/run.js`'s `run()` makes. A throwaway plugin
`@acme/os-ext` carries one command, `acme-hello`. `packages/cli/dist`
was not built, so the root's own command count is 0 in every leg. The
probe reads the plugin list and whether `acme-hello` registered.
| leg | root | data dir (`OS_DATA_DIR`) | plugins loaded | `acme-hello`
|
|---|---|---|---|---|
| A | `packages/cli` | empty | `@objectstack/cli` only | no |
| B | `packages/cli` | `package.json` lists the plugin as `type: user` |
`@objectstack/cli`, `@acme/os-ext` (user) | yes |
| C | a distribution: `oclif.plugins` plus `dependencies` | empty | dist
root, `@acme/os-ext` (core) | yes |
| D | a distribution: `oclif.plugins` plus `devDependencies` only |
empty | dist root only | no |
| E | a distribution listing `@objectstack/cli` and the plugin | empty |
dist root, `@objectstack/cli`, `@acme/os-ext` (all core) | yes |
| F | `packages/cli` | `package.json` lists the plugin as `type: link` |
`@objectstack/cli`, `@acme/os-ext` (link) | yes |
Legs C and D are the rule the new step states, with its control. Leg E
shows that a distribution loads `@objectstack/cli` itself as a core
plugin. That reading is at the plugin level only: `@objectstack/cli`'s
own commands are NOT MEASURED there, because its `dist` was not built.
**The reference page moves by exactly the changed sentences.** These are
the generator's own checks:
- With the base tree's page written back on disk (the old sentence
present, the new one absent), `pnpm check:docs` exits 1 and names one
file, `content/docs/references/kernel/cli-extension.mdx (out of date)`.
- The page was then restored from `HEAD`, and `git hash-object` matched
the `HEAD` blob `df95a843d9`.
- `pnpm --filter @objectstack/spec check:generated` (15 artifacts) is
green at that tree.
**Other mentions.** `git grep` over `packages/spec/**` and
`content/docs/**` for `os plugins`, `plugins install`, `plugin-plugins`
and `oclif.plugins` found no other spec-surface hit. The remaining hits
are `content/docs/plugins/index.mdx:402-410`, the callout, which is
already correct. See the acceptance notes for `objectstack plugin
install` (singular).
## Acceptance notes (not changed here)
- **`os` also 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 reads `package.json` in the data directory
(`$OS_DATA_DIR`, else `$XDG_DATA_HOME/objectstack`, else
`~/.local/share/objectstack`) and loads `type: user` and `type: link`
entries. Nothing `os` ships writes that file: it is the store
`@oclif/plugin-plugins` maintains. The new step does not name it and
does not claim the distribution is the only route. It also bears on the
separate `OclifPluginConfig` enforce-or-remove question. One more
consequence: `packages/cli/bin/run.js`'s comment that a linked-plugin
path "is not reachable today" holds only for `os plugins link`. A
hand-written `type: link` entry still loads (leg F). Carrier: none
(`domain:cli`'s file).
- **`content/docs/protocol/kernel/lifecycle.mdx` (lines 194, 287,
357-403)** documents `objectstack plugin install`, `plugin enable` and
`plugin test`. `packages/cli/src/commands/plugin/` holds only `build`,
`publish` and `sign`, and `packages/cli/README.md` says the group has no
`install`. 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.
- **The code comment under the module TSDoc in `cli-extension.zod.ts`**
(the retirement note) calls `OclifPluginConfigSchema` "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 build` exits 0 (the lock printed
`VERDICT command-exit 0`). Then `gen:docs` exits 0 ("Generated 227
files"), and `check:generated` exits 0 ("All 15 generated artifacts are
up to date").
- `pnpm --filter @objectstack/spec test` exits 0: 600 test files, 17681
passed, 1 todo.
- `pnpm --filter @objectstack/spec typecheck` exits 0, with
`check:test-typecheck: OK`.
- The red leg of `check:docs` is described under Measurements above.
- Gate derivation: `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.
- 103 exit 0. Five of them first refused with exit 3 (`PREREQUISITE NOT
MET`): `check:doc-formula-expressions`, `check:doc-security-posture`,
`check:skill-examples`, `check:docs-transcript-drift` and
`check:lean-entry-closure`. Each exits 0 after its prerequisite was
built with `turbo run build --filter=@objectstack/formula
--filter=@objectstack/lint --filter=@objectstack/client-react
--filter=@objectstack/objectql` (exit 0).
- `check:dual-build-cjs-loads` is NOT MEASURED. It needs every package's
`dist` (a full `pnpm build`, 86 packages). This narrowing is declared:
CI's `Lint & Repo Gates` runs it on a full build.
- `--ran` reconciliation: "104 derived famil(ies) accounted for — 103
run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3)".
- Left to CI and not run here: the artifact-roster, wide-population and
path-scheduled CI families, plus the type-check lanes that the
derivation lists outside its 104.
- The loader probe is a throwaway script and is not committed.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01UtnxvdiN376GF3sgXwAw4d)_
---------
Co-authored-by: Claude <noreply@anthropic.com>os (#21443)1 parent b793010 commit 53fd35e
3 files changed
Lines changed: 19 additions & 4 deletions
File tree
- .changeset
- content/docs/references/kernel
- packages/spec/src/kernel
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
20 | | - | |
21 | | - | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
22 | 25 | | |
23 | 26 | | |
24 | 27 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | | - | |
18 | | - | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
19 | 22 | | |
20 | 23 | | |
21 | 24 | | |
| |||
0 commit comments