Skip to content

Commit a31ff2e

Browse files
fix(cli): os init / os create emit overrides.vitest so new projects install on npm 10 (#23850)
Fixes #23805 Clause-②: no `os init` (all three templates) and `os create plugin` now emit `"overrides": { "vitest": "~4.0.0" }`, built from `SCAFFOLD_VITEST_RANGE` through one new export, `SCAFFOLD_NPM_OVERRIDES`. The scaffolded project now installs on npm 10, the npm that Node 22 bundles. `scripts/sync-scaffold-emission-policy.mjs` gains an `overrides.vitest` `POLICY_STAMPS` row, so the blank template's override is now generated from the same constant instead of being kept by hand. The template file's bytes do not change, because it already reads `~4.0.0`. ## Upstream re-measured first, as the card asks Read 2026-10-16T06:46Z with `npm view`: - `vitest` dist-tags: `V4` = `4.1.12`, `latest` = `5.0.5`. - `vitest@4.1.12` peers `"@vitest/browser-webdriverio": "^4.1.11"` (optional). Every other `@vitest/*` peer is pinned to exactly `4.1.12`. - `@vitest/browser-webdriverio` has no `4.1.12`. Its newest 4.x is `4.1.11`, which peers `"vitest": "4.1.11"`. - So the contradiction is still live upstream. The range itself is not changed here. ## Every emission site, with its verdict Measured 2026-10-16T06:57Z. Each manifest was installed in an empty directory with a fresh `--cache`, against the published `18.0.0-next.2`. "Before" is today's `main` emission. | Site | declares `vitest` directly | before, npm 10.9.9 | verdict | |---|---|---|---| | `os init -t app` (`init.ts`, `renderScaffoldPackageJson`) | no | exit 1, `edgesOut` | in scope: emits the override | | `os init -t plugin` (same renderer) | `~4.0.0` | exit 1, `edgesOut` | in scope: emits the override | | `os init -t empty` (same renderer) | no | exit 1, `edgesOut` | in scope: emits the override | | `os create plugin` standalone (`create.ts`) | `~4.0.0` | exit 0 | emits the override (card criterion; keeps it equal to the declaration) | | `os create plugin --in-repo` | `~4.0.0` | n/a (pnpm workspace member) | no override: npm reads `overrides` only from the root manifest and pnpm never reads it, so here it would do nothing | | `create-objectstack` blank template | `~4.0.0` | already overridden (landed earlier) | now stamped by the new `POLICY_STAMPS` row | `os create` has one template (`plugin`), and `os init` has three (`app`, `plugin`, `empty`), all rendered through `renderScaffoldPackageJson`. No other `packages/cli` code writes a scaffold `package.json`. ### Why `-t app` and `-t empty` too, against the card's plugin-only criterion The dispatch assumed that a site emitting no `vitest` needs no override. The measurement above shows otherwise: `-t app` and `-t empty` crash the same way, because what all three templates share is `@objectstack/cli` in `devDependencies`, and its closure carries optional `vitest` peers (`@objectstack/metadata-core` peers `^4.0.0`, better-auth peers `^2 || ^3 || ^4`). `-t app` is also the docs.objectos.ai quickstart's command, measured failing 3 of 3 in the card's thread. `os create plugin` has no `@objectstack/cli` in its closure, which is why it installed without the override. ## The installs after the change Each emitted manifest was produced by driving the real CLI (`tsx bin/run-dev.js init NAME -t T --no-install` and `create plugin NAME`), then installed in an empty directory with a fresh `--cache`: | manifest | npm 10.9.9 | npm 11.21.1 | vitest in the tree | |---|---|---|---| | `os init -t app` | exit 0 | exit 0 | none | | `os init -t plugin` | exit 0 | exit 0 | one copy, 4.0.18 | | `os init -t empty` | exit 0 | exit 0 | none | | `os create plugin` | exit 0 | exit 0 | one copy, 4.0.18 | ## Cost, measured On an emitted `-t app` with the override (npm 10.9.9): - A later bare `npm install -D vitest` is refused with `EOVERRIDE: Override for vitest@* conflicts with direct dependency`. - `npm install -D vitest@~4.0.0` installs (vitest 4.0.18). The refusal is loud and names the conflict; without the override the project could not install at all. The changeset gives the one-line fix. `"$vitest"` is not used: it needs a direct dependency, and two of the three `os init` templates have none. ## The stamp row `POLICY_STAMPS` gains `{ key: 'overrides.vitest', block: 'overrides', field: 'vitest', constant: 'SCAFFOLD_VITEST_RANGE' }`. The engine already locates any `"BLOCK": { … }` object and one field inside it, so no engine change was needed. The self-test: - Every fixture template carries `overrides.vitest`. - Battery B now parses both vitest stamps, instead of a substring check that one stale copy could still pass. - New battery J drifts the override alone while `devDependencies.vitest` agrees. It checks that `--check` exits 1 naming `overrides.vitest`, that the agreeing key is not blamed, that the rewrite touches only that span byte for byte, and that a template dropping the `overrides` block exits 1 naming it. - Roster floor 9 → 10. `--check` on the real template, before and after a mutation (through `scripts/ablation-replace.mjs`, which restores and checks the blob hash): - The blank template's `overrides.vitest` was mutated to `^4.1.0`. `--check` then exits 1 with `packages/create-objectstack/src/templates/blank/package.json: overrides.vitest is "^4.1.0" but the policy declares "~4.0.0"`. - Restored: blob `1bbbff43ce0f` equals HEAD, and `git diff HEAD` is empty. - Control: the same mutation under `main`'s script (`1ecb08a1c`, no row) exits 0 (`2 carrier(s) emit the shared policy`). So on `main`, an override drift that npm refuses with `EOVERRIDE` passed the gate. ## Pins `packages/cli/test/scaffold-npm-overrides.test.ts` is a unit-tier file. Every expectation is derived from the exported constants, with no literal range: - every `os init` template and `os create plugin` (standalone) emit `overrides` equal to `SCAFFOLD_NPM_OVERRIDES`, whose `vitest` is `SCAFFOLD_VITEST_RANGE`; - every override that names a direct dependency equals that dependency's spec (npm `EOVERRIDE`); - `--in-repo` emits no `overrides`; - a control checks that the harvest is non-empty and that the equality case ranges over the two manifests that declare vitest. Ablation, through `scripts/ablation-replace.mjs`. Each leg mutates, runs the file, restores, and proves the restored blob equals HEAD: - Deleting the override from `renderScaffoldPackageJson` fails the 3 `os init` cases (3 failed / 8 passed). - Deleting it from `create.ts` fails `os create plugin` (1 failed / 10 passed). - Forcing it on in-repo fails the in-repo case (1 failed / 10 passed). ## Verification All results below are at head `f8d18b092` unless a line says otherwise. Exit codes were captured before any pipe. - Gate union: `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` names 85 commands, derived from merge base `43567a8fc`. Run at `f8d18b092`: **85 of 85 exit 0**. `--ran` reconciliation: exit 0, `85 derived, 85 run, 0 NOT-MEASURED, 0 UNRUN`. - An earlier pass of the union, at `e521b5709`, found one real red: `check:cross-package-test-inputs` exit 1. A comment in `template-consistency.test.ts` spelled the stamp script's repo path, which the gate reads as a cross-package input. The comment was reworded in `f8d18b092`. - `node scripts/sync-scaffold-emission-policy.mjs --self-test`: exit 0, 60 assertions, 10 batteries. `--check`: exit 0. - `pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2` over the 23 non-e2e test files that import `commands/init` or `commands/create`, the new pin included: exit 0, **22 files / 501 tests passed**, at `d8a9a54f3`. The later commits touch no `packages/cli` file. - `test/generate-stack-reach.test.ts` is in the `integration` project. That tier and the nightly `scaffold-emission-policy.e2e.test.ts` are declared to CI. - `pnpm --filter @objectstack/cli typecheck`: exit 0 (`tsc --noEmit` plus `check:test-typecheck` OK), at `d8a9a54f3`. - `pnpm --filter create-objectstack test`: exit 0, 18 files / 275 tests. `typecheck`: exit 0. - `pnpm exec eslint --no-inline-config` over the five changed source and test files: exit 0. The repo-wide lint run belongs to the `Lint & Repo Gates` check-run. ## Acceptance notes - Finding, not fixed here: the published skill's copy-paste manifest has the same crash. This is `skills/objectstack-platform/references/bootstrap.md`, the "Complete Working Example" `package.json` fence (`@objectstack/cli ^17.0.0`, no override). Its `npm install` on npm 10.9.9 exits 1 with `Cannot read properties of null (reading 'edgesOut')`, and with `overrides.vitest: ~4.0.0` added it exits 0 (measured 2026-10-16T08:10Z). `skills/**` is a governed surface, and the stamp script's `PUBLISHED_RESTATEMENTS` leg only reads that fence and checks only `devDependencies.typescript`. So the fix is a hand edit landed the governed way, and adding `overrides.vitest` to that row's `keys` comes with it. This is reported for the seat to file, not filed from this PR. - The Docker image (#23801) and the optional `vitest` peers of `plugin-auth` / `metadata-core` (#23806) are untouched; both remain open. The blank template's override from the PR for #23788 is unchanged in bytes and is now generated. - `create-objectstack`'s shipped bytes do not change (`files` is `dist`, and the template is byte-identical), so the changeset names `@objectstack/cli` alone. --- _Generated by [Claude Code](https://claude.ai/code/session_018t6a5rvqPRvEDMCVVW9kYT)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 30ce56e commit a31ff2e

6 files changed

Lines changed: 283 additions & 12 deletions

File tree

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
'@objectstack/cli': patch
3+
---
4+
5+
Clause-②: no
6+
7+
`os init` (every template: `app`, `plugin`, `empty`) and `os create plugin` now emit
8+
`"overrides": { "vitest": "~4.0.0" }` in the scaffolded `package.json`, so the project installs on
9+
npm 10, the npm Node 22 bundles. Since vitest 4.1.12 shipped a peer set that contradicts itself,
10+
`npm install` of a fresh `os init` project crashed on npm 10.9.x with
11+
`Cannot read properties of null (reading 'edgesOut')`. The override routes every `vitest` edge in
12+
the npm graph to the range the scaffold declares; npm 11 installs the same tree, and pnpm ignores
13+
the field.
14+
15+
The override equals `devDependencies.vitest` wherever the manifest declares vitest directly,
16+
because npm refuses an override that differs from the direct dependency (`EOVERRIDE`). In an `app`
17+
or `empty` project, add vitest at the same range (`npm install -D vitest@~4.0.0`); a bare
18+
`npm install -D vitest` is refused with `EOVERRIDE` while the override is in place. Existing
19+
projects can add the same `overrides` block by hand. `os create plugin --in-repo` is unchanged.

‎packages/cli/src/commands/create.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ import {
134134
NPM_PACKAGE_NAME_MAX_LENGTH,
135135
renderPnpmWorkspaceYaml,
136136
renderScaffoldTsconfig,
137+
SCAFFOLD_NPM_OVERRIDES,
137138
SCAFFOLD_PNPM_RANGE,
138139
SCAFFOLD_TSCONFIG_INCLUDE_SRC_ONLY,
139140
SCAFFOLD_TYPES_NODE_RANGE,
@@ -408,6 +409,13 @@ export const templates: Record<string, CreateTemplate> = {
408409
typescript: SCAFFOLD_TYPESCRIPT_RANGE,
409410
vitest: SCAFFOLD_VITEST_RANGE,
410411
},
412+
// The same npm override `os init` emits, from the same constant, so
413+
// it always equals `devDependencies.vitest` above (npm refuses one
414+
// that differs: `EOVERRIDE`) — see SCAFFOLD_NPM_OVERRIDES for the
415+
// npm 10 crash it prevents. Standalone only: npm reads `overrides`
416+
// from the ROOT manifest alone and pnpm never reads it, so inside
417+
// this monorepo's workspace the block would be inert.
418+
...(standalone ? { overrides: { ...SCAFFOLD_NPM_OVERRIDES } } : {}),
411419
}),
412420
'tsconfig.json': (name: string) =>
413421
standalone

‎packages/cli/src/commands/init.ts‎

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -390,9 +390,13 @@ export const SCAFFOLD_TYPESCRIPT_RANGE = '^5.3.0';
390390
* `--cache` and a manifest holding only this one devDependency (the full matrix
391391
* is in the PR that set this value): on npm 10.9.4 and 10.9.9, `npm install`
392392
* exits 1 with `Cannot read properties of null (reading 'edgesOut')` from
393-
* arborist's `#loadPeerSet`, and npm 11.21.0 installs it. `~4.0.0` installs on
394-
* all three (vitest 4.0.18, vite 7.3.7), and so do both CLI-emitted plugin
395-
* manifests. The cost: a scaffold gets vitest 4.0.18 rather than 4.1.11.
393+
* arborist's `#loadPeerSet`, and npm 11.21.0 installs it. `~4.0.0` installed on
394+
* all three (vitest 4.0.18, vite 7.3.7), and so did both CLI-emitted plugin
395+
* manifests. The cost: a scaffold gets vitest 4.0.18 rather than 4.1.x.
396+
*
397+
* ⚠️ The range alone stopped being enough, so it is also emitted as an npm
398+
* OVERRIDE — see {@link SCAFFOLD_NPM_OVERRIDES}, which is built from this
399+
* constant, so the declared range and the override cannot disagree.
396400
*
397401
* The cause is upstream, in the peer graph. Every vitest 4.1.x admits vite 8.
398402
* vite 8 declares an optional `@vitejs/devtools` peer, which reaches
@@ -415,6 +419,56 @@ export const SCAFFOLD_TYPESCRIPT_RANGE = '^5.3.0';
415419
*/
416420
export const SCAFFOLD_VITEST_RANGE = '~4.0.0';
417421

422+
/**
423+
* The npm `overrides` block every STANDALONE scaffold emits: `os init`'s three
424+
* templates, `os create plugin` outside the monorepo, and — by generation, not
425+
* import — `create-objectstack`'s bundled template (the `overrides.vitest` row
426+
* in `scripts/sync-scaffold-emission-policy.mjs`'s `POLICY_STAMPS`).
427+
*
428+
* Why it exists. vitest 4.1.12 (published 2026-10-15) peers
429+
* `@vitest/browser-webdriverio ^4.1.11`, and that package's only match, 4.1.11,
430+
* peers `vitest: 4.1.11` exactly — a peer set that contradicts itself. A
431+
* scaffold reaches it even with vitest pinned to `~4.0.0` at its root, through
432+
* OPTIONAL `vitest` peers deeper in the closure (`@objectstack/metadata-core`
433+
* peers `^4.0.0`, better-auth peers `^2 || ^3 || ^4`), which npm 10 resolves to
434+
* vitest's newest 4.x. Measured 2026-10-16, each manifest in an empty
435+
* directory with a fresh `--cache`, against the published `18.0.0-next.2`:
436+
*
437+
* without the override npm 10.9.9 `os init -t app`, `-t plugin` and
438+
* `-t empty` all exit 1 with `Cannot
439+
* read properties of null (reading
440+
* 'edgesOut')`; `os create plugin` (no
441+
* `@objectstack/cli` in its closure)
442+
* exits 0
443+
* with the override npm 10.9.9 all four exit 0
444+
* npm 11.21.1 all four exit 0
445+
*
446+
* So the override goes on EVERY template, not only the ones that declare
447+
* vitest: `-t app` and `-t empty` declare none and crashed all the same,
448+
* because what they share is `@objectstack/cli`. Where a manifest does declare
449+
* vitest, the override equals that declaration — npm refuses an override that
450+
* differs from the direct dependency's own spec (`EOVERRIDE`).
451+
*
452+
* The cost, measured on an emitted `-t app` (npm 10.9.9): a later bare `npm
453+
* install -D vitest` is refused with `EOVERRIDE: Override for vitest@*
454+
* conflicts with direct dependency`; `npm install -D vitest@~4.0.0` (this
455+
* range) installs. Loud and self-describing, where the alternative was a
456+
* project that could not install at all. pnpm ignores npm's `overrides` field,
457+
* so pnpm users see no change.
458+
*
459+
* ⛔ Not `"$vitest"`: it needs a direct dependency to point at (two of the
460+
* three `os init` templates have none), and where it does apply, npm stops
461+
* hoisting `@objectstack/metadata-core` and nests copies of it (measured on the
462+
* bundled template) — a duplicated module is a duplicated `instanceof` identity.
463+
*
464+
* The re-check that lets this go: the same empty-directory install of an
465+
* emitted `-t app` manifest WITHOUT this block, on the newest npm 10 and on npm
466+
* 11. When both exit 0, delete it here and its `POLICY_STAMPS` row together.
467+
*/
468+
export const SCAFFOLD_NPM_OVERRIDES: Readonly<Record<string, string>> = Object.freeze({
469+
vitest: SCAFFOLD_VITEST_RANGE,
470+
});
471+
418472
/** The `@types/node` range a scaffolded project declares. */
419473
export const SCAFFOLD_TYPES_NODE_RANGE = '^22.0.0';
420474

@@ -495,6 +549,9 @@ export function renderScaffoldPackageJson(
495549
scripts: template.scripts,
496550
dependencies: template.dependencies,
497551
devDependencies: template.devDependencies,
552+
// Every template, whether or not it declares vitest itself — without it
553+
// npm 10 cannot install any of them (see SCAFFOLD_NPM_OVERRIDES).
554+
overrides: { ...SCAFFOLD_NPM_OVERRIDES },
498555
};
499556
}
500557

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
/**
4+
* PIN — every standalone manifest `os init` and `os create` emit carries the
5+
* npm `overrides` block, built from the one vitest constant.
6+
*
7+
* ## The defect
8+
*
9+
* vitest 4.1.12 shipped a self-contradicting peer set (it peers
10+
* `@vitest/browser-webdriverio ^4.1.11`, whose only release peers `vitest:
11+
* 4.1.11` exactly). npm 10 — the npm Node 22 bundles — reaches it through
12+
* OPTIONAL `vitest` peers in the `@objectstack/cli` closure, even with vitest
13+
* pinned to `~4.0.0` at the project root, and its arborist crashes with
14+
* `Cannot read properties of null (reading 'edgesOut')`. Measured 2026-10-16:
15+
* `os init -t app`, `-t plugin` and `-t empty` all failed `npm install` on npm
16+
* 10.9.9; with `"overrides": { "vitest": "~4.0.0" }` all of them, and `os
17+
* create plugin`, installed on npm 10.9.9 and npm 11.21.1. The full reading is
18+
* on `SCAFFOLD_NPM_OVERRIDES` in `src/commands/init.ts`.
19+
*
20+
* ## What is asserted, and why no range is written down here
21+
*
22+
* Every expectation is DERIVED from the exported constants, never a literal:
23+
* a pin comparing against `'~4.0.0'` would stay green on a tree where the
24+
* constant moved and one emission was left behind — the drift it exists to
25+
* catch.
26+
*
27+
* 1. Each emission's `overrides.vitest` IS `SCAFFOLD_VITEST_RANGE`.
28+
* 2. Where an emission also declares `vitest` directly, the two are equal —
29+
* npm refuses an override that differs from the direct dependency's own
30+
* spec (`EOVERRIDE`), so a mismatch is an install failure of its own.
31+
* 3. `os create plugin --in-repo` emits NO `overrides`: npm reads the field
32+
* only from the root manifest and pnpm never reads it, so inside the
33+
* workspace it would be a declaration nothing honours.
34+
*
35+
* That the emitted manifests really install is not decidable here; the npm
36+
* matrix above is the measurement, and `create-objectstack`'s bundled template
37+
* reaches the same constant through `scripts/sync-scaffold-emission-policy.mjs`
38+
* (`pnpm check:scaffold-emission-policy`).
39+
*/
40+
41+
import { describe, it, expect } from 'vitest';
42+
import {
43+
renderScaffoldPackageJson,
44+
SCAFFOLD_NPM_OVERRIDES,
45+
SCAFFOLD_VITEST_RANGE,
46+
TEMPLATES,
47+
} from '../src/commands/init.js';
48+
import { DEFAULT_PLACEMENT, templates } from '../src/commands/create.js';
49+
50+
const PROBE_NAME = 'overrides-probe';
51+
52+
type Manifest = {
53+
dependencies?: Record<string, string>;
54+
devDependencies?: Record<string, string>;
55+
overrides?: Record<string, string>;
56+
};
57+
58+
/** Every standalone manifest the two commands emit, derived from the live maps. */
59+
function standaloneManifests(): Array<{ id: string; manifest: Manifest }> {
60+
const out: Array<{ id: string; manifest: Manifest }> = [];
61+
for (const [key, template] of Object.entries(TEMPLATES)) {
62+
out.push({ id: `os init -t ${key}`, manifest: renderScaffoldPackageJson(PROBE_NAME, template) as Manifest });
63+
}
64+
for (const [key, template] of Object.entries(templates)) {
65+
const render = template.filesFor(DEFAULT_PLACEMENT)['package.json'];
66+
if (!render) continue;
67+
out.push({ id: `os create ${key}`, manifest: render(PROBE_NAME) as Manifest });
68+
}
69+
return out;
70+
}
71+
72+
describe('npm overrides in every standalone scaffold manifest', () => {
73+
it('harvests every emission, and the default placement IS standalone (control)', () => {
74+
expect(DEFAULT_PLACEMENT).toBe('standalone');
75+
const ids = standaloneManifests().map((m) => m.id);
76+
expect(ids).toEqual(expect.arrayContaining(['os init -t app', 'os init -t plugin', 'os create plugin']));
77+
// Assertion 2 below must range over something, or it certifies nothing.
78+
const direct = standaloneManifests().filter((m) => m.manifest.devDependencies?.vitest !== undefined);
79+
expect(direct.map((m) => m.id)).toEqual(expect.arrayContaining(['os init -t plugin', 'os create plugin']));
80+
});
81+
82+
it('the override map is built from the vitest constant', () => {
83+
expect(SCAFFOLD_NPM_OVERRIDES.vitest).toBe(SCAFFOLD_VITEST_RANGE);
84+
expect(Object.isFrozen(SCAFFOLD_NPM_OVERRIDES)).toBe(true);
85+
});
86+
87+
it.each(standaloneManifests())('$id emits overrides.vitest = SCAFFOLD_VITEST_RANGE', ({ manifest }) => {
88+
expect(manifest.overrides).toEqual({ ...SCAFFOLD_NPM_OVERRIDES });
89+
expect(manifest.overrides?.vitest).toBe(SCAFFOLD_VITEST_RANGE);
90+
});
91+
92+
it.each(standaloneManifests())(
93+
'$id: every override naming a direct dependency equals that dependency (npm EOVERRIDE)',
94+
({ manifest }) => {
95+
const direct = { ...(manifest.dependencies ?? {}), ...(manifest.devDependencies ?? {}) };
96+
for (const [name, range] of Object.entries(manifest.overrides ?? {})) {
97+
if (direct[name] === undefined) continue;
98+
expect(range, `overrides.${name} vs the direct ${name} dependency`).toBe(direct[name]);
99+
}
100+
},
101+
);
102+
103+
it('os create --in-repo emits no overrides block — npm and pnpm both ignore it in a workspace member', () => {
104+
const render = templates.plugin.filesFor('in-repo')['package.json'];
105+
const manifest = render(PROBE_NAME) as Manifest;
106+
// Control: the in-repo manifest is a real one, with vitest declared.
107+
expect(manifest.devDependencies?.vitest).toBe(SCAFFOLD_VITEST_RANGE);
108+
expect(manifest).not.toHaveProperty('overrides');
109+
});
110+
});

‎packages/create-objectstack/src/template-consistency.test.ts‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,11 @@ describe('bundled template declared version surfaces', () => {
218218
// The literal costs one thing instead, and loudly: npm refuses an override
219219
// that differs from the direct dependency's own spec (`EOVERRIDE: Override
220220
// for vitest@^4.1.0 conflicts with direct dependency`, measured), so the two
221-
// move together. That is the second assertion. `devDependencies.vitest` is
222-
// stamped from `SCAFFOLD_VITEST_RANGE` at build; this override is not.
221+
// move together. That is the second assertion. Both are stamped from
222+
// `SCAFFOLD_VITEST_RANGE` at build (the `devDependencies.vitest` and
223+
// `overrides.vitest` rows of the emission-policy stamp script's
224+
// `POLICY_STAMPS`), the constant `os init` / `os create` emit their own
225+
// override from.
223226
// ⛔ Not a shipped `.npmrc` with `legacy-peer-deps`, which changes peer
224227
// resolution for every npm user of the scaffold.
225228
it('package.json overrides vitest to its own declared range, so npm 10 installs it', () => {

0 commit comments

Comments
 (0)