Skip to content

fix(release): unblock the local-monorepo e2e smoke (stack packaging + entrypoint) - #238

Draft
Kunde21 wants to merge 2 commits into
happier-dev:devfrom
Kunde21:fix/local-monorepo-e2e-smoke
Draft

fix(release): unblock the local-monorepo e2e smoke (stack packaging + entrypoint)#238
Kunde21 wants to merge 2 commits into
happier-dev:devfrom
Kunde21:fix/local-monorepo-e2e-smoke

Conversation

@Kunde21

@Kunde21 Kunde21 commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Summary

The scripts/release/release-assets-e2e local-monorepo smoke (run.sh --mode=local --monorepo=local) was broken by two independent issues. Either alone blocks the stack container; together they prevented the smoke from ever passing. This PR fixes both — they are co-required for the smoke to reach [npm-e2e-smoke] OK.

1. Stack packaging: repo-root escape targets (apps/stack)

apps/stack/scripts/ reaches repo-root siblings through ../../../../../ imports. These resolve at the monorepo root in dev but, once @happier-dev/stack is npm pack-ed + installed standalone, the five ../ escape the package to the npm install root — ENOENT. npm's files glob can't traverse parent dirs to include them either. Two escape targets exist (comprehensive grep found no others):

  • `scripts/utils/proc/pm.mjs` (+ packed test) → `scripts/workspaces/{ensureWorkspacePackagesBuilt,execYarnCommand,workspacePackageBuildLock}.mjs`
  • `scripts/utils/stack/runtime_daemon_state.mjs` → `packages/cli-common/processInstance.mjs` (not bundled/exported by cli-common, so it must be vendored too)

Fix: add a postpack (mirroring apps/cli's patchPackedTarballForBun) that unpacks the tarball produced by npm pack, copies each escaped file into package/scripts/utils/workspaces/, rewrites every escaping import to the in-package copy, rewrites the helpers' own back-imports into apps/stack/scripts/utils/*, and repacks. Cross-device safe (copyFileSync, not renameSync). Repo-root sources stay canonical for monorepo builds.

The escaping imports were introduced by ed1cf5955 ("refactor(stack): centralize dependency refresh admission"); the published 0.2.1-preview predates them.

2. Entrypoint: git dubious ownership + phase1 server-light kill (scripts/release/release-assets-e2e)

2a. git dubious ownership. The host repo is bind-mounted read-only into the container as /repo, owned by the host user. git refuses to read it inside the container (different UID) → `git clone ` in hstack setup fails ("detected dubious ownership" + "Could not read from remote repository"). Set safe.directory '*' when HSTACK_HAPPIER_REPO is wired.

2b. kill_phase1_server_light missed the from-source invocation. The function matched `--import tsx ./sources/main.light.ts` (the dev invocation), but from-source the server-light runs `tsx --tsconfig ./tsconfig.json ./sources/main.light.ts` (apps/server `start:light`). The awk found nothing, the function returned early with no fallback, phase1's server-light survived into phase2 holding port 3005, and phase2's `start --restart` tripped `decideDevStartupTopology`'s guard (`ESERVERTOPOLOGYUNOWNED: healthy-unowned + restart`). Match the stable `main.light.ts` (covers dev + from-source) and add a pkill fallback mirroring `kill_phase1_no_ui_supervisor`.

Validation

End-to-end `run.sh --mode=local --monorepo=local --no-remote-daemon --no-remote-server` now reaches `[npm-e2e-smoke] OK` (exit 0): the stack container builds from source, the phase1 server-light is killed (`killing phase1 server-light: `), phase2 starts cleanly, the daemon registers, and the connectivity smoke passes.

  • patchPackedTarballForWorkspaces.test.mjs: 6/6 node:test cases (rewrite fns, escape map, extracted-dir transform, real tarball round-trip, source-drift guards for both escaping imports).
  • Real `npm pack` of `apps/stack`: both escapes fixed, all 4 files vendored, prepack's bundled `@happier-dev/*` deps preserved.

Notes

  • The two fixes touch disjoint files; keeping them in one PR because the smoke only passes with both.
  • Test-first: the postpack transform is covered by node:test; the entrypoint changes are bash + validated by the composed e2e smoke (no unit harness for the entrypoint).

Checklist

  • Full local-monorepo e2e smoke passes (exit 0)
  • postpack node:test suite (6/6)
  • No unrelated changes; primary worktree untouched

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Note

Fix local-monorepo e2e smoke by adding stack postpack tarball patching and entrypoint fixes

  • Adds a postpack lifecycle script to apps/stack that vendors workspace helper scripts into the packed tarball and rewrites their imports so the package works standalone outside the monorepo.
  • Implements patchPackedTarballForWorkspaces.mjs which extracts the tarball, copies vendored helpers into scripts/utils/workspaces/, rewrites escaping imports to point at vendored copies, then repacks in-place.
  • Fixes stack-entrypoint.sh to trust bind-mounted repo directories via git config --global --add safe.directory '*', avoiding dubious ownership errors in the container.
  • Broadens the kill_phase1_server_light process match pattern and adds a pkill fallback to reliably terminate lingering server-light processes and prevent port conflicts.

Macroscope summarized 8478bb0.

…hase1 server-light kill)

The release-assets-e2e local-monorepo smoke (`run.sh --mode=local --monorepo=local`)
hit two independent entrypoint issues that prevented the stack container from reaching
the daemon-registration smoke.

1. git dubious ownership of the bind-mounted repo. The host repo is mounted read-only
   into the container as /repo, owned by the host user. git refuses to read it inside the
   container (different UID) -> `git clone <repo>` in hstack setup fails with
   "detected dubious ownership" + "Could not read from remote repository". Set
   `safe.directory '*'` when HSTACK_HAPPIER_REPO is wired so the clone succeeds.

2. kill_phase1_server_light missed the from-source server-light invocation. The function
   matched `--import tsx ./sources/main.light.ts` (the dev invocation), but from-source the
   server-light runs via `tsx --tsconfig ./tsconfig.json ./sources/main.light.ts` (apps/server
   `start:light`), so the awk found nothing and the function returned early with NO fallback.
   The phase1 server-light survived into phase2, kept port 3005 occupied, and phase2's
   `start --restart` tripped decideDevStartupTopology's guard
   (`ESERVERTOPOLOGYUNOWNED: healthy-unowned + restart`). Match on the stable `main.light.ts`
   (covers dev + from-source) and add a pkill fallback mirroring kill_phase1_no_ui_supervisor.

Validated end-to-end: `run.sh --mode=local --monorepo=local` now reaches
`[npm-e2e-smoke] OK` (exit 0) — the stack container builds from source, the phase1
server-light is killed (`killing phase1 server-light: <pids>`), phase2 starts cleanly,
and the daemon registers + passes the connectivity smoke. (Requires the companion
@happier-dev/stack postpack fix for the escaped-import packaging bug to build at all.)
…ll via postpack

apps/stack/scripts/ reaches repo-root siblings through `../../../../../` imports that resolve
at the monorepo root in dev but, once @happier-dev/stack is `npm pack`-ed and installed
standalone, escape the package to the npm install root — ENOENT. npm's `files` glob also
cannot traverse parent dirs to include those files, so the packed tarball crashes on `hstack
setup`/`start` (any standalone install); the e2e local-monorepo smoke catches it.

Two escape targets exist (comprehensive grep of apps/stack/ found no others):
- scripts/utils/proc/pm.mjs (+ the packed test) -> scripts/workspaces/{ensureWorkspacePackagesBuilt,execYarnCommand,workspacePackageBuildLock}.mjs
- scripts/utils/stack/runtime_daemon_state.mjs -> packages/cli-common/processInstance.mjs
  (processInstance.mjs is not bundled/exported by cli-common, so it must be vendored too)

Add a postpack (mirroring apps/cli's patchPackedTarballForBun) that unpacks the tarball
produced by `npm pack`, copies each escaped file into package/scripts/utils/workspaces/
(basename preserved), rewrites every escaping import to the in-package vendored copy, and
rewrites the helpers' own back-imports into apps/stack/scripts/utils/* to in-package relative
paths, then repacks. Repo-root sources stay canonical for monorepo builds; only the published
tarball is made self-contained. Cross-device safe via copyFileSync (renameSync throws EXDEV
when the pack destination and tmpdir are on different mounts).

Validated: node:test suite (6 cases: rewrite fns, escape map, extracted-dir transform, real
tarball round-trip, source-drift guards for BOTH escaping imports), a real `npm pack` of
apps/stack (both escapes fixed, all 4 files vendored), and the e2e local-monorepo smoke —
the stack container installed hstack and progressed into setup, past the pm.mjs and
runtime_daemon_state crashes that blocked every prior run. (The smoke then failed on an
unrelated git dubious-ownership / no-network issue inside the container, beyond this fix.)

The escaping imports were introduced by ed1cf59 ("refactor(stack): centralize dependency
refresh admission") and later commits; the published 0.2.1-preview predates them, so the next
release from current source would ship broken without this.
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: de56330c-5901-44e3-a2c5-684022b5fda5

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant