Skip to content

Commit c8e5ac6

Browse files
claude[bot]os-salesclaude
authored
feat(cli)!: retire os create example; the refusal names os init (#16483) (#16665)
* feat(cli)!: retire `os create example`; the refusal names `os init` (#16483) The `example` template emitted a subset of what `os init` writes plus one README, the only template-level duplication #15531 found between the two scaffolder families. Removed under the #15531 ruling (batch #66, option B) with no alias and no deprecation window. The template is not merely deleted: `os create example` still answers, exits 1 and names `os init`, rather than falling through to `Unknown type:` and printing only the surviving roster. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YFY46JydE1gMxQG1TqBcMZ * docs(cli): make the retirement's citations match what is verifiable (#16483) Contract review on PR #16665, findings F1-F4. F1 — the "no alias, no deprecation window" ruling could not be located by the review: not in #15531's comments, not in ledger #12708 (whose earliest comment postdates the attributed date), not in the tree. The removal itself IS verified by the #15531 batch #66 entry, so create.ts and the e2e header now cite that and record the alias/window terms as recorded on card #16483, pending maintainer confirmation. The runtime message is deliberately unchanged: it describes what the code does, which is true whoever ruled it. F2 — `os init` does NOT write "the same objectstack.config.ts". The audit this card cites measures tsconfig.json byte-identical and the two manifests DIFFERENT (both ManifestSchema-valid). Runtime message and changeset now say "the same tsconfig.json and an equivalent objectstack.config.ts", and the changeset states the difference. F3 — `-t empty` writes five files and runs the install, so "objectstack.config.ts only" was wrong in the runtime message, the changeset and the doc callout this PR added. All three now read "config only, no src/objects". F4 — the changeset said the e2e file holds the doc pages (the docs pin is the separate queue-tier file) and that `--in-repo` is unchanged (its examples/ placement goes with the template). Both corrected. F5 is deliberately NOT acted on here: SCAFFOLD_TSX_RANGE stays, init.ts is held by #16654. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YFY46JydE1gMxQG1TqBcMZ --------- Co-authored-by: os-sales <sales@objectstack.ai> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent fc0a783 commit c8e5ac6

11 files changed

Lines changed: 601 additions & 164 deletions
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
---
2+
"@objectstack/cli": minor
3+
---
4+
5+
feat(cli)!: retire `os create example` — it was a weaker `os init` plus a README, and the refusal now names `os init` (#16483, #15531)
6+
7+
**BREAKING** — a published CLI surface is removed. `os create example <name>` is a
8+
command a user can run today and cannot run after this release. Graded `minor`
9+
rather than `major` under this repo's lockstep launch-window convention (no
10+
package here has ever shipped a `major` changeset); the break is stated here
11+
instead of in the number.
12+
13+
<!-- adr-0087: not-required (no-migration-prescription) the retired surface is a CLI subcommand, not authored metadata: no Zod schema, no `packages/spec` declaration, no authorable key and no stored `sys_metadata` shape changes, so `objectstack migrate meta` has nothing to rewrite and the ledger has no step to carry. The channel that reaches every affected caller is the command itself, which now exits non-zero naming `os init`. -->
14+
15+
**No alias and no deprecation window.** `os create example` will not come back,
16+
so change the command rather than pinning an older CLI. (Those terms are recorded
17+
on card #16483 and are pending maintainer confirmation — the removal itself is
18+
settled by the #15531 batch entry below. The behaviour ships either way, and it is
19+
the same shape `os g agent` already shipped.)
20+
21+
#15531 rendered the real emission of both scaffolder families and hashed it file
22+
by file. The only template-level duplication left between them was this one
23+
template: `os create example` wrote a **subset** of what `os init` writes, plus
24+
one README. The two families' emission policy is already unified through four
25+
shared exports, so the remaining duplicate was the template itself — and the
26+
ruling (decision batch #66, option B) is that it goes, not that the two command
27+
families merge. They emit two different artifacts: a kernel code `Plugin` is not
28+
a declarative app, and collapsing them would make that collision structural.
29+
30+
**What to run instead**
31+
32+
```bash
33+
os init <name> # a full application project
34+
os init <name> -t empty # config only, no src/objects
35+
```
36+
37+
`os init` writes the same `tsconfig.json` the retired template did (byte-identical,
38+
measured) and an **equivalent** `objectstack.config.ts` — both manifests are
39+
`ManifestSchema`-valid but they are not the same bytes: the retired template wrote
40+
`name: '<name>'`, `description: '<name> example application'` and commented-out
41+
barrels, where `os init` writes a title-cased `name`, an empty `description` and no
42+
barrels. On top of that `os init` adds `src/objects`, a `.gitignore` and the
43+
dependency install the retired template never had.
44+
45+
**`os create plugin` is unaffected.** It scaffolds the kernel code `Plugin`
46+
contract — `src/index.ts` exporting a `Plugin` with `init` / `destroy`, built by
47+
`tsc`, publishable as `@objectstack/plugin-<name>` — which `os init` does not
48+
emit. `os create`'s flags and its standalone emission policy are unchanged for
49+
`plugin`. ⚠️ `--in-repo` is narrowed rather than untouched: the flag survives, but
50+
its `examples/<name>` placement is removed with the template and gets no
51+
replacement — `--in-repo` now only ever lands in `packages/plugins/plugin-<name>`.
52+
53+
**The removal is a signpost, not a deletion.** `os create example` still answers:
54+
it exits **1** and names `os init`, rather than falling through to the generic
55+
`Unknown type:` roster. A reader arriving from an older tutorial or a CI script
56+
that still calls it learns what replaced it instead of learning only that their
57+
spelling is off the list. Pinned end-to-end by driving the real CLI in
58+
`packages/cli/test/create-example-retired.e2e.test.ts`, which asserts both halves
59+
— the non-zero exit **and** the message naming `os init`. The four public doc
60+
pages are held to the same promise by a SEPARATE pin,
61+
`packages/cli/test/create-example-retired-docs-parity.test.ts`: it spawns nothing,
62+
so unlike the `.e2e` file it runs in the per-PR tier rather than the nightly one.

content/docs/deployment/cli.mdx

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,7 +1241,7 @@ only.
12411241
| Command | Alias | Description |
12421242
|---------|-------|-------------|
12431243
| `os generate <type> <name>` | `os g` | Generate metadata files |
1244-
| `os create <type> [name]` | | Scaffold a standalone plugin or example project |
1244+
| `os create <type> [name]` | | Scaffold a standalone **kernel code** plugin project |
12451245

12461246
#### `os generate` (alias: `os g`)
12471247

@@ -1314,19 +1314,31 @@ third-party extension primitive, authored as `src/skills/<name>.skill.ts` with
13141314

13151315
#### `os create`
13161316

1317-
Scaffolds a **standalone** project — a **kernel code** plugin (the `Plugin` contract,
1317+
Scaffolds a **standalone** **kernel code** plugin project (the `Plugin` contract,
13181318
built by `tsc`, publishable; *not* the metadata plugin `os init -t plugin` emits — see
1319-
[Which scaffolder?](#os-init)), or an example application — into the current directory:
1319+
[Which scaffolder?](#os-init)) into the current directory:
13201320

13211321
```bash
13221322
os create plugin analytics # Create ./plugin-analytics
1323-
os create example my-app # Create ./my-app
13241323

13251324
cd plugin-analytics
13261325
pnpm install
13271326
pnpm build
13281327
```
13291328

1329+
<Callout type="warn" title="`os create example` is retired">
1330+
Use [`os init`](#os-init) to scaffold an application. `os create example` emitted a
1331+
subset of what `os init` writes plus one README, so it was withdrawn in
1332+
[#16483](https://github.com/objectstack-ai/objectstack/issues/16483) rather than kept as
1333+
a second, weaker way to do the same thing — with **no alias and no deprecation window**.
1334+
Running it now exits non-zero and names `os init`.
1335+
1336+
```bash
1337+
os init my-app # a full application project
1338+
os init my-app -t empty # config only, no src/objects
1339+
```
1340+
</Callout>
1341+
13301342
The emitted `package.json` declares its `@objectstack/*` dependencies as
13311343
published semver ranges pinned to the version of the CLI that generated it, and
13321344
the emitted `tsconfig.json` is self-contained, so the project installs and
@@ -1335,9 +1347,8 @@ builds anywhere — a workspace around it is neither needed nor assumed.
13351347
**Options:**
13361348
- `-d, --dir <directory>` — Write the project here instead of `./<name>`
13371349
- `--in-repo` — Scaffold **inside an ObjectStack monorepo checkout** instead
1338-
(`packages/plugins/<name>` for a plugin, `examples/<name>` for an example),
1339-
with `workspace:*` dependencies and a `tsconfig.json` that extends the
1340-
repository root config. For ObjectStack platform work only: the project it
1350+
(`packages/plugins/plugin-<name>`), with `workspace:*` dependencies and a
1351+
`tsconfig.json` that extends the repository root config. For ObjectStack platform work only: the project it
13411352
writes installs nowhere else, and the command refuses the flag when the
13421353
current directory is not a pnpm workspace root.
13431354

0 commit comments

Comments
 (0)