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:
parent
2a64c6716b
commit
566990382a
1 changed files with 70 additions and 18 deletions
|
|
@ -24,6 +24,10 @@ export function vitestSharedPaths(clientDir: string) {
|
|||
"react-dom",
|
||||
"@modelcontextprotocol/client",
|
||||
"@modelcontextprotocol/core",
|
||||
// Every SDK schema is a zod type, so a second copy breaks `instanceof`
|
||||
// across the whole surface. The alias below picks the install; this keeps
|
||||
// it to one copy within it.
|
||||
"zod",
|
||||
];
|
||||
|
||||
const nodeModulesAliases = [
|
||||
|
|
@ -131,6 +135,32 @@ export function vitestSharedPaths(clientDir: string) {
|
|||
find: /^@napi-rs\/keyring$/,
|
||||
replacement: path.resolve(repoRoot, "node_modules/@napi-rs/keyring"),
|
||||
},
|
||||
// `zod` and `open` are pinned for a different reason from everything above:
|
||||
// they resolve *somewhere* without help, and the somewhere is 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 resolves the client copy while
|
||||
// `core/` and the SDK packages resolve the root's (Copilot).
|
||||
//
|
||||
// For `open` that is merely wasteful. For `zod` it is the hazard this file
|
||||
// exists for: two copies in one process means a schema built by one and an
|
||||
// `instanceof` check made by the other, across the entire
|
||||
// `@modelcontextprotocol/*` surface. The versions are identical today and
|
||||
// `verify:dep-lockstep` is what keeps them that way, but identical is not
|
||||
// the same as single, and only a pin makes it single.
|
||||
//
|
||||
// `zod/v4` needs its own entry — first-party code imports both specifiers,
|
||||
// and pinning only the bare one would split the package across two installs
|
||||
// rather than collapse it.
|
||||
{ find: /^zod$/, replacement: path.resolve(repoRoot, "node_modules/zod") },
|
||||
{
|
||||
find: /^zod\/v4$/,
|
||||
replacement: path.resolve(repoRoot, "node_modules/zod/v4/index.js"),
|
||||
},
|
||||
{
|
||||
find: /^open$/,
|
||||
replacement: path.resolve(repoRoot, "node_modules/open"),
|
||||
},
|
||||
];
|
||||
|
||||
const projectResolve = {
|
||||
|
|
|
|||
Loading…
Reference in a new issue