Uh oh!
There was an error while loading. Please reload this page.
fix(create-objectstack): scaffolder "Next steps" names the pm it actually used - #11013
Conversation
…ly used npm vs pnpm vs `npm run`: a newcomer got three different answers to "what do I run next" — the scaffolder's own printed "Next steps" hardcoded `npm run dev` / `npm run validate` regardless of which package manager the run actually installed with, while the generated blank/README.md consistently said pnpm. Read at HEAD: `detectPackageManager()` (packages/create-objectstack/src/index.ts) still prefers pnpm and falls back to npm only when pnpm is unreachable — confirmed still the tool's real behaviour, matching triage's evidence. Also measured empirically with the built CLI: a real run with pnpm on PATH installs with pnpm (pnpm-lock.yaml, "Done in ... using pnpm vX") and then printed `npm run dev` / `npm run validate` as next steps — the exact three-answers defect. A second real run with pnpm made unreachable (PATH without it) correctly fell back to npm and produced package-lock.json, confirming the fallback is real and must not be stranded by deleting the npm path outright. Fix: detect the package manager once, up front (a read-only `<pm> --version` probe, so it costs nothing even under --skip-install), and reuse that one value for the install command, the install-failure remedy, and every line of "Next steps" — so the printed guidance always names the tool the run actually used, in both the pnpm and the npm-fallback case. Pinned end-to-end via tsx (scaffold-next-steps-pm.test.ts), exercising both branches by controlling PATH. Also names `validate` — the step the generated AGENTS.md calls unskippable — in the blank template's "Getting started" section, not only in its later "Verify your changes" section, so a newcomer reading top-to-bottom sees it at first touch. The README is a static template file (only its H1 is rewritten at scaffold time), so this is pinned as a source-text assertion (blank-readme-validate-disclosure.test.ts) rather than a runtime test. Root README.md's `npm create objectstack@latest` (cluster A) and the scaffolder's `◆ Create ObjectStack v6.x` banner (#10325, shared index.ts, still open) are deliberately untouched — out of this card's scope. Fixes#10322 Claude-Session: https://claude.ai/code/session_019bmVFqoQPq63zhKrxdYG1r
📓 Docs Drift Check4 anchor(s) derived from 2 changed package(s); no hand-written page names any of them. ✅ What this run could not see
Coarse fallback — 8 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 fe9e1d264fb1512d604f04e07a740e11173e5932 && git checkout fe9e1d264fb1512d604f04e07a740e11173e5932
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin f334d662ef3c2543d6add14b9140ab9350041cb2 af84683da6c21d37254c62a0b82af692bdedd0ca && git checkout -B drift-repro f334d662ef3c2543d6add14b9140ab9350041cb2 && git merge --no-ff af84683da6c21d37254c62a0b82af692bdedd0ca
node scripts/docs-audit/affected-docs.mjs --json f334d662ef3c2543d6add14b9140ab9350041cb2 |
…ge roster The Lint & Repo Gates check:cross-package-test-inputs failure on #10322: scaffold-next-steps-pm.test.ts's header comment cites packages/cli/src/commands/init.ts in backticks (contrasting create-objectstack's new detected-package-manager guidance with init.ts's own, already-threaded "Next steps"), and the flat literal collector takes quoted repo-relative paths without parsing comments. Per the roster's own settled precedent (serve.ts, gen-sdui-manifest.sh, publish-smoke.sh — mentions rather than reads), the fix is to declare the file, not reword the comment. Mirrors the entry into turbo.json's create-objectstack#test inputs.
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 32565262758 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
Fixes#10322
Premise check (Prime Directive #6)
Reproduced the "three different answers" state at the branch point (
origin/main@434af3038):README.md:49(cluster A, untouched)npm create objectstack@latest my-appindex.ts)npm run dev/npm run validateblank/README.mdpnpm install/pnpm devStill reproducible — confirmed by running the real, repo-built CLI (below). One part of the issue's premise does not hold at HEAD, though: "the generated README never mentions
npm run validate" is false —blank/README.md's "Verify your changes" section has namedpnpm validatesince7cf283a3fc(2026-06-22, well before this issue was filed). The real gap is narrower: that mention sits mid-document, not in the "Getting started" section a newcomer reads first — so I fixed that gap rather than treating the section as missing.Part 1 — which package manager, re-derived at HEAD
detectPackageManager()(packages/create-objectstack/src/index.ts) still triespnpm --versionfirst and falls back tonpmonly whenpnpmis unreachable — confirmed unchanged, matching triage's evidence.Part 2 — is the install actually redundant? (measured, not assumed)
Built the scaffolder from repo
distand ran it for real, twice:PATH(this container's default):Done in 10.5s using pnpm v10.33.0,pnpm-lock.yamlwritten,node_modules/populated — a real install, not a skip.PATHpointed at a dir with onlynode+npm): fell back tonpm install,package-lock.jsonwritten instead.So the install is conditional — skippable via
--skip-install, and on a real failure the scaffolder already tells the user to install manually. Deleting thepnpm installline from the generated README's "Getting started" section outright would strand exactly those two cases, and the README is also the project's durable, standalone doc (read again on a future re-clone, by a teammate who never ran the scaffolder at all) — re-runningpnpm installwhen deps already exist is a harmless no-op. So I left that line in place; this is a stop-and-report per the dispatch brief, not a quiet deletion.What was a real, fixable bug on this axis: the scaffolder's own dynamic output (its printed "Next steps" and the install-failure remedy) hardcoded
npmregardless of which package manager the run had just used — so a user who watchedpnpm installrun was then toldnpm run dev. That's the code fix below.The fix
packages/create-objectstack/src/index.ts: detect the package manager once, up front (a read-only<pm> --versionprobe — costs nothing even under--skip-install), and reuse that single value for the install command, the install-failure remedy, and every line of "Next steps". Verified against the rebuilt CLI in both branches:packages/create-objectstack/src/templates/blank/README.md: added one pointer sentence topnpm validateright after the "Getting started" quickstart block (before the reader moves on to the REST/Console/MCP sections), linking to the existing fuller "Verify your changes" explanation rather than duplicating it.Tests
Both
index.tsand the README are exercised by new pins (packages/create-objectstack/src/):scaffold-next-steps-pm.test.ts— runs the real CLI end-to-end viatsx(same no-build subprocess pattern asscaffold-description.test.ts;index.tscallsprogram.parse()at import time, so it can't be unit-tested directly), controllingPATHto exercise both the pnpm and the npm-fallback branch, plus a source-text pin on the install-failure remedy.blank-readme-validate-disclosure.test.ts— the README is a static template file (only its H1 is rewritten at scaffold time, everything else copied byte-for-byte), so there's no code path to unit-test; this is a source-text pin, following the existing pattern inblank-template-console-disclosure.test.ts.Reverse-verified: checked out
origin/main's pre-fixindex.ts/README.mdon top of the new tests — 3 tests went red (exactly the ones exercising the fix) — then restored the committed fix and confirmed all 110 tests green again.Gates (derived at final commit
8029fc20a0, vianode scripts/pm/dispatch-gates.mjs)Local gates the change surface matched, all green (verdict lines quoted, not bare exit codes):
pnpm check:changeset-gate-self-tests→✓ ... all checks passed(both self-tests)pnpm check:objectui-changeset→✓ objectui-changeset-digest --self-test: all checks passed/✓ objectui-range --self-test: all checks passedpnpm check:slot-lookup→✓ slot-lookup ratchet holds: 107 unswept site(s) ..., none newpnpm check:template-version-sync→✓ sync-template-versions --self-test: 40 assertions ...pnpm check:test-source-alias→check-test-source-alias OK — 72 packages ... scannedpnpm check:type-source-resolution→check-type-source-resolution OK — 77 packages ... scannednode scripts/check-adr-0087-registration.mjs→✓ this PR adds no declared-breaking changesetnode scripts/check-changeset-no-major.mjs→✓ This diff introduces no \major` bump.`node scripts/check-ci-filter-parity.mjs→OK: all 82 declared cross-package glob(s) ... coverednode scripts/check-empty-changeset.mjs→✓ No empty-frontmatter changeset introducednode scripts/check-plugin-teardown-shape.mjs→✓ ... 0 known-unreached, SHRINK-ONLY, baseline fully burned downnode scripts/docs-audit/check-affected-docs.mjs→✓ affected-docs self-test: 339 cases pass(exit 0)Convention-triggered (this PR adds test files):
pnpm check:query-options-erasure,check:engine-double-contract(OK — 377 pinned, 133 in the DEBT ledger, 2 exempt),check:where-matcher(✓ ... 0 silently-wrong and 0 unjudged ..., none new) — all green.pnpm check:type-check-coverage/check:type-check-debt— built the full workspace closure first (pnpm exec turbo run build --filter='./packages/*' --filter='./packages/*/*', 70/70 tasks successful), thencheck-type-check-coverage --re-measure: OK — 33 ledger entr(ies) re-measured ..., none above its recorded number. (One unrelated informational note:@objectstack/plugin-auth's TEST_DEBT ceiling has 12 spare raw errors it isn't touching — a pre-existing, unrelated ledger entry that could be lowered, not a regression from this diff.)Scaffold-specific gates named in the brief:
Scaffold with repo dist(scaffold-e2e.yml) — path-triggered bypackages/create-objectstack/**, so it will run in CI; it's explicitly not a locally-invocable check family (dispatch-gates: no-check-familiesin the workflow's own header) since it installs the generated project against the real npm registry and drives Docker. Ran its local-equivalent step by hand against the rebuilt CLI (node bin/create-objectstack.js e2e-app --skip-install --skip-skills) — succeeds, generates a valid project; the workflow's later steps (npm install,npm run validate,npm run build, Docker) never parse the CLI's stdout text, so this diff (console text + an additive README paragraph) can't affect them.Validate Package Dependencies(validate-deps.yml) — checked itspull_request.pathsfilter:**/package.json,pnpm-lock.yaml,.changeset/config.json,pnpm-workspace.yaml, plus its own gate scripts. This PR touches none of those, so the job is not triggered by this diff.Out of scope (left untouched, on purpose)
README.md:49'snpm create objectstack@latest— cluster A ([finding] The README'sclaude mcp addone-liner 401s as printed — the endpoint is fine, the documented command omits auth #10319/[finding] The README says "Count it yourself", prints the command, and the command disagrees with the sentence above it (1,930 vs 1,792); "72 published packages" expands to a ~45-row table #10320).◆ Create ObjectStack v6.xbanner inindex.ts— [finding]create-objectstack@17.1.0greets the user with a hardcoded "◆ Create ObjectStack v6.x" banner #10325, shared file, still open and deliberately unclaimed while this ran.packages/create-objectstack/src/templates/AGENTS.md:99linkshttps://objectstack.com/docs— wrong TLD entirely (.com, not the ruled canonicalhttps://objectstack.ai), not just an unratified alias. Filing this as its own finding rather than fixing it here since it's outside this card's declared file surface (blank/README.md+index.ts).Changeset
.changeset/scaffold-next-steps-package-manager.md—create-objectstack: patch.Generated by Claude Code
Generated by Claude Code