Skip to content

Commit ea4aa5c

Browse files
docs, cli: the on-ramp a first-time reader walks reads true (CONTRIBUTING, README curl, one pnpm floor, five examples, os dev / os init strings, tutorial transcript) (#22280)
Fixes #22156 Clause-②: no This PR fixes the seven on-ramp items #22156 lists, one by one, each measured on this branch. Five are docs-only. Two are CLI strings, and patch round 1 adds `os start`'s help text to them. Those carry the one patch changeset for `@objectstack/cli`. `Clause-②: no`: the CLI change is help text and printed text, with no change to the accept set or the public surface. ## Item by item | # | Item | Change | Files | |:--|:--|:--|:--| | 1 | CONTRIBUTING.md described the retired `spec` repository | Rewritten for this repository. It names `objectstack-ai/objectstack` in the clone, upstream, issue and discussion URLs, and the `internal/planning` links are gone. It lists real docs trees and says which are generated (`references/`) or release-owned (`releases/`), where it used to send authors to hand-write MDX in `references/`. The bilingual `.cn.mdx` section is gone (0 such files), and so is the dead `QUICK_START_IMPLEMENTATION.md` link. The pnpm floor is now 10, and the title covers the whole stack. It points to AGENTS.md for the rules instead of restating them: the restated naming, Zod-first and single-source copies are removed. The flow now includes the changeset step and the worktree-per-task note. The `needs:pack-smoke` criterion is kept word for word, because `pack-smoke-optin.yml` says authors meet it in this file. | `CONTRIBUTING.md` | | 2 | README's first `curl` answered 401 | It now signs in as the dev admin `os dev` seeds and sends the cookie. These are the two calls the scaffolded README and `your-first-project.mdx` show, and the sentence before them says a data call needs a session. | `README.md` | | 3 | Three pnpm floors | All four places now say **pnpm 10**, with `corepack enable` installing the pinned version. That is the floor the workspace enforces (measured below). Patch round 1 adds two more lines of the same drift. `examples/app-todo/README.md` said `pnpm 8+` for the monorepo and now says `pnpm 10 (corepack enable)`. `your-first-project.mdx`'s prerequisites row said `npm 9+ / pnpm 8+ / yarn / bun` for a scaffolded project and now says `npm 9+ / pnpm 10.15+ / yarn / bun`, the floor both scaffolders write (`engines.pnpm` in `create-objectstack/src/templates/blank/package.json` and `SCAFFOLD_PNPM_RANGE` in `init.ts`). The npm, yarn and bun parts were not measured and are unchanged, and so is the `engines.protocol` line #22215 edits. | `content/docs/getting-started/index.mdx`, `examples.mdx`, `your-first-project.mdx`, `CONTRIBUTING.md`, `examples/app-todo/README.md` (`README.md` already said pnpm 10) | | 4 | "three ready-to-run examples" against five | The opening now says five. It names the three runnable apps (each has a `pnpm dev:*` script), then `app-multi-package` (linked to its section lower on the page) and `embed-objectql`. | `content/docs/getting-started/examples.mdx` | | 5 | `os dev --help` named only `$PORT` | `Server port (overrides $OS_PORT; $PORT is the legacy alias)`. That is the order `readEnvWithDeprecation('OS_PORT', 'PORT')` reads them in. Patch round 1 fixes `os start --help` the same way: `Port to listen on (overrides $PORT, default 3000)` becomes `Port to listen on, default 3000 (overrides $OS_PORT; $PORT is the legacy alias)`. `os start` reads the same pair at `start.ts:327`, and "default 3000" is kept because it measured true. No test, snapshot or generated docs page pins either old string, and `deployment/cli.mdx` is hand-written and already says `OS_PORT` / `PORT`. | `packages/cli/src/commands/dev.ts`, `packages/cli/src/commands/start.ts` | | 6 | The tutorial's "clean" transcript left out a warning | The example now **is** clean. `ticket.view.ts` declares the create and edit `form` that places `description`, and the prompt asks for that form. One paragraph explains that a field nothing names draws `field-no-consumers`. In patch round 1 its consumer list became visibly non-exhaustive ("a view, a form, a flow, a formula or an action, among the others the rule counts"), because the rule also credits page blocks, dataset members, validations, view filters and hooks. The transcript also carries the `Logic:` and `Security:` lines the command prints today. | `content/docs/getting-started/build-with-claude-code.mdx` | | 7 | `os init --no-install` printed `npm install` | The package manager is now resolved before the install branch, by the same rule as before: the flag, then the invoking package manager, then npm. Before, a `--no-install` run kept the literal `'npm'` initialiser, whatever was asked. | `packages/cli/src/commands/init.ts`, new `init-next-steps-package-manager.test.ts` | ## Route choices ### Item 6: a clean example, not a printed warning I chose the PM's suggested route, measured against both alternatives on the four axes: - **Real business need.** A ticket's description is typed on the create form. The published Console already draws it there through the default form (PR #22204's Acceptance notes), and the lint rule deliberately does not credit that unkeyed fallback layout (`validate-field-consumers.ts` docblock). Declaring the form makes the placement explicit. A grid column for long text, the one-line alternative, would teach the wrong UI, and the prompt asked for `(subject, status, priority)` columns. - **Long-term fit.** The page promises every example passes `os validate` verbatim. A clean example keeps that promise whatever the rule later credits. A transcript that prints the ~900-character warning would drift again the day the rule changes. - **Keeping AI from writing bad metadata.** This is a page agents copy. Showing the warning with "this is expected" teaches that advisories are noise. Showing the field placed teaches that every declared field has a consumer, which is the rule's intent. - **Startup scope.** Docs only: one `form` block (11 lines) and one paragraph. No new gate. Narrative check: the Console step ("Create a ticket. Confirm the fields…") reads the same, and the counts stay `2 Objects 6 Fields` and `1 Apps 1 Views 1 Actions`. ### Item 7: what changes and what does not Measured (below): under `--no-install` all three invocations printed `npm install`, including `--package-manager pnpm`, because the variable was assigned only inside `if (flags.install)`. That contradicts the flag's own help and the contract `create-objectstack` pins in `scaffold-next-steps-pm.test.ts` (never a hardcoded npm). After the fix, `--package-manager pnpm` and a pnpm-invoked run print `pnpm install` and `pnpm exec objectstack …`. A plain `npx os init … --no-install`, the card's literal command, still prints `npm install`, and that is correct. The scaffold deliberately supports npm, yarn and bun: it declares `engines.pnpm`, never a `packageManager` stamp, and `init.test.ts` pins this ("does NOT pin a packageManager — the scaffold also supports npm, yarn and bun"). `pnpm-workspace.yaml` is inert for npm. So the card's alternative, dropping the pnpm files when recommending npm, would change which files the scaffold writes. That is outside this card, and the design says it is not needed. Rollback: revert the `init.ts` hunk. The variable goes back to being assigned in the install branch, and nothing else reads it. ## Measurements (this branch; the CLI built from the worktree) - **Item 2.** I booted a tutorial-shaped scaffold with `os dev --fresh` on a random port. `GET /api/v1/data/support_desk_ticket` with no session gave `401 {"error":"UNAUTHENTICATED",…}`. `POST /api/v1/auth/sign-in/email` as the dev admin gave 200. The same GET with the cookie gave `200 {"object":"support_desk_ticket","records":[],…}`. `/api/v1/health` and `/api/v1/discovery` answer without a session, but neither shows that the object's API exists, so the README signs in instead. The server was stopped by its recorded PID. - **Item 3.** Root `engines` declares only a Node floor (22.0.0). `packageManager` is `pnpm@10.31.0`. The global pnpm here is 10.28.0 outside the repo and runs as 10.31.0 inside it, so pnpm 10 switches to the pin. In a throwaway worktree at the base commit, `pnpm@8.15.9 install --frozen-lockfile --lockfile-only` failed with `ERR_PNPM_LOCKFILE_BREAKING_CHANGE`, and `pnpm@9.15.9` failed with `ERR_PNPM_LOCKFILE_CONFIG_MISMATCH … "overrides" configuration doesn't match`. The floor is therefore pnpm 10. - **Item 5.** `os dev --help` before (base source): `Server port (overrides $PORT)`. After: `Server port (overrides $OS_PORT; $PORT is the legacy alias)`. `os start --help` before, on the CLI built at `8fe75a222`: `Port to listen on (overrides $PORT, default 3000)`. After, on the CLI built at `fae81259b`: `Port to listen on, default 3000 (overrides $OS_PORT; $PORT is the legacy alias)`. The behaviour the new text states was measured on that build. Each `os start` ran in an empty directory, inside a private network namespace (`unshare -n`) so the shared box's port 3000 stayed untouched. With no port variable, the banner read `API: http://localhost:3000/`. With `OS_PORT=41077` it read `:41077`. With `OS_PORT=41077 --port 41078` it read `:41078`. - **Item 3, patch round 1.** On an `os init` scaffold, `pnpm@9.15.9 install` fails with `ERR_PNPM_UNSUPPORTED_ENGINE … Expected version` 10.15 or later, `Got: 9.15.9`. The monorepo's pnpm 8 refusal is the item 3 reading above. - **Item 6.** I scaffolded the `blank` starter from `create-objectstack` source (`--skip-install --skip-skills`), wrote the page's four files verbatim and wired their barrels, then ran `os validate`. With the page's original view: `✓ Validation passed`, then the `field-no-consumers` warning for `support_desk_ticket.description` (verdict `inert`). With the edited page, re-run at `fae81259b`: `Running author-time rules (50)…`, `✓ Validation passed`, no warning, and the six summary lines the transcript now shows. `tsc --noEmit` on the scaffold passes, and `--listFiles` confirms it compiled `ticket.view.ts`. - **Item 7.** `os init APP --no-install` before and after the fix: | invocation | before | after | |:--|:--|:--| | npm user agent, no flag | `npm install` | `npm install` (control) | | npm user agent, `--package-manager pnpm` | `npm install` | `pnpm install` | | pnpm user agent, no flag | `npm install` | `pnpm install` | ## Tests and gates, at `fae81259b` (this branch after patch round 1 and merging `main` at `c8bb3c8d9`) - New `packages/cli/src/commands/init-next-steps-package-manager.test.ts` (unit tier, in-process `Init.run`, nothing spawned): 3 cases. - **Ablation.** With the fix committed, `scripts/ablation-replace.mjs` put the old semantics back (`flags.install ? (flag ?? detect) : 'npm'`): anchor 1→0, blob `c4c2caca` → `9b93b146`. Result: 2 failed (the flag case and the pnpm-agent case), and the npm control passed. Restore: blob equals HEAD, and `git diff HEAD` is empty. - `pnpm --filter @objectstack/cli typecheck`: exit 0 at `fae81259b` (`tsc --noEmit` compiles `src/**`, the new test included, and `check:test-typecheck` says OK). - `pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2`: 265 files, 3918 tests passed, at `fae81259b` and before that at `8fe75a222`. The integration tier is left to CI: the diff touches no spawn entry and no integration-tier file. - Derived gates: `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` on the 12-path diff gave 95 commands; the round-1 files added `check:examples-live-imports`. All 95 exited 0 at `fae81259b`. `--ran` reconciliation: 95 derived, 95 run, 0 NOT-MEASURED (a derived zero: every command has a recorded exit code). The earlier round gave 94 of 94 at `8fe75a222`. On the first pass, `check-docs-section-name` caught the new form section's missing `name`, which is fixed. ## Acceptance notes - **Two scaffolders, two detection rules.** `create-objectstack` names pnpm whenever `pnpm --version` succeeds. `os init` reads `npm_config_user_agent`. So under `npx` with pnpm installed, one says pnpm and the other says npm. Both instructions install, so this is an observation, not a defect. Carrier: none. - **The `field-no-consumers` headline.** Its text says "nothing in this stack reads or displays it" for a field the default form does draw. The rule's docblock excludes that unkeyed fallback layout on purpose: crediting it would credit every visible field. I read it as working to its contract and did not edit `packages/lint`. Carrier: none. - **No browser check of the new form.** The Console was not driven against the new `form` view: no objectui build in this container. That the form view is what the create and edit surfaces render is a reading of `examples/app-crm/src/views/lead.view.ts`, not a measurement here. - `packages/cli/test/start-port-banner-agreement.e2e.test.ts:204` quotes the old `os start` help text ("overrides $PORT") in a comment. It asserts nothing, and the file is outside the surface, so it is left as is. --- _Generated by [Claude Code](https://claude.ai/code/session_0115N1oNnQS5WqofZ2DzaT3q)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 4578c56 commit ea4aa5c

12 files changed

Lines changed: 261 additions & 410 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
"@objectstack/cli": patch
3+
---
4+
5+
`os dev --help` and `os start --help` name `OS_PORT` for `--port`, and `os init --no-install` names the package manager it resolved in its Next steps.
6+
7+
Clause-②: no
8+
9+
- **`os dev --port`.** The help text read `Server port (overrides $PORT)`, though `os dev` reads `OS_PORT` first and `PORT` only as its legacy alias. It now reads `Server port (overrides $OS_PORT; $PORT is the legacy alias)`. Which variables are read, and in what order, is unchanged.
10+
- **`os start --port`.** The same drift: the help text read `Port to listen on (overrides $PORT, default 3000)`, though `os start` reads `OS_PORT` first as well. It now reads `Port to listen on, default 3000 (overrides $OS_PORT; $PORT is the legacy alias)`. The port behaviour is unchanged.
11+
- **`os init --no-install`.** The package manager was resolved only when an install ran, so a `--no-install` run always printed `npm install` and `npx objectstack …`, even with `--package-manager pnpm` or when invoked through pnpm. It is now resolved before the install step, the same way as before (the `--package-manager` flag, then the invoking package manager, then npm), so `os init my-app --no-install --package-manager pnpm` prints `pnpm install` and `pnpm exec objectstack …`. A run with no flag, invoked through npm or `npx`, still prints `npm install`: the scaffold supports npm, yarn and bun as well as pnpm.

0 commit comments

Comments
 (0)