fix: restore npm install -g comisai by keeping bundled copies inert#350
Merged
Conversation
added 2 commits
July 26, 2026 09:25
Adds the failing guards first; all five assertions fail on this commit. 1. umbrella-bundled-metadeps — npm counts a dependency of a bundled package as part of that bundle whenever it resolves into the bundling package's own node_modules/ (arborist Node#getBundler follows edgesIn). A GLOBAL install nests every comisai dependency exactly there, so npm skips unpacking those packages while still scheduling their lifecycle scripts; a script whose package was never unpacked runs with a missing cwd, which npm reports as the opaque `spawn sh ENOENT`. A local install hoists the same packages to the project root, outside the bundler, and succeeds -- so neither `pnpm validate`, nor `npm install comisai`, nor the tarball smoke (which packs but never installs) can see this class. 2. npm-peer-consistency — pnpm only warns on an unsatisfied peer, so the workspace stays green while `npm install` fails the same conflict with ERESOLVE. That breaks the installer's repair pass, which is a plain `npm install` inside the installed package. 3. installer-npm-failure-evidence — the installer captured npm with --silent, emptying the very log its diagnostics parse for the error code, syscall, errno, npm debug-log path and the "showing last log lines" tail. The operator got a bare failure with no evidence, and the temp log is deleted at exit. bundled-manifest.js carries the invariant the first two guards assert against: a bundled copy declares no dependencies, and everything it imports is a top-level umbrella dependency.
Every global install of the umbrella package died before building a single package: npm error code ENOENT npm error syscall spawn sh npm error path .../comisai/node_modules/@google/genai `@earendil-works/pi-ai` is bundled, and its manifest was copied into the tarball verbatim. npm therefore claimed all eleven of its dependencies for that bundle, skipped unpacking them, and still scheduled their lifecycle scripts -- and `@google/genai` ships a preinstall. The script ran in a directory that was never created, which npm reports as `spawn sh ENOENT`. Seven of those eleven were not umbrella dependencies at all, so they had nothing else installing them. prepack already stripped dependencies from the @comis/* copies for exactly this reason; the third-party path never got the same treatment. Route every bundled copy through serializeBundledManifest, hoist all of pi-ai's runtime dependencies to the umbrella, and fail the pack (Step 0) when a bundled package needs something the umbrella does not provide. Also revert @hono/node-server 2.0.11 -> 1.19.15. @hono/node-ws@1.3.1 peers on ^1.19.11 and upstream has published no release accepting 2.x. pnpm only warned, so the workspace stayed green while npm refused with ERESOLVE -- which broke repair_comisai_bundled_deps, the pass that repairs npm's separate, long-standing pruning of a non-bundled direct dep's transitive deps (the @earendil-works/pi-tui class). Finally, stop capturing npm with --silent. All six installer diagnostics fields are parsed out of that log, so silencing it turned a failed install into a bare "install failed" with the cause reachable only from npm's own debug log -- a path the installer could no longer extract. Add a fallback that names $(npm config get cache)/_logs when the log is empty. Verified end-to-end, not by mock: packed the tarball, installed it globally as the dedicated service user on a clean Ubuntu prefix through the real install.sh, and confirmed the CLI loads, all eleven pi-ai dependencies resolve from the bundled copy, the repair pass now succeeds, and the daemon boots with no errors. pnpm validate passes.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
This was referenced Jul 26, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Every global install of v1.0.55 dies before building a single package, so
curl https://comis.ai/install.sh | bashfails on a clean box:spawn sh ENOENTis npm's report for a missing working directory, not a PATH problem.Root cause. npm counts a dependency of a bundled package as part of that bundle: arborist's
Node#getBundler()walksedgesInand claims the dep as soon as any dependent is bundled and it resolves into the bundling package's ownnode_modules/. It then skips unpacking it — expecting the tarball to carry it — while still scheduling its lifecycle scripts.@google/genaiships apreinstall, so it ran in a directory that was never created.This is global-only: a global install nests every
comisaidependency undercomisai/node_modules/(the bundler's own directory); a local install hoists them to the project root, outside it.npm install comisaisucceeds, which is why nothing caught it.prepackalready stripped dependencies from the@comis/*copies for exactly this reason. When@earendil-works/pi-aiwas added tobundledDependencies, its registry manifest was copied verbatim — and 7 of its 11 dependencies were not umbrella dependencies at all, so nothing else installed them.Second regression.
@hono/node-serverwas bumped 1.19.14 → 2.0.11 while@hono/node-ws@1.3.1peers on^1.19.11(upstream has published no release accepting 2.x). pnpm only warns; npm fails withERESOLVE— which brokerepair_comisai_bundled_deps, the pass that repairs npm's separate, long-standing pruning of a non-bundled direct dep's transitive deps (the@earendil-works/pi-tuiclass). Reverted to1.19.15.Changes
bundled-manifest.js(new) — carries the invariant: a bundled copy declares no dependencies, and everything it imports is a top-level umbrella dependency.prepackStep 0 fails the pack when that's violated.prepack.js— every bundled copy's manifest now goes throughserializeBundledManifest, including the third-party ones.packages/comis/package.json— hoisted the 7 unprovided pi-ai dependencies; hono revert.install.sh— stop capturing npm with--silent. All six diagnostics fields are parsed from that log, so silencing it turned a failed install into a bare "install failed" with the cause reachable only from npm's own debug log — a path the installer could no longer extract. Adds a fallback naming$(npm config get cache)/_logs.Related Issue
Fixes #351
Type of Change
Checklist
pnpm validate)RED Test Proof
All five assertions fail on the test-first commit
04f8d1063, before the production patch in8e42dddd3:All 5 pass on
8e42dddd3.Evidence and Residual Risk
install.sh, and confirmed: install completes (previously died at@google/genai); all 11 pi-ai dependencies resolve from the bundled copy viacreateRequire;repair_comisai_bundled_depssucceeds (previously ERESOLVE);comis --versionreturns; the daemon boots with 0 errors and the gateway listens. Also confirmed v1.0.54 exhibits the identicalpi-tuiprune, establishing that part as pre-existing rather than a regression here.comissystem user, systemd service, fresh global prefix (rm -rfbetween runs);pnpm validateon macOS.pnpm validate:fulland a Docker build have not been run on Linux. No version bump — v1.0.55 stays broken on npm until a v1.0.56 ships. The new guards are static; the real gap that let both regressions through is that no gate anywhere runsnpm install -g <tarball>and loads the CLI, and that tier still does not exist. The hono revert pins a dependency backwards, so a future@hono/node-server2.x adoption is blocked until upstream publishes a@hono/node-wsthat accepts it.