diff --git a/genie/ci-scripts/ci-measurement-comparison.test.sh b/genie/ci-scripts/ci-measurement-comparison.test.sh index 80260faa5..8b2104157 100755 --- a/genie/ci-scripts/ci-measurement-comparison.test.sh +++ b/genie/ci-scripts/ci-measurement-comparison.test.sh @@ -7,19 +7,35 @@ cd "$ROOT" tmp_dir="$(mktemp -d)" trap 'rm -rf "$tmp_dir"' EXIT -run_bun() { +run_bun_to_file() { + local output_file="$1" + local script_file="$2" + if command -v bun >/dev/null 2>&1; then - bun "$@" + bun "$script_file" >"$output_file" + elif command -v nix >/dev/null 2>&1; then + nix run nixpkgs#bun -- "$script_file" >"$output_file" elif [ -n "${DEVENV_BIN:-}" ]; then - "$DEVENV_BIN" shell --no-reload -- bun "$@" + "$DEVENV_BIN" shell --no-reload -- bash -lc 'bun "$1" > "$2"' bash "$script_file" "$output_file" else - echo "bun is not available and DEVENV_BIN is not set" >&2 + echo "bun is not available and neither nix nor DEVENV_BIN is set" >&2 return 127 fi } emit_compare_script() { - run_bun -e "import { compareCiMeasurementsStep } from './genie/ci-workflow/measurements.ts'; process.stdout.write(compareCiMeasurementsStep({ currentDir: '$tmp_dir/current', baselineDir: '$tmp_dir/baseline', outputFile: '$tmp_dir/comparison.json', regressionMode: 'warn' }).run)" >"$tmp_dir/compare.sh" + local emitter="$tmp_dir/emit-compare.ts" + cat >"$emitter" <=0.73.0', }, }, + /** + * Materialize workspace deps as pnpm-injected package snapshots instead of + * plain source symlinks. This is required for the pure Nix/FOD package + * closure model: a package-local dependency build must hash every workspace + * package it consumes as dependency input, not accidentally reach outside the + * staged closure through a live symlink. + */ + injectWorkspacePackages: true as const, enableGlobalVirtualStore: true as const, storeDir: '.devenv/pnpm-store-pure-v1', packageImportMethod: 'clone-or-copy' as const, diff --git a/nix/oxc-config-plugin.nix b/nix/oxc-config-plugin.nix index 32d7289f1..060aaa874 100644 --- a/nix/oxc-config-plugin.nix +++ b/nix/oxc-config-plugin.nix @@ -28,7 +28,7 @@ let pnpm = pinnedPnpm; }; packageDir = "packages/@overeng/oxc-config"; - pnpmDepsHash = "sha256-0FpUv8pn7KNn9PdP5BzwDX2BUtgA/p56lv7eLEG1gio="; + pnpmDepsHash = "sha256-UPDXMkAo6ZbawNzCZRiQ7066m6fo+Shq6CfhMHHx07w="; srcPath = if builtins.isAttrs src && builtins.hasAttr "outPath" src then diff --git a/packages/@overeng/genie/nix/build.nix b/packages/@overeng/genie/nix/build.nix index ae8ec0268..fbb49ed50 100644 --- a/packages/@overeng/genie/nix/build.nix +++ b/packages/@overeng/genie/nix/build.nix @@ -25,7 +25,7 @@ let # Managed by the repo FOD refresh workflow — do not edit manually. depsBuilds = { "." = { - hash = "sha256-CJRcbIEpZes3jsGGYuhA6VhMY4AMxDEK+Fqpa/S7V8s="; + hash = "sha256-D7Z0w54Tn/LmKVZuun9ndutkAtJGM/dkDEAfKcgfJ1Q="; }; }; nativeNodePackages = [ opentuiCoreNative ]; diff --git a/packages/@overeng/genie/src/runtime/pnpm-workspace/mod.ts b/packages/@overeng/genie/src/runtime/pnpm-workspace/mod.ts index a6c36006b..cb1661b8b 100644 --- a/packages/@overeng/genie/src/runtime/pnpm-workspace/mod.ts +++ b/packages/@overeng/genie/src/runtime/pnpm-workspace/mod.ts @@ -113,6 +113,19 @@ export interface PnpmSettings { */ nodeLinker?: 'hoisted' | 'isolated' | 'pnp' + /** + * Hard-link local workspace dependencies as injected package snapshots + * instead of resolving them as plain live symlinks. + * + * This is a packaging-purity control for Nix/FOD package closures: when a + * package is built from a reduced package-local workspace, every consumed + * workspace package must be represented in the dependency graph and lockfile + * instead of being reached through an unstaged source path. + * + * @see https://pnpm.io/settings#inject-workspace-packages + */ + injectWorkspacePackages?: boolean + /** * Pnpm-lock.yaml will be deterministic and independent of system environment. * @see https://pnpm.io/settings#use-lockfile-v6 @@ -699,6 +712,19 @@ export interface PnpmWorkspaceData { */ nodeLinker?: 'hoisted' | 'isolated' | 'pnp' + /** + * Hard-link local workspace dependencies as injected package snapshots + * instead of resolving them as plain live symlinks. + * + * This is a packaging-purity control for Nix/FOD package closures: when a + * package is built from a reduced package-local workspace, every consumed + * workspace package must be represented in the dependency graph and lockfile + * instead of being reached through an unstaged source path. + * + * @see https://pnpm.io/settings#inject-workspace-packages + */ + injectWorkspacePackages?: boolean + /** * Store dependency contents in a global content-addressed store keyed by * dependency graph hash. Required for identity convergence: equivalent @@ -980,6 +1006,10 @@ const buildPnpmWorkspaceYaml = ({ result.nodeLinker = data.nodeLinker } + if (data.injectWorkspacePackages !== undefined) { + result.injectWorkspacePackages = data.injectWorkspacePackages + } + if (data.enableGlobalVirtualStore !== undefined) { result.enableGlobalVirtualStore = data.enableGlobalVirtualStore } diff --git a/packages/@overeng/megarepo/nix/build.nix b/packages/@overeng/megarepo/nix/build.nix index 2b2945ac0..d3555e3e1 100644 --- a/packages/@overeng/megarepo/nix/build.nix +++ b/packages/@overeng/megarepo/nix/build.nix @@ -24,7 +24,7 @@ let # Managed by the repo FOD refresh workflow — do not edit manually. depsBuilds = { "." = { - hash = "sha256-l3vx+W5mdMqQjTkRQZT15ic9suFBFMPL12FW4NjekDQ="; + hash = "sha256-AgCjUDGkQ115HNjU9GSRRKkJEofXLgaHzEtObR54Nmo="; }; }; nativeNodePackages = [ opentuiCoreNative ]; diff --git a/packages/@overeng/notion-cli/nix/build.nix b/packages/@overeng/notion-cli/nix/build.nix index 744e91985..12095e473 100644 --- a/packages/@overeng/notion-cli/nix/build.nix +++ b/packages/@overeng/notion-cli/nix/build.nix @@ -21,7 +21,7 @@ let # Managed by the repo FOD refresh workflow — do not edit manually. depsBuilds = { "." = { - hash = "sha256-VrpW4MT6ZDqpsE7Utu/CXXA1UOSJsD+HDHXEPZ/lp9g="; + hash = "sha256-Nzrd6Wz7OWympJSsLBU0uodHL5/v1fgfvBvx/Q9IBf4="; }; }; nativeNodePackages = [ opentuiCoreNative ]; diff --git a/packages/@overeng/notion-md/nix/build.nix b/packages/@overeng/notion-md/nix/build.nix index 369edbb05..a9e5e2246 100644 --- a/packages/@overeng/notion-md/nix/build.nix +++ b/packages/@overeng/notion-md/nix/build.nix @@ -20,7 +20,7 @@ let # Managed by the repo FOD refresh workflow — do not edit manually. depsBuilds = { "." = { - hash = "sha256-kP5yTW/T7gelOOPjXjzi0DCs2qb2lejvTTjvSiveTeY="; + hash = "sha256-jU1WCdUEuiPC6EJRfbg8poF+JGVR8+KJ7ACnmjsnerw="; }; }; smokeTestArgs = [ "--help" ]; diff --git a/packages/@overeng/tui-stories/nix/build.nix b/packages/@overeng/tui-stories/nix/build.nix index 5b224c017..a7305a594 100644 --- a/packages/@overeng/tui-stories/nix/build.nix +++ b/packages/@overeng/tui-stories/nix/build.nix @@ -21,7 +21,7 @@ let # Managed by the repo FOD refresh workflow — do not edit manually. depsBuilds = { "." = { - hash = "sha256-vbypLXWgCH8YNb7nxLg1o3eHWwys3oqVhqBnr0dDEGs="; + hash = "sha256-0VxYgFoPszkCa1bpaSEWGFm5TBIO1g8CMDhVzrKNVx8="; }; }; nativeNodePackages = [ opentuiCoreNative ]; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 62f1e672e..dfcbcad99 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3,6 +3,7 @@ lockfileVersion: '9.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false + injectWorkspacePackages: true packageExtensionsChecksum: sha256-6cS8D25oV8JxyYRUXZukPZaGz7zpUutYoZpOLuoEA/g= @@ -440,7 +441,7 @@ importers: version: link:../tui-core '@overeng/tui-react': specifier: workspace:^ - version: file:packages/@overeng/tui-react(3320b31dac93676200353be3de13ceca) + version: link:../tui-react '@overeng/utils': specifier: workspace:^ version: link:../utils @@ -567,7 +568,7 @@ importers: version: link:../kdl-effect '@overeng/tui-react': specifier: workspace:^ - version: file:packages/@overeng/tui-react(3320b31dac93676200353be3de13ceca) + version: link:../tui-react '@overeng/utils': specifier: workspace:^ version: link:../utils @@ -694,7 +695,7 @@ importers: version: link:../tui-core '@overeng/tui-react': specifier: workspace:^ - version: file:packages/@overeng/tui-react(3320b31dac93676200353be3de13ceca) + version: link:../tui-react '@overeng/utils': specifier: workspace:^ version: link:../utils @@ -1326,7 +1327,7 @@ importers: version: link:../tui-core '@overeng/tui-react': specifier: workspace:^ - version: file:packages/@overeng/tui-react(3320b31dac93676200353be3de13ceca) + version: link:../tui-react '@overeng/utils': specifier: workspace:^ version: link:../utils @@ -2256,23 +2257,6 @@ packages: react-devtools-core: ^7.0.1 ws: ^8.18.0 - '@overeng/tui-react@file:packages/@overeng/tui-react': - resolution: {directory: packages/@overeng/tui-react, type: directory} - peerDependencies: - '@effect-atom/atom': ^0.5.3 - '@effect-atom/atom-react': ^0.5.0 - '@effect/cli': ^0.75.1 - '@effect/platform-node': ^0.106.0 - '@opentui/core': ^0.1.88 - '@opentui/react': ^0.1.88 - '@storybook/react': ^10.2.3 - '@types/react': ^19.2.7 - '@types/react-reconciler': ^0.28.9 - effect: ^3.21.2 - react: ^19.2.3 - react-dom: ^19.2.3 - react-reconciler: ^0.33.0 - '@oxfmt/darwin-arm64@0.23.0': resolution: {integrity: sha512-shGng2EjBspvuqtFtcjcKf0WoZ9QCdL8iLYgdOoKSiSQ9pPyLJ4jQf62yhm4b2PpZNVcV/20gV6d8SyKzg6SZQ==} cpu: [arm64] @@ -5767,71 +5751,6 @@ snapshots: - typescript - web-tree-sitter - '@overeng/tui-react@file:packages/@overeng/tui-react(3320b31dac93676200353be3de13ceca)': - dependencies: - '@effect-atom/atom': 0.5.3(@effect/experimental@0.60.0(@effect/platform@0.96.1(patch_hash=08d6466db56675b7a32a3a3c64815a5b784f583b310b6758471a97d3db6edd32)(effect@3.21.2))(effect@3.21.2)(ioredis@5.6.1))(@effect/platform@0.96.1(patch_hash=08d6466db56675b7a32a3a3c64815a5b784f583b310b6758471a97d3db6edd32)(effect@3.21.2))(@effect/rpc@0.75.1(@effect/platform@0.96.1(patch_hash=08d6466db56675b7a32a3a3c64815a5b784f583b310b6758471a97d3db6edd32)(effect@3.21.2))(effect@3.21.2))(effect@3.21.2) - '@effect-atom/atom-react': 0.5.0(@effect/experimental@0.60.0(@effect/platform@0.96.1(patch_hash=08d6466db56675b7a32a3a3c64815a5b784f583b310b6758471a97d3db6edd32)(effect@3.21.2))(effect@3.21.2)(ioredis@5.6.1))(@effect/platform@0.96.1(patch_hash=08d6466db56675b7a32a3a3c64815a5b784f583b310b6758471a97d3db6edd32)(effect@3.21.2))(@effect/rpc@0.75.1(@effect/platform@0.96.1(patch_hash=08d6466db56675b7a32a3a3c64815a5b784f583b310b6758471a97d3db6edd32)(effect@3.21.2))(effect@3.21.2))(effect@3.21.2)(react@19.2.3)(scheduler@0.27.0) - '@effect/cli': 0.75.1(@effect/platform@0.96.1(patch_hash=08d6466db56675b7a32a3a3c64815a5b784f583b310b6758471a97d3db6edd32)(effect@3.21.2))(@effect/printer-ansi@0.49.0(@effect/typeclass@0.40.0(effect@3.21.2))(effect@3.21.2))(@effect/printer@0.49.0(@effect/typeclass@0.40.0(effect@3.21.2))(effect@3.21.2))(effect@3.21.2) - '@effect/cluster': 0.58.2(f335cd339cca8128b299febedcdd4641) - '@effect/experimental': 0.60.0(@effect/platform@0.96.1(patch_hash=08d6466db56675b7a32a3a3c64815a5b784f583b310b6758471a97d3db6edd32)(effect@3.21.2))(effect@3.21.2)(ioredis@5.6.1) - '@effect/opentelemetry': 0.63.0(@effect/platform@0.96.1(patch_hash=08d6466db56675b7a32a3a3c64815a5b784f583b310b6758471a97d3db6edd32)(effect@3.21.2))(@opentelemetry/api@1.9.0)(@opentelemetry/resources@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-logs@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-metrics@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-node@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-web@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0)(effect@3.21.2) - '@effect/platform': 0.96.1(patch_hash=08d6466db56675b7a32a3a3c64815a5b784f583b310b6758471a97d3db6edd32)(effect@3.21.2) - '@effect/platform-node': 0.106.0(@effect/cluster@0.58.2(f335cd339cca8128b299febedcdd4641))(@effect/platform@0.96.1(patch_hash=08d6466db56675b7a32a3a3c64815a5b784f583b310b6758471a97d3db6edd32)(effect@3.21.2))(@effect/rpc@0.75.1(@effect/platform@0.96.1(patch_hash=08d6466db56675b7a32a3a3c64815a5b784f583b310b6758471a97d3db6edd32)(effect@3.21.2))(effect@3.21.2))(@effect/sql@0.51.1(@effect/experimental@0.60.0(@effect/platform@0.96.1(patch_hash=08d6466db56675b7a32a3a3c64815a5b784f583b310b6758471a97d3db6edd32)(effect@3.21.2))(effect@3.21.2)(ioredis@5.6.1))(@effect/platform@0.96.1(patch_hash=08d6466db56675b7a32a3a3c64815a5b784f583b310b6758471a97d3db6edd32)(effect@3.21.2))(effect@3.21.2))(effect@3.21.2) - '@effect/rpc': 0.75.1(@effect/platform@0.96.1(patch_hash=08d6466db56675b7a32a3a3c64815a5b784f583b310b6758471a97d3db6edd32)(effect@3.21.2))(effect@3.21.2) - '@effect/vitest': 0.29.0(effect@3.21.2)(vitest@3.2.4(@types/debug@4.1.13)(@types/node@25.3.3)(happy-dom@18.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.3)) - '@effect/workflow': 0.18.0(@effect/experimental@0.60.0(@effect/platform@0.96.1(patch_hash=08d6466db56675b7a32a3a3c64815a5b784f583b310b6758471a97d3db6edd32)(effect@3.21.2))(effect@3.21.2)(ioredis@5.6.1))(@effect/platform@0.96.1(patch_hash=08d6466db56675b7a32a3a3c64815a5b784f583b310b6758471a97d3db6edd32)(effect@3.21.2))(@effect/rpc@0.75.1(@effect/platform@0.96.1(patch_hash=08d6466db56675b7a32a3a3c64815a5b784f583b310b6758471a97d3db6edd32)(effect@3.21.2))(effect@3.21.2))(effect@3.21.2) - '@opentui/core': 0.1.88(stage-js@1.0.2)(typescript@5.9.3)(web-tree-sitter@0.25.10) - '@opentui/react': 0.1.88(react-devtools-core@7.0.1)(react@19.2.3)(stage-js@1.0.2)(typescript@5.9.3)(web-tree-sitter@0.25.10)(ws@8.20.0) - '@overeng/tui-core': link:packages/@overeng/tui-core - '@overeng/utils': link:packages/@overeng/utils - '@playwright/test': 1.59.1 - '@storybook/react': 10.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.2.3(@testing-library/dom@10.4.1)(prettier@3.8.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3) - '@types/react': 19.2.7 - '@types/react-reconciler': 0.28.9(@types/react@19.2.7) - '@xterm/addon-fit': 0.11.0 - '@xterm/addon-webgl': 0.19.0 - '@xterm/headless': 6.0.0 - '@xterm/xterm': 6.0.0 - cli-truncate: 5.1.1 - effect: 3.21.2 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - react-reconciler: 0.33.0(react@19.2.3) - string-width: 7.2.0 - vitest: 3.2.4(@types/debug@4.1.13)(@types/node@25.3.3)(happy-dom@18.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.3) - yoga-layout: 3.2.1 - transitivePeerDependencies: - - '@edge-runtime/vm' - - '@effect/sql' - - '@opentelemetry/api' - - '@opentelemetry/resources' - - '@opentelemetry/sdk-logs' - - '@opentelemetry/sdk-metrics' - - '@opentelemetry/sdk-trace-base' - - '@opentelemetry/sdk-trace-node' - - '@opentelemetry/sdk-trace-web' - - '@opentelemetry/semantic-conventions' - - '@types/debug' - - '@types/node' - - '@vitest/browser' - - '@vitest/ui' - - happy-dom - - ioredis - - jiti - - jsdom - - less - - lightningcss - - lmdb - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - '@oxfmt/darwin-arm64@0.23.0': optional: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 84353d5b1..b5b758fda 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -66,6 +66,8 @@ dedupePeerDependents: true strictPeerDependencies: true +injectWorkspacePackages: true + enableGlobalVirtualStore: true storeDir: .devenv/pnpm-store-pure-v1