Skip to content

chore: consolidate duplicated runtime dependencies into the root package.json - #2200

Merged
cliffhall merged 5 commits into
v2/mainfrom
v2/chore/2195-consolidate-root-deps
Sep 1, 2026
Merged

chore: consolidate duplicated runtime dependencies into the root package.json#2200
cliffhall merged 5 commits into
v2/mainfrom
v2/chore/2195-consolidate-root-deps

Conversation

@cliffhall

Copy link
Copy Markdown
Member

Closes #2195

Step 1 of two on #2030.

Every runtime dependency core/ imports is now declared once, in the repo-root package.json. Deleting the client-side copies rather than aligning them is the point: a package installs only into an install root that declares it, so with no second declaration a second copy cannot be created at all — the failure class #1896 was opened for and #1965 / #2029 built verify:dep-lockstep to detect.

What moved

Removed from clients/{web,cli,tui,launcher} as each applied:

ajv, atomically, chokidar, commander, open, pino, zod, @napi-rs/keyring, hono, @hono/node-server, react

All eleven were already declared at the root, so this PR is purely the deletion of the duplicate side. undici was in the scope list but was already root-only (#2067) — no change. clients/cli and clients/launcher now declare no runtime dependencies at all, which is the expected steady state, not an omission.

Left where they are, as the issue specifies: ink-form / ink-scroll-view (inlined into the TUI bundle, #1952) and web's UI stack (@mantine/*, @dnd-kit/*, @emotion/react, react-dom, react-icons, react-markdown, react-syntax-highlighter, remark-gfm, papaparse, plus ace-builds / react-ace) — all bundled into dist.

Root hono went ^4.12.18^4.13.1. The two declarations disagreed, and consolidating onto the root's floor would have silently lowered web's; keeping the higher range is the no-op choice.

react stays ^19.0.0 at the root. The clients' ^19.2.4 is what went away, per the constraint — narrowing the root range would reopen #1952 for the ink renderer itself.

Bundler external lists

tsup externalizes only what the nearest manifest declares, so a package that moves to the root is inlined unless named explicitly. Added:

Bundle Added
clients/cli/tsup.config.ts ajv, atomically, open, zod
clients/tui/tsup.config.ts ajv, atomically, zod
clients/web/tsup.runner.config.ts ajv, zod

npm run verify:bundle-externals passes, and a banner scan of the built output confirms the only npm packages still inlined anywhere are the TUI's deliberate ink-form / ink-scroll-view tree (chalk, figures, ink-select-input, ink-text-input, is-unicode-supported, to-rotated) — nothing new was dragged in.

vitest.shared.mts

The pins could not retire — the opposite. pino, hono, @hono/node-server, atomically, chokidar and @napi-rs/keyring were pinned to <client>/node_modules, which after this change is a path that no longer exists for most of them. Worse for the ones where it does still exist: chokidar is present in every client install transitively via vite, and react arrives as a peer of react-dom and ink — so an unpinned or stale specifier resolves the transitive copy rather than the root's, which is the duplicate the pin list exists to prevent.

Those six therefore move to repoRoot, joining express, yaml and proper-lockfile. react / react-dom stay client-pinned so the pair stays version-matched within one install (web resolves 19.2.8 for both; pinning react at the root would have paired 19.2.7 with web's 19.2.8 react-dom).

Verification

  • npm run local:gate — pass.
  • npm run pack:verify — pass. The tarball installs clean into a fresh consumer and the real bin drives web (served dist + an MCP App through the shipped sandbox proxy), cli (stdio tools/list) and tui (help).
  • npm run verify:dep-lockstep candidate set: 4 → 2. Before: @standard-schema/spec, hono, pino, zod. After: @standard-schema/spec, zod. Both remaining candidates agree across installs, and TOLERATED_SKEW stays empty.
  • Postinstall cascade (scripts/install-clients.mjs) is unaffected by a client manifest with no dependencies key — it gates on the presence of package.json, not on its contents, and the root npm install cascaded into all four clients successfully.

Docs

AGENTS.md's dependency-placement section, the root README's setup paragraph, and the local-dev skill (which owns the reasoning) all describe the consolidated layout, including the two things that read as bugs and are not: two clients with zero runtime dependencies, and root-owned package names still appearing in a client's node_modules transitively.

⚠️ The issue asked for a .github/copilot-instructions.md mirror to be updated in the same PR. That file does not exist in this repo.github/ holds only ISSUE_TEMPLATE/, workflows/, dependabot.yml and pull_request_template.md — so there was no mirror to update. Flagging rather than creating one, since introducing that file is a separate decision.

…age.json

Every runtime dependency core/ imports is now declared once, in the repo-root
package.json, and nowhere else. Deleting the client-side copies does not merely
align them: a package installs only into an install root that declares it, so
with no second declaration a second copy cannot be created at all — the failure
class #1896 was opened for and #1965/#2029 built verify:dep-lockstep to detect.

- clients/{web,cli,tui,launcher}: dropped ajv, atomically, chokidar, commander,
  open, pino, zod, @napi-rs/keyring, hono, @hono/node-server and react, as each
  applied. clients/cli and clients/launcher now declare no runtime dependencies.
- Root hono floor raised ^4.12.18 -> ^4.13.1, keeping the higher of the two
  ranges that were in the tree rather than silently lowering web's.
- tsup external lists: added ajv and zod to all three bundles, plus atomically
  and open (cli) and atomically (tui). tsup externalizes only what the nearest
  manifest declares, so a package that moves to the root is inlined unless it is
  named explicitly.
- vitest.shared.mts: repointed the pino, hono, @hono/node-server, atomically,
  chokidar and @napi-rs/keyring pins from <client>/node_modules to the repo
  root, joining express, yaml and proper-lockfile. Left behind they would
  resolve to a directory that no longer exists, or to a transitive copy an
  unrelated dependency dragged in. react and react-dom stay client-pinned so
  the pair stays version-matched within an install.
- Docs: AGENTS.md dependency placement, the root README and the local-dev skill
  describe the consolidated layout.

verify:dep-lockstep candidate set: 4 -> 2 (hono and pino fell out; only
@standard-schema/spec and zod still reach one tsc program from two installs).
npm run local:gate and npm run pack:verify both pass.

Signed-off-by: cliffhall <cliff@futurescale.com>
@cliffhall cliffhall added the v2 Issues and PRs for v2 label Aug 31, 2026
@cliffhall
cliffhall requested a balanced review from Copilot August 31, 2026 23:09

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The external lists remain incomplete against the documented invariant, and several new dependency-resolution explanations are inaccurate.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Consolidates shared runtime dependencies at the repository root to prevent version skew across client installations.

Changes:

  • Removes duplicate client dependency declarations and refreshes lockfiles.
  • Updates bundler externals and Vitest resolution aliases.
  • Documents the consolidated dependency model.
File summaries
File Description
package.json Updates the consolidated Hono range.
package-lock.json Records the root Hono range.
vitest.shared.mts Redirects selected dependency aliases to the root.
README.md Documents root-owned runtime dependencies.
AGENTS.md Expands dependency-placement rules.
.claude/skills/local-dev/SKILL.md Explains the consolidation rationale.
clients/web/package.json Removes shared runtime dependencies.
clients/web/package-lock.json Regenerates the web dependency tree.
clients/web/tsup.runner.config.ts Adds explicit runner externals.
clients/tui/package.json Retains only TUI-specific dependencies.
clients/tui/package-lock.json Regenerates the TUI dependency tree.
clients/tui/tsup.config.ts Adds explicit TUI externals.
clients/cli/package.json Removes all CLI runtime declarations.
clients/cli/package-lock.json Regenerates the CLI dependency tree.
clients/cli/tsup.config.ts Adds explicit CLI externals.
clients/launcher/package.json Removes the launcher dependency section.
clients/launcher/package-lock.json Removes the launcher’s local Commander copy.
Review details

Files not reviewed (4)

  • clients/cli/package-lock.json: Generated file
  • clients/launcher/package-lock.json: Generated file
  • clients/tui/package-lock.json: Generated file
  • clients/web/package-lock.json: Generated file
  • Files reviewed: 12/17 changed files
  • Comments generated: 6
  • Review effort level: Balanced

Comment thread clients/cli/tsup.config.ts
Comment thread clients/tui/tsup.config.ts
Comment thread clients/web/tsup.runner.config.ts
Comment thread AGENTS.md Outdated
Comment thread .claude/skills/local-dev/SKILL.md Outdated
Comment thread vitest.shared.mts Outdated
- Complete the bundler external lists against the AGENTS.md invariant rather
  than against today's reachability: chokidar, hono and react to clients/cli,
  chokidar and hono to clients/tui, react to the web runner. Every root-declared
  package core/ imports at runtime is now named in all three, so a new import in
  core/ cannot silently inline one.
- AGENTS.md: split the single over-broad bullet in two. commander, open,
  @hono/node-server, vite and @vitejs/plugin-react are root dependencies reached
  only from client code, so they are not part of the core/ set and need naming
  only in the external list of the client that imports them. Give the
  vitest.shared.mts pins their own rule, stating the react/react-dom exception
  instead of implying every root-owned package is aliased to the root.
- vitest.shared.mts: the umbrella comment now says root-OWNED rather than root
  runtime dependency — express is test-only and lives in the root
  devDependencies — and notes that the list is deliberately not the complete
  root set, since a package that resolves unambiguously needs no pin.
- local-dev skill: document why react/react-dom stay client-pinned, which the
  previous text contradicted.

npm run local:gate and npm run verify:bundle-externals pass.

Signed-off-by: cliffhall <cliff@futurescale.com>
@cliffhall

Copy link
Copy Markdown
Member Author

Copilot review round 1 — all six addressed

Mirroring at PR level, since inline replies go hidden once the threads go outdated.

# Comment Response
1–3 external lists still omit root-owned chokidar / hono / react Done. Added chokidar, hono, react to clients/cli; chokidar, hono to clients/tui; react to the web runner.
4 AGENTS.md bullet conflates three different sets Done. Split into separate rules.
5 local-dev skill contradicts the react/react-dom client pin Done. Exception documented.
6 vitest.shared.mts umbrella comment calls express a runtime dependency Done. Reworded.

On 1–3

Correct catch, and the fix is the one you named: the list has to satisfy the invariant, not today's reachability. I verified the core/ side rather than taking it on faith — core/mcp/remote/node/server.ts imports chokidar and hono, and eighteen files under core/react/ import react — so all three belong in every list regardless of which client currently reaches those paths. Externalizing a package a bundle never imports emits nothing, so the cost is zero and the guard is real: a new import in core/ can no longer silently inline one of them into a client that had not reached it before.

On 4

The single bullet was making three claims and only one of them held. It now reads as three rules:

  • What core/ importsajv, atomically, chokidar, hono, @napi-rs/keyring, pino, proper-lockfile, react, undici, zod, plus the SDK packages. Each checked against core/ rather than inherited from the issue's scope list.
  • Root-declared but client-importedcommander, open, @hono/node-server, vite, @vitejs/plugin-react. Root dependencies because a published install resolves every externalized import from the root manifest, which is independent of whether core/ reaches them. These need naming only in the external list of the client that actually imports them.
  • The vitest.shared.mts pins — now a rule of its own, stating the react/react-dom exception rather than implying everything is aliased to the root.

On 5 and 6

Both were my text describing the change inaccurately.

react/react-dom stay client-pinned because they are a matched pair and react-dom is still web-declared: npm installs it together with its React peer inside clients/web/node_modules (19.2.8, against the root's 19.2.7). Pinning react at the root while react-dom resolves from the client would pair a renderer with a React it was not installed against — the same split the pin list exists to prevent, reached from the other side.

The alias comment now says root-owned rather than root runtime dependency (express is test-only, in the root devDependencies), and says outright that the list is not the complete root runtime set — ajv, commander, open, undici and zod resolve unambiguously and deliberately carry no pin.

npm run local:gate and npm run verify:bundle-externals pass on the updated branch.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Web TypeScript mappings and local-development documentation remain inconsistent with the consolidated ownership model.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Files not reviewed (4)

  • clients/cli/package-lock.json: Generated file
  • clients/launcher/package-lock.json: Generated file
  • clients/tui/package-lock.json: Generated file
  • clients/web/package-lock.json: Generated file

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

.claude/skills/local-dev/SKILL.md:105

  • This rationale still groups client-only imports (commander, open, and @hono/node-server) with core/ dependencies and says #2195 moved undici, although AGENTS.md:89 distinguishes those client imports and this PR explicitly records undici as already root-only. It also implies the whole list is represented by root aliases, while vitest.shared.mts:58-60 says several intentionally have no alias. Split the core-owned and client-owned cases so this procedure does not contradict the governing rule.
has no manifest of its own (`test-servers/src`, `core/`) — hence the repo-root
alias for those in `vitest.shared.mts`. That used to be `express` and `yaml`
alone; #2195 made it the general case, moving `ajv`, `atomically`, `chokidar`,
`commander`, `hono`, `@hono/node-server`, `@napi-rs/keyring`, `open`, `pino`,
`react`, `undici` and `zod` to the root as well.
  • Files reviewed: 12/17 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread clients/web/package.json
- clients/web/tsconfig.{app,node,test}.json: repoint the pino, hono,
  hono/streaming, @hono/node-server, atomically, chokidar and @napi-rs/keyring
  path mappings from ./node_modules to ../../node_modules. The stale mappings
  were not failing the build — an unresolvable paths entry falls back to
  ordinary walk-up resolution, which finds the root copy — but chokidar is the
  case where the fallback never runs: Vite's transitive copy still sits under
  clients/web, so tsc was type-checking against the client's copy while Vitest
  and the shipped bundle both resolved the root's. Same version today, silent
  skew tomorrow. Both path prefixes now carry a comment saying which ownership
  each one asserts.
- local-dev skill: the consolidation rationale no longer groups commander, open
  and @hono/node-server (client-imported) with the core/ set, no longer claims
  #2195 moved undici (it was already root-only), and no longer implies every
  root-declared package has an alias.

npm run local:gate passes with clients/web/node_modules/.tmp cleared, so the
tsc results are from a cold build rather than an incremental cache.

Signed-off-by: cliffhall <cliff@futurescale.com>
@cliffhall

Copy link
Copy Markdown
Member Author

Copilot review round 2 — both addressed

1. Web tsconfig paths still pinned the moved packages to ./node_modules

Real gap, and the most useful finding on this PR. Repointed pino, hono, hono/streaming, @hono/node-server, atomically, chokidar and @napi-rs/keyring to ../../node_modules in tsconfig.app.json, tsconfig.node.json and tsconfig.test.json.

Why the build stayed green with stale mappings, since that is the part worth recording: an unresolvable paths entry is not an error — TypeScript falls back to ordinary walk-up resolution, which found the root copy. chokidar is the one where the fallback never ran. Vite's transitive copy really does sit under clients/web/node_modules, so tsc was type-checking against the client's copy while Vitest and the shipped bundle both resolved the root's. Same version today (4.0.3 either way), which is precisely why nothing failed and why it would not have failed later either, right up until the two diverged.

Left on ./node_modules deliberately: @types/react, @types/react-dom, @types/express, vitest and yaml are client-declared. Both prefixes now carry a comment stating which ownership each one asserts, so the next person adding a mapping picks the right one on purpose.

Re-ran the gate with clients/web/node_modules/.tmp removed first, so the tsc -b results are from a cold build rather than an incremental cache that could have been holding the old resolutions.

2. Suppressed comment — local-dev skill still conflated the three sets

Correct on all three counts. The rationale now:

  • keeps commander, open and @hono/node-server out of the core/ set, as client-imported;
  • says undici and proper-lockfile were already root-only rather than moved by this PR;
  • states that root-declared and aliased are different things, and that ajv, commander, open, undici and zod are deliberately absent from both the vitest.shared.mts pins and the tsconfig paths because they resolve unambiguously by walk-up.

npm run local:gate passes.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Resolution guidance remains inaccurate about root aliases and transitive web copies.

Review details

Files not reviewed (4)

  • clients/cli/package-lock.json: Generated file
  • clients/launcher/package-lock.json: Generated file
  • clients/tui/package-lock.json: Generated file
  • clients/web/package-lock.json: Generated file

Suppressed comments (2)

Previously missed (1) — in code that hasn't changed since the last review.

.claude/skills/local-dev/SKILL.md:117

  • zod and open do not currently resolve unambiguously by walk-up in the web client: clients/web/package-lock.json still installs top-level copies transitively (zod via eslint-plugin-react-hooks, open via Storybook), and web tests/server code import both directly. The PR also records zod as a remaining cross-install TypeScript candidate. Either pin these specifiers to the root (including zod/v4 and the applicable TypeScript paths) or document the actual reason that resolving the client-transitive copies is intentional; the current guidance would lead maintainers to overlook a real two-install resolution path.
  the `clients/web/tsconfig.*.json` `paths` cover the packages whose resolution
  is genuinely ambiguous — a transitive copy sits in the client install, or the
  importer is `core/`, which has no manifest to resolve from. A package that
  resolves unambiguously by walk-up (`ajv`, `commander`, `open`, `undici`,
  `zod`) is deliberately absent from both.

vitest.shared.mts:95

  • Repointing these aliases to repoRoot leaves the consumer comments inaccurate: clients/web/vite.config.ts:145-158,276-280,332-335 and clients/web/server/start-vite-dev-server.ts:34-40 still say the shared aliases resolve pino/hono and other core dependencies from clients/web/node_modules. Those comments now describe the opposite ownership model and could cause a future edit to restore client-local resolution. Update them to distinguish the client-pinned React pair from the root-owned aliases.
    // The rest of `core/`'s runtime dependencies, consolidated into the root
    // manifest by #2195. Each of these used to be declared by the clients that
    // reached it and was pinned to `<client>/node_modules` accordingly; once
    // the declarations went away those paths stopped existing, so the pin has
    // to follow the package to the root. Left un-repointed they would resolve
  • Files reviewed: 15/20 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

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>
@cliffhall

Copy link
Copy Markdown
Member Author

Copilot review round 3 — both suppressed comments addressed

No new inline comments this round; both findings came through the suppressed block, and both were right.

1. zod and open do not resolve unambiguously by walk-up

My claim, and it was wrong. Verified before changing anything: clients/web/node_modules carries top-level copies of both — zod 4.4.3 under eslint-plugin-react-hooks, open 10.2.0 under Storybook — and web code imports both directly (web-server-config.ts, and the core/ + integration test suites). So an unpinned bare import from a web test resolved the client copy while core/ and the SDK packages resolved the root's.

Took the pin arm rather than the document arm, because for zod the consequence is not cosmetic: every @modelcontextprotocol/* schema is a zod type, so two copies in one process means a schema built by one and an instanceof check made by the other. Identical versions make that survivable, not correct, and verify:dep-lockstep guarantees only the former.

  • vitest.shared.mts: zod, zod/v4 and open pinned to the repo root, and zod added to dedupe.
  • clients/web/tsconfig.{app,node,test}.json: matching paths.
  • zod/v4 has its own entry, as you flagged — first-party code imports both specifiers, so pinning only the bare one would have split the package across two installs instead of collapsing it.

verify:dep-lockstep still reports 2 candidates (@standard-schema/spec, zod), unchanged: zod also reaches a program from the TUI install, which has its own transitive copy. No regression, and web's runtime resolution is now single-copy.

2. Consumer comments describe the old ownership model

Also correct, and this is the one that would have caused a bad edit later. Four sites still said the shared aliases resolve pino / hono and the rest from clients/web/node_modules:

  • clients/web/vite.config.ts — the resolve.alias note, the dedupe note, and the unit and integration project notes.
  • clients/web/server/start-vite-dev-server.ts — the "pass the client dir so bare-module pins resolve against clients/web/node_modules" line.

All four now state the split rather than one model: react / react-dom from the client install, everything root-declared from the repo root, with the choice named as vitest.shared.mts's to make rather than the consumer's.

3. local-dev skill

Replaced the wrong list with the distinction that actually matters, since the failure mode here is a reasoning error rather than a missing fact: deleting a declaration is not the same as the package resolving from the root. chokidar, zod, open and react all sit in a client install transitively without being declared there — check the install, not the manifest. ajv, commander and undici carry no pin because no client install has a copy of them at all.

npm run local:gate passes from a cold tsc build, and npm run pack:verify is re-running against the final bundle.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The shared alias documentation contains two contradictory dependency classifications that should be corrected.

Review details

Files not reviewed (4)

  • clients/cli/package-lock.json: Generated file
  • clients/launcher/package-lock.json: Generated file
  • clients/tui/package-lock.json: Generated file
  • clients/web/package-lock.json: Generated file

Suppressed comments (2)

vitest.shared.mts:64

  • open and zod are described here as unpinned, but this same array adds root aliases for both below because client-local transitive copies make their resolution ambiguous. Remove them from the no-pin examples so this guidance does not encourage deleting the required aliases.
    // `devDependencies`. Nor is this the complete root runtime set; a package
    // that resolves unambiguously without help (`ajv`, `commander`, `open`,
    // `undici`, `zod`) needs no pin and has none.

vitest.shared.mts:95

  • This group includes @hono/node-server, which is imported only by web client code rather than core/ (as the new AGENTS.md rule notes). Describe the group as root-owned aliases instead of core/ runtime dependencies so the resolution rationale remains accurate.
    // The rest of `core/`'s runtime dependencies, consolidated into the root
  • Files reviewed: 17/22 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Both findings are my own comments contradicting each other, in the same file.

- The no-pin example list still named `open` and `zod`, which the array right
  below it now pins. It names `ajv`, `commander` and `undici` instead, and says
  what the criterion actually is: absence is a statement about the installed
  tree, not about the manifests.
- The consolidated group is described as root-OWNED aliases rather than
  `core/`'s runtime dependencies, since `@hono/node-server` is reached from web
  client code alone and is here for the resolution reason, not because `core/`
  imports it.

Comments only. npm run local:gate passes.

Signed-off-by: cliffhall <cliff@futurescale.com>
@cliffhall

Copy link
Copy Markdown
Member Author

Copilot review round 4 — both addressed

Both findings were my own comments in vitest.shared.mts contradicting each other, which is a fair thing to catch — a comment that disagrees with the array beneath it is worse than no comment.

1. The no-pin example list still named open and zod — the two packages the array right below it now pins. Removed. It names ajv, commander and undici instead, and states the criterion rather than just the examples: absence from the list is a claim about the installed tree, not about the manifests, so check the tree before adding or removing an entry. That is exactly the reasoning error round 3 caught, so it belongs in the comment rather than only in the skill.

2. The consolidated group is not purely core/'s runtime dependencies@hono/node-server is reached from web client code alone. The group is now described as root-owned aliases, with that exception named, so the heading matches the AGENTS.md rule this PR added rather than restating the broader claim it was written to replace.

Comments only, no behavior change. npm run local:gate passes.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

Dependency declarations, lockfiles, bundler externals, resolution aliases, and documentation are consistent with the repository’s packaging model.

Review details

Files not reviewed (4)

  • clients/cli/package-lock.json: Generated file
  • clients/launcher/package-lock.json: Generated file
  • clients/tui/package-lock.json: Generated file
  • clients/web/package-lock.json: Generated file
  • Files reviewed: 17/22 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@cliffhall
cliffhall merged commit 2eb160d into v2/main Sep 1, 2026
5 checks passed
@cliffhall
cliffhall deleted the v2/chore/2195-consolidate-root-deps branch September 1, 2026 03:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v2 Issues and PRs for v2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

chore: consolidate duplicated runtime dependencies into the root package.json

2 participants