diff --git a/hatch_build.py b/hatch_build.py index 0f4e9d5..1924711 100644 --- a/hatch_build.py +++ b/hatch_build.py @@ -47,8 +47,24 @@ def initialize(self, version: str, build_data: dict) -> None: # noqa: ARG002 f"The wheel needs the built {' and '.join(missing)} under share/, and npm is not " "on PATH to build them. Run `make build` first, or set DATALAYER_DECKS_SKIP_JS=1." ) - if not (ROOT / "node_modules").is_dir() and not (ROOT.parent.parent.parent / "node_modules").is_dir(): + workspace = ROOT.parent.parent.parent / "node_modules" + if not (ROOT / "node_modules").is_dir() and not workspace.is_dir(): subprocess.run([npm, "install"], cwd=ROOT, check=True) + # The interface (app/) is a package of its own, never a workspace + # member: nothing hoists its dependencies, and its bundler has to be + # its own -- after a `git clean`, app/ otherwise resolves whatever + # rsbuild the workspace hoisted, which is not the one it was written + # against. The plugin is a workspace member when there is a workspace + # (hoisted, nothing to install: `npm install` inside a member would + # redirect to the whole workspace) and a package of its own in a plain + # checkout, where CI installs it too. + own = [ROOT / "app"] + if not workspace.is_dir(): + own.append(ROOT / "plugins" / "ai-agents") + for package in own: + if not (package / "node_modules").is_dir(): + self.app.display_info(f"Installing {package.relative_to(ROOT)}'s dependencies ...") + subprocess.run([npm, "install", "--no-audit", "--no-fund"], cwd=package, check=True) self.app.display_info(f"Building the {' and '.join(missing)} into share/ ...") subprocess.run([npm, "run", "build:all"], cwd=ROOT, check=True) for name, marker in (("interface", APP), ("container", CONTAINER)):