You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(run): keep an explicit bundleFile from diverging load's root in a monorepo (#56)
`stasis run --bundle=load --bundle-file=<path>` crashed in a nested-package
(monorepo) layout with `Cannot find module '/.../node_modules/<dep>/index.js'`
(thrown from patchCjsResolution's Module._resolveFilename shim, hooks.js), or the
sibling `stasis: file not attested in bundle` / `file is outside the project root`.
Root cause is State's root discovery, not the CJS shim. An explicit `bundleFile`
(a --bundle-file flag or EXODUS_STASIS_BUNDLE_FILE) is a rootDir-INDEPENDENT path:
reading it yields the same file at every candidate root. It was used as a
per-rootDir root-detection signal, so at load it matched the INNERMOST package.json
dir and committed that as `state.root` -- while capture, run before the bundle
existed (so with no such signal), committed the OUTER repo root. Because every
bundle key is stored relative to the capture root, that divergence puts a dependency
hoisted to <repo>/node_modules OUTSIDE the (leaf) load root, so the loader classifies
it as non-bundled: it defers to Node, and Node's ESM->CJS translator re-resolves the
dependency through Module._load(absolutePath, /* no parent */). That call falls
through the shim's `typeof parent?.filename === 'string'` guard to native disk
resolution and throws when node_modules was pruned / never shipped.
Fix: treat an explicit bundleFile exactly like explicitLockPath -- suppress it as a
per-rootDir selection signal (root is chosen from rootDir-DEPENDENT signals:
stasis.config.json, the default lockfile/bundle at the dir), then load it at the
committed root, or at the outermost root post-loop when nothing else committed. This
keeps capture and load agreed on the root, so a hoisted dependency stays in-root and
is served from the bundle (integrity preserved) instead of read from disk. A
`bundleFile` that comes only from stasis.config.json is left as a signal: it lives at
a dir already carrying the (rootDir-dependent) config signal, so it selects that dir
consistently at capture and load alike. The shared bundle-absorption logic is
extracted into #absorbCodeBundle for the in-loop and post-loop paths.
Test: monorepo (.git + root package.json + packages/app with no stasis.config.json)
with a CJS dependency hoisted to the repo-root node_modules, run from the leaf with
an explicit --bundle-file; a bundle=add then bundle=load round-trip serves the dep
from the bundle (verified by tampering the on-disk copy) instead of crashing.
Claude-Session: https://claude.ai/code/session_01UenCGinFJrGDyt8E7XEftP
Co-authored-by: Claude <noreply@anthropic.com>
0 commit comments