chore: address Copilot review round 3 on #2200

Two suppressed comments, both accurate.

- Pin zod, zod/v4 and open to the root in vitest.shared.mts, and add matching
  paths to the three clients/web tsconfigs. The claim they replace — that these
  resolve unambiguously by walk-up — was wrong: both still sit at the top level
  of clients/web/node_modules as transitive copies (zod under
  eslint-plugin-react-hooks, open under Storybook), so an unpinned bare import
  from a web test resolved the client copy while core/ and the SDK packages
  resolved the root's. For open that is only wasteful; for zod it is a schema
  built by one copy and an instanceof check made by the other across the whole
  @modelcontextprotocol/* surface. zod is deduped as well, and zod/v4 gets its
  own entry because first-party code imports both specifiers and pinning one
  would split the package rather than collapse it.
- Update the consumer comments that #2195 falsified. clients/web/vite.config.ts
  (three places) and server/start-vite-dev-server.ts all still said the shared
  aliases resolve pino/hono and friends from clients/web/node_modules; they now
  state the split — react and react-dom from the client install, everything
  root-declared from the repo root.
- local-dev skill: replace the wrong 'resolves unambiguously' list with the
  distinction that actually matters. Deleting a declaration is not the same as
  the package resolving from the root, because chokidar, zod, open and react
  all sit in a client install transitively; check the install, not the manifest.
  ajv, commander and undici carry no pin because no client install has a copy.

npm run local:gate passes from a cold tsc build.

Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-08-31 20:27:08 -04:00
commit 566990382a
5 changed files with 70 additions and 18 deletions

View file

@ -36,8 +36,9 @@ export async function startViteDevServer(
// `server.fs.allow` here. Without them, App.tsx's `@inspector/core/*`
// imports fail to resolve and the page 500s (#1452 smoke test). The aliases
// and dedupe are factored into `vitest.shared.mts` so both paths stay in
// sync — pass the client dir (`root`) so bare-module pins resolve against
// `clients/web/node_modules`.
// sync — pass the client dir (`root`), which is what the `react` /
// `react-dom` pins resolve against. The root-declared packages resolve from
// the repo root instead, which that file derives from the same argument.
const { repoRoot, sharedAliases, sharedDedupe, nodeModulesAliases } =
vitestSharedPaths(root);
const inlineConfig: InlineConfig = {

View file

@ -57,6 +57,9 @@
"atomically": ["../../node_modules/atomically"],
"chokidar": ["../../node_modules/chokidar"],
"@napi-rs/keyring": ["../../node_modules/@napi-rs/keyring"],
"zod": ["../../node_modules/zod"],
"zod/v4": ["../../node_modules/zod/v4"],
"open": ["../../node_modules/open"],
"react-syntax-highlighter/dist/esm/prism-light": [
"./src/types/react-syntax-highlighter-prism-light"
],

View file

@ -55,7 +55,10 @@
"@hono/node-server": ["../../node_modules/@hono/node-server"],
"atomically": ["../../node_modules/atomically"],
"chokidar": ["../../node_modules/chokidar"],
"@napi-rs/keyring": ["../../node_modules/@napi-rs/keyring"]
"@napi-rs/keyring": ["../../node_modules/@napi-rs/keyring"],
"zod": ["../../node_modules/zod"],
"zod/v4": ["../../node_modules/zod/v4"],
"open": ["../../node_modules/open"]
}
},
"include": ["vite.config.ts", "tsup.runner.config.ts", "server/**/*.ts"]

View file

@ -21,6 +21,9 @@
"express": ["./node_modules/@types/express"],
"yaml": ["./node_modules/yaml"],
"@napi-rs/keyring": ["../../node_modules/@napi-rs/keyring"],
"zod": ["../../node_modules/zod"],
"zod/v4": ["../../node_modules/zod/v4"],
"open": ["../../node_modules/open"],
"react-syntax-highlighter/dist/esm/prism-light": [
"./src/types/react-syntax-highlighter-prism-light"
],

View file

@ -143,8 +143,12 @@ export default defineConfig(({ command }) => {
// (#1244), the browser dep graph reached bare-module subpaths in core/
// that Rolldown couldn't resolve against `core/`'s parent (it has no
// node_modules of its own). Promote the same bare-module aliases the
// vitest projects use so `vite dev` / `vite build` can resolve them
// from `clients/web/node_modules`.
// vitest projects use so `vite dev` / `vite build` can resolve them.
//
// Which install each alias points at is `vitest.shared.mts`'s decision,
// not this file's, and since #2195 it is no longer one answer: `react`
// and `react-dom` resolve from `clients/web/node_modules`, everything
// root-declared resolves from the repo root.
alias: [
...Object.entries(sharedAliases).map(([find, replacement]) => ({
find,
@ -153,9 +157,9 @@ export default defineConfig(({ command }) => {
...nodeModulesAliases,
],
// Source files in core/ import bare modules (react, @testing-library/react,
// etc.) that only exist in clients/web/node_modules. Dedupe ensures Vite
// resolves them from this package rather than walking up from core/'s
// location (which has no node_modules of its own yet).
// etc.) that core/ cannot resolve for itself, having no node_modules of
// its own. Dedupe collapses each of these to a single copy per install,
// whichever install the alias above selected.
dedupe: sharedDedupe,
},
// Pin the Vite dev server to the same port and host the Hono plugin
@ -274,10 +278,11 @@ export default defineConfig(({ command }) => {
{
extends: true,
// Vitest projects don't inherit `resolve` from the parent. The unit
// project runs from repoRoot (so vitest's coverage transformer can
// reach core/), but repoRoot has no node_modules of its own — the
// shared regex aliases redirect bare `react`/`pino`/etc. imports
// from core/ back into clients/web/node_modules.
// project runs from repoRoot so vitest's coverage transformer can
// reach core/, which leaves core/'s own bare imports with nothing to
// resolve against — the shared regex aliases are what answer them,
// sending `react` to clients/web/node_modules and the root-declared
// packages (`pino`, `hono`, …) to the repo root (#2195).
resolve: projectResolve,
test: {
name: "unit",
@ -331,8 +336,9 @@ export default defineConfig(({ command }) => {
extends: true,
// See note on the unit project: integration tests also run from
// repoRoot and import core/ modules, so they need the same alias
// setup. The shared bare-module aliases keep `pino`, `hono`, etc.
// resolving against clients/web/node_modules.
// setup, with the same split — `react` from this client's install,
// `pino` / `hono` and the rest of the root-declared set from the
// repo root.
resolve: projectResolve,
test: {
name: "integration",