diff --git a/.buckconfig b/.buckconfig new file mode 100644 index 0000000000..495ec1734d --- /dev/null +++ b/.buckconfig @@ -0,0 +1,35 @@ +[cells] + effect_utils = . + capabilities = .buck2/capabilities + prelude = prelude + +[cell_aliases] + config = prelude + ovr_config = prelude + fbsource = prelude + toolchains = effect_utils + +[external_cells] + prelude = bundled + +[parser] + target_platform_detector_spec = target:effect_utils//...->effect_utils//buck2/platforms:host_platform + +[build] + execution_platforms = effect_utils//buck2/platforms:host_execution_platform + +[buck2] + file_watcher = notify + default_allow_cache_upload = true + digest_algorithms = SHA256 + +[buck2_re_client] + action_cache_address = grpc://dev3:41045 + cas_address = grpc://dev3:41045 + engine_address = grpc://dev3:41045 + http_headers = authorization: Basic $BUCK2_REMOTE_CACHE_BASIC_AUTH + instance_name = effect-utils + tls = false + +[project] + ignore = **/__pycache__,**/dist,**/node_modules,**/node_modules/**,**/target,**/target/**,.buck2/capabilities.candidate.*,.devenv,.git,buck-out,node_modules,packages/.editor-view,target,tmp diff --git a/.buckroot b/.buckroot new file mode 100644 index 0000000000..e69de29bb2 diff --git a/.github/repo-settings.json b/.github/repo-settings.json index 91fee715b5..fbe79eb683 100644 --- a/.github/repo-settings.json +++ b/.github/repo-settings.json @@ -50,18 +50,6 @@ { "context": "test-megarepo-cold-gc" }, - { - "context": "nix-check (namespace-profile-linux-x86-64)" - }, - { - "context": "nix-check (namespace-profile-macos-arm64)" - }, - { - "context": "nix-fod-check (namespace-profile-linux-x86-64)" - }, - { - "context": "nix-fod-check (namespace-profile-macos-arm64)" - }, { "context": "pnpm-builder-contract" }, diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4418ca4908..4a7eafaee9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -545,12 +545,12 @@ jobs: ! grep -q '\[otel\] Using' "$tmp_log" test "$(git status --porcelain=v1)" = "$before" rm -f "$tmp_log" - - name: Type check (Buck authority + residual root solution) + - name: Type check (Buck) env: GITHUB_TOKEN: ${{ github.token }} run: | __genie_ci_retry_script='${{ runner.temp }}/composition-state/ci-runtime/run-with-nix-gc-race-retry.sh' - bash "$__genie_ci_retry_script" 'devenv tasks run buck2:check ts:check:strict' 'cd "${EFFECT_UTILS_MEMBER_ROOT:-${GITHUB_WORKSPACE:-$PWD}}" && if [ -n "${NIX_CONFIG:-}" ]; then NIX_CONFIG_WITH_APPEND=$(printf '"'"'%s\n%s'"'"' "$NIX_CONFIG" '"'"'restrict-eval = false'"'"'); else NIX_CONFIG_WITH_APPEND='"'"'restrict-eval = false'"'"'; fi; NIX_CONFIG="$NIX_CONFIG_WITH_APPEND" DEVENV_TASK_PASSTHROUGH=1 DEVENV_TUI=false "${DEVENV_BIN:?DEVENV_BIN not set}" tasks run buck2:check ts:check:strict' + bash "$__genie_ci_retry_script" 'devenv tasks run buck2:check' 'cd "${EFFECT_UTILS_MEMBER_ROOT:-${GITHUB_WORKSPACE:-$PWD}}" && if [ -n "${NIX_CONFIG:-}" ]; then NIX_CONFIG_WITH_APPEND=$(printf '"'"'%s\n%s'"'"' "$NIX_CONFIG" '"'"'restrict-eval = false'"'"'); else NIX_CONFIG_WITH_APPEND='"'"'restrict-eval = false'"'"'; fi; NIX_CONFIG="$NIX_CONFIG_WITH_APPEND" DEVENV_TASK_PASSTHROUGH=1 DEVENV_TUI=false "${DEVENV_BIN:?DEVENV_BIN not set}" tasks run buck2:check' - name: Nix diagnostics summary if: failure() shell: bash @@ -2698,7 +2698,8 @@ jobs: "${DEVENV_BIN:?DEVENV_BIN not set}" shell -- bun test \ genie/buck2/typescript-package-projection.unit.test.ts \ genie/buck2/javascript-candidates.unit.test.ts \ - packages/@overeng/buck2-tools/src/package-command-runner.unit.test.ts + packages/@overeng/buck2-tools/src/package-command-runner.unit.test.ts \ + packages/@overeng/buck2-tools/src/javascript-runner.unit.test.ts - name: Check product publisher and manifest import contracts env: GITHUB_TOKEN: ${{ github.token }} @@ -2710,7 +2711,7 @@ jobs: run: | cd "${EFFECT_UTILS_MEMBER_ROOT:-${GITHUB_WORKSPACE:-$PWD}}" && set -euo pipefail tracked_editor=$(git ls-files -- '**/.editor-view/**' '.editor-view/**') - tracked_product=$(git ls-files -- 'nix/buck2-products/**' | grep -Ev '^nix/buck2-products/(default\.nix|manifest\.json|publish\.sh)$' || true) + tracked_product=$(git ls-files -- 'nix/buck2-products/**' | grep -Ev '^nix/buck2-products/(default\.nix|manifest\.json|publish\.sh|targets\.json|targets\.json\.genie\.ts)$' || true) if [ -n "$tracked_editor$tracked_product" ]; then printf 'Tracked inert payload bytes are forbidden:\n%s\n%s\n' "$tracked_editor" "$tracked_product" >&2 exit 1 @@ -2724,10 +2725,10 @@ jobs: cd "${EFFECT_UTILS_WORKSPACE_ROOT:?EFFECT_UTILS_WORKSPACE_ROOT not set}" buck="$PWD/.megarepo/bin/buck2" "$buck" query effect_utils//packages/@overeng/ci-tools:ci-tools-candidate - "$buck" query effect_utils//packages/@overeng/tui-core:editor_view_inputs + "$buck" query effect_utils//:editor_view_inputs "$buck" build \ effect_utils//packages/@overeng/ci-tools:ci-tools-candidate \ - effect_utils//packages/@overeng/tui-core:editor_view_inputs + effect_utils//:editor_view_inputs ' - name: Cleanup effect-utils composition if: always() @@ -3639,7 +3640,7 @@ jobs: measure 'shell_eval_warm' 'Warm shell eval' 'devenv shell' 'Activates the mutation-free warm shell; repository setup is explicit and Buck must not run.' '' '1' '5' '{"enabled":true,"comparisonMode":"paired","minPairedSamples":5,"minBaselineSources":10,"minCurrentSamples":5,"warnRatio":1.1,"failRatio":1.2,"warnAbs":0.25,"failAbs":1,"noiseFloor":0.1,"statisticalToleranceRatio":0.1,"statisticalToleranceAbs":0.25}' '{"path":["devenv","shell"],"dimensions":{"workload":"setup-free-activation","setupMode":"disabled","buckExpected":"not-invoked"}}' '$DEVENV_BIN' 'shell' '--no-reload' '--' 'true' measure 'tasks_list' 'devenv tasks list' 'devenv cli' 'Lists devenv tasks to measure task graph loading overhead.' '' '1' '9' '{"enabled":true,"comparisonMode":"paired","minPairedSamples":7,"minBaselineSources":10,"minCurrentSamples":5,"warnRatio":1.25,"failRatio":1.5,"warnAbs":0.05,"failAbs":0.15,"noiseFloor":0.03,"statisticalToleranceRatio":0.1,"statisticalToleranceAbs":0.03}' '{"path":[],"dimensions":{}}' '$DEVENV_BIN' 'tasks' 'list' measure 'processes_help' 'devenv processes --help' 'devenv cli' 'Loads the devenv processes command help path.' '' '1' '9' '{"enabled":true,"comparisonMode":"paired","minPairedSamples":7,"minBaselineSources":10,"minCurrentSamples":5,"warnRatio":1.25,"failRatio":1.5,"warnAbs":0.05,"failAbs":0.15,"noiseFloor":0.03,"statisticalToleranceRatio":0.1,"statisticalToleranceAbs":0.03}' '{"path":[],"dimensions":{}}' '$DEVENV_BIN' 'processes' '--help' - measure 'task_pnpm_install' 'pnpm install task' 'workspace setup' 'Runs the cached pnpm install devenv task.' '' '1' '5' '{"enabled":true,"comparisonMode":"paired","minPairedSamples":5,"minBaselineSources":10,"minCurrentSamples":5,"warnRatio":1.1,"failRatio":1.2,"warnAbs":0.25,"failAbs":1,"noiseFloor":0.1,"statisticalToleranceRatio":0.1,"statisticalToleranceAbs":0.25}' '{"path":[],"dimensions":{}}' '$DEVENV_BIN' 'tasks' 'run' 'pnpm:install' '--show-output' + measure 'task_buck2_editor_publish' 'Editor dependency publication' 'workspace setup' 'Publishes the complete Buck-owned editor dependency surface.' '' '1' '5' '{"enabled":true,"comparisonMode":"paired","minPairedSamples":5,"minBaselineSources":10,"minCurrentSamples":5,"warnRatio":1.1,"failRatio":1.2,"warnAbs":0.25,"failAbs":1,"noiseFloor":0.1,"statisticalToleranceRatio":0.1,"statisticalToleranceAbs":0.25}' '{"path":[],"dimensions":{}}' '$DEVENV_BIN' 'tasks' 'run' 'buck2:editor:publish' '--show-output' measure 'task_genie_run' 'Genie run task' 'genie' 'Runs the normal devenv genie:run task including its declared dependencies.' '' '1' '5' '{"enabled":true,"comparisonMode":"paired","minPairedSamples":5,"minBaselineSources":10,"minCurrentSamples":5,"warnRatio":1.1,"failRatio":1.2,"warnAbs":0.25,"failAbs":1,"noiseFloor":0.1,"statisticalToleranceRatio":0.1,"statisticalToleranceAbs":0.25}' '{"path":[],"dimensions":{}}' '$DEVENV_BIN' 'tasks' 'run' 'genie:run' '--show-output' measure 'task_check_quick_warm' 'Warm cached check:quick' 'quality gates' 'Runs the fast local quality gate through devenv after a warmup. This measures the cached no-op path and task/status orchestration overhead.' '' '1' '5' '{"enabled":true,"comparisonMode":"paired","minPairedSamples":5,"minBaselineSources":10,"minCurrentSamples":5,"warnRatio":1.1,"failRatio":1.2,"warnAbs":0.25,"failAbs":1,"noiseFloor":0.1,"statisticalToleranceRatio":0.1,"statisticalToleranceAbs":0.25}' '{"path":["quality gates","check:quick"],"dimensions":{"workload":"cached-no-op","taskCacheMode":"warm"}}' '$DEVENV_BIN' 'tasks' 'run' 'check:quick' '--show-output' measure 'task_check_quick_forced' 'Forced check:quick' 'quality gates' 'Runs the fast local quality gate through devenv with task-cache refresh. This measures the developer-facing quick-check workload rather than the cached no-op path.' '' '0' '3' '{"enabled":true,"comparisonMode":"paired","minPairedSamples":3,"minBaselineSources":10,"minCurrentSamples":3,"warnRatio":1.15,"failRatio":1.3,"warnAbs":1.5,"failAbs":4,"noiseFloor":0.75,"statisticalToleranceRatio":0.15,"statisticalToleranceAbs":1}' '{"path":["quality gates","check:quick"],"dimensions":{"workload":"forced-task-cache","taskCacheMode":"refresh"}}' '$DEVENV_BIN' 'tasks' 'run' 'check:quick' '--show-output' '--refresh-task-cache' @@ -6523,7 +6524,7 @@ jobs: shell_eval_warm: 'Warm shell eval', tasks_list: 'devenv tasks list', processes_help: 'devenv processes --help', - task_pnpm_install: 'pnpm:install', + task_buck2_editor_publish: 'buck2:editor:publish', task_genie_run: 'genie:run', task_check_quick: 'check:quick', task_check_quick_warm: 'Warm cached check:quick', @@ -6604,7 +6605,7 @@ jobs: shell_eval_warm: 'Warm shell eval', tasks_list: 'devenv tasks list', processes_help: 'processes --help', - task_pnpm_install: 'pnpm:install', + task_buck2_editor_publish: 'buck2:editor:publish', task_genie_run: 'genie:run', task_check_quick: 'check:quick', task_check_quick_warm: 'Warm cached check:quick', @@ -7812,7 +7813,7 @@ jobs: run: | cd "${EFFECT_UTILS_MEMBER_ROOT:-${GITHUB_WORKSPACE:-$PWD}}" && netlify_pkg="$(nix build --no-link --print-out-paths .#netlify-cli)" export CI_TOOLS_LIVE_NETLIFY_BIN="$netlify_pkg/bin/netlify" - DEVENV_TASK_PASSTHROUGH=1 DEVENV_TUI=false "${DEVENV_BIN:?DEVENV_BIN not set}" tasks run pnpm:install + DEVENV_TASK_PASSTHROUGH=1 DEVENV_TUI=false "${DEVENV_BIN:?DEVENV_BIN not set}" tasks run buck2:editor:publish DEVENV_TUI=false "${DEVENV_BIN:?DEVENV_BIN not set}" shell --no-reload -- bun test packages/@overeng/ci-tools/src/deploy-netlify.live.e2e.test.ts if: steps.live-netlify-preflight.outputs.run == 'true' - name: Live Vercel ci-tools E2E @@ -7829,7 +7830,7 @@ jobs: run: | cd "${EFFECT_UTILS_MEMBER_ROOT:-${GITHUB_WORKSPACE:-$PWD}}" && vercel_pkg="$(nix build --no-link --print-out-paths .#vercel-cli)" export CI_TOOLS_LIVE_VERCEL_BIN="$vercel_pkg/bin/vercel" - DEVENV_TASK_PASSTHROUGH=1 DEVENV_TUI=false "${DEVENV_BIN:?DEVENV_BIN not set}" tasks run pnpm:install + DEVENV_TASK_PASSTHROUGH=1 DEVENV_TUI=false "${DEVENV_BIN:?DEVENV_BIN not set}" tasks run buck2:editor:publish DEVENV_TUI=false "${DEVENV_BIN:?DEVENV_BIN not set}" shell --no-reload -- bun test packages/@overeng/ci-tools/src/deploy-vercel.live.e2e.test.ts if: steps.live-vercel-preflight.outputs.run == 'true' - name: Nix diagnostics summary @@ -8139,8 +8140,6 @@ jobs: - test-playwright-utils - test-playwright-tui-react - test-megarepo-cold-gc - - nix-check - - nix-fod-check - pnpm-builder-contract - pnpm-regression - bundle-smoke diff --git a/.github/workflows/ci.yml.genie.ts b/.github/workflows/ci.yml.genie.ts index 17e151b01e..f881a7ed34 100644 --- a/.github/workflows/ci.yml.genie.ts +++ b/.github/workflows/ci.yml.genie.ts @@ -9,7 +9,6 @@ import { prepareCiScriptsStep, prepareEffectUtilsCompositionStep, notifyAlignmentJob, - evictCachedPnpmDepsStep, pnpmBuilderContractStep, preparePinnedDevenvStep, installNixStep, @@ -29,14 +28,12 @@ import { namespaceRunner, nixClosureMeasurementSteps, sourceShapeMeasurementStep, - validateColdPnpmDepsStep, nixDiagnosticsArtifactStep, workflowReportCommentBodyStep, workflowReportCollectorStep, workflowReportPublisherStep, deployPreviewWorkflowReportPathOutputName, netlifyDeployStep, - nixCacheSetupStep, validateNixStoreStep, withCiSourceRoot, defaultRefPolicyCheckJob, @@ -66,10 +63,6 @@ const baseSteps = [ prepareCiScriptsStep, preparePinnedDevenvStep, validateNixStoreStep, - evictCachedPnpmDepsStep({ - flakeRef: '.#oxlint-npm', - name: 'Evict cached pnpm deps for oxlint-npm', - }), /** * Temporary debug switch for #272 to validate failure-path diagnostics without waiting for a real flake. * Remove once #201/#272 are root-caused and diagnostics instrumentation is removed. @@ -152,7 +145,7 @@ const liveNetlifyCiToolsE2EStep = { [ 'netlify_pkg="$(nix build --no-link --print-out-paths .#netlify-cli)"', 'export CI_TOOLS_LIVE_NETLIFY_BIN="$netlify_pkg/bin/netlify"', - 'DEVENV_TASK_PASSTHROUGH=1 DEVENV_TUI=false "${DEVENV_BIN:?DEVENV_BIN not set}" tasks run pnpm:install', + 'DEVENV_TASK_PASSTHROUGH=1 DEVENV_TUI=false "${DEVENV_BIN:?DEVENV_BIN not set}" tasks run buck2:editor:publish', 'DEVENV_TUI=false "${DEVENV_BIN:?DEVENV_BIN not set}" shell --no-reload -- bun test packages/@overeng/ci-tools/src/deploy-netlify.live.e2e.test.ts', ].join('\n'), ), @@ -214,7 +207,7 @@ const liveVercelCiToolsE2EStep = { [ 'vercel_pkg="$(nix build --no-link --print-out-paths .#vercel-cli)"', 'export CI_TOOLS_LIVE_VERCEL_BIN="$vercel_pkg/bin/vercel"', - 'DEVENV_TASK_PASSTHROUGH=1 DEVENV_TUI=false "${DEVENV_BIN:?DEVENV_BIN not set}" tasks run pnpm:install', + 'DEVENV_TASK_PASSTHROUGH=1 DEVENV_TUI=false "${DEVENV_BIN:?DEVENV_BIN not set}" tasks run buck2:editor:publish', 'DEVENV_TUI=false "${DEVENV_BIN:?DEVENV_BIN not set}" shell --no-reload -- bun test packages/@overeng/ci-tools/src/deploy-vercel.live.e2e.test.ts', ].join('\n'), ), @@ -438,16 +431,12 @@ const nativeDepPolicyAuditStep = { // Core product jobs keyed by the shared Genie CI source of truth. const jobs: Record | ReturnType> = { - // Typecheck authority is split after the Buck cutover, so this lane gates on both halves: - // - `buck2:check` owns typecheck and dist for every package carrying Buck `authority`. - // - `ts:check:strict` owns only the residual root TypeScript solution (the projects with - // no Buck authority). It consumes Buck-owned declarations through the dist overlays that - // `buck2:typescript:materialize-dist` publishes, so it is ordered after the materializer. + // Buck is the single TypeScript check and declaration authority. typecheck: job({ step: { - name: 'Type check (Buck authority + residual root solution)', + name: 'Type check (Buck)', env: githubTokenEnv(), - run: runDevenvTasksBefore('buck2:check', 'ts:check:strict'), + run: runDevenvTasksBefore('buck2:check'), }, extraSteps: [verifyOtelShellEntryStep], }), @@ -520,9 +509,9 @@ const jobs: Record | ReturnType = { '"${DEVENV_BIN:?DEVENV_BIN not set}" shell -- bun test \\', ' genie/buck2/typescript-package-projection.unit.test.ts \\', ' genie/buck2/javascript-candidates.unit.test.ts \\', - ' packages/@overeng/buck2-tools/src/package-command-runner.unit.test.ts', + ' packages/@overeng/buck2-tools/src/package-command-runner.unit.test.ts \\', + ' packages/@overeng/buck2-tools/src/javascript-runner.unit.test.ts', ].join('\n'), ), }, @@ -729,7 +719,7 @@ const extraJobs: Record = { [ 'set -euo pipefail', "tracked_editor=$(git ls-files -- '**/.editor-view/**' '.editor-view/**')", - `tracked_product=$(git ls-files -- 'nix/buck2-products/**' | grep -Ev '^nix/buck2-products/(default\\.nix|manifest\\.json|publish\\.sh)$' || true)`, + `tracked_product=$(git ls-files -- 'nix/buck2-products/**' | grep -Ev '^nix/buck2-products/(default\\.nix|manifest\\.json|publish\\.sh|targets\\.json|targets\\.json\\.genie\\.ts)$' || true)`, 'if [ -n "$tracked_editor$tracked_product" ]; then', ' printf \'Tracked inert payload bytes are forbidden:\\n%s\\n%s\\n\' "$tracked_editor" "$tracked_product" >&2', ' exit 1', @@ -747,10 +737,10 @@ const extraJobs: Record = { ' cd "${EFFECT_UTILS_WORKSPACE_ROOT:?EFFECT_UTILS_WORKSPACE_ROOT not set}"', ' buck="$PWD/.megarepo/bin/buck2"', ' "$buck" query effect_utils//packages/@overeng/ci-tools:ci-tools-candidate', - ' "$buck" query effect_utils//packages/@overeng/tui-core:editor_view_inputs', + ' "$buck" query effect_utils//:editor_view_inputs', ' "$buck" build \\', ' effect_utils//packages/@overeng/ci-tools:ci-tools-candidate \\', - ' effect_utils//packages/@overeng/tui-core:editor_view_inputs', + ' effect_utils//:editor_view_inputs', "'", ].join('\n'), ), @@ -961,10 +951,10 @@ const extraJobs: Record = { setupSteps: baseSteps, taskProbes: [ { - task: 'pnpm:install', - label: 'pnpm install task', + task: 'buck2:editor:publish', + label: 'Editor dependency publication', group: 'workspace setup', - description: 'Runs the cached pnpm install devenv task.', + description: 'Publishes the complete Buck-owned editor dependency surface.', warmupRepetitions: 1, repetitions: 5, }, diff --git a/.oxlintrc.json b/.oxlintrc.json index 3b0ef665c8..90a03a8bf4 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -346,6 +346,12 @@ "oxc/no-barrel-file": "off" } }, + { + "files": ["**/react-inspector/src/schema/mod.tsx"], + "rules": { + "oxc/no-barrel-file": "off" + } + }, { "files": ["**/restate-effect/src/testing/**"], "rules": { diff --git a/.oxlintrc.json.genie.ts b/.oxlintrc.json.genie.ts index 27765d0d8b..3d45c80bd5 100644 --- a/.oxlintrc.json.genie.ts +++ b/.oxlintrc.json.genie.ts @@ -113,6 +113,12 @@ export default oxlintConfig({ files: ['**/utils/src/node/otel.ts', '**/utils/src/node/otel-attrs.ts'], rules: { 'oxc/no-barrel-file': 'off' }, }, + // This file is the package's intentional public schema subpath. Keep the + // public contract explicit instead of de-barreling the consumer-facing API. + { + files: ['**/react-inspector/src/schema/mod.tsx'], + rules: { 'oxc/no-barrel-file': 'off' }, + }, // restate-effect's `./testing` harness has a benign barrel-induced cycle: // `testing.ts` aggregates and re-exports `RestateTestEnv`, which imports the // harness back from `testing.ts`. Test-infra aggregation, not a runtime diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 92e5300c50..eed95e2efc 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -2,81 +2,23 @@ "version": "2.0.0", "tasks": [ // ============================================================ - // install + // dependency views // ============================================================ { - "label": "install", + "label": "publish dependencies", "type": "shell", - "command": "devenv tasks run pnpm:install", + "command": "devenv tasks run buck2:editor:publish", "problemMatcher": [], "presentation": { "focus": true, "panel": "shared", - "group": "install", + "group": "dependency views", "showReuseMessage": false, "clear": false, "close": true } }, - // ============================================================ - // ts - // ============================================================ - { - "label": "ts", - "type": "shell", - "command": "devenv tasks run ts:check", - "problemMatcher": ["$tsc"], - "presentation": { - "focus": false, - "panel": "shared", - "group": "ts", - "showReuseMessage": false, - "clear": false - } - }, - { - "label": "ts:build-watch", - "type": "shell", - "command": "devenv tasks run ts:build-watch", - "problemMatcher": ["$tsc-watch"], - "isBackground": true, - "presentation": { - "focus": false, - "panel": "shared", - "group": "ts", - "showReuseMessage": false, - "clear": false - } - }, - { - "label": "ts:clean", - "type": "shell", - "command": "devenv tasks run ts:clean", - "problemMatcher": ["$tsc"], - "presentation": { - "focus": false, - "panel": "shared", - "group": "ts", - "showReuseMessage": false, - "clear": false - } - }, - { - "label": "ts:clean:build-watch", - "type": "shell", - "command": "devenv tasks run ts:clean && devenv tasks run ts:build-watch", - "problemMatcher": ["$tsc-watch"], - "isBackground": true, - "presentation": { - "focus": false, - "panel": "shared", - "group": "ts", - "showReuseMessage": false, - "clear": false - } - }, - // ============================================================ // lint // ============================================================ @@ -108,7 +50,7 @@ }, // ============================================================ - // buck2 — Buck owns typecheck + dist for the authoritative packages + // buck2 — complete TypeScript check and declaration authority // ============================================================ { "label": "buck2:check", @@ -171,19 +113,6 @@ // ============================================================ // misc // ============================================================ - { - "label": "build", - "type": "shell", - "command": "devenv tasks run ts:build", - "problemMatcher": ["$tsc"], - "presentation": { - "focus": true, - "panel": "shared", - "group": "misc", - "showReuseMessage": false, - "clear": false - } - }, { "label": "clean", "type": "shell", diff --git a/AGENTS.md b/AGENTS.md index 8a578e2813..275d608b87 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,19 +6,19 @@ Use `devenv tasks run ` (devenv tasks) to execute tasks with dependencies: -- **TypeScript**: `devenv tasks run ts:check` or `devenv tasks run ts:build-watch` (watch mode) or `devenv tasks run ts:clean` +- **TypeScript**: `devenv tasks run buck2:check` +- **Declaration publication**: `devenv tasks run buck2:typescript:materialize-dist` - **Linting**: `devenv tasks run lint:check` or `devenv tasks run lint:fix` - **Testing**: `devenv tasks run test:run` (all) or `devenv tasks run test:` (single package) or `devenv tasks run test:watch` -- **Build**: `devenv tasks run ts:build` -- **Install**: `devenv tasks run pnpm:install` +- **Dependencies**: `devenv tasks run buck2:editor:publish` - **Genie**: `devenv tasks run genie:run` or `devenv tasks run genie:watch` or `devenv tasks run genie:check` -- **Check all**: `devenv tasks run check:quick` (ts + lint) or `devenv tasks run check:all` (ts + lint + test) +- **Check all**: `devenv tasks run check:quick` or `devenv tasks run check:all` Use the `--no-tui` flag to see all output. If tools aren't directly in `$PATH`, enter the dev environment first with `devenv shell`. We're using megarepo for repo management. We're using `pnpm` temporarily for installs (bun is still used to run scripts) and `devenv` to manage the development environment. -The TypeScript tasks (`ts:check`, `ts:check:strict`, `ts:build`, `ts:emit`, `ts:build-watch`) consume Buck-owned package declarations from published `dist` directories, so they run after `buck2:typescript:materialize-dist`. That publisher needs a composed megarepo workspace: in a detached/flat clone it can only verify declarations a composed workspace already published, and it refuses with the exact package and path it could not find rather than type-checking against an absent `dist`. Work on this repo through its megarepo composition. +Buck owns checking for all 39 TypeScript projects and declaration production for every emitting project. `buck2:typescript:materialize-dist` publishes those declarations atomically for source-side consumers such as type-aware lint. Publication requires the repository's reciprocal composed megarepo worktree and fails in a detached or lookalike checkout; work on this repo through its megarepo composition. # Genie (Config File Generation) diff --git a/BUCK b/BUCK index 5597234714..af4f4260c2 100644 --- a/BUCK +++ b/BUCK @@ -1,4 +1,16 @@ +# Generated file - DO NOT EDIT +# Source: BUCK.genie.ts + +# Projection source: BUCK.genie.ts +# Projection schema version: 1 +# Projection generator: effect-utils/genie/buck2-root-aggregate-projection +# Semantic fingerprint: sha256:8862262d9f5166e14c5b9ebd8a066e40baade59d8c5659d2f64b250418b77bff +# Semantic inputs: BUCK.genie.ts, genie/buck2/mod.ts, genie/buck2/root-aggregate-projection.ts, genie/buck2/typescript-admissions.ts, context/effect/socket/BUCK.genie.ts, context/opentui/BUCK.genie.ts, packages/@overeng/agent-session-ingest/BUCK.genie.ts, packages/@overeng/buck2-tools/BUCK.genie.ts, packages/@overeng/ci-tools/BUCK.genie.ts, packages/@overeng/content-address/BUCK.genie.ts, packages/@overeng/effect-ai-claude-cli/BUCK.genie.ts, packages/@overeng/effect-distributed-lock/BUCK.genie.ts, packages/@overeng/effect-path/BUCK.genie.ts, packages/@overeng/effect-react/BUCK.genie.ts, packages/@overeng/effect-rpc-tanstack/BUCK.genie.ts, packages/@overeng/effect-rpc-tanstack/examples/basic/BUCK.genie.ts, packages/@overeng/effect-schema-form-aria/BUCK.genie.ts, packages/@overeng/effect-schema-form/BUCK.genie.ts, packages/@overeng/genie/BUCK.genie.ts, packages/@overeng/gh-ci-utils/BUCK.genie.ts, packages/@overeng/kdl-effect/BUCK.genie.ts, packages/@overeng/kdl/BUCK.genie.ts, packages/@overeng/megarepo/BUCK.genie.ts, packages/@overeng/notion-cli/BUCK.genie.ts, packages/@overeng/notion-core/BUCK.genie.ts, packages/@overeng/notion-datasource-sync/BUCK.genie.ts, packages/@overeng/notion-effect-client/BUCK.genie.ts, packages/@overeng/notion-effect-schema/BUCK.genie.ts, packages/@overeng/notion-md/BUCK.genie.ts, packages/@overeng/notion-property-write/BUCK.genie.ts, packages/@overeng/notion-react/BUCK.genie.ts, packages/@overeng/npm-release/BUCK.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/oxc-config/BUCK.genie.ts, packages/@overeng/pty-effect/BUCK.genie.ts, packages/@overeng/react-inspector/BUCK.genie.ts, packages/@overeng/restate-effect/BUCK.genie.ts, packages/@overeng/stylex-tokens/BUCK.genie.ts, packages/@overeng/tui-core/BUCK.genie.ts, packages/@overeng/tui-react/BUCK.genie.ts, packages/@overeng/tui-stories/BUCK.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils/BUCK.genie.ts +# Regenerate: devenv tasks run genie:run + +load("//buck2:editor_view.bzl", "editor_view_inputs") load("@prelude//toolchains:genrule.bzl", "system_genrule_toolchain") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") # Conventional prelude toolchain targets, owned by the platform hub. # @@ -41,61 +53,64 @@ system_genrule_toolchain( visibility = ["PUBLIC"], ) -# The package-tree runner and its complete relative-import closure, staged side -# by side in one directory so the runner's sibling imports resolve inside the -# action. A Buck action sees only declared inputs: a module missing here fails -# closed at run time instead of silently reaching into the source tree. -# Declared in genie/buck2/runtime-modules.ts and gated by -# genie/buck2/buck2-runtime-closure.unit.test.ts. -filegroup( - name = "package_tree_runtime", - srcs = { - "package-tree.ts": "packages/@overeng/buck2-tools/src/package-tree.ts", - "real-path.ts": "packages/@overeng/buck2-tools/src/real-path.ts", - }, +export_file( + name = "package.json", + src = "package.json", visibility = ["PUBLIC"], ) -# Package command actions execute this runner beside its only relative import. -# The rules address the entry inside this declared tree rather than reaching -# back into the source checkout. -filegroup( - name = "package_command_runtime", - srcs = { - "package-command-runner.ts": "packages/@overeng/buck2-tools/src/package-command-runner.ts", - "typescript-runner.ts": "packages/@overeng/buck2-tools/src/typescript-runner.ts", - "real-path.ts": "packages/@overeng/buck2-tools/src/real-path.ts", - }, +alias( + name = "node_modules", + actual = "//packages/@overeng/genie:node_modules", visibility = ["PUBLIC"], ) -# JavaScript command and test actions execute this runner beside its declared -# import closure. `//buck2:javascript.bzl` addresses the entry inside this tree, -# so the runner never reaches back into the source checkout for its own modules. -filegroup( - name = "javascript_action_runtime", - srcs = { - "javascript-runner.ts": "packages/@overeng/buck2-tools/src/javascript-runner.ts", - "typescript-runner.ts": "packages/@overeng/buck2-tools/src/typescript-runner.ts", - }, +alias( + name = "editor_inputs", + actual = ":node_modules", visibility = ["PUBLIC"], ) -# Hermetic TypeScript actions execute this source with their pinned Bun runtime. -# Single-file staging: this runner must import nothing relative. -export_file( - name = "packages/@overeng/buck2-tools/src/typescript-runner.ts", - src = "packages/@overeng/buck2-tools/src/typescript-runner.ts", +alias( + name = "root_editor_package_tree", + actual = "//packages/@overeng/genie:package_tree", visibility = ["PUBLIC"], ) -# Stateless completeness gate: Git supplies candidates and Buck remains the sole owner matcher. -# Single-file staging: this runner must import nothing relative. -export_file( - name = "packages/@overeng/buck2-tools/src/owned-files.ts", - src = "packages/@overeng/buck2-tools/src/owned-files.ts", +editor_view_inputs( + name = "editor_view_inputs", + editor_inputs = ":editor_inputs", + package_tree = ":root_editor_package_tree", visibility = ["PUBLIC"], ) +static_source_set( + name = "static_sources", + prefix = "", + srcs = glob( + [ + root + "/" + pattern + for root in ["context", "packages", "scripts"] + for pattern in STATIC_SOURCE_GLOBS + ], + exclude = [ + root + "/" + pattern + for root in ["context", "packages", "scripts"] + for pattern in STATIC_SOURCE_EXCLUDES + ], + ) + [ + ".oxfmtrc.json", + ".oxlintrc.json", + "devenv.lock", + "devenv.yaml", + "flake.lock", + "flake.nix", + "megarepo.kdl", + "megarepo.lock", + "tsconfig.lint.json", + ], + visibility = ["PUBLIC"], +) + # Workspace patches are declared inputs to the generated pnpm extraction actions. export_file( @@ -103,3 +118,132 @@ export_file( src = "patches/@myobie__pty@0.10.0.patch", visibility = ["PUBLIC"], ) + +# Scoped repository checks derived from the TypeScript admission registry. +filegroup( + name = "quick", + srcs = { + "000": "//context/effect/socket:typecheck", + "001": "//context/opentui:typecheck", + "002": "//packages/@overeng/agent-session-ingest:typecheck", + "003": "//packages/@overeng/buck2-tools:typecheck", + "004": "//packages/@overeng/ci-tools:typecheck", + "005": "//packages/@overeng/content-address:typecheck", + "006": "//packages/@overeng/effect-ai-claude-cli:typecheck", + "007": "//packages/@overeng/effect-distributed-lock:typecheck", + "008": "//packages/@overeng/effect-path:typecheck", + "009": "//packages/@overeng/effect-react:typecheck", + "010": "//packages/@overeng/effect-rpc-tanstack:typecheck", + "011": "//packages/@overeng/effect-rpc-tanstack/examples/basic:typecheck", + "012": "//packages/@overeng/effect-schema-form:typecheck", + "013": "//packages/@overeng/effect-schema-form-aria:typecheck", + "014": "//packages/@overeng/genie:typecheck", + "015": "//packages/@overeng/gh-ci-utils:typecheck", + "016": "//packages/@overeng/kdl:typecheck", + "017": "//packages/@overeng/kdl-effect:typecheck", + "018": "//packages/@overeng/megarepo:typecheck", + "019": "//packages/@overeng/notion-cli:typecheck", + "020": "//packages/@overeng/notion-core:typecheck", + "021": "//packages/@overeng/notion-datasource-sync:typecheck", + "022": "//packages/@overeng/notion-effect-client:typecheck", + "023": "//packages/@overeng/notion-effect-schema:typecheck", + "024": "//packages/@overeng/notion-md:typecheck", + "025": "//packages/@overeng/notion-property-write:typecheck", + "026": "//packages/@overeng/notion-react:typecheck", + "027": "//packages/@overeng/npm-release:typecheck", + "028": "//packages/@overeng/otel-contract:typecheck", + "029": "//packages/@overeng/oxc-config:typecheck", + "030": "//packages/@overeng/pty-effect:typecheck", + "031": "//packages/@overeng/react-inspector:typecheck", + "032": "//packages/@overeng/react-inspector:strict_consumer_typecheck", + "033": "//packages/@overeng/restate-effect:typecheck", + "034": "//packages/@overeng/stylex-tokens:typecheck", + "035": "//packages/@overeng/tui-core:typecheck", + "036": "//packages/@overeng/tui-react:typecheck", + "037": "//packages/@overeng/tui-stories:typecheck", + "038": "//packages/@overeng/utils:typecheck", + "039": "//packages/@overeng/utils-dev:typecheck", + }, + visibility = ["PUBLIC"], +) + +filegroup( + name = "all", + srcs = { + "000": ":quick", + "001": "//packages/@overeng/agent-session-ingest:dist", + "002": "//packages/@overeng/buck2-tools:dist", + "003": "//packages/@overeng/ci-tools:dist", + "004": "//packages/@overeng/content-address:dist", + "005": "//packages/@overeng/effect-ai-claude-cli:dist", + "006": "//packages/@overeng/effect-distributed-lock:dist", + "007": "//packages/@overeng/effect-path:dist", + "008": "//packages/@overeng/effect-react:dist", + "009": "//packages/@overeng/effect-rpc-tanstack:dist", + "010": "//packages/@overeng/effect-schema-form:dist", + "011": "//packages/@overeng/effect-schema-form-aria:dist", + "012": "//packages/@overeng/genie:dist", + "013": "//packages/@overeng/gh-ci-utils:dist", + "014": "//packages/@overeng/kdl:dist", + "015": "//packages/@overeng/kdl-effect:dist", + "016": "//packages/@overeng/megarepo:dist", + "017": "//packages/@overeng/notion-cli:dist", + "018": "//packages/@overeng/notion-core:dist", + "019": "//packages/@overeng/notion-datasource-sync:dist", + "020": "//packages/@overeng/notion-effect-client:dist", + "021": "//packages/@overeng/notion-effect-schema:dist", + "022": "//packages/@overeng/notion-md:dist", + "023": "//packages/@overeng/notion-property-write:dist", + "024": "//packages/@overeng/notion-react:dist", + "025": "//packages/@overeng/npm-release:dist", + "026": "//packages/@overeng/otel-contract:dist", + "027": "//packages/@overeng/oxc-config:dist", + "028": "//packages/@overeng/pty-effect:dist", + "029": "//packages/@overeng/react-inspector:dist", + "030": "//packages/@overeng/restate-effect:dist", + "031": "//packages/@overeng/stylex-tokens:dist", + "032": "//packages/@overeng/tui-core:dist", + "033": "//packages/@overeng/tui-react:dist", + "034": "//packages/@overeng/tui-stories:dist", + "035": "//packages/@overeng/utils:dist", + "036": "//packages/@overeng/utils-dev:dist", + "037": "effect_utils//packages/@overeng/agent-session-ingest:test", + "038": "effect_utils//packages/@overeng/ci-tools:test", + "039": "effect_utils//packages/@overeng/content-address:test", + "040": "effect_utils//packages/@overeng/effect-ai-claude-cli:test", + "041": "effect_utils//packages/@overeng/effect-distributed-lock:test", + "042": "effect_utils//packages/@overeng/effect-path:test", + "043": "effect_utils//packages/@overeng/effect-react:test", + "044": "effect_utils//packages/@overeng/effect-rpc-tanstack:test", + "045": "effect_utils//packages/@overeng/effect-schema-form-aria:test", + "046": "effect_utils//packages/@overeng/effect-schema-form:test", + "047": "effect_utils//packages/@overeng/genie:test", + "048": "effect_utils//packages/@overeng/gh-ci-utils:test", + "049": "effect_utils//packages/@overeng/kdl-effect:test", + "050": "effect_utils//packages/@overeng/kdl:test", + "051": "effect_utils//packages/@overeng/megarepo:test", + "052": "effect_utils//packages/@overeng/notion-cli:test", + "053": "effect_utils//packages/@overeng/notion-core:test", + "054": "effect_utils//packages/@overeng/notion-datasource-sync:test", + "055": "effect_utils//packages/@overeng/notion-effect-client:test", + "056": "effect_utils//packages/@overeng/notion-effect-schema:test", + "057": "effect_utils//packages/@overeng/notion-md:test", + "058": "effect_utils//packages/@overeng/notion-property-write:test", + "059": "effect_utils//packages/@overeng/notion-react:test", + "060": "effect_utils//packages/@overeng/npm-release:test", + "061": "effect_utils//packages/@overeng/otel-contract:test", + "062": "effect_utils//packages/@overeng/oxc-config:test", + "063": "effect_utils//packages/@overeng/pty-effect:bundle_smoke", + "064": "effect_utils//packages/@overeng/pty-effect:test", + "065": "effect_utils//packages/@overeng/react-inspector:test", + "066": "effect_utils//packages/@overeng/restate-effect:test", + "067": "effect_utils//packages/@overeng/tui-core:test", + "068": "effect_utils//packages/@overeng/tui-react:test", + "069": "effect_utils//packages/@overeng/tui-stories:test", + "070": "effect_utils//packages/@overeng/utils-dev:test", + "071": "effect_utils//packages/@overeng/utils:test", + "072": "//buck2/toolchains:archive_tool", + "073": "//buck2/toolchains:product_tool", + }, + visibility = ["PUBLIC"], +) diff --git a/BUCK.genie.ts b/BUCK.genie.ts new file mode 100644 index 0000000000..5e9fad6f39 --- /dev/null +++ b/BUCK.genie.ts @@ -0,0 +1,3 @@ +import { rootBuckAggregateProjection } from './genie/buck2/root-aggregate-projection.ts' + +export default rootBuckAggregateProjection() diff --git a/CHANGELOG.md b/CHANGELOG.md index df465b100c..85b8d45862 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ All notable changes to this project will be documented in this file. dependencies mid-session and full-page-reload a running story or browser test; Vite consumers can drop their app-local `@stylexjs/stylex` `optimizeDeps.include` entries. +- **Buck2 checks**: Add standalone project roots, Nix-owned capability + projections shared with composed roots, registry-derived `//:quick` and + `//:all` aggregates, check-verb wiring, and a guard against untracked + Buck-versus-legacy producer overlap. - **Devenv tasks**: Add a reusable 50,000-file recursive eval-cache input budget that names the offending cached attribute and gates quick and full @@ -247,6 +251,21 @@ character after JSON`, failing every build against such a lockfile. top-level Buck member manifest fields while retaining strict validation of known fields; generate composed roots during `store worktree new`; and preserve failed `mr` exit codes in shared devenv tasks. +- **@overeng/genie**: YAML block scalars no longer indent empty lines, keeping + generated workflows free of trailing whitespace. + +- **@overeng/megarepo**: unchanged composed members now preserve validated + published overlays instead of advancing the member mount and rebuilding every + declared overlay. Aggregate no-op apply skips Buck when all overlay identities + are already current. + +- **@overeng/megarepo**: composition capability realizations stay GC-rooted + until their resolution handles are released, preventing automatic Nix GC from + deleting projected executables during long aggregate overlay publication. + +- **nix/oxlint-with-plugins.nix**: include `tsgolint` in the wrapper's runtime + closure so type-aware linting remains hermetic inside Buck actions rather than + depending on the developer shell's `PATH`. - **CI**: keep draft assistant PRs mergeable by completing the auto-review job successfully when no review request is needed. - **CI**: stop requiring `main`-only Notion integration, live-deploy, and @@ -364,6 +383,34 @@ character after JSON`, failing every build against such a lockfile. reports 12.4.1, the store layout stays `v11`, and `pnpm install --frozen-lockfile --ignore-scripts` over all 39 workspace projects succeeds with the lockfile unchanged. +- **Buck2 / TypeScript authority**: transfer all 39 TypeScript projects to + package-local Buck targets, including the independent React Inspector strict + consumer and the five bootstrap-critical packages. Delete the root + `tsconfig.check.json` / `tsconfig.emit.json` producers and `ts:*` task graph; + CI and aggregate checks now use `buck2:check` as the only check authority. + Declaration publication accepts only Buck products from a reciprocal + composition worktree, with no source-compiler comparison fallback. The + staged Buck action runners move into their owning `@overeng/buck2-tools` + package so admitting that package does not leave its sources root-owned. + +- **Buck2 / editor authority**: replace the repository pnpm install with 39 + atomically published Buck dependency views: one root source-generator closure + plus every workspace package. A committed-graph bootstrap makes + `genie:check` runnable without trusting stale generated graph evidence; fresh + generation and composition then replay whole-workspace ownership, publication, + and staleness checks. Source tests resolve the Nix-built `node-pty` through a + process-wide Node resolver hook instead of mutating published `node_modules`. + Root install, native graft, package-specific editor tasks, install dashboards, + and install-dependent CI and developer entrypoints are removed. + +- **Buck2 / Rust product authority**: compile the complete five-member Rust + workspace through Buck, fetch Cargo-locked third-party crates as hash-pinned + Buck archives, and publish `otelite` plus `otel-scrape` as strict, + content-addressed native products for x86_64 Linux, aarch64 Linux, and + aarch64 Darwin. Nix now independently verifies and imports those immutable + assets; flake packages, apps, devenv, and observability consume the imports. + The superseded `rustPlatform.buildRustPackage` product derivations, their + narrow-source helper, and the direct Cargo release build are removed. - **pnpm**: move the ecosystem pin from pnpm 11.8.0 to 12.3.4 and retire the separate lock mutator. pnpm 12 ships the CLI as a native Rust executable, so diff --git a/README.md b/README.md index a5cda0245b..cfa4a07f41 100644 --- a/README.md +++ b/README.md @@ -112,20 +112,6 @@ Key features: - **Read-only protection** - Generated files are read-only by default - **CI integration** - `--check` mode verifies files are up to date -### Rebuild and reload binaries - -```bash -devenv tasks run nix:build:genie -devenv tasks run nix:build -devenv tasks run nix:check -``` - -After `pnpm-lock.yaml` changes: - -```bash -refresh Nix FOD hashes for genie -refresh all stale Nix FOD hashes with your repo workflow -``` ## Quick Start @@ -137,22 +123,23 @@ This repo uses `devenv` to provide a consistent toolchain. Run commands inside t devenv shell ``` -### Install Dependencies +### Publish Dependency Views ```bash -devenv tasks run bun:install +devenv tasks run buck2:editor:publish ``` -### Build All Packages +### Check All TypeScript Projects ```bash -devenv tasks run ts:build +devenv tasks run buck2:check ``` -Fast emit-only build (skips full type checking): +Publish Buck-produced declarations to package `dist` directories for source-side +consumers such as type-aware lint: ```bash -devenv tasks run ts:emit +devenv tasks run buck2:typescript:materialize-dist ``` ### Run Tests @@ -174,16 +161,10 @@ devenv tasks run test:watch ### Type Checking -Continuous type checking across the entire monorepo (project references): - -```bash -devenv tasks run ts:build-watch -``` - -Or one-off type check: +Buck is the only repository-wide TypeScript check authority: ```bash -devenv tasks run ts:check +devenv tasks run buck2:check ``` ### Linting diff --git a/buck2-member.json b/buck2-member.json index a329ca3223..b1e0acb5fe 100644 --- a/buck2-member.json +++ b/buck2-member.json @@ -26,6 +26,10 @@ "target": "//packages/@overeng/agent-session-ingest:dist", "destination": "packages/@overeng/agent-session-ingest/dist" }, + { + "target": "//packages/@overeng/buck2-tools:dist", + "destination": "packages/@overeng/buck2-tools/dist" + }, { "target": "//packages/@overeng/ci-tools:dist", "destination": "packages/@overeng/ci-tools/dist" @@ -54,14 +58,34 @@ "target": "//packages/@overeng/effect-rpc-tanstack:dist", "destination": "packages/@overeng/effect-rpc-tanstack/dist" }, + { + "target": "//packages/@overeng/effect-schema-form-aria:dist", + "destination": "packages/@overeng/effect-schema-form-aria/dist" + }, { "target": "//packages/@overeng/effect-schema-form:dist", "destination": "packages/@overeng/effect-schema-form/dist" }, + { + "target": "//packages/@overeng/genie:dist", + "destination": "packages/@overeng/genie/dist" + }, + { + "target": "//packages/@overeng/gh-ci-utils:dist", + "destination": "packages/@overeng/gh-ci-utils/dist" + }, + { + "target": "//packages/@overeng/kdl-effect:dist", + "destination": "packages/@overeng/kdl-effect/dist" + }, { "target": "//packages/@overeng/kdl:dist", "destination": "packages/@overeng/kdl/dist" }, + { + "target": "//packages/@overeng/megarepo:dist", + "destination": "packages/@overeng/megarepo/dist" + }, { "target": "//packages/@overeng/notion-cli:dist", "destination": "packages/@overeng/notion-cli/dist" @@ -130,6 +154,10 @@ "target": "//packages/@overeng/tui-react:dist", "destination": "packages/@overeng/tui-react/dist" }, + { + "target": "//packages/@overeng/tui-stories:dist", + "destination": "packages/@overeng/tui-stories/dist" + }, { "target": "//packages/@overeng/utils-dev:dist", "destination": "packages/@overeng/utils-dev/dist" @@ -164,6 +192,18 @@ "flakePackage": "buck2-node", "executable": "bin/node" }, + { + "toolId": "oxfmt", + "protocol": "oxc/oxfmt/v1", + "flakePackage": "oxfmt", + "executable": "bin/oxfmt" + }, + { + "toolId": "oxlint", + "protocol": "oxc/oxlint/v1", + "flakePackage": "oxlint-with-plugins", + "executable": "bin/oxlint" + }, { "toolId": "product", "protocol": "effect-utils/buck2-product/v1", diff --git a/buck2-member.json.genie.ts b/buck2-member.json.genie.ts index 68ee57d995..d4708344c0 100644 --- a/buck2-member.json.genie.ts +++ b/buck2-member.json.genie.ts @@ -1,5 +1,5 @@ -import { projectionArtifact } from './packages/@overeng/genie/src/runtime/mod.ts' import { buck2TypeScriptDistOverlays } from './genie/buck2/typescript-admissions.ts' +import { projectionArtifact } from './packages/@overeng/genie/src/runtime/mod.ts' import { COMPOSITION_ROOT_SCHEMA_VERSION, decodeBuckMemberManifest, @@ -87,6 +87,18 @@ const manifestProjection = { }, ], }, + { + toolId: 'oxfmt', + protocol: 'oxc/oxfmt/v1', + flakePackage: 'oxfmt', + executable: 'bin/oxfmt', + }, + { + toolId: 'oxlint', + protocol: 'oxc/oxlint/v1', + flakePackage: 'oxlint-with-plugins', + executable: 'bin/oxlint', + }, { toolId: 'archive-tool', protocol: 'effect-utils/buck2-archive-tool/v2', diff --git a/buck2-operation-dispositions.json b/buck2-operation-dispositions.json new file mode 100644 index 0000000000..861639d90a --- /dev/null +++ b/buck2-operation-dispositions.json @@ -0,0 +1,159 @@ +{ + "ciOperations": [ + { + "disposition": "outside-by-policy:pre-composition-trust-gate", + "operation": "default-ref-policy" + }, + { + "disposition": "buck-owned", + "operation": "typecheck" + }, + { + "disposition": "outside-by-policy:includes-stage-zero-freshness", + "operation": "lint" + }, + { + "disposition": "outside-by-policy:aggregate-includes-policy-excluded-tests", + "operation": "test" + }, + { + "disposition": "outside-by-policy:browser-integration", + "operation": "test-playwright-utils" + }, + { + "disposition": "outside-by-policy:browser-integration", + "operation": "test-playwright-tui-react" + }, + { + "disposition": "outside-by-policy:filesystem-integration", + "operation": "test-megarepo-cold-gc" + }, + { + "disposition": "outside-by-policy:nix-builder-contract", + "operation": "pnpm-builder-contract" + }, + { + "disposition": "outside-by-policy:nix-builder-contract", + "operation": "pnpm-regression" + }, + { + "disposition": "buck-owned", + "operation": "bundle-smoke" + }, + { + "disposition": "outside-by-policy:aggregate-includes-rust-quality-gates", + "operation": "cargo" + }, + { + "disposition": "outside-by-policy:aggregate-includes-change-relative-and-live-integration", + "operation": "weaver" + }, + { + "disposition": "outside-by-policy:bootstrap-integration", + "operation": "bootstrap-cold-proof" + }, + { + "disposition": "outside-by-policy:nix-realization", + "operation": "nix-closure-sizes" + }, + { + "disposition": "outside-by-policy:ci-measurement-with-run-timestamp", + "operation": "source-shape" + }, + { + "disposition": "outside-by-policy:service-integration", + "operation": "test-integration-restate" + }, + { + "disposition": "outside-by-policy:operator-benchmark", + "operation": "devenv-perf" + }, + { + "disposition": "outside-by-policy:secret-service-integration", + "operation": "test-integration-notion" + }, + { + "disposition": "outside-by-policy:live-deployment", + "operation": "test-live-deploy-ci-tools" + }, + { + "disposition": "outside-by-policy:live-deployment", + "operation": "deploy-storybooks" + }, + { + "disposition": "outside-by-policy:ci-control-plane", + "operation": "ci-measurements-report" + }, + { + "disposition": "outside-by-policy:ci-control-plane", + "operation": "notify-alignment" + } + ], + "developerOperations": [ + { + "disposition": "buck-owned", + "operation": "buck2:check" + }, + { + "disposition": "outside-by-policy:workspace-publication", + "operation": "buck2:editor:publish" + }, + { + "disposition": "outside-by-policy:workspace-publication", + "operation": "buck2:typescript:materialize-dist" + }, + { + "disposition": "outside-by-policy:cross-boundary-aggregate", + "operation": "check:all" + }, + { + "disposition": "outside-by-policy:cross-boundary-aggregate", + "operation": "check:quick" + }, + { + "disposition": "outside-by-policy:stage-zero-bootstrap-freshness", + "operation": "genie:check" + }, + { + "disposition": "outside-by-policy:authoring-mutation", + "operation": "genie:run" + }, + { + "disposition": "outside-by-policy:long-lived-watcher", + "operation": "genie:watch" + }, + { + "disposition": "outside-by-policy:includes-stage-zero-freshness", + "operation": "lint:check" + }, + { + "disposition": "outside-by-policy:authoring-mutation", + "operation": "lint:fix" + }, + { + "disposition": "outside-by-policy:aggregate-includes-policy-excluded-tests", + "operation": "test:" + }, + { + "disposition": "outside-by-policy:aggregate-includes-policy-excluded-tests", + "operation": "test:genie" + }, + { + "disposition": "outside-by-policy:secret-service-integration", + "operation": "test:integration" + }, + { + "disposition": "outside-by-policy:aggregate-includes-policy-excluded-tests", + "operation": "test:run" + }, + { + "disposition": "outside-by-policy:aggregate-includes-policy-excluded-tests", + "operation": "test:utils" + }, + { + "disposition": "outside-by-policy:long-lived-watcher", + "operation": "test:watch" + } + ], + "schemaVersion": 1 +} diff --git a/buck2-operation-dispositions.json.genie.ts b/buck2-operation-dispositions.json.genie.ts new file mode 100644 index 0000000000..e1e6553c23 --- /dev/null +++ b/buck2-operation-dispositions.json.genie.ts @@ -0,0 +1,29 @@ +import { operationDispositionProjection } from './genie/buck2/operation-dispositions.ts' +import { + projectionArtifact, + projectionValidators, +} from './packages/@overeng/genie/src/runtime/mod.ts' + +/** + * Inspectable authority ledger for every public developer command root and generated CI job. + * + * Rows are deliberately dispositions, not task wiring: Buck-owned work is distinguished from + * scheduled transfer and explicit policy exclusions without pretending cross-boundary orchestration + * is a hermetic build action. Coverage tests fail when either public surface grows without a row. + */ +export default projectionArtifact.json({ + schemaVersion: 1, + data: operationDispositionProjection, + validators: [ + projectionValidators.uniqueValues({ + rule: 'buck2-operation-disposition-unique-developer-operation', + label: 'buck2-operation-dispositions.json', + values: ({ data }) => data.developerOperations.map(({ operation }) => operation), + }), + projectionValidators.uniqueValues({ + rule: 'buck2-operation-disposition-unique-ci-operation', + label: 'buck2-operation-dispositions.json', + values: ({ data }) => data.ciOperations.map(({ operation }) => operation), + }), + ], +}) diff --git a/buck2-test-authority.json b/buck2-test-authority.json index 5288cebc6f..158241522f 100644 --- a/buck2-test-authority.json +++ b/buck2-test-authority.json @@ -178,6 +178,20 @@ "unboundedAfter": [], "unboundedFiles": [] }, + { + "collectionTarget": "effect_utils//packages/@overeng/effect-schema-form-aria:test_collect", + "excludes": [], + "packageName": "effect-schema-form-aria", + "packagePath": "packages/@overeng/effect-schema-form-aria", + "runner": "vitest", + "selectedTestFiles": ["src/mod.unit.test.tsx"], + "sourceOwners": {}, + "target": "effect_utils//packages/@overeng/effect-schema-form-aria:test", + "taskName": "test:effect-schema-form-aria", + "testFiles": ["src/mod.unit.test.tsx"], + "unboundedAfter": [], + "unboundedFiles": [] + }, { "collectionTarget": "effect_utils//packages/@overeng/effect-schema-form:test_collect", "excludes": [], @@ -289,6 +303,70 @@ ], "unboundedTaskName": "test:genie:unbounded" }, + { + "collectionTarget": "effect_utils//packages/@overeng/gh-ci-utils:test_collect", + "excludes": [], + "packageName": "gh-ci-utils", + "packagePath": "packages/@overeng/gh-ci-utils", + "runner": "vitest", + "selectedTestFiles": [ + "test/GitHubClient.test.ts", + "test/GitHubClientLogs.test.ts", + "test/GitHubInternal.test.ts", + "test/GitHubSchemas.test.ts", + "test/GitHubSession.test.ts", + "test/RunId.test.ts", + "test/RunnerClient.test.ts", + "test/azureBlobError.test.ts", + "test/cliTokenFallback.test.ts", + "test/exitCode.test.ts", + "test/format.test.ts", + "test/inspectAssessment.test.ts", + "test/inspectJsonContract.test.ts", + "test/jsonContract.test.ts", + "test/jsonOutput.test.ts", + "test/logFilter.test.ts", + "test/namespaceAdapter.test.ts", + "test/ndjsonHeartbeat.test.ts", + "test/rateLimit.test.ts", + "test/rerun.test.ts", + "test/runSelection.test.ts", + "test/runnerIdentity.test.ts", + "test/toolFailure.test.ts", + "test/watchPlan.test.ts" + ], + "sourceOwners": {}, + "target": "effect_utils//packages/@overeng/gh-ci-utils:test", + "taskName": "test:gh-ci-utils", + "testFiles": [ + "test/GitHubClient.test.ts", + "test/GitHubClientLogs.test.ts", + "test/GitHubInternal.test.ts", + "test/GitHubSchemas.test.ts", + "test/GitHubSession.test.ts", + "test/RunId.test.ts", + "test/RunnerClient.test.ts", + "test/azureBlobError.test.ts", + "test/cliTokenFallback.test.ts", + "test/exitCode.test.ts", + "test/format.test.ts", + "test/inspectAssessment.test.ts", + "test/inspectJsonContract.test.ts", + "test/jsonContract.test.ts", + "test/jsonOutput.test.ts", + "test/logFilter.test.ts", + "test/namespaceAdapter.test.ts", + "test/ndjsonHeartbeat.test.ts", + "test/rateLimit.test.ts", + "test/rerun.test.ts", + "test/runSelection.test.ts", + "test/runnerIdentity.test.ts", + "test/toolFailure.test.ts", + "test/watchPlan.test.ts" + ], + "unboundedAfter": [], + "unboundedFiles": [] + }, { "collectionTarget": "effect_utils//packages/@overeng/kdl-effect:test_collect", "excludes": [], @@ -1176,22 +1254,53 @@ "unboundedAfter": [], "unboundedFiles": [] }, + { + "collectionTarget": "effect_utils//packages/@overeng/pty-effect:bundle_smoke_collect", + "excludes": [], + "packageName": "pty-effect", + "packagePath": "packages/@overeng/pty-effect", + "runner": "vitest", + "selectedTestFiles": ["src/bundle-smoke.unit.test.ts"], + "sourceOwners": { + "src/client.test.ts": "test:pty-effect:unbounded", + "src/client.unit.test.ts": "test:pty-effect", + "src/PtySession.test.ts": "test:pty-effect:unbounded" + }, + "target": "effect_utils//packages/@overeng/pty-effect:bundle_smoke", + "taskName": "test:pty-effect:bundle_smoke", + "testFiles": [ + "src/PtySession.test.ts", + "src/bundle-smoke.unit.test.ts", + "src/client.test.ts", + "src/client.unit.test.ts" + ], + "unboundedAfter": [], + "unboundedFiles": [] + }, { "collectionTarget": "effect_utils//packages/@overeng/pty-effect:test_collect", - "excludes": ["src/PtySession.test.ts", "src/client.test.ts"], + "excludes": ["src/PtySession.test.ts", "src/bundle-smoke.unit.test.ts", "src/client.test.ts"], "packageName": "pty-effect", "packagePath": "packages/@overeng/pty-effect", "runner": "vitest", "selectedTestFiles": [ "src/PtySession.test.ts", + "src/bundle-smoke.unit.test.ts", "src/client.test.ts", "src/client.unit.test.ts" ], - "sourceOwners": {}, + "sourceOwners": { + "src/bundle-smoke.unit.test.ts": "bundle:smoke" + }, "target": "effect_utils//packages/@overeng/pty-effect:test", "taskName": "test:pty-effect", - "testFiles": ["src/PtySession.test.ts", "src/client.test.ts", "src/client.unit.test.ts"], - "unboundedAfter": ["pnpm:link-native-node-packages"], + "testFiles": [ + "src/PtySession.test.ts", + "src/bundle-smoke.unit.test.ts", + "src/client.test.ts", + "src/client.unit.test.ts" + ], + "unboundedAfter": [], "unboundedFiles": ["src/PtySession.test.ts", "src/client.test.ts"], "unboundedTaskName": "test:pty-effect:unbounded" }, diff --git a/buck2/dependencies/BUCK b/buck2/dependencies/BUCK index 43aa3b094a..abe658c3a0 100644 --- a/buck2/dependencies/BUCK +++ b/buck2/dependencies/BUCK @@ -3,7 +3,7 @@ # Generated file - DO NOT EDIT # Source: pnpm-lock.yaml -# Store fingerprint: sha256:16a278467c691012e2e9ef7dd1fc35ac733347393610c6ffd74817cf80b0a9f0 +# Store fingerprint: sha256:98cc3eb33479f30ffc8a81298e73dfda9f3313b9ff2940860caf9023b2518c4f load("//buck2:materialization.bzl", "export_materialization_inputs") @@ -18753,6 +18753,7 @@ pnpm_store_view( name = "view_packages_overeng_effect_rpc_tanstack_examples_basic_cdf25b205fd8", runtime = ":assemble-store.ts", direct = { + "@effect/platform-node": "@effect+platform-node@4.0.0-rc.112_effect@4.0.0-rc.112_redis@6.2.1_@opentelemetry+api@1.9.1", "@playwright/test": "@playwright+test@1.63.0", "@tanstack/react-router": "@tanstack+react-router@1.170.33_react-dom@19.2.8_react@19.2.8_react@19.2.8", "@tanstack/react-start": "@tanstack+react-start@1.168.50_esbuild@0.28.2_react-dom@19.2.8_react@19.2.8_react@19.2.8_rolldown@1.2.7_a0857534a42afd6c", @@ -18786,6 +18787,8 @@ pnpm_store_view( "@babel+template@7.29.7": ":entry_babel_template_7_29_7_a226ca8d0afd", "@babel+traverse@7.29.8": ":entry_babel_traverse_7_29_8_312274327df7", "@babel+types@7.29.8": ":entry_babel_types_7_29_8_95b409a45bd5", + "@effect+platform-node-shared@4.0.0-rc.112_effect@4.0.0-rc.112": ":entry_effect_platform_node_shared_4_0_0_rc_112_effect_4_0_0_rc_112_6dc74cb25388", + "@effect+platform-node@4.0.0-rc.112_effect@4.0.0-rc.112_redis@6.2.1_@opentelemetry+api@1.9.1": ":entry_effect_platform_node_4_0_0_rc_112_effect_4_0_0_rc_112_redis_6_2_1_opente_19ca92e99e71", "@jridgewell+gen-mapping@0.3.13": ":entry_jridgewell_gen_mapping_0_3_13_145bee95e179", "@jridgewell+remapping@2.3.5": ":entry_jridgewell_remapping_2_3_5_43ae96c027a1", "@jridgewell+resolve-uri@3.1.2": ":entry_jridgewell_resolve_uri_3_1_2_3ba312251f16", @@ -18795,8 +18798,14 @@ pnpm_store_view( "@oozcitak+infra@2.0.2": ":entry_oozcitak_infra_2_0_2_da5498d4e3b2", "@oozcitak+url@3.0.0": ":entry_oozcitak_url_3_0_0_04f342ba97d9", "@oozcitak+util@10.0.0": ":entry_oozcitak_util_10_0_0_be347663f31e", + "@opentelemetry+api@1.9.1": ":entry_opentelemetry_api_1_9_1_65aff18a9fc4", "@oxc-project+types@0.148.0": ":entry_oxc_project_types_0_148_0_25bb4dfc3213", "@playwright+test@1.63.0": ":entry_playwright_test_1_63_0_9bc3d88e065e", + "@redis+bloom@6.2.1_@redis+client@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_bloom_6_2_1_redis_client_6_2_1_opentelemetry_api_1_9_1_06ad217998cb", + "@redis+client@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_client_6_2_1_opentelemetry_api_1_9_1_80c951e97547", + "@redis+json@6.2.1_@redis+client@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_json_6_2_1_redis_client_6_2_1_opentelemetry_api_1_9_1_9e468cc3d6d8", + "@redis+search@6.2.1_@redis+client@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_search_6_2_1_redis_client_6_2_1_opentelemetry_api_1_9_1_ff890285deba", + "@redis+time-series@6.2.1_@redis+client@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_time_series_6_2_1_redis_client_6_2_1_opentelemetry_api_1_9_1_e4d2523e153b", "@rolldown+pluginutils@1.0.1": ":entry_rolldown_pluginutils_1_0_1_3f649c36a41c", "@tanstack+history@1.162.2": ":entry_tanstack_history_1_162_2_9750431e44f3", "@tanstack+react-router@1.170.33_react-dom@19.2.8_react@19.2.8_react@19.2.8": ":entry_tanstack_react_router_1_170_33_react_dom_19_2_8_react_19_2_8_react_19_2__c9c448bd3b20", @@ -18823,6 +18832,7 @@ pnpm_store_view( "@types+node@26.5.0": ":entry_types_node_26_5_0_a0142d056efc", "@types+react-dom@19.2.7_@types+react@19.2.18": ":entry_types_react_dom_19_2_7_types_react_19_2_18_cafde4f429b3", "@types+react@19.2.18": ":entry_types_react_19_2_18_231c43c28c72", + "@types+ws@8.18.1": ":entry_types_ws_8_18_1_ee1128304b54", "@vitejs+plugin-react@6.1.1_vite@8.2.2_@types+node@26.5.0_esbuild@0.28.2_jiti@2.7.0": ":entry_vitejs_plugin_react_6_1_1_vite_8_2_2_types_node_26_5_0_esbuild_0_28_2_ji_5d0b50c5cdea", "ansis@4.3.1": ":entry_ansis_4_3_1_98911a9a2b39", "argparse@2.0.1": ":entry_argparse_2_0_1_eb6fb2df860c", @@ -18831,6 +18841,7 @@ pnpm_store_view( "browserslist@4.28.8": ":entry_browserslist_4_28_8_3a679ad65cca", "caniuse-lite@1.0.30001810": ":entry_caniuse_lite_1_0_30001810_2279b0f6b9ea", "chokidar@5.0.0": ":entry_chokidar_5_0_0_6fd1ad8d2f8f", + "cluster-key-slot@1.1.2": ":entry_cluster_key_slot_1_1_2_c0f5d819d288", "convert-source-map@2.0.0": ":entry_convert_source_map_2_0_0_46e32cfc1207", "cookie-es@3.1.1": ":entry_cookie_es_3_1_1_9684ebb91f36", "csstype@3.2.3": ":entry_csstype_3_2_3_d75166202534", @@ -18856,6 +18867,7 @@ pnpm_store_view( "lightningcss@1.33.0": ":entry_lightningcss_1_33_0_7129b0f44113", "lru-cache@5.1.1": ":entry_lru_cache_5_1_1_fe7f0a2f2cf4", "magic-string@0.30.21": ":entry_magic_string_0_30_21_a2e515768834", + "mime@4.1.0": ":entry_mime_4_1_0_6887a25dc460", "ms@2.1.3": ":entry_ms_2_1_3_2083576c5af8", "msgpackr-extract@3.0.4": ":entry_msgpackr_extract_3_0_4_dfa8bdf9fa66", "msgpackr@2.1.0": ":entry_msgpackr_2_1_0_4167decebcf1", @@ -18873,6 +18885,7 @@ pnpm_store_view( "react-dom@19.2.8_react@19.2.8": ":entry_react_dom_19_2_8_react_19_2_8_322c46404300", "react@19.2.8": ":entry_react_19_2_8_f0ed5178d6d7", "readdirp@5.1.1": ":entry_readdirp_5_1_1_df5701fc5bfa", + "redis@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_6_2_1_opentelemetry_api_1_9_1_1f4d9a664fc3", "rolldown@1.2.7": ":entry_rolldown_1_2_7_f28636c54a2e", "rou3@0.8.1": ":entry_rou3_0_8_1_ea3766bc9408", "scheduler@0.27.0": ":entry_scheduler_0_27_0_e21311c62741", @@ -18886,12 +18899,14 @@ pnpm_store_view( "typescript@7.0.2": ":entry_typescript_7_0_2_a7cefd323dc7", "ufo@1.6.4": ":entry_ufo_1_6_4_5edfa10acbf0", "undici-types@8.9.0": ":entry_undici_types_8_9_0_53cb0487b88b", + "undici@8.10.1": ":entry_undici_8_10_1_2c8ef7984324", "unplugin@3.3.0_esbuild@0.28.2_rolldown@1.2.7_vite@8.2.2_@types+node@26.5.0_esbuild@0.28.2_jiti@2.7.0": ":entry_unplugin_3_3_0_esbuild_0_28_2_rolldown_1_2_7_vite_8_2_2_types_node_26_5__5b95d906a093", "update-browserslist-db@1.3.2_browserslist@4.28.8": ":entry_update_browserslist_db_1_3_2_browserslist_4_28_8_ce2be52fa5c9", "use-sync-external-store@1.6.0_react@19.2.8": ":entry_use_sync_external_store_1_6_0_react_19_2_8_6b5cba987dec", "vite@8.2.2_@types+node@26.5.0_esbuild@0.28.2_jiti@2.7.0": ":entry_vite_8_2_2_types_node_26_5_0_esbuild_0_28_2_jiti_2_7_0_d58a93b60214", "vitefu@1.1.3_vite@8.2.2_@types+node@26.5.0_esbuild@0.28.2_jiti@2.7.0": ":entry_vitefu_1_1_3_vite_8_2_2_types_node_26_5_0_esbuild_0_28_2_jiti_2_7_0_4b6ba3979ce5", "webpack-virtual-modules@0.6.2": ":entry_webpack_virtual_modules_0_6_2_59ac599676ed", + "ws@8.21.3": ":entry_ws_8_21_3_d250ffc75a80", "xmlbuilder2@4.0.3": ":entry_xmlbuilder2_4_0_3_66f6670a014a", "yallist@3.1.1": ":entry_yallist_3_1_1_63b110ffd187", "zod@4.5.4": ":entry_zod_4_5_4_cff108573f06", @@ -18914,6 +18929,8 @@ pnpm_store_view( "@babel+template@7.29.7": ":entry_babel_template_7_29_7_a226ca8d0afd", "@babel+traverse@7.29.8": ":entry_babel_traverse_7_29_8_312274327df7", "@babel+types@7.29.8": ":entry_babel_types_7_29_8_95b409a45bd5", + "@effect+platform-node-shared@4.0.0-rc.112_effect@4.0.0-rc.112": ":entry_effect_platform_node_shared_4_0_0_rc_112_effect_4_0_0_rc_112_6dc74cb25388", + "@effect+platform-node@4.0.0-rc.112_effect@4.0.0-rc.112_redis@6.2.1_@opentelemetry+api@1.9.1": ":entry_effect_platform_node_4_0_0_rc_112_effect_4_0_0_rc_112_redis_6_2_1_opente_19ca92e99e71", "@esbuild+linux-arm64@0.28.2": ":entry_esbuild_linux_arm64_0_28_2_a67bfa3d5003", "@jridgewell+gen-mapping@0.3.13": ":entry_jridgewell_gen_mapping_0_3_13_145bee95e179", "@jridgewell+remapping@2.3.5": ":entry_jridgewell_remapping_2_3_5_43ae96c027a1", @@ -18925,8 +18942,14 @@ pnpm_store_view( "@oozcitak+infra@2.0.2": ":entry_oozcitak_infra_2_0_2_da5498d4e3b2", "@oozcitak+url@3.0.0": ":entry_oozcitak_url_3_0_0_04f342ba97d9", "@oozcitak+util@10.0.0": ":entry_oozcitak_util_10_0_0_be347663f31e", + "@opentelemetry+api@1.9.1": ":entry_opentelemetry_api_1_9_1_65aff18a9fc4", "@oxc-project+types@0.148.0": ":entry_oxc_project_types_0_148_0_25bb4dfc3213", "@playwright+test@1.63.0": ":entry_playwright_test_1_63_0_9bc3d88e065e", + "@redis+bloom@6.2.1_@redis+client@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_bloom_6_2_1_redis_client_6_2_1_opentelemetry_api_1_9_1_06ad217998cb", + "@redis+client@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_client_6_2_1_opentelemetry_api_1_9_1_80c951e97547", + "@redis+json@6.2.1_@redis+client@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_json_6_2_1_redis_client_6_2_1_opentelemetry_api_1_9_1_9e468cc3d6d8", + "@redis+search@6.2.1_@redis+client@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_search_6_2_1_redis_client_6_2_1_opentelemetry_api_1_9_1_ff890285deba", + "@redis+time-series@6.2.1_@redis+client@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_time_series_6_2_1_redis_client_6_2_1_opentelemetry_api_1_9_1_e4d2523e153b", "@rolldown+binding-linux-arm64-gnu@1.2.7": ":entry_rolldown_binding_linux_arm64_gnu_1_2_7_b564cdf057d1", "@rolldown+pluginutils@1.0.1": ":entry_rolldown_pluginutils_1_0_1_3f649c36a41c", "@tanstack+history@1.162.2": ":entry_tanstack_history_1_162_2_9750431e44f3", @@ -18954,6 +18977,7 @@ pnpm_store_view( "@types+node@26.5.0": ":entry_types_node_26_5_0_a0142d056efc", "@types+react-dom@19.2.7_@types+react@19.2.18": ":entry_types_react_dom_19_2_7_types_react_19_2_18_cafde4f429b3", "@types+react@19.2.18": ":entry_types_react_19_2_18_231c43c28c72", + "@types+ws@8.18.1": ":entry_types_ws_8_18_1_ee1128304b54", "@typescript+typescript-linux-arm64@7.0.2": ":entry_typescript_typescript_linux_arm64_7_0_2_dbe899afde8f", "@vitejs+plugin-react@6.1.1_vite@8.2.2_@types+node@26.5.0_esbuild@0.28.2_jiti@2.7.0": ":entry_vitejs_plugin_react_6_1_1_vite_8_2_2_types_node_26_5_0_esbuild_0_28_2_ji_5d0b50c5cdea", "ansis@4.3.1": ":entry_ansis_4_3_1_98911a9a2b39", @@ -18963,6 +18987,7 @@ pnpm_store_view( "browserslist@4.28.8": ":entry_browserslist_4_28_8_3a679ad65cca", "caniuse-lite@1.0.30001810": ":entry_caniuse_lite_1_0_30001810_2279b0f6b9ea", "chokidar@5.0.0": ":entry_chokidar_5_0_0_6fd1ad8d2f8f", + "cluster-key-slot@1.1.2": ":entry_cluster_key_slot_1_1_2_c0f5d819d288", "convert-source-map@2.0.0": ":entry_convert_source_map_2_0_0_46e32cfc1207", "cookie-es@3.1.1": ":entry_cookie_es_3_1_1_9684ebb91f36", "csstype@3.2.3": ":entry_csstype_3_2_3_d75166202534", @@ -18989,6 +19014,7 @@ pnpm_store_view( "lightningcss@1.33.0": ":entry_lightningcss_1_33_0_7129b0f44113", "lru-cache@5.1.1": ":entry_lru_cache_5_1_1_fe7f0a2f2cf4", "magic-string@0.30.21": ":entry_magic_string_0_30_21_a2e515768834", + "mime@4.1.0": ":entry_mime_4_1_0_6887a25dc460", "ms@2.1.3": ":entry_ms_2_1_3_2083576c5af8", "msgpackr-extract@3.0.4": ":entry_msgpackr_extract_3_0_4_dfa8bdf9fa66", "msgpackr@2.1.0": ":entry_msgpackr_2_1_0_4167decebcf1", @@ -19006,6 +19032,7 @@ pnpm_store_view( "react-dom@19.2.8_react@19.2.8": ":entry_react_dom_19_2_8_react_19_2_8_322c46404300", "react@19.2.8": ":entry_react_19_2_8_f0ed5178d6d7", "readdirp@5.1.1": ":entry_readdirp_5_1_1_df5701fc5bfa", + "redis@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_6_2_1_opentelemetry_api_1_9_1_1f4d9a664fc3", "rolldown@1.2.7": ":entry_rolldown_1_2_7_f28636c54a2e", "rou3@0.8.1": ":entry_rou3_0_8_1_ea3766bc9408", "scheduler@0.27.0": ":entry_scheduler_0_27_0_e21311c62741", @@ -19019,12 +19046,14 @@ pnpm_store_view( "typescript@7.0.2": ":entry_typescript_7_0_2_a7cefd323dc7", "ufo@1.6.4": ":entry_ufo_1_6_4_5edfa10acbf0", "undici-types@8.9.0": ":entry_undici_types_8_9_0_53cb0487b88b", + "undici@8.10.1": ":entry_undici_8_10_1_2c8ef7984324", "unplugin@3.3.0_esbuild@0.28.2_rolldown@1.2.7_vite@8.2.2_@types+node@26.5.0_esbuild@0.28.2_jiti@2.7.0": ":entry_unplugin_3_3_0_esbuild_0_28_2_rolldown_1_2_7_vite_8_2_2_types_node_26_5__5b95d906a093", "update-browserslist-db@1.3.2_browserslist@4.28.8": ":entry_update_browserslist_db_1_3_2_browserslist_4_28_8_ce2be52fa5c9", "use-sync-external-store@1.6.0_react@19.2.8": ":entry_use_sync_external_store_1_6_0_react_19_2_8_6b5cba987dec", "vite@8.2.2_@types+node@26.5.0_esbuild@0.28.2_jiti@2.7.0": ":entry_vite_8_2_2_types_node_26_5_0_esbuild_0_28_2_jiti_2_7_0_d58a93b60214", "vitefu@1.1.3_vite@8.2.2_@types+node@26.5.0_esbuild@0.28.2_jiti@2.7.0": ":entry_vitefu_1_1_3_vite_8_2_2_types_node_26_5_0_esbuild_0_28_2_jiti_2_7_0_4b6ba3979ce5", "webpack-virtual-modules@0.6.2": ":entry_webpack_virtual_modules_0_6_2_59ac599676ed", + "ws@8.21.3": ":entry_ws_8_21_3_d250ffc75a80", "xmlbuilder2@4.0.3": ":entry_xmlbuilder2_4_0_3_66f6670a014a", "yallist@3.1.1": ":entry_yallist_3_1_1_63b110ffd187", "zod@4.5.4": ":entry_zod_4_5_4_cff108573f06", @@ -19047,6 +19076,8 @@ pnpm_store_view( "@babel+template@7.29.7": ":entry_babel_template_7_29_7_a226ca8d0afd", "@babel+traverse@7.29.8": ":entry_babel_traverse_7_29_8_312274327df7", "@babel+types@7.29.8": ":entry_babel_types_7_29_8_95b409a45bd5", + "@effect+platform-node-shared@4.0.0-rc.112_effect@4.0.0-rc.112": ":entry_effect_platform_node_shared_4_0_0_rc_112_effect_4_0_0_rc_112_6dc74cb25388", + "@effect+platform-node@4.0.0-rc.112_effect@4.0.0-rc.112_redis@6.2.1_@opentelemetry+api@1.9.1": ":entry_effect_platform_node_4_0_0_rc_112_effect_4_0_0_rc_112_redis_6_2_1_opente_19ca92e99e71", "@esbuild+linux-x64@0.28.2": ":entry_esbuild_linux_x64_0_28_2_a925772984e9", "@jridgewell+gen-mapping@0.3.13": ":entry_jridgewell_gen_mapping_0_3_13_145bee95e179", "@jridgewell+remapping@2.3.5": ":entry_jridgewell_remapping_2_3_5_43ae96c027a1", @@ -19058,8 +19089,14 @@ pnpm_store_view( "@oozcitak+infra@2.0.2": ":entry_oozcitak_infra_2_0_2_da5498d4e3b2", "@oozcitak+url@3.0.0": ":entry_oozcitak_url_3_0_0_04f342ba97d9", "@oozcitak+util@10.0.0": ":entry_oozcitak_util_10_0_0_be347663f31e", + "@opentelemetry+api@1.9.1": ":entry_opentelemetry_api_1_9_1_65aff18a9fc4", "@oxc-project+types@0.148.0": ":entry_oxc_project_types_0_148_0_25bb4dfc3213", "@playwright+test@1.63.0": ":entry_playwright_test_1_63_0_9bc3d88e065e", + "@redis+bloom@6.2.1_@redis+client@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_bloom_6_2_1_redis_client_6_2_1_opentelemetry_api_1_9_1_06ad217998cb", + "@redis+client@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_client_6_2_1_opentelemetry_api_1_9_1_80c951e97547", + "@redis+json@6.2.1_@redis+client@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_json_6_2_1_redis_client_6_2_1_opentelemetry_api_1_9_1_9e468cc3d6d8", + "@redis+search@6.2.1_@redis+client@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_search_6_2_1_redis_client_6_2_1_opentelemetry_api_1_9_1_ff890285deba", + "@redis+time-series@6.2.1_@redis+client@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_time_series_6_2_1_redis_client_6_2_1_opentelemetry_api_1_9_1_e4d2523e153b", "@rolldown+binding-linux-x64-gnu@1.2.7": ":entry_rolldown_binding_linux_x64_gnu_1_2_7_2b8bc0885731", "@rolldown+pluginutils@1.0.1": ":entry_rolldown_pluginutils_1_0_1_3f649c36a41c", "@tanstack+history@1.162.2": ":entry_tanstack_history_1_162_2_9750431e44f3", @@ -19087,6 +19124,7 @@ pnpm_store_view( "@types+node@26.5.0": ":entry_types_node_26_5_0_a0142d056efc", "@types+react-dom@19.2.7_@types+react@19.2.18": ":entry_types_react_dom_19_2_7_types_react_19_2_18_cafde4f429b3", "@types+react@19.2.18": ":entry_types_react_19_2_18_231c43c28c72", + "@types+ws@8.18.1": ":entry_types_ws_8_18_1_ee1128304b54", "@typescript+typescript-linux-x64@7.0.2": ":entry_typescript_typescript_linux_x64_7_0_2_f03df44f666b", "@vitejs+plugin-react@6.1.1_vite@8.2.2_@types+node@26.5.0_esbuild@0.28.2_jiti@2.7.0": ":entry_vitejs_plugin_react_6_1_1_vite_8_2_2_types_node_26_5_0_esbuild_0_28_2_ji_5d0b50c5cdea", "ansis@4.3.1": ":entry_ansis_4_3_1_98911a9a2b39", @@ -19096,6 +19134,7 @@ pnpm_store_view( "browserslist@4.28.8": ":entry_browserslist_4_28_8_3a679ad65cca", "caniuse-lite@1.0.30001810": ":entry_caniuse_lite_1_0_30001810_2279b0f6b9ea", "chokidar@5.0.0": ":entry_chokidar_5_0_0_6fd1ad8d2f8f", + "cluster-key-slot@1.1.2": ":entry_cluster_key_slot_1_1_2_c0f5d819d288", "convert-source-map@2.0.0": ":entry_convert_source_map_2_0_0_46e32cfc1207", "cookie-es@3.1.1": ":entry_cookie_es_3_1_1_9684ebb91f36", "csstype@3.2.3": ":entry_csstype_3_2_3_d75166202534", @@ -19122,6 +19161,7 @@ pnpm_store_view( "lightningcss@1.33.0": ":entry_lightningcss_1_33_0_7129b0f44113", "lru-cache@5.1.1": ":entry_lru_cache_5_1_1_fe7f0a2f2cf4", "magic-string@0.30.21": ":entry_magic_string_0_30_21_a2e515768834", + "mime@4.1.0": ":entry_mime_4_1_0_6887a25dc460", "ms@2.1.3": ":entry_ms_2_1_3_2083576c5af8", "msgpackr-extract@3.0.4": ":entry_msgpackr_extract_3_0_4_dfa8bdf9fa66", "msgpackr@2.1.0": ":entry_msgpackr_2_1_0_4167decebcf1", @@ -19139,6 +19179,7 @@ pnpm_store_view( "react-dom@19.2.8_react@19.2.8": ":entry_react_dom_19_2_8_react_19_2_8_322c46404300", "react@19.2.8": ":entry_react_19_2_8_f0ed5178d6d7", "readdirp@5.1.1": ":entry_readdirp_5_1_1_df5701fc5bfa", + "redis@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_6_2_1_opentelemetry_api_1_9_1_1f4d9a664fc3", "rolldown@1.2.7": ":entry_rolldown_1_2_7_f28636c54a2e", "rou3@0.8.1": ":entry_rou3_0_8_1_ea3766bc9408", "scheduler@0.27.0": ":entry_scheduler_0_27_0_e21311c62741", @@ -19152,12 +19193,14 @@ pnpm_store_view( "typescript@7.0.2": ":entry_typescript_7_0_2_a7cefd323dc7", "ufo@1.6.4": ":entry_ufo_1_6_4_5edfa10acbf0", "undici-types@8.9.0": ":entry_undici_types_8_9_0_53cb0487b88b", + "undici@8.10.1": ":entry_undici_8_10_1_2c8ef7984324", "unplugin@3.3.0_esbuild@0.28.2_rolldown@1.2.7_vite@8.2.2_@types+node@26.5.0_esbuild@0.28.2_jiti@2.7.0": ":entry_unplugin_3_3_0_esbuild_0_28_2_rolldown_1_2_7_vite_8_2_2_types_node_26_5__5b95d906a093", "update-browserslist-db@1.3.2_browserslist@4.28.8": ":entry_update_browserslist_db_1_3_2_browserslist_4_28_8_ce2be52fa5c9", "use-sync-external-store@1.6.0_react@19.2.8": ":entry_use_sync_external_store_1_6_0_react_19_2_8_6b5cba987dec", "vite@8.2.2_@types+node@26.5.0_esbuild@0.28.2_jiti@2.7.0": ":entry_vite_8_2_2_types_node_26_5_0_esbuild_0_28_2_jiti_2_7_0_d58a93b60214", "vitefu@1.1.3_vite@8.2.2_@types+node@26.5.0_esbuild@0.28.2_jiti@2.7.0": ":entry_vitefu_1_1_3_vite_8_2_2_types_node_26_5_0_esbuild_0_28_2_jiti_2_7_0_4b6ba3979ce5", "webpack-virtual-modules@0.6.2": ":entry_webpack_virtual_modules_0_6_2_59ac599676ed", + "ws@8.21.3": ":entry_ws_8_21_3_d250ffc75a80", "xmlbuilder2@4.0.3": ":entry_xmlbuilder2_4_0_3_66f6670a014a", "yallist@3.1.1": ":entry_yallist_3_1_1_63b110ffd187", "zod@4.5.4": ":entry_zod_4_5_4_cff108573f06", @@ -19180,6 +19223,8 @@ pnpm_store_view( "@babel+template@7.29.7": ":entry_babel_template_7_29_7_a226ca8d0afd", "@babel+traverse@7.29.8": ":entry_babel_traverse_7_29_8_312274327df7", "@babel+types@7.29.8": ":entry_babel_types_7_29_8_95b409a45bd5", + "@effect+platform-node-shared@4.0.0-rc.112_effect@4.0.0-rc.112": ":entry_effect_platform_node_shared_4_0_0_rc_112_effect_4_0_0_rc_112_6dc74cb25388", + "@effect+platform-node@4.0.0-rc.112_effect@4.0.0-rc.112_redis@6.2.1_@opentelemetry+api@1.9.1": ":entry_effect_platform_node_4_0_0_rc_112_effect_4_0_0_rc_112_redis_6_2_1_opente_19ca92e99e71", "@esbuild+darwin-arm64@0.28.2": ":entry_esbuild_darwin_arm64_0_28_2_721282d04d4b", "@jridgewell+gen-mapping@0.3.13": ":entry_jridgewell_gen_mapping_0_3_13_145bee95e179", "@jridgewell+remapping@2.3.5": ":entry_jridgewell_remapping_2_3_5_43ae96c027a1", @@ -19191,8 +19236,14 @@ pnpm_store_view( "@oozcitak+infra@2.0.2": ":entry_oozcitak_infra_2_0_2_da5498d4e3b2", "@oozcitak+url@3.0.0": ":entry_oozcitak_url_3_0_0_04f342ba97d9", "@oozcitak+util@10.0.0": ":entry_oozcitak_util_10_0_0_be347663f31e", + "@opentelemetry+api@1.9.1": ":entry_opentelemetry_api_1_9_1_65aff18a9fc4", "@oxc-project+types@0.148.0": ":entry_oxc_project_types_0_148_0_25bb4dfc3213", "@playwright+test@1.63.0": ":entry_playwright_test_1_63_0_9bc3d88e065e", + "@redis+bloom@6.2.1_@redis+client@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_bloom_6_2_1_redis_client_6_2_1_opentelemetry_api_1_9_1_06ad217998cb", + "@redis+client@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_client_6_2_1_opentelemetry_api_1_9_1_80c951e97547", + "@redis+json@6.2.1_@redis+client@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_json_6_2_1_redis_client_6_2_1_opentelemetry_api_1_9_1_9e468cc3d6d8", + "@redis+search@6.2.1_@redis+client@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_search_6_2_1_redis_client_6_2_1_opentelemetry_api_1_9_1_ff890285deba", + "@redis+time-series@6.2.1_@redis+client@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_time_series_6_2_1_redis_client_6_2_1_opentelemetry_api_1_9_1_e4d2523e153b", "@rolldown+binding-darwin-arm64@1.2.7": ":entry_rolldown_binding_darwin_arm64_1_2_7_c213ca2a9ab4", "@rolldown+pluginutils@1.0.1": ":entry_rolldown_pluginutils_1_0_1_3f649c36a41c", "@tanstack+history@1.162.2": ":entry_tanstack_history_1_162_2_9750431e44f3", @@ -19220,6 +19271,7 @@ pnpm_store_view( "@types+node@26.5.0": ":entry_types_node_26_5_0_a0142d056efc", "@types+react-dom@19.2.7_@types+react@19.2.18": ":entry_types_react_dom_19_2_7_types_react_19_2_18_cafde4f429b3", "@types+react@19.2.18": ":entry_types_react_19_2_18_231c43c28c72", + "@types+ws@8.18.1": ":entry_types_ws_8_18_1_ee1128304b54", "@typescript+typescript-darwin-arm64@7.0.2": ":entry_typescript_typescript_darwin_arm64_7_0_2_38ca3d6d9939", "@vitejs+plugin-react@6.1.1_vite@8.2.2_@types+node@26.5.0_esbuild@0.28.2_jiti@2.7.0": ":entry_vitejs_plugin_react_6_1_1_vite_8_2_2_types_node_26_5_0_esbuild_0_28_2_ji_5d0b50c5cdea", "ansis@4.3.1": ":entry_ansis_4_3_1_98911a9a2b39", @@ -19229,6 +19281,7 @@ pnpm_store_view( "browserslist@4.28.8": ":entry_browserslist_4_28_8_3a679ad65cca", "caniuse-lite@1.0.30001810": ":entry_caniuse_lite_1_0_30001810_2279b0f6b9ea", "chokidar@5.0.0": ":entry_chokidar_5_0_0_6fd1ad8d2f8f", + "cluster-key-slot@1.1.2": ":entry_cluster_key_slot_1_1_2_c0f5d819d288", "convert-source-map@2.0.0": ":entry_convert_source_map_2_0_0_46e32cfc1207", "cookie-es@3.1.1": ":entry_cookie_es_3_1_1_9684ebb91f36", "csstype@3.2.3": ":entry_csstype_3_2_3_d75166202534", @@ -19256,6 +19309,7 @@ pnpm_store_view( "lightningcss@1.33.0": ":entry_lightningcss_1_33_0_7129b0f44113", "lru-cache@5.1.1": ":entry_lru_cache_5_1_1_fe7f0a2f2cf4", "magic-string@0.30.21": ":entry_magic_string_0_30_21_a2e515768834", + "mime@4.1.0": ":entry_mime_4_1_0_6887a25dc460", "ms@2.1.3": ":entry_ms_2_1_3_2083576c5af8", "msgpackr-extract@3.0.4": ":entry_msgpackr_extract_3_0_4_dfa8bdf9fa66", "msgpackr@2.1.0": ":entry_msgpackr_2_1_0_4167decebcf1", @@ -19273,6 +19327,7 @@ pnpm_store_view( "react-dom@19.2.8_react@19.2.8": ":entry_react_dom_19_2_8_react_19_2_8_322c46404300", "react@19.2.8": ":entry_react_19_2_8_f0ed5178d6d7", "readdirp@5.1.1": ":entry_readdirp_5_1_1_df5701fc5bfa", + "redis@6.2.1_@opentelemetry+api@1.9.1": ":entry_redis_6_2_1_opentelemetry_api_1_9_1_1f4d9a664fc3", "rolldown@1.2.7": ":entry_rolldown_1_2_7_f28636c54a2e", "rou3@0.8.1": ":entry_rou3_0_8_1_ea3766bc9408", "scheduler@0.27.0": ":entry_scheduler_0_27_0_e21311c62741", @@ -19286,12 +19341,14 @@ pnpm_store_view( "typescript@7.0.2": ":entry_typescript_7_0_2_a7cefd323dc7", "ufo@1.6.4": ":entry_ufo_1_6_4_5edfa10acbf0", "undici-types@8.9.0": ":entry_undici_types_8_9_0_53cb0487b88b", + "undici@8.10.1": ":entry_undici_8_10_1_2c8ef7984324", "unplugin@3.3.0_esbuild@0.28.2_rolldown@1.2.7_vite@8.2.2_@types+node@26.5.0_esbuild@0.28.2_jiti@2.7.0": ":entry_unplugin_3_3_0_esbuild_0_28_2_rolldown_1_2_7_vite_8_2_2_types_node_26_5__5b95d906a093", "update-browserslist-db@1.3.2_browserslist@4.28.8": ":entry_update_browserslist_db_1_3_2_browserslist_4_28_8_ce2be52fa5c9", "use-sync-external-store@1.6.0_react@19.2.8": ":entry_use_sync_external_store_1_6_0_react_19_2_8_6b5cba987dec", "vite@8.2.2_@types+node@26.5.0_esbuild@0.28.2_jiti@2.7.0": ":entry_vite_8_2_2_types_node_26_5_0_esbuild_0_28_2_jiti_2_7_0_d58a93b60214", "vitefu@1.1.3_vite@8.2.2_@types+node@26.5.0_esbuild@0.28.2_jiti@2.7.0": ":entry_vitefu_1_1_3_vite_8_2_2_types_node_26_5_0_esbuild_0_28_2_jiti_2_7_0_4b6ba3979ce5", "webpack-virtual-modules@0.6.2": ":entry_webpack_virtual_modules_0_6_2_59ac599676ed", + "ws@8.21.3": ":entry_ws_8_21_3_d250ffc75a80", "xmlbuilder2@4.0.3": ":entry_xmlbuilder2_4_0_3_66f6670a014a", "yallist@3.1.1": ":entry_yallist_3_1_1_63b110ffd187", "zod@4.5.4": ":entry_zod_4_5_4_cff108573f06", @@ -19303,9 +19360,11 @@ pnpm_store_view( "vite": "vite@8.2.2_@types+node@26.5.0_esbuild@0.28.2_jiti@2.7.0\tbin/vite.js", }, workspace_trees = { + "workspace_packages_overeng_effect_rpc_tanstack_588b5851e29c": "//packages/@overeng/effect-rpc-tanstack:package_tree", "workspace_packages_overeng_utils_e8a24aadff3a": "//packages/@overeng/utils:package_tree", }, workspace_dependencies = { + "@overeng/effect-rpc-tanstack": "workspace_packages_overeng_effect_rpc_tanstack_588b5851e29c", "@overeng/utils": "workspace_packages_overeng_utils_e8a24aadff3a", }, visibility = ["PUBLIC"], diff --git a/buck2/dependencies/pnpm-lock.sha256.json b/buck2/dependencies/pnpm-lock.sha256.json index dfc1a43056..9caba3e5f3 100644 --- a/buck2/dependencies/pnpm-lock.sha256.json +++ b/buck2/dependencies/pnpm-lock.sha256.json @@ -1,6 +1,6 @@ { "schema": "effect-utils/buck2-pnpm-sha256/v1", - "lockfileFingerprint": "sha256:434484af779f79b2934082c5cd8486a1eb27253611b5894c9c6317aa2d70bb1f", + "lockfileFingerprint": "sha256:6576be6285eedaf4910ee780d13fe24ace08f74ab9d34eaa1f9a783c4ebe9d0b", "source": "pnpm-lock.yaml", "generator": "buck2/dependencies/pnpm-lock.sha256.json.genie.ts", "regenerate": "devenv tasks run genie:run", @@ -3447,5 +3447,5 @@ "sha256": "2c162e000f5fb5a816987d6f8ad7aad295203f777a5992d514ae4660778a51a4" } }, - "fingerprint": "sha256:ecf281a27e3a46ebc7d5fadcba4584cf62391a62812b3cae4f125438eae428d9" + "fingerprint": "sha256:8874c8c2363b0a1e1ab7f908249890ad825c35509b92efe741a21fb026cd8a3c" } diff --git a/buck2/javascript.bzl b/buck2/javascript.bzl index 9b0cd748d5..8cd28bb14d 100644 --- a/buck2/javascript.bzl +++ b/buck2/javascript.bzl @@ -106,7 +106,7 @@ bun_executable = rule( "test_files": attrs.list(attrs.string(), default = []), "excludes": attrs.list(attrs.string(), default = []), "_runner": attrs.default_only(attrs.dep( - default = "//:javascript_action_runtime", + default = "//packages/@overeng/buck2-tools:javascript_action_runtime", providers = [DefaultInfo], )), "_javascript": attrs.default_only(attrs.exec_dep( @@ -174,7 +174,7 @@ _TEST_ATTRS = { "labels": attrs.list(attrs.string(), default = []), "contacts": attrs.list(attrs.string(), default = []), "_runner": attrs.default_only(attrs.dep( - default = "//:javascript_action_runtime", + default = "//packages/@overeng/buck2-tools:javascript_action_runtime", providers = [DefaultInfo], )), "_javascript": attrs.default_only(attrs.exec_dep( diff --git a/buck2/package_tools.bzl b/buck2/package_tools.bzl index ca707e6560..29860aa942 100644 --- a/buck2/package_tools.bzl +++ b/buck2/package_tools.bzl @@ -2,6 +2,7 @@ load("//buck2/dependencies:defs.bzl", "PnpmPlatformGatedPackagesInfo") load("//buck2/materialization.bzl", "PackageTreeInfo") +load("//buck2/platforms:defs.bzl", "root_allow_cache_uploads", "root_remote_cache_enabled") load("//buck2/toolchains:defs.bzl", "BunToolchainInfo") JavaScriptModuleInfo = provider(fields = { "module": Artifact, @@ -105,7 +106,7 @@ package_bin_check = rule( providers = [BunToolchainInfo], )), "_runner": attrs.default_only(attrs.dep( - default = "//:package_command_runtime", + default = "//packages/@overeng/buck2-tools:package_command_runtime", providers = [DefaultInfo], )), }, @@ -138,7 +139,7 @@ package_bin_build = rule( providers = [BunToolchainInfo], )), "_runner": attrs.default_only(attrs.dep( - default = "//:package_command_runtime", + default = "//packages/@overeng/buck2-tools:package_command_runtime", providers = [DefaultInfo], )), }, @@ -195,7 +196,7 @@ package_bin = rule( providers = [BunToolchainInfo], )), "_runner": attrs.default_only(attrs.dep( - default = "//:package_command_runtime", + default = "//packages/@overeng/buck2-tools:package_command_runtime", providers = [DefaultInfo], )), }, @@ -264,7 +265,7 @@ def _package_bundle_impl(ctx): args, category = "package_bin_artifact", local_only = True, - allow_cache_upload = False, + allow_cache_upload = root_remote_cache_enabled() and root_allow_cache_uploads(), ) return [ DefaultInfo( @@ -300,7 +301,7 @@ _package_bin_artifact = rule( providers = [PnpmPlatformGatedPackagesInfo], )), "_runner": attrs.default_only(attrs.dep( - default = "//:package_command_runtime", + default = "//packages/@overeng/buck2-tools:package_command_runtime", providers = [DefaultInfo], )), }, diff --git a/buck2/platforms/BUCK b/buck2/platforms/BUCK index 7ff598bab0..067e0b6ef0 100644 --- a/buck2/platforms/BUCK +++ b/buck2/platforms/BUCK @@ -44,6 +44,21 @@ product_platform( visibility = ["PUBLIC"], ) +product_platform( + name = "linux_x86_64_static", + os = "linux", + architecture = "x86_64", + abi = "glibc", + rust_target_triple = "x86_64-unknown-linux-gnu", + runtime_contract = "elf-static/v1", + constraint_values = [ + "prelude//abi/constraints:gnu", + "prelude//cpu/constraints:x86_64", + "prelude//os/constraints:linux", + ], + visibility = ["PUBLIC"], +) + product_platform( name = "linux_aarch64", os = "linux", @@ -59,6 +74,21 @@ product_platform( visibility = ["PUBLIC"], ) +product_platform( + name = "linux_aarch64_static", + os = "linux", + architecture = "aarch64", + abi = "glibc", + rust_target_triple = "aarch64-unknown-linux-gnu", + runtime_contract = "elf-static/v1", + constraint_values = [ + "prelude//abi/constraints:gnu", + "prelude//cpu/constraints:arm64", + "prelude//os/constraints:linux", + ], + visibility = ["PUBLIC"], +) + product_platform( name = "macos_aarch64", os = "darwin", diff --git a/buck2/platforms/defs.bzl b/buck2/platforms/defs.bzl index c3209adf31..9e5b1b0bc8 100644 --- a/buck2/platforms/defs.bzl +++ b/buck2/platforms/defs.bzl @@ -14,7 +14,9 @@ def admitted_rust_target_triple(os, architecture, abi, runtime_contract): triple = { "darwin:aarch64:darwin:mach-o-dynamic/v1": "aarch64-apple-darwin", "linux:aarch64:glibc:elf-dynamic/v1": "aarch64-unknown-linux-gnu", + "linux:aarch64:glibc:elf-static/v1": "aarch64-unknown-linux-gnu", "linux:x86_64:glibc:elf-dynamic/v1": "x86_64-unknown-linux-gnu", + "linux:x86_64:glibc:elf-static/v1": "x86_64-unknown-linux-gnu", }.get("{}:{}:{}:{}".format(os, architecture, abi, runtime_contract)) if triple == None: fail("platform fields do not identify an admitted native Rust pair") @@ -178,6 +180,17 @@ def host_platform_label(): return "//buck2/platforms:macos_aarch64" fail("host_platform supports only x86_64-linux, aarch64-linux, and aarch64-darwin") +def host_standalone_platform_label(): + """Selects the host platform for a product shipped without adjacent libraries.""" + host = host_info() + if host.os.is_linux and host.arch.is_x86_64: + return "//buck2/platforms:linux_x86_64_static" + if host.os.is_linux and host.arch.is_aarch64: + return "//buck2/platforms:linux_aarch64_static" + if host.os.is_macos and host.arch.is_aarch64: + return "//buck2/platforms:macos_aarch64" + fail("host standalone platform supports only x86_64-linux, aarch64-linux, and aarch64-darwin") + def host_execution_platform_label(): host = host_info() if host.os.is_linux and host.arch.is_x86_64: @@ -195,10 +208,18 @@ def native_execution_constraints(target_platform): "prelude//cpu/constraints:x86_64", "prelude//os/constraints:linux", ], + "//buck2/platforms:linux_x86_64_static": [ + "prelude//cpu/constraints:x86_64", + "prelude//os/constraints:linux", + ], "//buck2/platforms:linux_aarch64": [ "prelude//cpu/constraints:arm64", "prelude//os/constraints:linux", ], + "//buck2/platforms:linux_aarch64_static": [ + "prelude//cpu/constraints:arm64", + "prelude//os/constraints:linux", + ], "//buck2/platforms:macos_aarch64": [ "prelude//cpu/constraints:arm64", "prelude//os/constraints:macos", @@ -216,11 +237,21 @@ def product_platform_constraints(target_platform): "prelude//cpu/constraints:x86_64", "prelude//os/constraints:linux", ], + "//buck2/platforms:linux_x86_64_static": [ + "prelude//abi/constraints:gnu", + "prelude//cpu/constraints:x86_64", + "prelude//os/constraints:linux", + ], "//buck2/platforms:linux_aarch64": [ "prelude//abi/constraints:gnu", "prelude//cpu/constraints:arm64", "prelude//os/constraints:linux", ], + "//buck2/platforms:linux_aarch64_static": [ + "prelude//abi/constraints:gnu", + "prelude//cpu/constraints:arm64", + "prelude//os/constraints:linux", + ], "//buck2/platforms:macos_aarch64": [ "prelude//cpu/constraints:arm64", "prelude//os/constraints:macos", diff --git a/buck2/products/defs.bzl b/buck2/products/defs.bzl index 986aaea77e..aac9386d9e 100644 --- a/buck2/products/defs.bzl +++ b/buck2/products/defs.bzl @@ -1,8 +1,9 @@ """Language-neutral portable build-product packaging contract.""" +load("//buck2/materialization.bzl", "PackageTreeInfo") load("//buck2/package_tools.bzl", "JavaScriptModuleInfo") -load("//buck2/platforms:defs.bzl", "ProductPlatformInfo", "native_execution_constraints") -load("//buck2/provenance:defs.bzl", "ProductExecutableInfo") +load("//buck2/platforms:defs.bzl", "ProductPlatformInfo", "native_execution_constraints", "product_platform_constraints", "root_allow_cache_uploads", "root_remote_cache_enabled") +load("//buck2/provenance:defs.bzl", "ProductExecutableInfo", "product_executable_info") load("//buck2/toolchains:defs.bzl", "BunToolchainInfo") BuildProductInfo = provider(fields = { @@ -57,7 +58,7 @@ def _javascript_product_impl(ctx): args, category = "javascript_product_descriptor", local_only = True, - allow_cache_upload = False, + allow_cache_upload = root_remote_cache_enabled() and root_allow_cache_uploads(), ) return [ DefaultInfo( @@ -82,7 +83,7 @@ _javascript_product = rule( providers = [BunToolchainInfo], )), "_runner": attrs.default_only(attrs.dep( - default = "//:package_command_runtime", + default = "//packages/@overeng/buck2-tools:package_command_runtime", providers = [DefaultInfo], )), }, @@ -105,6 +106,133 @@ def javascript_product( **kwargs ) + +def _validate_relative_path(value, subject): + if not value or value.startswith("/"): + fail("{} must be a normalized relative path".format(subject)) + for component in value.split("/"): + if component == "" or component == "." or component == "..": + fail("{} must be a normalized relative path".format(subject)) + + +def _package_tree_product_executable_impl(ctx): + package_tree = ctx.attrs.package_tree[PackageTreeInfo] + target_platform = ctx.attrs.target_platform[ProductPlatformInfo] + platform_key = "{}-{}-{}".format( + target_platform.architecture, + target_platform.os, + target_platform.abi, + ) + executable_path = ctx.attrs.executable_paths.get(platform_key) + if executable_path == None: + fail("package_tree_product_executable has no executable path for {}".format(platform_key)) + _validate_relative_path(ctx.attrs.package_anchor, "package_tree_product_executable package anchor") + _validate_relative_path(executable_path, "package_tree_product_executable executable path") + # Package trees link dependency entries. Resolve the anchor's real store + # entry before materializing declared sibling files. + executable = ctx.actions.declare_output("executable") + anchor = cmd_args(package_tree.tree, format = "{}/" + ctx.attrs.package_anchor) + args = cmd_args([ + ctx.attrs._bun[BunToolchainInfo].executable, + "-e", + "import { chmod, realpath } from 'node:fs/promises'; import { dirname, join } from 'node:path'; const anchor = await realpath(process.argv[1]); await Bun.write(process.argv[3], Bun.file(join(dirname(anchor), process.argv[2]))); await chmod(process.argv[3], 0o555)", + anchor, + executable_path, + executable.as_output(), + ]) + args.add(cmd_args(hidden = package_tree.read_roots)) + ctx.actions.run( + args, + category = "package_tree_product_executable", + local_only = True, + allow_cache_upload = root_remote_cache_enabled() and root_allow_cache_uploads(), + ) + support_tree = None + support_directory_path = ctx.attrs.support_directory_paths.get(platform_key) + if support_directory_path != None: + _validate_relative_path(support_directory_path, "package_tree_product_executable support directory path") + _validate_relative_path(ctx.attrs.support_destination, "package_tree_product_executable support destination") + support_tree = ctx.actions.declare_output("support-tree", dir = True) + support_args = cmd_args([ + ctx.attrs._bun[BunToolchainInfo].executable, + "-e", + "import { mkdir, readdir, realpath } from 'node:fs/promises'; import { dirname, join, relative } from 'node:path'; const root = dirname(await realpath(process.argv[1])); const source = join(root, process.argv[2]); const executable = join(root, process.argv[3]); const output = join(process.argv[5], process.argv[4]); const copy = async (from, to) => { await mkdir(to, { recursive: true }); for (const entry of (await readdir(from, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) { const input = join(from, entry.name); const destination = join(to, entry.name); if (input === executable) continue; if (entry.isSymbolicLink()) throw new Error(`support tree contains symlink: ${relative(source, input)}`); if (entry.isDirectory()) await copy(input, destination); else if (entry.isFile()) await Bun.write(destination, Bun.file(input)); else throw new Error(`support tree contains special file: ${relative(source, input)}`); } }; await copy(source, output)", + anchor, + support_directory_path, + executable_path, + ctx.attrs.support_destination, + support_tree.as_output(), + ]) + support_args.add(cmd_args(hidden = package_tree.read_roots)) + ctx.actions.run( + support_args, + category = "package_tree_product_support", + local_only = True, + allow_cache_upload = root_remote_cache_enabled() and root_allow_cache_uploads(), + ) + product_executable = product_executable_info( + ctx, + executable, + ctx.attrs.recipe, + ctx.attrs.toolchain, + target_platform, + support_tree = support_tree, + ) + return [ + DefaultInfo( + default_output = executable, + other_outputs = [product_executable.provenance.artifact] + ([support_tree] if support_tree != None else []), + ), + product_executable, + ] + + +_package_tree_product_executable = rule( + impl = _package_tree_product_executable_impl, + attrs = { + "executable_paths": attrs.dict(key = attrs.string(), value = attrs.string()), + "package_tree": attrs.dep(providers = [PackageTreeInfo]), + "package_anchor": attrs.string(), + "support_destination": attrs.string(default = "support"), + "support_directory_paths": attrs.dict(key = attrs.string(), value = attrs.string(), default = {}), + "recipe": attrs.string(), + "target_platform": attrs.dep(providers = [ProductPlatformInfo]), + "toolchain": attrs.string(), + "_bun": attrs.default_only(attrs.exec_dep( + default = "//buck2/toolchains:bun", + providers = [BunToolchainInfo], + )), + }, +) + + +def package_tree_product_executable( + name, + package_tree, + package_anchor, + executable_paths, + recipe, + target_platform, + toolchain, + support_directory_paths = {}, + support_destination = "support", + **kwargs): + """Projects a platform executable from a lockfile-derived package tree.""" + _package_tree_product_executable( + name = name, + package_tree = package_tree, + executable_paths = executable_paths, + package_anchor = package_anchor, + recipe = recipe, + support_directory_paths = support_directory_paths, + support_destination = support_destination, + toolchain = toolchain, + target_platform = target_platform, + default_target_platform = target_platform, + target_compatible_with = product_platform_constraints(target_platform), + **kwargs + ) + def _build_product_impl(ctx): if not ctx.attrs.product_name: fail("build_product product_name must not be empty") @@ -149,6 +277,8 @@ def _build_product_impl(ctx): "--provenance", provenance.artifact, "--descriptor", descriptor.as_output(), ]) + if product_executable.support_tree != None: + args.add("--support-tree", product_executable.support_tree) # One action owns deterministic archive creation, native executable # inspection, and digesting the exact archive named by the descriptor. ctx.actions.run(args, category = "build_product_package", local_only = True) diff --git a/buck2/provenance/defs.bzl b/buck2/provenance/defs.bzl index 1aca7eae93..99b960cd89 100644 --- a/buck2/provenance/defs.bzl +++ b/buck2/provenance/defs.bzl @@ -10,6 +10,7 @@ BuildProvenanceInfo = provider(fields = { ProductExecutableInfo = provider(fields = { "executable": Artifact, + "support_tree": typing.Any, "provenance": provider_field(BuildProvenanceInfo), "target_platform_abi": str, "target_platform_architecture": str, @@ -17,7 +18,7 @@ ProductExecutableInfo = provider(fields = { "target_platform_runtime_contract": str, }) -def product_executable_info(ctx, executable, recipe, toolchain, target_platform): +def product_executable_info(ctx, executable, recipe, toolchain, target_platform, support_tree = None): """Builds the provider a language producer returns with its executable.""" for field, value in {"recipe": recipe, "toolchain": toolchain}.items(): if not value or "\n" in value or "\r" in value or "\x00" in value: @@ -35,6 +36,7 @@ def product_executable_info(ctx, executable, recipe, toolchain, target_platform) ) return ProductExecutableInfo( executable = executable, + support_tree = support_tree, provenance = provenance, target_platform_abi = target_platform.abi, target_platform_architecture = target_platform.architecture, diff --git a/buck2/static/BUCK b/buck2/static/BUCK new file mode 100644 index 0000000000..cf779c4721 --- /dev/null +++ b/buck2/static/BUCK @@ -0,0 +1,95 @@ +# Generated file - DO NOT EDIT +# Source: BUCK.genie.ts + +# Generated file - DO NOT EDIT +# Source: TypeScript admission package boundaries and root static source ownership + +load("//buck2:static_checks.bzl", "repository_static_checks") + +repository_static_checks( + name = "check", + declared_packages = [ + "context/effect/socket", + "context/opentui", + "packages/@overeng/agent-session-ingest", + "packages/@overeng/buck2-tools", + "packages/@overeng/ci-tools", + "packages/@overeng/content-address", + "packages/@overeng/effect-ai-claude-cli", + "packages/@overeng/effect-distributed-lock", + "packages/@overeng/effect-path", + "packages/@overeng/effect-react", + "packages/@overeng/effect-rpc-tanstack", + "packages/@overeng/effect-rpc-tanstack/examples/basic", + "packages/@overeng/effect-schema-form", + "packages/@overeng/effect-schema-form-aria", + "packages/@overeng/genie", + "packages/@overeng/gh-ci-utils", + "packages/@overeng/kdl", + "packages/@overeng/kdl-effect", + "packages/@overeng/megarepo", + "packages/@overeng/notion-cli", + "packages/@overeng/notion-core", + "packages/@overeng/notion-datasource-sync", + "packages/@overeng/notion-effect-client", + "packages/@overeng/notion-effect-schema", + "packages/@overeng/notion-md", + "packages/@overeng/notion-property-write", + "packages/@overeng/notion-react", + "packages/@overeng/npm-release", + "packages/@overeng/otel-contract", + "packages/@overeng/oxc-config", + "packages/@overeng/pty-effect", + "packages/@overeng/react-inspector", + "packages/@overeng/restate-effect", + "packages/@overeng/stylex-tokens", + "packages/@overeng/tui-core", + "packages/@overeng/tui-react", + "packages/@overeng/tui-stories", + "packages/@overeng/utils", + "packages/@overeng/utils-dev" +], + source_sets = [ + "//:static_sources", + "//context/effect/socket:static_sources", + "//context/opentui:static_sources", + "//packages/@overeng/agent-session-ingest:static_sources", + "//packages/@overeng/buck2-tools:static_sources", + "//packages/@overeng/ci-tools:static_sources", + "//packages/@overeng/content-address:static_sources", + "//packages/@overeng/effect-ai-claude-cli:static_sources", + "//packages/@overeng/effect-distributed-lock:static_sources", + "//packages/@overeng/effect-path:static_sources", + "//packages/@overeng/effect-react:static_sources", + "//packages/@overeng/effect-rpc-tanstack/examples/basic:static_sources", + "//packages/@overeng/effect-rpc-tanstack:static_sources", + "//packages/@overeng/effect-schema-form-aria:static_sources", + "//packages/@overeng/effect-schema-form:static_sources", + "//packages/@overeng/genie:static_sources", + "//packages/@overeng/gh-ci-utils:static_sources", + "//packages/@overeng/kdl-effect:static_sources", + "//packages/@overeng/kdl:static_sources", + "//packages/@overeng/megarepo:static_sources", + "//packages/@overeng/notion-cli:static_sources", + "//packages/@overeng/notion-core:static_sources", + "//packages/@overeng/notion-datasource-sync:static_sources", + "//packages/@overeng/notion-effect-client:static_sources", + "//packages/@overeng/notion-effect-schema:static_sources", + "//packages/@overeng/notion-md:static_sources", + "//packages/@overeng/notion-property-write:static_sources", + "//packages/@overeng/notion-react:static_sources", + "//packages/@overeng/npm-release:static_sources", + "//packages/@overeng/otel-contract:static_sources", + "//packages/@overeng/oxc-config:static_sources", + "//packages/@overeng/pty-effect:static_sources", + "//packages/@overeng/react-inspector:static_sources", + "//packages/@overeng/restate-effect:static_sources", + "//packages/@overeng/stylex-tokens:static_sources", + "//packages/@overeng/tui-core:static_sources", + "//packages/@overeng/tui-react:static_sources", + "//packages/@overeng/tui-stories:static_sources", + "//packages/@overeng/utils-dev:static_sources", + "//packages/@overeng/utils:static_sources" +], + visibility = ["PUBLIC"], +) diff --git a/buck2/static/BUCK.genie.ts b/buck2/static/BUCK.genie.ts new file mode 100644 index 0000000000..cd80737d6c --- /dev/null +++ b/buck2/static/BUCK.genie.ts @@ -0,0 +1,30 @@ +import { pnpmWorkspaceMemberPaths } from '../../genie/packages.ts' +import { createGenieOutput } from '../../packages/@overeng/genie/src/runtime/core.ts' + + +const declaredPackages = pnpmWorkspaceMemberPaths + +const sourceSets = [ + '//:static_sources', + ...pnpmWorkspaceMemberPaths.map((packagePath) => `//${packagePath}:static_sources`), +].toSorted() + +if (new Set(sourceSets).size !== sourceSets.length) { + throw new Error('Static source-set census contains duplicate Buck labels') +} + +export default createGenieOutput({ + data: { declaredPackages, sourceSets }, + stringify: () => `# Generated file - DO NOT EDIT +# Source: TypeScript admission package boundaries and root static source ownership + +load("//buck2:static_checks.bzl", "repository_static_checks") + +repository_static_checks( + name = "check", + declared_packages = ${JSON.stringify(declaredPackages, null, 4)}, + source_sets = ${JSON.stringify(sourceSets, null, 4)}, + visibility = ["PUBLIC"], +) +`, +}) diff --git a/buck2/static_checks.bzl b/buck2/static_checks.bzl new file mode 100644 index 0000000000..f74c82f21d --- /dev/null +++ b/buck2/static_checks.bzl @@ -0,0 +1,216 @@ +"""Repository-wide static checks over exact package-local source manifests.""" + +load("//buck2/platforms:defs.bzl", "root_allow_cache_uploads", "root_remote_cache_enabled") +load("//buck2/toolchains:configured.bzl", "BuckSupportToolInfo") +load("//buck2/toolchains:defs.bzl", "EffectTsgoToolchainInfo") + +STATIC_SOURCE_GLOBS = [ + "**/*.cjs", + "**/*.cts", + "**/*.css", + "**/*.gql", + "**/*.graphql", + "**/*.handlebars", + "**/*.hbs", + "**/*.html", + "**/*.js", + "**/*.json", + "**/*.json5", + "**/*.jsonc", + "**/*.jsx", + "**/*.less", + "**/*.markdown", + "**/*.md", + "**/*.mdx", + "**/*.mjs", + "**/*.mts", + "**/*.sass", + "**/*.scss", + "**/*.toml", + "**/*.ts", + "**/*.tsx", + "**/*.vue", + "**/*.yaml", + "**/*.yml", +] +STATIC_SOURCE_EXCLUDES = [ + "**/dist/**", + "**/node_modules/**", + "**/storybook-static/**", + "**/tmp/**", +] + +StaticSourceSetInfo = provider(fields = { + "files": provider_field(list[Artifact]), + "node_modules": provider_field(list[Artifact]), + "prefix": str, +}) + + +def _static_source_set_impl(ctx): + node_modules = [] if ctx.attrs.node_modules == None else ctx.attrs.node_modules[DefaultInfo].default_outputs + if len(node_modules) > 1: + fail("static source set node_modules dependency must expose exactly one tree") + return [ + DefaultInfo(), + StaticSourceSetInfo(files = ctx.attrs.srcs, node_modules = node_modules, prefix = ctx.attrs.prefix), + ] + + +_static_source_set = rule( + impl = _static_source_set_impl, + attrs = { + "prefix": attrs.string(), + "node_modules": attrs.option(attrs.dep(), default = None), + "srcs": attrs.list(attrs.source()), + }, +) + + +def static_source_set(name, prefix, srcs, node_modules = None, **kwargs): + """Declares one package boundary's governed static source files and dependency view.""" + _static_source_set(name = name, node_modules = node_modules, prefix = prefix, srcs = srcs, **kwargs) + +def _collect_static_sources(ctx, output, include_node_modules): + sources = {} + for source_set_target in ctx.attrs.source_sets: + source_set = source_set_target[StaticSourceSetInfo] + for source in source_set.files: + destination = source.short_path if not source_set.prefix else source_set.prefix + "/" + source.short_path + if destination in sources: + fail("duplicate static source destination: {}".format(destination)) + sources[destination] = source + if include_node_modules: + for node_modules in source_set.node_modules: + destination = source_set.prefix + "/node_modules" + if destination in sources: + fail("duplicate static dependency destination: {}".format(destination)) + sources[destination] = node_modules + return sources, ctx.actions.copied_dir(output, sources) + + +def _repository_static_check_impl(ctx): + tool = ctx.attrs.tool[BuckSupportToolInfo] + toolchain = ctx.attrs._javascript[EffectTsgoToolchainInfo] + sources, source_tree = _collect_static_sources(ctx, "source", True) + result = ctx.actions.declare_output("{}.json".format(ctx.attrs.name)) + args = cmd_args([ + toolchain.bun, + ctx.attrs._runner, + "--kind", + ctx.attrs.kind, + "--source", + source_tree, + "--tool", + tool.executable, + "--output", + result.as_output(), + ]) + for source_path in sorted(sources.keys()): + args.add("--path", source_path) + args.add(cmd_args(hidden = [source_tree, tool.manifest])) + ctx.actions.run( + args, + category = "{}_check".format(ctx.attrs.kind), + identifier = ctx.attrs.name, + local_only = True, + allow_cache_upload = root_remote_cache_enabled() and root_allow_cache_uploads(), + ) + return [DefaultInfo(default_output = result)] + + +_repository_static_check = rule( + impl = _repository_static_check_impl, + attrs = { + "kind": attrs.enum(["format", "lint"]), + "source_sets": attrs.list(attrs.dep(providers = [StaticSourceSetInfo])), + "tool": attrs.exec_dep(providers = [BuckSupportToolInfo]), + "_javascript": attrs.default_only(attrs.exec_dep( + default = "//buck2/toolchains:effect_tsgo", + providers = [EffectTsgoToolchainInfo], + )), + "_runner": attrs.default_only(attrs.source( + default = "//packages/@overeng/buck2-tools:src/static-check-runner.ts", + )), + }, +) + + +def _repository_policy_check_impl(ctx): + toolchain = ctx.attrs._javascript[EffectTsgoToolchainInfo] + sources, source_tree = _collect_static_sources(ctx, "policy_source", False) + manifest = ctx.actions.declare_output("policy_manifest.json") + ctx.actions.write_json(manifest, { + "declaredPackages": sorted(ctx.attrs.declared_packages), + "sourcePaths": sorted(sources.keys()), + }) + result = ctx.actions.declare_output("{}.json".format(ctx.attrs.name)) + ctx.actions.run( + cmd_args([ + toolchain.bun, + ctx.attrs._runner, + "--manifest", + manifest, + "--source", + source_tree, + "--output", + result.as_output(), + ], hidden = [source_tree]), + category = "repository_policy_check", + identifier = ctx.attrs.name, + local_only = True, + allow_cache_upload = root_remote_cache_enabled() and root_allow_cache_uploads(), + ) + return [DefaultInfo(default_output = result)] + + +_repository_policy_check = rule( + impl = _repository_policy_check_impl, + attrs = { + "declared_packages": attrs.list(attrs.string()), + "source_sets": attrs.list(attrs.dep(providers = [StaticSourceSetInfo])), + "_javascript": attrs.default_only(attrs.exec_dep( + default = "//buck2/toolchains:effect_tsgo", + providers = [EffectTsgoToolchainInfo], + )), + "_runner": attrs.default_only(attrs.source( + default = "//packages/@overeng/buck2-tools:src/repository-policy-runner.ts", + )), + }, +) + +def repository_static_checks( + name, + declared_packages, + source_sets, + **kwargs): + """Checks formatting, lint, and source policy against one repository snapshot.""" + _repository_static_check( + name = name + "_format", + kind = "format", + source_sets = source_sets, + tool = "//buck2/toolchains:tool_oxfmt", + **kwargs + ) + _repository_static_check( + name = name + "_lint", + kind = "lint", + source_sets = source_sets, + tool = "//buck2/toolchains:tool_oxlint", + **kwargs + ) + _repository_policy_check( + name = name + "_policy", + declared_packages = declared_packages, + source_sets = source_sets, + **kwargs + ) + native.filegroup( + name = name, + srcs = [ + ":" + name + "_format", + ":" + name + "_lint", + ":" + name + "_policy", + ], + **kwargs + ) diff --git a/buck2/toolchains/BUCK b/buck2/toolchains/BUCK index 02b178709a..4ac7cf2124 100644 --- a/buck2/toolchains/BUCK +++ b/buck2/toolchains/BUCK @@ -1,4 +1,4 @@ -load("//.buck2/capabilities:defs.bzl", "CAPABILITIES", "GENERATION") +load("@capabilities//:defs.bzl", "CAPABILITIES", "GENERATION") load("//buck2/platforms:defs.bzl", "host_platform_label") load("//buck2/toolchains:defs.bzl", "bun_toolchain", "configured_rust_toolchain", "effect_tsgo_toolchain", "host_rust_target_triple", "nix_go_bootstrap_toolchain", "nix_python_bootstrap_toolchain") load("//buck2/rust:toolchains.bzl", "native_rust_toolchains") @@ -46,6 +46,22 @@ support_tool( visibility = ["PUBLIC"], ) +# Source-static tools remain Nix-realized capabilities; Buck owns their declared +# repository inputs, invocation, invalidation, and result identity. +support_tool( + name = "tool_oxfmt", + protocol = "oxc/oxfmt/v1", + tool_id = "oxfmt", + visibility = ["PUBLIC"], +) + +support_tool( + name = "tool_oxlint", + protocol = "oxc/oxlint/v1", + tool_id = "oxlint", + visibility = ["PUBLIC"], +) + native_rust_toolchains( capabilities = CAPABILITIES, generation = GENERATION, @@ -89,7 +105,7 @@ effect_tsgo_toolchain( name = "effect_tsgo", capabilities = CAPABILITIES, generation = GENERATION, - runner = "//:packages/@overeng/buck2-tools/src/typescript-runner.ts", + runner = "//packages/@overeng/buck2-tools:typescript-runner.ts", visibility = ["PUBLIC"], ) diff --git a/buck2/toolchains/configured.bzl b/buck2/toolchains/configured.bzl index 64cbdc0492..162d372107 100644 --- a/buck2/toolchains/configured.bzl +++ b/buck2/toolchains/configured.bzl @@ -2,7 +2,7 @@ load("//buck2/platforms:defs.bzl", "host_execution_constraints") load("//buck2/toolchains:defs.bzl", "host_capability_platform") -load("//.buck2/capabilities:defs.bzl", "CAPABILITIES") +load("@capabilities//:defs.bzl", "CAPABILITIES") BuckSupportToolInfo = provider(fields = { "content_digest": str, @@ -56,7 +56,7 @@ _support_tool = rule( def support_tool(name, protocol, tool_id, **kwargs): platform = host_capability_platform() metadata = CAPABILITIES[platform][tool_id] - capability = "//.buck2/capabilities/generations/{}/{}/{}".format(metadata["generation"], platform, tool_id) + capability = "capabilities//generations/{}/{}/{}".format(metadata["generation"], platform, tool_id) _support_tool( name = name, content_digest = metadata["contentDigest"], diff --git a/context/buck2/.decisions/0005-operation-dependency-roots.md b/context/buck2/.decisions/0005-operation-dependency-roots.md index 2344d81802..d3857efcfd 100644 --- a/context/buck2/.decisions/0005-operation-dependency-roots.md +++ b/context/buck2/.decisions/0005-operation-dependency-roots.md @@ -85,5 +85,5 @@ is compile-time authoring safety, not runtime identity or a security boundary. observationally equivalent and avoid projection cycles. - Named shared root sets may be syntax sugar only if expanded before semantic identity. Output-data extraction remains migration-only. -- Rust retains authored Cargo manifests as request authority pending separate - Cargo/Reindeer experiments; this decision does not impose a universal schema. +- Rust retains authored Cargo manifests as request authority. Buck/Reindeer now resolves and builds + those requests without introducing a second dependency schema. diff --git a/context/buck2/.decisions/0028-hermetic-python-bootstrap-for-consumer-cells.md b/context/buck2/.decisions/0028-hermetic-python-bootstrap-for-consumer-cells.md index eb0ba81431..0f896ca23d 100644 --- a/context/buck2/.decisions/0028-hermetic-python-bootstrap-for-consumer-cells.md +++ b/context/buck2/.decisions/0028-hermetic-python-bootstrap-for-consumer-cells.md @@ -157,3 +157,31 @@ schema. by its own `contentDigest` instead of by whole-projection `GENERATION`, and whether the remaining top-level `rust-*`/`archive-tool`/`product` capabilities should also move under named authorities. + +## Amendment 1 — Nix Owns The Capability Projection + +Accepted 2026-09-17 for the standalone Buck root and aggregate cutover. + +The flake is now the sole producer of capability projection bytes. +`packages..buck2-capabilities` reads the tracked `buck2-member.json`, +realizes the manifest's `flakePackage` outputs, obtains each transitive runtime +closure through `pkgs.closureInfo`, and invokes the shared TypeScript projection +renderer in a pure derivation. The derivation does not invoke Nix recursively. + +The resolver remains the verification boundary, not a second producer. With +`MR_CAPABILITY_PROJECTION`, it checks the Nix output's platform, exact root and +tool BUCK bytes, manifests, executable digests and store paths, closure +membership, and generation identity. `mr apply` then atomically links that +verified output at the composition root's `.buck2/capabilities`. A standalone +devenv shell links the same output at the standalone root. Both roots declare +that directory as the `capabilities//` cell, and hub toolchains use only +cross-cell labels into it. + +This amendment supersedes the “mr's resolver is the sole producer” row and +paragraph above. The invariant remains one producer, one tool set, and one +generation digest; ownership moves from mr's imperative resolver path to the +flake's pure package output. The resolver and atomic installer remain +load-bearing consumers and verifiers. The legacy resolver projection path stays +available only through the absence of `MR_CAPABILITY_PROJECTION` until +composition adoption reaches L3; it is not used by the standalone or composed +effect-utils paths. diff --git a/context/buck2/.decisions/0035-source-side-generation-freshness-gate.md b/context/buck2/.decisions/0035-source-side-generation-freshness-gate.md new file mode 100644 index 0000000000..7e27201ea6 --- /dev/null +++ b/context/buck2/.decisions/0035-source-side-generation-freshness-gate.md @@ -0,0 +1,54 @@ +# Decision 0035: Source-side generation freshness gates Buck entrypoints + +## Status + +Accepted on 2026-09-11. + +## Problem + +Generated `BUCK`, composition, capability, dependency, and authority files define the graph Buck +analyzes. A target inside that graph cannot prove the graph is current: stale generation can omit the +target, omit an input, or preserve an old command and still report success. Making Buck run the +generator would also make the consumer of generated graph state a second producer of that state. + +## Decision + +`genie:check` remains an explicit source-side stage-zero operation and is classified +`outside-by-policy:stage-zero-bootstrap-freshness`. Every public task that enters the governed Buck +authority surface depends on this check before its Buck process starts. CI invokes the same task graph; +a stale projection therefore blocks the job before Buck analysis. + +The stage-zero check compares regenerated bytes in memory with committed projections. It does not +write files, compile products, inspect Buck outputs, or derive expectations from the graph it checks. +`genie:run` remains the only projection producer and stays an authoring mutation outside Buck. + +`buck2:editor:bootstrap` is the narrow pre-freshness exception required to make +that source-side closure runnable without a root install. It may only materialize +editor dependency views from committed generated targets; it reports no governed +build, test, lint, or product evidence. `genie:check` then validates those +committed projections before `mr:apply` and the authoritative editor publication +replay the fresh graph. A stale bootstrap graph may make freshness fail, but +cannot make a governed operation pass. + +Buck may validate deterministic generated artifacts whose source of truth is independent of Buck graph +generation, but it must not host the freshness proof for any file that can add, remove, or change the +proof target itself. + +## Consequences + +- Direct `buck2` CLI use is an expert bypass, not a public checked entrypoint. The documented task roots + carry freshness ordering. +- Generation freshness cannot be counted as a Buck-owned static operation. The disposition census + makes this exception reviewable instead of hiding it in orchestration. +- The editor-authority cutover preserves the runnable source-side Genie closure + through a committed-graph dependency bootstrap, not a root package-manager + installation. +- Freshness failure stops the entrypoint; Buck never runs against a graph already known to be stale. + +## Rejected alternatives + +- **A Buck freshness target:** circular authority; a stale graph can omit or weaken its own verifier. +- **Regenerate during Buck analysis:** turns read-only analysis into mutation and creates a second + producer race with `genie:run`. +- **Rely only on a parallel CI lint job:** merge blocking would catch drift eventually, but individual + Buck jobs could still publish false-green evidence from stale graph state. diff --git a/context/buck2/.decisions/0036-static-operation-authority-boundary.md b/context/buck2/.decisions/0036-static-operation-authority-boundary.md new file mode 100644 index 0000000000..10fc7f5ab2 --- /dev/null +++ b/context/buck2/.decisions/0036-static-operation-authority-boundary.md @@ -0,0 +1,58 @@ +# Decision 0036: Static operation authority follows bounded inputs + +## Status + +Accepted on 2026-09-11. + +## Problem + +The former CI static lanes mixed deterministic repository checks with package-manager installation, +change-relative history, Nix realization, and live integration. Treating each aggregate job as one +portable Buck action would either hide undeclared inputs or duplicate those external producers inside +Buck. + +## Decision + +Buck owns deterministic formatting, type-aware linting, repository policy, and the Vite/Rollup bundle +contract. Each action consumes generated package views or explicit repository source sets and publishes +one target-addressed result. Source tasks and CI call those targets; they do not retain alternate +implementations. + +The remaining aggregate boundaries are classified rather than disguised: + +- `lint:check` and the CI `lint` job remain outside Buck only because each aggregate includes the + stage-zero generation-freshness gate. Their deterministic lint members are Buck-owned, and the + editor-authority cutover removed the former root `pnpm install` producer. +- `default-ref-policy` remains an outside-Buck trust gate. It checks the checkout before composition, + because applying non-default first-party refs before rejecting them would execute the inputs the gate + exists to reject. +- The CI `weaver` job remains outside Buck because it deliberately combines a merge-base-relative API + diff, a live OTLP subprocess integration, and Nix-realized Weaver availability semantics. These are + not bounded repository-static actions. +- `source-shape` remains a CI measurement producer: its run-stamped comparison artifact is evidence, + not a reproducible build product. +- Generation freshness remains the stage-zero exception in Decision 0035. Default-ref policy is the + corresponding pre-composition trust-gate exception. + +## Consequences + +- `bundle:smoke` is a Buck Vitest lane over the normalized `@overeng/pty-effect` package view. Vite and + Rollup resolve only from that declared dependency closure. +- A package may publish multiple independently named Buck test lanes. Targets, task names, collection + artifacts, and cross-lane source ownership remain unique; package identity is not incorrectly treated + as the lane identity. +- Weaver policy remains visible in the operation-disposition artifact instead of producing false + hermeticity claims. +- Moving a remaining aggregate to `buck-owned` requires first splitting or eliminating its external + members. + +## Rejected alternatives + +- **Reimplement Weaver validation in TypeScript:** duplicates an upstream semantic validator and would + provide weaker evidence. +- **Run default-ref policy through composed Buck:** rejects invalid first-party refs only after + `mr:apply` has materialized and executed setup from them, reversing the trust boundary. +- **Let Buck invoke `nix build` or inspect the live Git merge base:** creates undeclared, mutable inputs + inside an action. +- **Call the whole lint job Buck-owned now:** its lockfile check still realizes and mutates the root pnpm + dependency topology. diff --git a/context/buck2/.experiments/2026-09-18-standalone-buck-root.md b/context/buck2/.experiments/2026-09-18-standalone-buck-root.md new file mode 100644 index 0000000000..c202029f7c --- /dev/null +++ b/context/buck2/.experiments/2026-09-18-standalone-buck-root.md @@ -0,0 +1,114 @@ +# Standalone Buck root + +Date: 2026-09-18 +Host: dev3 (x86_64-linux) + +## Question + +Does a plain effect-utils worktree build the admitted Buck graph without megarepo composition, and do the warm no-op, warm-cache/fresh-output, `check:quick`, and shell-entry measurements remain within the accepted budgets? + +## Method + +Run every Buck, Nix, and devenv command through `/srv/bulk/coding-agents/_briefs/buck2-heavy.sh`. Before each accepted sample, record `MemAvailable`, `user-1000.slice/memory.current`, and memory PSI `some avg60`. Measure at least three samples for each regime: + +1. `buck2 build //:quick` after an unchanged successful build. +2. `buck2 build //:quick` with a fresh Buck output directory and a warm remote cache. +3. `check:quick` before and after the standalone-root change. +4. `devenv shell -- true` after one untimed warm-up. + +Use a fresh `git worktree add` checkout with no megarepo state for the standalone samples. Use an `mr store worktree new` root only for the composed compatibility proof. Verify the deliberately broken admitted-package control and the unchanged rerun's local action count separately from the timing samples. + +## Result + +Revision `e2073b0882` passed the original standalone Buck proofs. Revision +`5b249696f4` then changed only the standalone root to Buck's `notify` watcher. +The branch was rebased onto current PR #1283 and reconciled at revision +`f8528ed38e`, preserving the current parent composition behavior. + +- A fresh detached Git worktree with no megarepo state built + `//packages/@overeng/tui-core:typecheck`. +- `mr store worktree new --commit e2073b0882` produced the compatibility-control + worktree, and the same target built there. +- The full `//:quick` aggregate completed from the plain worktree. +- After adding a deliberate `number`-to-`string` error to the admitted + `tui-core` source, `//:quick` failed at + `//packages/@overeng/tui-core:typecheck` with TS2322. Restoring the source + returned the worktree to a clean state. +- With Watchman, three unchanged reruns completed in 16-18 ms with no network + traffic and no scheduled command summary, which is Buck's zero-command + result. +- With `notify`, three unchanged reruns completed in 16-50 ms with the same + zero-command and zero-network result. + +All accepted samples ran through the shared heavy-command gate. The readings +below were captured immediately before each timed sample. + +| Watcher and regime | Elapsed samples | Resource readings before samples | Result | +| --- | --- | --- | --- | +| Watchman, unchanged `//:quick` | 17 ms, 18 ms, 16 ms; median 17 ms | `MemAvailable` 25,741,880 / 25,705,348 / 25,677,884 KiB; slice memory 84,167,573,504 / 84,169,175,040 / 84,181,024,768 bytes; PSI `some avg60` 0.78 / 0.78 / 0.78 | PASS: all samples are below the 5 s BUCK-R07 warm no-op budget | +| `notify`, unchanged `//:quick` | 17 ms, 50 ms, 16 ms; median 17 ms | `MemAvailable` 22,256,252 / 22,243,932 / 22,220,676 KiB; slice memory 82,014,629,888 / 82,013,585,408 / 82,014,101,504 bytes; PSI `some avg60` 0.72 / 0.72 / 0.72 | PASS: all samples are below the 5 s budget; no warm no-op regression | +| Watchman, fresh `buck-out`, warm shared cache | 18.077 s, 8.443 s, 6.412 s; median 8.443 s | `MemAvailable` 25,086,560 / 27,771,072 / 27,709,148 KiB; slice memory 81,304,829,952 / 82,396,282,880 / 82,268,454,912 bytes; PSI `some avg60` 1.38 / 1.08 / 0.95 | PASS: all samples are below the 3 min BUCK-R07 budget; each reported 1,208 cached commands, 100% cache hits, and zero local commands | +| `notify`, fresh `buck-out` | 18.726 s | `MemAvailable` 27,053,620 KiB; slice memory 79,179,030,528 bytes; PSI `some avg60` 1.37 | PASS: below 3 min; 1,208 commands, 668 cache hits (55%), and 540 local commands | +| sandboxed second context, fresh `HOME` / `TMPDIR` / hostname / uid / `buck-out` | 15 min 36.3 s | Heavy-command gate admitted the run; Buck reported 648 MiB peak process memory | FAIL BUCK-R16: 556 cached actions, 633 local actions, 561 other actions, and zero remote actions. Local classes were `package_tree`, `pnpm_store_entry`, `pnpm_store_scc`, `pnpm_store_view`, `tsgo_emit`, and `tsgo_typecheck`. The build later reached the same pre-existing `preferSchemaOverJson` warning and exited non-zero | +| dev4 aarch64 (informational), fresh `buck-out` | 64.2 s | dev4: 31 GiB total memory; 666 MiB peak process memory | INFORMATIONAL: 1,185 cached actions, 8 local actions, 561 other actions, and zero remote actions; local action classes included `package_tree`, `tsgo_typecheck`, and `tsgo_emit`. The build reached the pre-existing `preferSchemaOverJson` warning in `composition-root-publisher.integration.test.ts` and exited non-zero because tsgo treats the warning as exit 2 | +| Warm `devenv shell -- true` | 505 ms, 424 ms, 446 ms; median 446 ms | `MemAvailable` 25,855,352 / 25,799,616 / 25,786,556 KiB; slice memory 81,212,649,472 / 81,204,805,632 / 81,209,909,248 bytes; PSI `some avg60` 1.18 / 1.18 / 1.14 | PASS: all samples are below the 20 s shell-entry budget | + +The checked-in standalone root now uses `file_watcher = notify`. The composition +root generator continues to own and emit `file_watcher = watchman`. A regression +guard checks both choices. `notify` retains the 17 ms warm median, stays far +inside the 5 s budget, and avoids the shared Watchman daemon that previously +timed out during root synchronization. The single requested fresh `notify` +sample was 0.649 s slower than the slowest accepted Watchman fresh sample and +had a lower remote-cache hit rate, but it remained far inside the 3 min budget. + +The `check:quick` before/after control is the named **S14 mr-row deletion +dependency** under decision 0034. `check:quick` still runs `mr:*` gates that +cannot pass in a standalone worktree by construction. Amendment 3 defers their +deletion and the composed control to S14. The standalone `//:quick` fresh-output +and unchanged-rerun proofs above satisfy S8's aggregate acceptance; S8 makes no +`check:quick` wall-clock claim. + +Decision q40 / BUCK-R16 adds a same-platform second-context proof and an +informational cross-architecture observation. The sandbox used a fresh +`HOME`, `TMPDIR`, hostname (`other-host`), uid/gid (4242), and `buck-out` while +sharing only the checked-out revision, `/nix/store`, the Nix database, system +certificates, and the network. It produced 633 local actions, so the required +zero-local-action acceptance does not hold. `buck2 log what-ran` identified +`package_tree`, `pnpm_store_entry`, `pnpm_store_scc`, `pnpm_store_view`, +`tsgo_emit`, and `tsgo_typecheck` as the local action classes. Per q40, the +sandbox was not tuned further to hide this BUCK-R06 key-stability regression. + +The dev4 row is the cross-architecture evidence cited by the portable-product +question in `context/buck2/04-reuse/open-questions.md` on PR #1309. The +aarch64 keys were also not fully reusable: eight actions ran locally, across +`package_tree`, `tsgo_typecheck`, and `tsgo_emit`. This is informational and +does not change S8 acceptance. + +Strict VRS validation remains blocked by the pre-existing decision-shape errors +in decisions 0035 and 0036 (`Status:`, `Context`, `Evidence and Argument`, and +`Options` are absent according to the current strict schema). + +## Conclusion + +The standalone Buck root and aggregate meet the original BUCK-R07 warm and +fresh-context budgets. Shell entry also remains within its accepted budget. The +composed store-worktree target control and the broken-package control both +behave as required. `notify` does not regress warm no-op performance and +removes the standalone root's dependency on the flaky shared Watchman daemon. + +The new BUCK-R16 second-context proof does not achieve zero local actions: +633 actions ran locally. Under q40, this BUCK-R06 key-stability regression is +the finding and deliverable; no sandbox tuning was used to conceal it. +The `check:quick` composed control is deferred to the named S14 mr-row deletion +dependency by Amendment 3 and does not block S8. + +## VRS Impact + +This experiment closes the original S8 standalone-root, aggregate, watcher, +and shell-entry measurement gaps. It also records that the amended +same-platform cache-reuse requirement fails with 633 local actions. The open +[reuse delta](../04-reuse/.delta/DELTA-001-second-context-local-reexecution.md) +tracks that BUCK-R06/REUSE-R02 implementation divergence without changing +thresholds or authority. S14 owns deletion of the remaining +composition-dependent `check:quick` residual gates and its composed +before/after control. diff --git a/context/buck2/.experiments/2026-09-19-nativelink-remote-execution.md b/context/buck2/.experiments/2026-09-19-nativelink-remote-execution.md new file mode 100644 index 0000000000..54e7aa05d2 --- /dev/null +++ b/context/buck2/.experiments/2026-09-19-nativelink-remote-execution.md @@ -0,0 +1,123 @@ +# NativeLink action-level remote execution on dev4 + +Date: 2026-09-19 +Target revision: `948d397a2e09a3dc8556535eee5bb083717d3630` (`schickling-assistant/2026-09-15-quick-aggregate`) +Host: dev4 (`aarch64-linux`, 30 GiB RAM) + +## Question + +Can a fresh NativeLink CAS, action cache, scheduler, and one aarch64 worker execute +real `//:quick` graph actions remotely when Buck local execution is disabled, then +execute changed actions again and serve unchanged actions from the action cache? + +## Method + +1. Wait for dev4 after its incident #2914 reboot; use only an isolated clone and + `/srv/bulk/coding-agents/tmp/nativelink` or `/tmp` state. +2. Prefer `nixpkgs#nativelink`; when absent, realize NativeLink from its flake. +3. Apply the fixture patch, which adds an opt-in remote-only + `exec_linux_aarch64_remote` platform and relaxes the graph's explicit + `local_only = True` only when the experiment buckconfig enables RE. This was + necessary for `package_tree`, the three pnpm-store assembly classes, + `tsgo_typecheck`, `tsgo_emit`, Vitest collection, and the test executor. +4. Run one localhost NativeLink process with a verified filesystem CAS, filesystem + AC, scheduler, and one exactly-matched worker. Realize `.#buck2-capabilities` + on the same host and expose its complete `/nix/store` closure to the worker. +5. With a fresh service and fresh `buck-out`, run the content-address package's + typecheck, emit, and unit test plus `//:quick`; append a source comment and run + the three actions again; wipe only Buck local state and repeat unchanged. + Retain timings, NativeLink execution lines, and `buck2 log what-ran` per step. +6. Stop before action execution if obtaining NativeLink threatens the shared host. + +The action proof did not run: step 2 could not safely complete. The current +NativeLink flake (`45a3b1b`, Cargo version 1.7.1) failed on aarch64 while building +LLVM compiler-rt 22.1.8: `cpu_model/aarch64.c:51:10: fatal error: +'sys/auxv.h' file not found`. A retry with pinned NativeLink 1.6.6 +flake (`a21edb0f`) reached 1,819 build-log lines, requested 38,201,159,680 bytes of +auto-GC, and coincided with a separate dev4 NixOS CI build. The host reached 99% +root-disk use, about 1.0 GiB MemAvailable, 7.8/8.0 GiB swap, and memory PSI +`full avg60=58.80`; the retry was terminated before another reboot. + +## Fixtures + +- `2026-09-19-nativelink-remote-execution/nativelink.json5`: one 1 GiB verified + CAS (`verify_size` + `verify_hash`), 128 MiB AC, 1 GiB worker fast tier, + scheduler, worker, and localhost ports 51051/51061. +- `2026-09-19-nativelink-remote-execution/buckconfig.local`: all three REAPI + addresses, no TLS, isolated instance name, and remote-only platform selection. +- `2026-09-19-nativelink-remote-execution/remote-execution.patch`: opt-in platform + properties `platform=exec_linux_aarch64_remote`, `OSFamily=linux`, and + `cpu_arch=aarch64`, with defaults unchanged when the experiment config is absent. +- `2026-09-19-nativelink-remote-execution/run-dev4.sh`: acquisition, clean-state + matrix, evidence capture, source restoration, process stop, and state teardown. +- Buck documents the required client addresses and `CommandExecutorConfig` + fields at . The NativeLink + all-in-one topology follows + . + +## Result + +| Action | Fresh CAS: miss -> remote | Source changed -> remote | Unchanged + fresh Buck state -> AC hit | +| --- | --- | --- | --- | +| `tsgo_typecheck` (`content-address:typecheck`) | NOT RUN: NativeLink unrealized | NOT RUN | NOT RUN | +| `tsgo_emit` (`content-address:dist`) | NOT RUN: NativeLink unrealized | NOT RUN | NOT RUN | +| unit test (`content-address:test`) | NOT RUN: NativeLink unrealized | NOT RUN | NOT RUN | + +`//:quick` was also not invoked. There are no NativeLink worker logs, execution +metrics, or `buck2 log what-ran` claims to interpret as execution evidence. +Action-level RE is therefore **not proven or falsified**; the acquisition and +host-capacity prerequisites are falsified for this dev4 run. + +## Timing + +| Step | Wall time | Result | +| --- | ---: | --- | +| Wait for dev4 recovery | 23m 59s | five-minute probe 5 succeeded | +| NativeLink 1.7.1 flake realization | about 10m | deterministic compiler-rt failure | +| NativeLink 1.6.6 flake retry | 11m 13s | stopped at shared-host safety boundary | +| Buck action matrix | 0s | not reached | + +## What broke + +- nixpkgs on dev4 did not expose `nativelink`; the required flake path was not a + practical aarch64 acquisition path in this run. The latest pin failed; the + older pin's large uncached closure exhausted the remaining safe host envelope. +- The real graph is not platform-toggle-ready: execution platforms disable RE + (`buck2/platforms/defs.bzl:147-152`), TypeScript actions set `local_only` + (`buck2/typescript.bzl:49-55,103-109`), and tests install their own local-only + executor (`buck2/javascript.bzl:120-143`). The fixture patch also covers the + local-only pnpm/package-tree prerequisites identified by the 2026-09-18 run. +- Same-host workers can read the already-realized absolute `/nix/store` paths. + A different worker host would require the exact `nix path-info -r` closure to + be copied/substituted there before registration; REAPI input upload does not + transport those ambient absolute paths. +- No action ran, so HOME, pnpm-store, hostname assumptions and output-digest + equality against dev3's bazel-remote AC were not tested. Platform properties + also intentionally change the action identity, so AC keys are not directly + comparable; output bytes would need comparison after successful execution. +- The fixture deliberately has localhost-only plaintext gRPC and no auth. It is + an execution proof fixture, not an acceptable network deployment boundary. +- Teardown restored the clone, removed config/capability links and all experiment + state, removed the clone, and left neither process nor listener on 51051/51061. + +## Falsifiers + +- Feasibility remains open until a substituted/packageable aarch64 NativeLink + starts without violating dev4's disk and memory envelope. +- Any representative row with a local command, no worker `Executing command`, or + no remote line in `what-ran` falsifies remote-only execution. +- A changed input served as an AC hit, or an unchanged run executing again after + local-state wipe, falsifies the expected key/cache behavior. +- A missing `/nix/store` executable on the worker falsifies same-host capability + visibility; differing output bytes falsify cross-backend reproducibility. + +## Conclusion + +The experiment establishes a prepared action-level RE probe but no execution +verdict. NativeLink acquisition on aarch64 and safe dev4 capacity are blocking +prerequisites; no cache or execution result is claimed. + +## VRS Impact + +No requirement or decision changes. This evidence records an unresolved +execution proof and preserves the exact rerunnable fixture. diff --git a/context/buck2/.experiments/2026-09-19-nativelink-remote-execution/buckconfig.local b/context/buck2/.experiments/2026-09-19-nativelink-remote-execution/buckconfig.local new file mode 100644 index 0000000000..1892187c72 --- /dev/null +++ b/context/buck2/.experiments/2026-09-19-nativelink-remote-execution/buckconfig.local @@ -0,0 +1,15 @@ +[build] + execution_platforms = effect_utils//buck2/platforms:exec_linux_aarch64_remote + +[buck2] + remote_execution_enabled = true + remote_cache_enabled = true + allow_cache_uploads = true + +[buck2_re_client] + action_cache_address = grpc://127.0.0.1:51051 + cas_address = grpc://127.0.0.1:51051 + engine_address = grpc://127.0.0.1:51051 + http_headers = x-effect-utils-experiment: nativelink-remote-execution + instance_name = effect-utils-nativelink-re + tls = false diff --git a/context/buck2/.experiments/2026-09-19-nativelink-remote-execution/nativelink.json5 b/context/buck2/.experiments/2026-09-19-nativelink-remote-execution/nativelink.json5 new file mode 100644 index 0000000000..f80b3caa34 --- /dev/null +++ b/context/buck2/.experiments/2026-09-19-nativelink-remote-execution/nativelink.json5 @@ -0,0 +1,99 @@ +{ + stores: [ + { + name: "CAS_FILESYSTEM", + filesystem: { + content_path: "/srv/bulk/coding-agents/tmp/nativelink/cas/content", + temp_path: "/srv/bulk/coding-agents/tmp/nativelink/cas/temp", + eviction_policy: { max_bytes: 1073741824 }, + }, + }, + { + name: "CAS", + verify: { + backend: { ref_store: { name: "CAS_FILESYSTEM" } }, + verify_size: true, + verify_hash: true, + }, + }, + { + name: "AC", + filesystem: { + content_path: "/srv/bulk/coding-agents/tmp/nativelink/ac/content", + temp_path: "/srv/bulk/coding-agents/tmp/nativelink/ac/temp", + eviction_policy: { max_bytes: 134217728 }, + }, + }, + { + name: "WORKER_CAS", + fast_slow: { + fast: { + filesystem: { + content_path: "/srv/bulk/coding-agents/tmp/nativelink/worker-cas/content", + temp_path: "/srv/bulk/coding-agents/tmp/nativelink/worker-cas/temp", + eviction_policy: { max_bytes: 1073741824 }, + }, + }, + slow: { ref_store: { name: "CAS" } }, + }, + }, + ], + schedulers: [ + { + name: "MAIN_SCHEDULER", + simple: { + supported_platform_properties: { + platform: "exact", + OSFamily: "exact", + cpu_arch: "exact", + }, + }, + }, + ], + workers: [ + { + local: { + name: "dev4-aarch64", + worker_api_endpoint: { uri: "grpc://127.0.0.1:51061" }, + cas_fast_slow_store: "WORKER_CAS", + upload_action_result: { ac_store: "AC" }, + work_directory: "/srv/bulk/coding-agents/tmp/nativelink/worker", + platform_properties: { + platform: { values: ["exec_linux_aarch64_remote"] }, + OSFamily: { values: ["linux"] }, + cpu_arch: { values: ["aarch64"] }, + }, + }, + }, + ], + servers: [ + { + name: "client", + listener: { http: { socket_address: "127.0.0.1:51051" } }, + services: { + cas: [{ instance_name: "effect-utils-nativelink-re", cas_store: "CAS" }], + ac: [{ instance_name: "effect-utils-nativelink-re", ac_store: "AC" }], + bytestream: [{ instance_name: "effect-utils-nativelink-re", cas_store: "CAS" }], + execution: [{ + instance_name: "effect-utils-nativelink-re", + cas_store: "CAS", + scheduler: "MAIN_SCHEDULER", + }], + capabilities: [{ + instance_name: "effect-utils-nativelink-re", + remote_execution: { scheduler: "MAIN_SCHEDULER" }, + }], + health: {}, + }, + }, + { + name: "worker-api", + listener: { http: { socket_address: "127.0.0.1:51061" } }, + services: { + worker_api: { scheduler: "MAIN_SCHEDULER" }, + health: {}, + }, + }, + ], + global: { max_open_files: 24576 }, +} diff --git a/context/buck2/.experiments/2026-09-19-nativelink-remote-execution/remote-execution.patch b/context/buck2/.experiments/2026-09-19-nativelink-remote-execution/remote-execution.patch new file mode 100644 index 0000000000..879b70ef76 --- /dev/null +++ b/context/buck2/.experiments/2026-09-19-nativelink-remote-execution/remote-execution.patch @@ -0,0 +1,231 @@ +diff --git a/buck2/dependencies/defs.bzl b/buck2/dependencies/defs.bzl +index 02a323f1..ec85dae9 100644 +--- a/buck2/dependencies/defs.bzl ++++ b/buck2/dependencies/defs.bzl +@@ -43,6 +43,7 @@ maps have exactly the keys ``linux_x86_64``, ``linux_aarch64``, and + """ + + load("//buck2/toolchains:defs.bzl", "BunToolchainInfo") ++load("//buck2/platforms:defs.bzl", "root_remote_execution_enabled") + + PnpmPackageInfo = provider(fields = { + "bins": provider_field(dict[str, str]), +@@ -451,7 +452,7 @@ def _store_entry_impl(ctx): + args, + category = "pnpm_store_entry", + identifier = ctx.attrs.name, +- local_only = True, ++ local_only = not root_remote_execution_enabled(), + allow_cache_upload = True, + ) + return [ +@@ -565,7 +566,7 @@ def _store_scc_impl(ctx): + args, + category = "pnpm_store_scc", + identifier = ctx.attrs.name, +- local_only = True, ++ local_only = not root_remote_execution_enabled(), + allow_cache_upload = True, + ) + return [ +@@ -689,7 +690,7 @@ def _store_view_impl(ctx): + args, + category = "pnpm_store_view", + identifier = ctx.attrs.name, +- local_only = True, ++ local_only = not root_remote_execution_enabled(), + allow_cache_upload = True, + ) + return [ +diff --git a/buck2/javascript.bzl b/buck2/javascript.bzl +index 8cd28bb1..fe2ab4fe 100644 +--- a/buck2/javascript.bzl ++++ b/buck2/javascript.bzl +@@ -7,7 +7,7 @@ input. The runner hashes all declared inputs before and after execution. + load("//buck2/materialization.bzl", "PackageTreeInfo") + load("//buck2/toolchains:configured.bzl", "BuckSupportToolInfo") + load("//buck2/toolchains:defs.bzl", "EffectTsgoToolchainInfo") +-load("//buck2/platforms:defs.bzl", "root_allow_cache_uploads", "root_remote_cache_enabled") ++load("//buck2/platforms:defs.bzl", "linux_aarch64_remote_execution_properties", "root_allow_cache_uploads", "root_remote_cache_enabled", "root_remote_execution_enabled") + + JavaScriptExecutableInfo = provider(fields = { + "package_tree": Artifact, +@@ -123,6 +123,7 @@ def _test_info(ctx, command, positional): + fail("tests inheriting the environment must set cacheable = False") + cache_enabled = ctx.attrs.cacheable and root_remote_cache_enabled() + cache_uploads = ctx.attrs.cacheable and root_allow_cache_uploads() ++ remote_enabled = root_remote_execution_enabled() + return [ + DefaultInfo(), + RunInfo(args = args), +@@ -133,10 +134,12 @@ def _test_info(ctx, command, positional): + labels = ctx.attrs.labels, + contacts = ctx.attrs.contacts, + default_executor = CommandExecutorConfig( +- local_enabled = True, +- remote_enabled = False, ++ local_enabled = not remote_enabled, ++ remote_enabled = remote_enabled, + remote_cache_enabled = cache_enabled, + allow_cache_uploads = cache_uploads, ++ remote_execution_properties = linux_aarch64_remote_execution_properties(), ++ remote_output_paths = "output_paths", + ), + run_from_project_root = False, + use_project_relative_paths = False, +@@ -228,7 +231,7 @@ def _vitest_collect_impl(ctx): + args, + category = "vitest_collect", + identifier = ctx.attrs.name, +- local_only = True, ++ local_only = not root_remote_execution_enabled(), + allow_cache_upload = root_remote_cache_enabled() and root_allow_cache_uploads(), + ) + return [DefaultInfo(default_output = collection)] +diff --git a/buck2/materialization.bzl b/buck2/materialization.bzl +index 51aa2afd..47f3e67f 100644 +--- a/buck2/materialization.bzl ++++ b/buck2/materialization.bzl +@@ -2,6 +2,7 @@ + + load("//buck2/dependencies:defs.bzl", "PnpmDeclaredClosureInfo") + load("//buck2/toolchains:defs.bzl", "BunToolchainInfo") ++load("//buck2/platforms:defs.bzl", "root_remote_execution_enabled") + + + PackageTreeInfo = provider(fields = { +@@ -84,7 +85,7 @@ def _package_tree_impl(ctx): + args, + category = "package_tree", + identifier = ctx.attrs.name, +- local_only = True, ++ local_only = not root_remote_execution_enabled(), + allow_cache_upload = True, + ) + return [ +diff --git a/buck2/platforms/BUCK b/buck2/platforms/BUCK +index 067e0b6e..a9fd694d 100644 +--- a/buck2/platforms/BUCK ++++ b/buck2/platforms/BUCK +@@ -1,4 +1,4 @@ +-load("//buck2/platforms:defs.bzl", "host_execution_platform_label", "host_platform_label", "native_execution_platform", "portable_product_platform", "product_platform") ++load("//buck2/platforms:defs.bzl", "host_execution_platform_label", "host_platform_label", "native_execution_platform", "portable_product_platform", "product_platform", "remote_native_execution_platform") + + native_execution_platform( + name = "exec_linux_x86_64", +@@ -20,6 +20,17 @@ native_execution_platform( + visibility = ["PUBLIC"], + ) + ++remote_native_execution_platform( ++ name = "exec_linux_aarch64_remote", ++ constraint_values = [ ++ "prelude//abi/constraints:gnu", ++ "prelude//cpu/constraints:arm64", ++ "prelude//os/constraints:linux", ++ ], ++ visibility = ["PUBLIC"], ++) ++ ++ + native_execution_platform( + name = "exec_macos_aarch64", + constraint_values = [ +diff --git a/buck2/platforms/defs.bzl b/buck2/platforms/defs.bzl +index 9e5b1b0b..86dbf238 100644 +--- a/buck2/platforms/defs.bzl ++++ b/buck2/platforms/defs.bzl +@@ -136,6 +136,18 @@ def root_remote_cache_enabled(): + def root_allow_cache_uploads(): + return read_root_config("buck2", "allow_cache_uploads", "true") == "true" + ++def root_remote_execution_enabled(): ++ return read_root_config("buck2", "remote_execution_enabled", "false") == "true" ++ ++ ++def linux_aarch64_remote_execution_properties(): ++ return { ++ "platform": "exec_linux_aarch64_remote", ++ "OSFamily": "linux", ++ "cpu_arch": "aarch64", ++ } ++ ++ + def _native_execution_platform_impl(ctx): + constraints = {} + for dep in ctx.attrs.constraint_values: +@@ -170,6 +182,44 @@ native_execution_platform = rule( + }, + ) + ++def _remote_native_execution_platform_impl(ctx): ++ constraints = {} ++ for dep in ctx.attrs.constraint_values: ++ value = dep[ConstraintValueInfo] ++ constraints[value.setting.label] = value ++ configuration = ConfigurationInfo(constraints = constraints, values = {}) ++ platform = ExecutionPlatformInfo( ++ label = ctx.label.raw_target(), ++ configuration = configuration, ++ executor_config = CommandExecutorConfig( ++ local_enabled = False, ++ remote_enabled = True, ++ remote_cache_enabled = True, ++ allow_cache_uploads = True, ++ remote_execution_properties = linux_aarch64_remote_execution_properties(), ++ remote_output_paths = "output_paths", ++ use_windows_path_separators = False, ++ ), ++ ) ++ return [ ++ DefaultInfo(), ++ platform, ++ PlatformInfo(label = str(ctx.label.raw_target()), configuration = configuration), ++ ExecutionPlatformRegistrationInfo( ++ platforms = [platform], ++ exec_marker_constraint = get_exec_platform_marker(), ++ ), ++ ] ++ ++ ++remote_native_execution_platform = rule( ++ impl = _remote_native_execution_platform_impl, ++ attrs = { ++ "constraint_values": attrs.list(attrs.dep(providers = [ConstraintValueInfo])), ++ }, ++) ++ ++ + def host_platform_label(): + host = host_info() + if host.os.is_linux and host.arch.is_x86_64: +diff --git a/buck2/typescript.bzl b/buck2/typescript.bzl +index b9734253..06d1a5b3 100644 +--- a/buck2/typescript.bzl ++++ b/buck2/typescript.bzl +@@ -7,6 +7,7 @@ before and after execution so TypeScript actions remain write-free. + + load("//buck2/materialization.bzl", "PackageTreeInfo") + load("//buck2/toolchains:defs.bzl", "EffectTsgoToolchainInfo") ++load("//buck2/platforms:defs.bzl", "root_remote_execution_enabled") + + TsgoTypecheckInfo = provider(fields = { + "toolchain_identity": str, +@@ -50,7 +51,7 @@ def _tsgo_typecheck_impl(ctx): + args, + category = "tsgo_typecheck", + identifier = ctx.attrs.name, +- local_only = True, ++ local_only = not root_remote_execution_enabled(), + allow_cache_upload = True, + ) + return [ +@@ -104,7 +105,7 @@ def _tsgo_emit_impl(ctx): + args, + category = "tsgo_emit", + identifier = ctx.attrs.name, +- local_only = True, ++ local_only = not root_remote_execution_enabled(), + allow_cache_upload = True, + ) + return [ diff --git a/context/buck2/.experiments/2026-09-19-nativelink-remote-execution/run-dev4.sh b/context/buck2/.experiments/2026-09-19-nativelink-remote-execution/run-dev4.sh new file mode 100755 index 0000000000..8c4b50074c --- /dev/null +++ b/context/buck2/.experiments/2026-09-19-nativelink-remote-execution/run-dev4.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [ "$(uname -m)" != aarch64 ]; then + echo "run-dev4.sh requires aarch64-linux" >&2 + exit 2 +fi +if [ ! -f buck2/platforms/defs.bzl ] || [ ! -f flake.nix ]; then + echo "run from the effect-utils repository root" >&2 + exit 2 +fi + +fixture="$PWD/context/buck2/.experiments/2026-09-19-nativelink-remote-execution" +state=/srv/bulk/coding-agents/tmp/nativelink +evidence=/tmp/nativelink-remote-execution-evidence +archive=/tmp/nativelink-remote-execution-evidence.tar.gz +source_input=packages/@overeng/content-address/src/mod.ts +native_pid= + +rm -rf "$state" "$evidence" "$archive" +mkdir -p "$state" "$evidence" +exec > >(tee -a "$evidence/orchestrator.log") 2>&1 + +cleanup() { + status=$? + trap - EXIT INT TERM + set +e + if [ -n "$native_pid" ] && kill -0 "$native_pid" 2>/dev/null; then + kill "$native_pid" + wait "$native_pid" + fi + git restore buck2/dependencies/defs.bzl buck2/javascript.bzl buck2/materialization.bzl buck2/platforms/BUCK buck2/platforms/defs.bzl buck2/typescript.bzl "$source_input" + rm -f .buckconfig.local .buck2/capabilities + tar -C "$evidence" -czf "$archive" . + rm -rf "$state" + echo "evidence: $archive" + exit "$status" +} +trap cleanup EXIT INT TERM + +if ! git diff --quiet; then + echo "tracked worktree changes present before experiment" >&2 + exit 2 +fi +if ss -ltn | grep -Eq '127\.0\.0\.1:(51051|51061) '; then + echo "NativeLink experiment port already occupied" >&2 + exit 2 +fi + +git apply --check "$fixture/remote-execution.patch" +git apply "$fixture/remote-execution.patch" +cp "$fixture/buckconfig.local" .buckconfig.local + +nativelink_ref=${NATIVELINK_REF:-nixpkgs#nativelink} +if [ "$nativelink_ref" = nixpkgs#nativelink ] && ! nix eval --raw "$nativelink_ref.outPath" >/dev/null 2>&1; then + nativelink_ref=github:TraceMachina/nativelink/a21edb0fc56879124e308bb9a67be679f8eaf885#nativelink +fi +printf 'NativeLink source: %s\n' "$nativelink_ref" | tee "$evidence/versions.txt" +nativelink_out=$(nix build --no-link --print-out-paths "$nativelink_ref") +buck2_out=$(nix build --no-link --print-out-paths .#buck2) +capabilities_out=$(nix build --no-link --print-out-paths .#buck2-capabilities) +nativelink_bin="$nativelink_out/bin/nativelink" +buck2_bin="$buck2_out/bin/buck2" +{ + "$nativelink_bin" --version || true + "$buck2_bin" --version + printf 'capabilities=%s\n' "$capabilities_out" + nix path-info -r "$capabilities_out" +} | tee -a "$evidence/versions.txt" + +mkdir -p .buck2 +ln -s "$capabilities_out" .buck2/capabilities + +RUST_LOG='info,nativelink_worker=debug,nativelink_scheduler=debug' \ + nohup "$nativelink_bin" "$fixture/nativelink.json5" \ + >"$evidence/nativelink.log" 2>&1 & +native_pid=$! +printf '%s\n' "$native_pid" >"$evidence/nativelink.pid" + +ready=false +for _ in $(seq 1 60); do + if ! kill -0 "$native_pid" 2>/dev/null; then + echo "NativeLink exited during startup" >&2 + break + fi + if (exec 3<>/dev/tcp/127.0.0.1/51051) 2>/dev/null && (exec 3<>/dev/tcp/127.0.0.1/51061) 2>/dev/null; then + ready=true + break + fi + sleep 1 +done +if [ "$ready" != true ]; then + cat "$evidence/nativelink.log" + exit 1 +fi + +buck2() { + "$buck2_bin" --isolation-dir=nativelink-re "$@" +} + +fresh_buck_state() { + buck2 kill >/dev/null 2>&1 || true + rm -rf buck-out +} + +run_buck() { + label=$1 + shift + start_ms=$(date +%s%3N) + set +e + buck2 "$@" >"$evidence/$label.stdout.log" 2>"$evidence/$label.stderr.log" + status=$? + set -e + end_ms=$(date +%s%3N) + elapsed_ms=$((end_ms - start_ms)) + set +e + buck2 log what-ran >"$evidence/$label.what-ran.txt" 2>&1 + what_ran_status=$? + set -e + native_log_lines=$(wc -l <"$evidence/nativelink.log") + printf '%s\t%s\t%s\t%s\t%s\n' "$label" "$elapsed_ms" "$status" "$what_ran_status" "$native_log_lines" | tee -a "$evidence/timings.tsv" +} + +printf 'step\telapsed_ms\tcommand_status\twhat_ran_status\tnativelink_log_lines\n' >"$evidence/timings.tsv" + +# Cold server state plus a cold Buck state proves execution rather than reuse. +fresh_buck_state +run_buck miss-typecheck build //packages/@overeng/content-address:typecheck +run_buck miss-emit build //packages/@overeng/content-address:dist +run_buck miss-test test //packages/@overeng/content-address:test +run_buck miss-quick build //:quick + +# A declared source change creates new action keys while the NativeLink service stays warm. +printf '\n// nativelink remote-execution invalidation probe\n' >>"$source_input" +run_buck changed-typecheck build //packages/@overeng/content-address:typecheck +run_buck changed-emit build //packages/@overeng/content-address:dist +run_buck changed-test test //packages/@overeng/content-address:test + +# Wipe Buck's local state but leave NativeLink intact; identical keys must be AC hits. +fresh_buck_state +run_buck unchanged-typecheck build //packages/@overeng/content-address:typecheck +run_buck unchanged-emit build //packages/@overeng/content-address:dist +run_buck unchanged-test test //packages/@overeng/content-address:test + +# Keep concise machine-readable proof alongside the full logs. +grep -nE 'Worker registered with scheduler|Received request to run action|Executing command|Command complete|No candidate workers' \ + "$evidence/nativelink.log" >"$evidence/nativelink-execution-lines.txt" || true +grep -HnE 'tsgo_typecheck|tsgo_emit|vitest|Remote|Cache|remote|cache' \ + "$evidence"/*.what-ran.txt >"$evidence/what-ran-summary.txt" || true diff --git a/context/buck2/02-execution/.experiments/2026-09-11-buck-owned-unit-tests.md b/context/buck2/02-execution/.experiments/2026-09-11-buck-owned-unit-tests.md index ce631b9b42..6e00674280 100644 --- a/context/buck2/02-execution/.experiments/2026-09-11-buck-owned-unit-tests.md +++ b/context/buck2/02-execution/.experiments/2026-09-11-buck-owned-unit-tests.md @@ -63,6 +63,34 @@ Source-only package partition: The three counts are disjoint and total the 433-file repository census. +### Follow-up admission — `@overeng/effect-schema-form-aria` (2026-09-12) + +The original totals above are the accepted proof snapshot. At the exact +`24ce88a08c729df567689260300ed5c767f8fb58` baseline, later test additions had +grown the repository census to 435 files and the registry to 33 lanes. The +source-only partition contained 14 files: 13 in `@overeng/buck2-tools` and the +sole collectable `@overeng/effect-schema-form-aria` test, +`src/mod.unit.test.tsx`. The latter package had no test lane in its local +`BUCK.genie.ts` and no row in `buck2-test-authority.json`, so the derived +source-side `test:effect-schema-form-aria` task was its sole producer. + +The package-local admission now projects the default Vitest execution and +collection targets over that exact one-file census. The lane has no excludes, +explicit source owners, or generic unbounded files, so its source complement is +empty and source Vitest no longer schedules the package. The story files are +not Vitest test modules and remain outside this census; there are no package +integration or Playwright test files to assign. The registry now carries 34 +lanes, and the only source-only test package is `@overeng/buck2-tools` with its +13 files; the repository census remains 435. + +#### Deletion ledger + +- Removed the package from the derived source-only test-package partition by + admitting its complete collectable census to Buck. +- Added no fallback or duplicate source producer: an empty complement projects + no `test:effect-schema-form-aria:unbounded` task, while the public + `test:effect-schema-form-aria` task now addresses the Buck lane. + ### Deliberate constraints - Duplicate and nested lane packages are rejected in generation and the runtime decoder. Adding an overlapping lane is a hard failure, not ambiguous ownership. diff --git a/context/buck2/02-execution/.experiments/2026-09-11-complete-typescript-authority.md b/context/buck2/02-execution/.experiments/2026-09-11-complete-typescript-authority.md new file mode 100644 index 0000000000..3b2527f711 --- /dev/null +++ b/context/buck2/02-execution/.experiments/2026-09-11-complete-typescript-authority.md @@ -0,0 +1,51 @@ +# Complete TypeScript Authority + +Status: accepted +Date: 2026-09-11 + +## Question + +Can Buck become the sole TypeScript checker and declaration producer for every repository project, including independent strict-consumer projects and the source tools that generate the Buck graph, without retaining a root compiler fallback? + +## Method + +The package-local TypeScript projection now declares one or more project authorities. Each project owns its project file and typecheck target; at most one project in a package may own declaration publication. One registry derives the complete check plan and its declaration-producing subset. + +The transfer admitted the ten-project residual: the two context examples, effect-schema-form-aria, the effect-rpc-tanstack basic example, React Inspector's independent strict consumer, buck2-tools, Genie, kdl-effect, megarepo, and tui-stories. The old root check and emit solutions and their devenv tasks were deleted in the same tranche. The remaining root `tsconfig.lint.json` is a lint program, not a compiler producer. + +Bootstrap-critical projects use an explicit stage-zero boundary: the already available source Genie executable writes the committed Buck graph before Buck analysis. No Buck target generates the graph that defines itself. Once generated, Genie, kdl-effect, megarepo, buck2-tools, and tui-stories are checked and emitted only by their package-local Buck targets. + +Proof used the synthesized composition at `/tmp/effect-utils-unit-proof-fresh`, the composition-owned Buck wrapper, pinned Bun/effect-tsgo toolchains, and local-only execution. The declaration runtime then built and atomically published every emitting target. A negative control inserted `const buckAuthorityNegativeProof: string = 42` into the admitted socket project, built only that package's typecheck target, restored the source, and rebuilt the target. + +## Result + +- **Complete registry PASS:** the authority registry contains 39 unique TypeScript projects. Its declaration subset contains 35 unique publishers. +- **Complete check PASS:** `typescript-authority-runtime.ts build` successfully built the complete 39-project check plan plus the governed test/toolchain targets in the synthesized composition. The final post-cleanup proof executed 72 local commands in 47.33 seconds, used no remote execution, and reported `BUILD SUCCEEDED`. +- **Strict consumer PASS:** `effect_utils//packages/@overeng/react-inspector:strict_consumer_typecheck` built successfully as an independent project target. +- **Declaration publication PASS:** `typescript-authority-runtime.ts materialize-dist` built and atomically published all 35 declaration targets. Every target reported `BUILD SUCCEEDED`; total wall time was 89.65 seconds. Publication validates each declared entrypoint before accepting the tree. +- **Negative control PASS:** the socket mutation failed `effect_utils//context/effect/socket:typecheck` with TS2322, `Type 'number' is not assignable to type 'string'`. After restoration, the same target succeeded. +- **Authority unit PASS:** the projection, admission, runtime-plan, and runtime-closure suites passed 55/55 tests. The declaration runner suite passed 12/12 tests. The focused atomic publisher cases passed 4/4 rollback and replacement scenarios. +- **Legacy deletion PASS:** the active devenv, CI, editor-task, README, AGENTS, and script surfaces contain no positive invocation of `ts:check`, `ts:check:strict`, `ts:build`, `ts:build-watch`, `ts:emit`, `tsconfig.check.json`, or `tsconfig.emit.json`. The task-graph guard retains those names only to assert that they are absent. +- **Bootstrap boundary PASS:** direct stage-zero Genie generation completed before the synthetic Buck proof. All five bootstrap-critical projects participate in the successful 39-project Buck plan; there is no root TypeScript execution path to mask a failed Buck project. + +### Deliberate constraints + +- The shared exported Nix TypeScript task module remains available to downstream repositories. This repository no longer imports it; deleting a reusable downstream API is not part of transferring this repository's authority. +- Declaration publication remains a deliberate filesystem projection outside the Buck action. Buck is the only producer; the wrapper only validates and atomically swaps Buck output into package `dist` paths consumed by source tools and editors. +- Full local Nix builds were not run because the host root filesystem was at its safety threshold. The proof instead used direct generator execution, unit suites, the synthesized Buck runtime, explicit negative causality, and end-to-end declaration publication. + +### Complexity reconciliation + +The final stack was measured against `11e463` with documentation, tests, and lockfiles excluded. The remaining implementation diff is +18,479/-5,809 lines, net +12,670. Source-authored machinery accounts for +9,997/-4,178, net +5,819. Committed projections account for +8,482/-1,631, net +6,851. The projection class includes generated `BUCK`, package, TypeScript, CI, editor, authority, release-target, and product-manifest files. These files stay committed because they are the reviewable and reproducible interface consumed before Genie or Buck can run. + +The source cost is shared across 39 TypeScript projects, 35 declaration publishers, 11 JavaScript products, and three native products published for three platforms. The generated majority is therefore not a second implementation. It is the checked-in expansion of those shared registries and rules. + +At implementation head `7c8f81825` (immediately before this evidence-only update), an isolated local-only build of all 11 JavaScript product descriptors, with remote action caching disabled, executed 919 local actions in 13.3 seconds after `buck2 clean` and transferred 57 MiB of package inputs. An immediate repeat executed no actions, transferred no data, and completed in 0.6 seconds. The native TypeScript API server was also built on x86_64 Linux, aarch64 Linux, and aarch64 Darwin; the Darwin build completed 599 local actions in approximately 59 seconds. + +## Conclusion + +The repository has one TypeScript producer. Buck checks all 39 projects and emits all 35 declaration products; strict-consumer and bootstrap-critical projects are first-class targets rather than exceptions. Root compiler execution, residual project membership, source-mode declaration fallback, and duplicate check/emit task edges are absent. + +## VRS Impact + +Completes the TypeScript execution portion of BUCK-R06, BUCK-R09, BUCK-R12, and BUCK-R16. Static-operation, editor-view/root-install, platform/Rust, and composed-consumer authority remain separate tranches. diff --git a/context/buck2/03-materialization/.experiments/2026-09-11-workspace-editor-authority.md b/context/buck2/03-materialization/.experiments/2026-09-11-workspace-editor-authority.md new file mode 100644 index 0000000000..cffeeb6640 --- /dev/null +++ b/context/buck2/03-materialization/.experiments/2026-09-11-workspace-editor-authority.md @@ -0,0 +1,82 @@ +# Workspace Editor Authority + +Date: 2026-09-11 — Host: dev3 (x86_64-linux) — Buck2 2026-09-01. + +## Question + +Does the package-local editor mechanism cover the complete admitted workspace, +and can a real package consumer resolve through the published Buck view without +a root dependency installation? + +## Method + +1. Derived the editor plan and ownership requirement from the root source-generator + consumer plus the canonical workspace package registry. +2. Queried Buck for every `:editor_view_inputs` target under the effect-utils + cell. +3. Built the tui-core manifest, published its finite declared-root snapshot, + and ran the staleness checker against that snapshot. +4. Temporarily removed the repository-root `node_modules` link and ran tsgo + against tui-core's package tsconfig through its published package-local view. +5. Built and published the oxc-config view, then ran the repository-wide Buck + static aggregate. This exercises a JavaScript lint plugin loaded from the + source checkout while its dependency resolves through package-local + `node_modules`. +6. Published the root source-generator view from the committed graph, ran + `genie:check`, regenerated the two expected changed authority projections, + and proved all 148 generated files fresh. +7. Replayed authoritative publication from the fresh graph and checked every + root and package view. +8. Ran the native PTY source complement through the package view with an + immutable Nix `node-pty` resolver hook rather than mutating `node_modules`. +9. Ran the focused orchestration, ownership, publication, retention, + package-projection, generator-census, pnpm-module, and static-authority checks. + +## Result + +- The source registry exposes 38 package editor manifests and the root + source-generator consumer, for 39 authoritative consumers. The nested + `effect-rpc-tanstack/examples/basic` package is independently admitted; its + parent static source set excludes `examples/basic/**`, so ownership does not + overlap. +- Tui-core publish and immediate check both succeeded. With root + `node_modules` absent, `tsgo --noEmit -p packages/@overeng/tui-core/tsconfig.json` + exited 0. +- The first static run failed because oxc-config had no package-local view and + therefore could not resolve `@stylexjs/eslint-plugin`. Publishing the + oxc-config view fixed that real consumer boundary. The unchanged + `effect_utils//buck2/static:check` invocation then succeeded. +- Committed-graph bootstrap published 39 views. Root `node_modules` became + `.editor-view/root/node_modules`; source-side Genie ran through it without a + root package-manager install. Fresh-graph publication and the independent + checker both covered all 39 consumers. +- A committed-tree cold archive with no `node_modules` ran all 42 marked + bootstrap-phase generators through the existing packaged Genie binary; none + errored. +- The native PTY complement passed 23 tests with one skipped through the Nix + resolver hook. The combined editor/generator suite passed 109 tests with + 3,533 assertions; the pnpm module smoke suite passed; the complete Buck + static authority built successfully. +- Nix syntax evaluation of `devenv.nix` and both changed task modules succeeded. + Direct module evaluation proved both Nix hash-check prerequisite arrays empty + when dependency publication is disabled. No Nix build or devenv task + invocation was run because available root space remained below the enforced + 200 GB policy floor. + +## Conclusion + +The workspace publication product is derived from one complete +root-plus-package registry rather than package-specific task wiring. Runtime +evidence covers committed-graph bootstrap, source-generation freshness, +fresh-graph publication and checking, root-install-independent TypeScript and +JavaScript consumers, and native source tests without mutable dependency-tree +grafting. The previous continuously attached Neovim/vtsls soak remains the live +language-server evidence for the same atomic pointer and settle-signal mechanism. + +## VRS Impact + +Closes the package and root source-generator surface of decision 0015, +supersedes the old `tui-core`-only task contract, and completes the root +package-manager installation producer deletion. Decision 0035 records the +narrow committed-graph bootstrap exception that keeps source freshness +non-circular. diff --git a/context/buck2/03-materialization/spec.md b/context/buck2/03-materialization/spec.md index 9be9dd0542..360cfdf8a6 100644 --- a/context/buck2/03-materialization/spec.md +++ b/context/buck2/03-materialization/spec.md @@ -68,94 +68,96 @@ DEPS-R02. ## Editor Surface +The repository-root source-generator consumer and each admitted workspace +package `` expose `:` as their canonical Buck dependency +view and `:editor_view_inputs` as the manifest joining that view, the package +tree, and every provider-declared backing root. The stable filesystem shapes are: + ```text -packages/@overeng/tui-core/node_modules - -> ../../.editor-view/tui-core/node_modules (stable first hop) -packages/.editor-view/tui-core - -> .store/tui-core- (atomic current pointer) -packages/.editor-view/.store/tui-core-/ +/node_modules + -> ../../.editor-view//node_modules +/../../.editor-view/ + -> .store/- +/../../.editor-view/.store/-/ editor-view.json - node_modules/ (hardlink snapshot) + node_modules/ + .backing/ ``` -The literal two-level first hop is part of the scoped contract. From -`packages/@overeng/tui-core` it resolves to `packages/.editor-view`, not the -repository-root `.editor-view`; `packages/.editor-view` is therefore the owning -state root for scoped `packages/@overeng/*` editor views. - -`//packages/@overeng/tui-core:editor_inputs` exposes the canonical Stage-1 -descriptor tree carried by `PnpmNodeModulesInfo.editor_inputs`. The existing -`:node_modules` default output and provider identity remain valid. The -publisher fingerprints the built `:editor_inputs` artifact rather than -reimplementing manifest discovery. - -Every published snapshot contains this repository-local record: - -```json -{ - "schema": "effect-utils/editor-view/v1", - "package": "packages/@overeng/tui-core", - "cell": "tui-core", - "target": "//packages/@overeng/tui-core:editor_inputs", - "editorInputsFingerprint": "", - "snapshot": ".store/tui-core-", - "nodeModulesTreeDigest": "" -} +```text +node_modules + -> .editor-view/root/node_modules +.editor-view/root + -> .store/root- ``` -The tree digest begins with the `effect-utils/tree-digest/v1` domain separator. -Entries are traversed by unsigned UTF-8 byte order. Each entry frames its kind -and repository-relative path with an unsigned 64-bit big-endian byte length; -regular files additionally frame size then bytes, symlinks frame their target, -and directories frame their own entry. Unsupported special files and entries that mutate while hashing fail closed. - -Publication holds the exclusive `packages/.editor-view/.publish.lock`, created -atomically. Any existing lock rejects publication immediately and prints the -explicit token-gated `recover-lock` operation; there is no age heuristic, -sleep, timeout, or automatic stale-lock theft. Under the lock the publisher: - -1. hashes the admitted `editor_inputs` and `node_modules` outputs; -2. creates same-filesystem `.store/.candidate-*` state; -3. invokes the immutable Nix GNU `cp -al` without a byte-copy fallback; -4. verifies every regular file shares device and inode with the admitted tree, - verifies the complete candidate digest, and writes `editor-view.json`; -5. renames the candidate to deterministic - `.store/tui-core-`; -6. creates a same-directory candidate symlink and renames it over `tui-core`; -7. installs the package first hop once. If root pnpm left a directory or other - entry there, immutable Nix GNU `mv --exchange --no-copy` swaps it with the - candidate link without an absent-path window, and the exchanged entry is - retained under `.legacy/`. - -An already-correct first hop is validated and never mutated during later -refreshes. Published snapshots are immutable and are never deleted by publish, -check, or lock recovery; snapshot garbage collection is outside this spec. A -failure before the current-pointer rename leaves the old current view intact. - -The flip target is a `cp -al` snapshot of the action output, not `buck-out` -itself: Buck deletes an action's output directory before re-running it, which -would leave the stable link dangling for the whole action (measured 3.06 s -window). Hardlink snapshot publication closes that window without duplicating -file bytes. +Package consumers share a two-level state root; the root source-generator +consumer uses the repository-local `.editor-view/root` state. Every published +link remains inside the repository while context packages, +`packages/@overeng/*`, nested workspace packages, and root generators use the +same publisher. + +Each schema-v2 record binds the package, Buck cell and target, selected +`editor_inputs` fingerprint, normalized declared-root digest, exact selected +view digest, exact byte-owned snapshot digest, and deterministic snapshot name. +Tree digests use the `effect-utils/tree-digest/v1` domain separator, unsigned +UTF-8 byte ordering, length framing, and fail-closed checks for special or +concurrently changing files. + +Before publication, `buck2:editor:authority` compares the canonical admission +registry with tracked package manifests and a Buck `owner(...)` census. The +resulting authority file must name identical required and owned package sets; +every package publication validates it. + +Publication holds the exclusive state-root `.publish.lock`, created atomically. +An existing lock fails immediately and prints the explicit token-gated recovery +operation. There is no age heuristic, timeout, or automatic lock theft. Under +the lock, the publisher: + +1. fingerprints the selected dependency view and finite declared roots; +2. recursively copies the selected view and disjoint backing roots into a + same-filesystem candidate with dereferenced, byte-owned regular files; +3. relocates internal links into `.backing/`, rejects links outside the declared + roots, and proves no snapshot file shares an inode with a disposable source; +4. verifies the complete payload digest and writes `editor-view.json`; +5. hardens the candidate read-only and renames it to the deterministic snapshot; +6. atomically renames the current pointer, installs or validates the package + first hop, and emits the package-manifest settle signal required by live + language servers; +7. checks the published view, updates its retention record, and garbage-collects + snapshots outside the configured finite retention set. + +If a legacy root install occupies the first hop, immutable GNU +`mv --exchange --no-copy` installs the symlink without an absent-path window and +retains the exchanged entry under `.legacy/`. A failure before the pointer flip +leaves the prior current view intact. Snapshot payloads never retain links into +`buck-out`, whose action directories Buck may delete before rebuilding. ## Staleness Gate -The scoped `buck2:tui-core:publish-editor` and -`buck2:tui-core:check-editor` tasks each build the current `:editor_inputs` and -`:node_modules` outputs with a task-private Buck daemon into ignored scratch, -then stop the daemon and remove both scratch and its private Buck output. They -call the pinned Bun publisher or checker respectively. The checker validates -record schema and identity, both symlink hops, store containment, pointer -liveness, snapshot completeness, and admitted versus recorded versus snapshot -node_modules digests. It does not call tsgo as an oracle. +`buck2:editor:bootstrap` first derives a dependency-only consumer set from the +committed generated root manifest. It may publish those committed-graph views +only to make `genie:check` runnable; it reports no governed evidence. After +freshness and workspace reconciliation, `buck2:editor:publish` and +`buck2:editor:check` derive the complete root-plus-package set from the canonical +source registry, regenerate whole-workspace ownership authority, build every +`:editor_view_inputs` manifest in one Buck invocation, then publish or validate +each consumer in deterministic order. The checker validates record schema and +identity, both symlink hops, state-root containment, pointer liveness, snapshot +completeness, immutable payloads, retention state, and admitted versus recorded +digests. It does not use tsgo as an oracle. + +The mutating `buck2:editor:materialize` entrypoint serializes `mr:setup`, +bootstrap publication, `genie:run`, `genie:check`, `mr:apply`, and authoritative +editor publication. TypeScript declaration publication waits for that barrier. +This does not change the standalone freshness contract: `genie:check` still +runs after bootstrap without invoking `genie:run`, so it cannot repair the +projection it proves. Missing, malformed, escaping, dangling, incomplete, or stale state fails with -both the recorded and current editor-input fingerprints named. The scoped -publish/check tasks are intentionally not dependencies of global check, test, -or TypeScript tasks during this cutover. -`buck2:tui-core:recover-editor-lock` is the only recovery surface; it requires -the exact printed owner token through `EDITOR_VIEW_LOCK_TOKEN` and neither -builds nor mutates snapshots (DEPS-R06). +the recorded and current identities. `buck2:editor:recover-lock` is the only +recovery surface; it requires both `EDITOR_VIEW_PACKAGE` and the exact printed +`EDITOR_VIEW_LOCK_TOKEN`, and neither builds nor mutates snapshots. ## Relationship to Exact Closure Materialization diff --git a/context/buck2/04-reuse/.delta/DELTA-001-second-context-local-reexecution.md b/context/buck2/04-reuse/.delta/DELTA-001-second-context-local-reexecution.md new file mode 100644 index 0000000000..fa5ccfc45d --- /dev/null +++ b/context/buck2/04-reuse/.delta/DELTA-001-second-context-local-reexecution.md @@ -0,0 +1,46 @@ +# DELTA-001: Second context re-executes unchanged actions + +Status: open + +## Divergence + +BUCK-R06 and REUSE-R02 require an unchanged admitted target to re-execute zero +actions in a second same-platform context at the identical revision. The S8 +sandbox proof at `f8528ed38e` re-executed 633 actions locally despite a warm +shared remote cache. + +## VRS + +- [BUCK-R06](../../requirements.md) defines any same-platform local + re-execution at an identical revision as a key-stability regression. +- [REUSE-R02](../requirements.md) requires zero local re-execution and requires + the violation to be triaged as a defect rather than accepted as noise. +- [The S8 experiment](../../.experiments/2026-09-18-standalone-buck-root.md) + records the sandbox boundary, event-log summary, action classes, and the + informational aarch64 observation. + +## Implementation + +A `bwrap` context with a fresh `HOME`, `TMPDIR`, hostname, uid/gid, and +`buck-out` reported 556 cached actions, 633 local actions, 561 other actions, +and zero remote actions. The locally executed classes were `package_tree`, +`pnpm_store_entry`, `pnpm_store_scc`, `pnpm_store_view`, `tsgo_emit`, and +`tsgo_typecheck`. + +The sandbox retained the identical source revision, Nix store, Nix database, +system certificates, network, and cache endpoint. The proof was not tuned to +hide local execution. The experiment does not identify the unstable key input; +root-cause investigation is outside S8. + +## Direction + +update implementation + +## Resolution Signal + +- Repeat the S8 sandbox boundary at an identical revision with a warm shared + cache. +- The unchanged `//:quick` target reports zero local actions across every + admitted action class. +- The run reaches green within the BUCK-R07 fresh-context budget. +- Record the stable identity mechanism and remove this delta. diff --git a/context/buck2/05-composition/open-questions.md b/context/buck2/05-composition/open-questions.md index 8a7f57981e..8a40553528 100644 --- a/context/buck2/05-composition/open-questions.md +++ b/context/buck2/05-composition/open-questions.md @@ -29,18 +29,19 @@ Remaining blocker: the constitutional edits (vision criterion 6, BUCK-R05/R06, COMP-R01/R02) are Johannes', and pnpm's injected-workspace pruning must be shown to be a strict no-op on the second install. -## Open 2026-09-12: root-owned capability cell +## Resolved 2026-09-17: root-owned capability cell -The hub loads the per-host capability projection from inside its own cell -(`buck2/toolchains/BUCK:1`, `configured.bzl:5,59`: -`//.buck2/capabilities/…`), so mr must write the projection into every mount -and no fetched or read-only hub can carry it -([2026-09-12-hub-as-external-cell](./.experiments/2026-09-12-hub-as-external-cell.md)). -Moving it to a root-provided `capabilities//` cell (declared by the root -generator, referenced by cross-cell labels) is the right ownership boundary in -every option on the table and is a precondition for rules-only external-cell -distribution of the hub. Blocked on: deciding the cell's contract (visibility, -generation identity checks) and the mr change that declares it. +The composition root declares `capabilities = .buck2/capabilities`, and hub +toolchains load `capabilities//:defs.bzl` plus generation-keyed labels from that +cell. Nix is the sole producer: `packages..buck2-capabilities` derives +the projection from the tracked member manifest and the same flake package +outputs that the resolver consumes. The devenv shell links that store output +for a standalone root. `mr apply` verifies the same output and atomically links +it into the composition root. The shared TypeScript renderer defines the +projection bytes and generation identity for both paths. This removes the +per-mount write requirement while retaining strict manifest, platform, +executable, closure, and generation checks. Decision 0028 Amendment 1 records +the ownership change. ## Resolved 2026-08-30: consumers share the hub's toolchain pins diff --git a/context/buck2/05-composition/spec.md b/context/buck2/05-composition/spec.md index b0d9db44a8..8a81b1a2d9 100644 --- a/context/buck2/05-composition/spec.md +++ b/context/buck2/05-composition/spec.md @@ -23,18 +23,15 @@ The mr-generated root `.buckconfig` (validated on real content): ```ini [cells] - workspace = . # the synthesized shell; declares no targets + workspace = . # the synthesized shell prelude = prelude - toolchains = toolchains - none = none + capabilities = .buck2/capabilities # root-owned, Nix-produced projection = repos/ # one line per member incl. the owned repo [cell_aliases] config = prelude ovr_config = prelude - fbcode = none - fbsource = none - fbcode_macros = none - buck = none + fbsource = prelude + toolchains = [external_cells] prelude = bundled [parser] @@ -110,18 +107,19 @@ shared-pin contract, not silent inheritance. owns the invocation wrapper that fixes it (COMP-R07); an unwrapped `buck2` call relies on the default and is consistent by accident only. -Member repositories ship no `.buckconfig` project root of their own: deleting -effect-utils' `.buckconfig` is part of landing the generator, so the -unsupported bare-checkout shape fails loudly instead of silently building a -cache island. (A member's `.buckconfig` is inert under composition — only its -`[cell_aliases]` are honored — so nothing else is lost.) The gitignored -`.buck2/capabilities` cell is per-host projected state with exactly one -producer, mr's composition capability resolver: the mount pipeline projects it -per read-only mount, and `mr apply` installs it into the owned member. A member -ships no projector of its own, and a member-shipped script under `scripts/` is -inert data the resolver never reads or executes. Buck analysis of the hub's -`buck2/toolchains` package reads that projection, so every task that invokes -Buck is ordered after `mr apply`. +Member repositories can also be standalone Buck project roots. Their tracked +`.buckconfig` declares the member cell at `.`, the bundled Prelude, and the +root-owned `capabilities//` cell. The devenv shell links the pure +`packages..buck2-capabilities` output at `.buck2/capabilities`; no +projector runs during shell entry. + +The same Nix output is the only capability projection used by composition. +`mr apply` treats the member manifest as data, verifies the projection's exact +BUCK and `defs.bzl` bytes, platform, tool and executable identities, closure +paths, and generation, then atomically links the output at the composition +root's `.buck2/capabilities`. A member-shipped projector remains inert data. +Hub toolchains address the projection through `capabilities//`, so read-only +member mounts do not carry or mutate a projection. ## Workspace Anatomy diff --git a/context/buck2/roadmap.md b/context/buck2/roadmap.md index 1ffbc8447a..8c2564cfe5 100644 --- a/context/buck2/roadmap.md +++ b/context/buck2/roadmap.md @@ -99,13 +99,39 @@ resolution paths. ## Phase 5 — Rust operations and products -**Entry conditions:** Cargo metadata binding, target and feature semantics, -platform toolchains, third-party source supply, strict fixup handling, and -independent Nix import are proved for the exact operation tuple. - -**Sequence:** Admit deterministic Cargo operations before product builds. -Transfer each repository tool or product only after its Buck output passes the -independent BuildProduct import boundary. +- The complete five-member Rust workspace now compiles through Buck: otelite, + otel-scrape, archive-tool, core, and product. Cargo manifests and the root + lock remain request and resolution authority; generated first-party rules and + the strict Reindeer graph project that authority without a second lock. +- Third-party Rust sources are Buck-fetched per + [decision 0023](./.decisions/0023-buck-fetched-rust-crates.md): Reindeer uses + `vendor = false`, 126 `http_archive` targets take their sha256 from the + authoritative lock, and build/buildscript actions remain offline. The former + Nix vendor realization, vendor symlink task, and vendored Cargo config are + gone. +- `otelite` and `otel-scrape` emit strict `buck-build-product/v1` products for + x86_64 Linux glibc, aarch64 Linux glibc, and aarch64 Darwin. Every tuple was + executed natively, published under an immutable payload-addressed release, + and independently imported through Nix with descriptor, digest, archive, + runtime, entrypoint, and ad-hoc-signature validation. +- Flake packages/apps, devenv, and the reusable observability module now consume + only the reviewed native-product manifest. The two + `rustPlatform.buildRustPackage` product derivations, their shared narrow-source + helper, and the direct Cargo release build are deleted. The independently + realized Nix providers for stage-zero archive/product tools remain the + intentional cycle-breaking boundary admitted by + [decision 0010](./.decisions/0010-admit-rust-stage-zero-support-tools.md). +- The CI `cargo` operation remains outside Buck by policy: it aggregates the + workspace contract, Cargo tests, Clippy, and rustfmt. Buck owns Rust + compilation and shipped products; the operation ledger does not claim that + the broader source-quality lane moved with them. +- Zero repository JavaScript pnpm-deps FOD producers remain. The last one, + `oxc-config`, now emits its first-party plugin and StyleX upstream namespace + shim as two explicit Buck module products; Nix imports their reviewed, + content-addressed artifacts without rebuilding package sources. The + repository CLI products remain on the same manifest-pinned import boundary. + +## Phase 6 — composed consumers **Dissolution target:** Delete Cargo or Nix source producers, vendoring tasks and configuration, hand-maintained repository adapters that projection diff --git a/context/effect/socket/BUCK b/context/effect/socket/BUCK new file mode 100644 index 0000000000..48753a3b79 --- /dev/null +++ b/context/effect/socket/BUCK @@ -0,0 +1,96 @@ +# Generated file - DO NOT EDIT +# Source: BUCK.genie.ts + +# Projection source: context/effect/socket/BUCK.genie.ts +# Projection schema version: 11 +# Projection generator: effect-utils/genie/buck2-typescript-package-projection +# Semantic fingerprint: sha256:db436764dbf81dd81dd3d7e1cbda9bf3644d856fb0b4dab523d595b24fa9162c +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, context/effect/socket/BUCK.genie.ts, context/effect/socket/BUCK.genie.ts, context/effect/socket/examples/**/*.cts, context/effect/socket/examples/**/*.js, context/effect/socket/examples/**/*.mts, context/effect/socket/examples/**/*.spec.cjs, context/effect/socket/examples/**/*.spec.jsx, context/effect/socket/examples/**/*.spec.mjs, context/effect/socket/examples/**/*.test.cjs, context/effect/socket/examples/**/*.test.jsx, context/effect/socket/examples/**/*.test.mjs, context/effect/socket/examples/**/*.ts, context/effect/socket/examples/**/*.tsx, context/effect/socket/examples/**/__snapshots__/*.snap, context/effect/socket/package.json.genie.ts, context/effect/socket/tsconfig.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts +# Regenerate: devenv tasks run genie:run + +load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") +load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") +load("//buck2:typescript.bzl", "tsgo_typecheck") + +export_file( + name = "package.json", + src = "package.json", + visibility = ["PUBLIC"], +) + +export_materialization_inputs([ + "examples/http-ws-combined.ts", + "examples/rpc-schema.ts", + "examples/rpc-ws-client.ts", + "examples/rpc-ws-server.ts", + "examples/tcp-echo-client.ts", + "examples/tcp-echo-server.ts", + "examples/ws-broadcast-client.ts", + "examples/ws-broadcast-server.ts", + "examples/ws-echo-client.ts", + "examples/ws-echo-server.ts", + "examples/ws-json-client.ts", + "examples/ws-json-server.ts", +]) + +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "context/effect/socket", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + +alias( + name = "node_modules", + actual = "//buck2/dependencies:view_context_effect_socket_63f203470f7c", + visibility = ["PUBLIC"], +) + +alias( + name = "editor_inputs", + actual = ":node_modules", + visibility = ["PUBLIC"], +) + +package_view( + name = "package_tree", + dependency_view = "//buck2/dependencies:view_context_effect_socket_63f203470f7c", + files = { + "examples/http-ws-combined.ts": "examples/http-ws-combined.ts", + "examples/rpc-schema.ts": "examples/rpc-schema.ts", + "examples/rpc-ws-client.ts": "examples/rpc-ws-client.ts", + "examples/rpc-ws-server.ts": "examples/rpc-ws-server.ts", + "examples/tcp-echo-client.ts": "examples/tcp-echo-client.ts", + "examples/tcp-echo-server.ts": "examples/tcp-echo-server.ts", + "examples/ws-broadcast-client.ts": "examples/ws-broadcast-client.ts", + "examples/ws-broadcast-server.ts": "examples/ws-broadcast-server.ts", + "examples/ws-echo-client.ts": "examples/ws-echo-client.ts", + "examples/ws-echo-server.ts": "examples/ws-echo-server.ts", + "examples/ws-json-client.ts": "examples/ws-json-client.ts", + "examples/ws-json-server.ts": "examples/ws-json-server.ts", + "package.json": "package.json", + "tsconfig.json": "tsconfig.json", + }, + workspace_dist = { + }, + workspace_dependency_views = { + }, + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", + runtime_entry = "package-tree.ts", + visibility = ["PUBLIC"], +) + +editor_view_inputs( + name = "editor_view_inputs", + editor_inputs = ":editor_inputs", + package_tree = ":package_tree", + visibility = ["PUBLIC"], +) + +tsgo_typecheck( + name = "typecheck", + package_tree = ":package_tree", + visibility = ["PUBLIC"], +) diff --git a/context/effect/socket/BUCK.genie.ts b/context/effect/socket/BUCK.genie.ts new file mode 100644 index 0000000000..7daff49013 --- /dev/null +++ b/context/effect/socket/BUCK.genie.ts @@ -0,0 +1,13 @@ +import type { Buck2TypeScriptAdmission } from '../../../genie/buck2/typescript-admissions.ts' +import { buck2TypeScriptPackageProjection } from '../../../genie/buck2/typescript-package-projection.ts' + +export const buck2TypeScriptAdmission = { + dependencyImporter: '//buck2/dependencies:importer_context_effect_socket_63f203470f7c', + packageName: 'effect-socket-examples', + packagePath: 'context/effect/socket', + projectionSource: 'context/effect/socket/BUCK.genie.ts', + sourceRoots: ['examples'], + authorities: [{ projectFile: 'tsconfig.json' }], +} as const satisfies Buck2TypeScriptAdmission + +export default buck2TypeScriptPackageProjection(buck2TypeScriptAdmission) diff --git a/context/opentui/BUCK b/context/opentui/BUCK new file mode 100644 index 0000000000..c72545662d --- /dev/null +++ b/context/opentui/BUCK @@ -0,0 +1,78 @@ +# Generated file - DO NOT EDIT +# Source: BUCK.genie.ts + +# Projection source: context/opentui/BUCK.genie.ts +# Projection schema version: 11 +# Projection generator: effect-utils/genie/buck2-typescript-package-projection +# Semantic fingerprint: sha256:f68ac3b9a0ff55e201f5c32fd28be65458dc9bce1b2d4e8ed75302286e206447 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, context/opentui/BUCK.genie.ts, context/opentui/BUCK.genie.ts, context/opentui/examples/**/*.cts, context/opentui/examples/**/*.js, context/opentui/examples/**/*.mts, context/opentui/examples/**/*.spec.cjs, context/opentui/examples/**/*.spec.jsx, context/opentui/examples/**/*.spec.mjs, context/opentui/examples/**/*.test.cjs, context/opentui/examples/**/*.test.jsx, context/opentui/examples/**/*.test.mjs, context/opentui/examples/**/*.ts, context/opentui/examples/**/*.tsx, context/opentui/examples/**/__snapshots__/*.snap, context/opentui/package.json.genie.ts, context/opentui/tsconfig.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts +# Regenerate: devenv tasks run genie:run + +load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") +load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") +load("//buck2:typescript.bzl", "tsgo_typecheck") + +export_file( + name = "package.json", + src = "package.json", + visibility = ["PUBLIC"], +) + +export_materialization_inputs([ + "examples/dynamic-height.tsx", + "examples/effect-atoms-keyboard.tsx", + "examples/simple-counter.tsx", +]) + +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "context/opentui", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + +alias( + name = "node_modules", + actual = "//buck2/dependencies:view_context_opentui_be69c4c22aa3", + visibility = ["PUBLIC"], +) + +alias( + name = "editor_inputs", + actual = ":node_modules", + visibility = ["PUBLIC"], +) + +package_view( + name = "package_tree", + dependency_view = "//buck2/dependencies:view_context_opentui_be69c4c22aa3", + files = { + "examples/dynamic-height.tsx": "examples/dynamic-height.tsx", + "examples/effect-atoms-keyboard.tsx": "examples/effect-atoms-keyboard.tsx", + "examples/simple-counter.tsx": "examples/simple-counter.tsx", + "package.json": "package.json", + "tsconfig.json": "tsconfig.json", + }, + workspace_dist = { + }, + workspace_dependency_views = { + }, + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", + runtime_entry = "package-tree.ts", + visibility = ["PUBLIC"], +) + +editor_view_inputs( + name = "editor_view_inputs", + editor_inputs = ":editor_inputs", + package_tree = ":package_tree", + visibility = ["PUBLIC"], +) + +tsgo_typecheck( + name = "typecheck", + package_tree = ":package_tree", + visibility = ["PUBLIC"], +) diff --git a/context/opentui/BUCK.genie.ts b/context/opentui/BUCK.genie.ts new file mode 100644 index 0000000000..6e4c4de6b0 --- /dev/null +++ b/context/opentui/BUCK.genie.ts @@ -0,0 +1,13 @@ +import type { Buck2TypeScriptAdmission } from '../../genie/buck2/typescript-admissions.ts' +import { buck2TypeScriptPackageProjection } from '../../genie/buck2/typescript-package-projection.ts' + +export const buck2TypeScriptAdmission = { + dependencyImporter: '//buck2/dependencies:importer_context_opentui_be69c4c22aa3', + packageName: 'opentui-examples', + packagePath: 'context/opentui', + projectionSource: 'context/opentui/BUCK.genie.ts', + sourceRoots: ['examples'], + authorities: [{ projectFile: 'tsconfig.json' }], +} as const satisfies Buck2TypeScriptAdmission + +export default buck2TypeScriptPackageProjection(buck2TypeScriptAdmission) diff --git a/context/otel.md b/context/otel.md index 95415d0de8..e2698bbd5b 100644 --- a/context/otel.md +++ b/context/otel.md @@ -20,7 +20,7 @@ devenv shell devenv up # 3. Run tasks -- automatically traced when stack is running -devenv tasks run pnpm:install +devenv tasks run buck2:editor:publish devenv tasks run check:quick # 4. View traces @@ -107,8 +107,8 @@ Subcommands: ```bash otel-span run -- [args...] -otel-span run effect-utils-devenv devenv.task.exec --attr task.name=pnpm:install -- pnpm install -otel-span emit-span effect-utils-devenv typescript.project.check --attr-string span.label=socket +otel-span run effect-utils-devenv devenv.task.exec --attr task.name=buck2:editor:publish -- buck2 build effect_utils//:editor_view_inputs +otel-span emit-span effect-utils-devenv devenv.task.status --attr-string span.label=buck2:check printf '%s' "$otlp_json" | otel-span emit ``` @@ -124,18 +124,14 @@ stable span names and low-cardinality attributes instead of synthetic services. `trace.nix`: ```nix -# In task modules (e.g., ts.nix): +# In task modules: trace = import ../lib/trace.nix { inherit lib; }; -exec = trace.exec "ts:check" "tsc --build tsconfig.check.json"; +exec = trace.exec "buck2:check" "buck2 build "; ``` -**Compiler measurement spans**: TypeScript build diagnostics emit children of -the `ts:check`/`ts:build` task span with stable operation names: -`typescript.project.check` and `typescript.build.aggregate`. - -`TRACEPARENT`/`OTEL_TASK_TRACEPARENT` chains the spans: task wrappers create -`devenv.task.*` spans, and compiler diagnostics emit child measurement spans -under the task span. +`TRACEPARENT`/`OTEL_TASK_TRACEPARENT` chains nested task wrappers under the +calling `devenv.task.*` span. Buck owns TypeScript compiler execution; the +retired root compiler wrapper no longer emits a parallel TypeScript span tree. ## Span Conventions @@ -148,21 +144,16 @@ under the task span. ### Span Attributes (devenv tasks) -| Attribute | Type | Description | Example | -| ----------------- | --------- | ------------------------------------- | --------------------------------------------- | -| `name` | span name | Stable operation name | `devenv.task.exec`, `devenv.task.status` | -| `span.label` | string | Human-readable short label | `ts:check`, `socket`, `aggregate` | -| `tool.name` | string | Tool namespace | `devenv`, `typescript` | -| `task.name` | string | Devenv task name | `pnpm:install`, `ts:check` | -| `task.phase` | string | Task wrapper phase | `exec`, `status` | -| `task.cached` | bool | Whether task was cached/skipped | `true`, `false` | -| `status.method` | string | Cache/status check strategy | `binary`, `hash`, `path` | -| `exit.code` | int | Process exit code | `0`, `1` | -| `compiler.name` | string | TypeScript compiler binary | `tsgo`, `tsc` | -| `ts.project` | string | Repo-relative TypeScript project path | `context/effect/socket` | -| `ts.project.name` | string | Short TypeScript project label | `socket` | -| `tsconfig.path` | string | TypeScript build config | `tsconfig.check.json` | -| `typescript.*` | typed | Compiler timings/counters | `typescript.total_time_s`, `typescript.files` | +| Attribute | Type | Description | Example | +| --------------- | --------- | ------------------------------- | ---------------------------------------- | +| `name` | span name | Stable operation name | `devenv.task.exec`, `devenv.task.status` | +| `span.label` | string | Human-readable short label | `buck2:check` | +| `tool.name` | string | Tool namespace | `devenv` | +| `task.name` | string | Devenv task name | `buck2:editor:publish`, `buck2:check` | +| `task.phase` | string | Task wrapper phase | `exec`, `status` | +| `task.cached` | bool | Whether task was cached/skipped | `true`, `false` | +| `status.method` | string | Cache/status check strategy | `binary`, `hash`, `path` | +| `exit.code` | int | Process exit code | `0`, `1` | `trace.exec` adds `task.cached=false` for executed tasks. `trace.status` derives `task.cached` from the status command exit code. Raw command arguments and diff --git a/devenv.nix b/devenv.nix index ff60389f69..895769f08b 100644 --- a/devenv.nix +++ b/devenv.nix @@ -29,7 +29,9 @@ let ''; builtins.getFlake "git+file://${toString ./.}"; currentSystem = pkgs.stdenv.hostPlatform.system; + buck2Capabilities = repoFlake.packages.${currentSystem}.buck2-capabilities; flakePkgs = import repoFlake.inputs.nixpkgs { system = currentSystem; }; + trackedBuck2Products = import ./nix/buck2-products { pkgs = flakePkgs; }; # `restate` ships under BSL-1.1; scope allowUnfree to just that package so the # rest of the closure stays free-only. restatePkgs = import repoFlake.inputs.nixpkgs { @@ -38,11 +40,11 @@ let }; restate = import ./nix/restate.nix { pkgs = restatePkgs; }; cliBuildStamp = import ./nix/workspace-tools/lib/cli-build-stamp.nix { inherit pkgs; }; - # Use npm oxlint with NAPI bindings to enable JavaScript plugin support + # Use npm oxlint with NAPI bindings and the two tracked Buck plugin modules. oxlintNpm = import ./nix/oxlint-npm.nix { pkgs = flakePkgs; bun = flakePkgs.bun; - src = repoFlake; + products = trackedBuck2Products.products; }; oxlintWithPlugins = import ./nix/oxlint-with-plugins.nix { inherit pkgs oxlintNpm; @@ -70,7 +72,6 @@ let # Shared task modules (from shared/ directory) taskModules = { genie = ./nix/devenv-modules/tasks/shared/genie.nix; - ts = import ./nix/devenv-modules/tasks/shared/ts.nix; worktree-guard = import ./nix/devenv-modules/tasks/shared/worktree-guard.nix; setup = import ./nix/devenv-modules/tasks/shared/setup.nix; check = import ./nix/devenv-modules/tasks/shared/check.nix; @@ -83,11 +84,11 @@ let workflow-report = import ./nix/devenv-modules/tasks/shared/workflow-report.nix; lint-genie = ./nix/devenv-modules/tasks/shared/lint-genie.nix; lint-nix = import ./nix/devenv-modules/tasks/shared/lint-nix.nix; + nix-cli = import ./nix/devenv-modules/tasks/shared/nix-cli.nix; lint-oxc = import ./nix/devenv-modules/tasks/shared/lint-oxc.nix; bun = import ./nix/devenv-modules/tasks/shared/bun.nix; pnpm = import ./nix/devenv-modules/tasks/shared/pnpm.nix; megarepo = import ./nix/devenv-modules/tasks/shared/megarepo.nix; - nix-cli = import ./nix/devenv-modules/tasks/shared/nix-cli.nix; secretspec = import ./nix/devenv-modules/tasks/shared/secretspec.nix; bootstrap-closure = import ./nix/devenv-modules/tasks/shared/bootstrap-closure.nix; weaver = import ./nix/devenv-modules/tasks/shared/weaver.nix; @@ -96,7 +97,6 @@ let weaver-version-smoke = import ./nix/devenv-modules/tasks/shared/weaver-version-smoke.nix; context = ./nix/devenv-modules/tasks/shared/context.nix; devenv-module-tests = ./nix/devenv-modules/tasks/local/devenv-module-tests.nix; - asset-import-type-reference = ./nix/devenv-modules/tasks/local/asset-import-type-reference.nix; }; # Repository CLIs come from the reviewed Buck product boundary, not from a # source entrypoint that exists only here. The activated shell, the flake @@ -108,7 +108,6 @@ let # and exec these via absolute store path under passthrough, so they are passed # as `*Pkg` reals to the task modules instead of also being top-level profile # providers (which would collide with the guards in buildEnv). See cli-guard.nix. - effectTsgo = inputs.tsgo.packages.${currentSystem}.effect-tsgo; pnpmPkg = import ./nix/pnpm.nix { inherit pkgs; }; genieCli = repoPackages.genie; mrCli = repoPackages.megarepo; @@ -137,50 +136,10 @@ let } ]; - # Explicit workspace members for the repo-root pnpm workspace. - # NOTE: Using pnpm temporarily due to bun bugs. Plan to switch back once fixed. - # See: context/workarounds/bun-issues.md - allPackages = [ - "packages/@overeng/agent-session-ingest" - "packages/@overeng/buck2-tools" - "packages/@overeng/content-address" - "packages/@overeng/utils" - "packages/@overeng/utils-dev" - "packages/@overeng/effect-ai-claude-cli" - "packages/@overeng/effect-distributed-lock" - "packages/@overeng/effect-path" - "packages/@overeng/effect-react" - "packages/@overeng/effect-rpc-tanstack" - "packages/@overeng/effect-rpc-tanstack/examples/basic" - "packages/@overeng/effect-schema-form" - "packages/@overeng/effect-schema-form-aria" - "packages/@overeng/genie" - "packages/@overeng/gh-ci-utils" - "packages/@overeng/kdl" - "packages/@overeng/kdl-effect" - "packages/@overeng/megarepo" - "packages/@overeng/notion-cli" - "packages/@overeng/notion-core" - "packages/@overeng/notion-datasource-sync" - "packages/@overeng/notion-effect-client" - "packages/@overeng/notion-effect-schema" - "packages/@overeng/notion-md" - "packages/@overeng/notion-property-write" - "packages/@overeng/notion-react" - "packages/@overeng/npm-release" - "packages/@overeng/otel-contract" - "packages/@overeng/oxc-config" - "packages/@overeng/pty-effect" - "packages/@overeng/react-inspector" - "packages/@overeng/restate-effect" - "packages/@overeng/stylex-tokens" - "packages/@overeng/tui-core" - "packages/@overeng/tui-react" - "packages/@overeng/tui-stories" - "packages/@overeng/ci-tools" - "context/opentui" - "context/effect/socket" - ]; + # The generated root package manifest is the workspace package authority. + # Consuming it here removes the former hand-maintained Nix package list and + # makes Genie freshness the single stage-zero synchronization boundary. + allPackages = (builtins.fromJSON (builtins.readFile ./package.json)).workspaces; packageTestQuarantine = { }; validatedPackageTestQuarantine = lib.mapAttrs ( @@ -245,7 +204,7 @@ let buck2TestAuthorityFile = ./buck2-test-authority.json; buck2TestAuthority = builtins.fromJSON (builtins.readFile buck2TestAuthorityFile); # Deliberate floor, not a derived value: shrinking the registry means editing this number. - buck2TestAuthorityMinimumLanes = 32; + buck2TestAuthorityMinimumLanes = 34; buck2TestAuthorityLanes = if (buck2TestAuthority.schemaVersion or null) == 2 then buck2TestAuthority.lanes @@ -365,7 +324,6 @@ let buck2TestAuthorityCollectionTargets = builtins.concatMap ( lane: lib.optional (lane ? collectionTarget) lane.collectionTarget ) buck2TestAuthorityLanes; - buck2TestAuthorityPackagePaths = map (lane: lane.packagePath) buck2TestAuthorityLanes; buck2TestAuthorityIssues = builtins.concatMap buck2TestLaneIssues buck2TestAuthorityLanes ++ @@ -384,11 +342,7 @@ let ++ lib.optional ( builtins.length (lib.unique buck2TestAuthorityCollectionTargets) != builtins.length buck2TestAuthorityCollectionTargets - ) "lanes declare a duplicate collection target" - ++ lib.optional ( - builtins.length (lib.unique buck2TestAuthorityPackagePaths) - != builtins.length buck2TestAuthorityPackagePaths - ) "more than one lane per package is not supported"; + ) "lanes declare a duplicate collection target"; discoveredTestPackagePaths = map (pkg: pkg.path) packagesWithTests; # A lane whose package carries no discovered Vitest tests (or is quarantined) means the # generated bridge and the filesystem have drifted apart; fail every consumer of the lanes @@ -421,6 +375,24 @@ let }) (builtins.filter (lane: lane.unboundedFiles != [ ]) buck2TestLanes); sourceTestPackages = sourceOnlyTestPackages ++ unboundedTestPackages; + buck2BuildExec = + { name, targets }: + trace.exec name '' + set -euo pipefail + root="''${DEVENV_ROOT:-$PWD}" + export PATH=${ + lib.makeBinPath [ + pkgs.coreutils + pkgs.watchman + ] + } + workspace_root="$(${pkgs.coreutils}/bin/realpath "$root/../..")" + buck="$workspace_root/.megarepo/bin/buck2" + exec "$buck" build \ + --target-platforms effect_utils//buck2/platforms:host_platform \ + ${lib.concatStringsSep " \\\n " targets} + ''; + # Buck-invoking tasks discover the same pinned composed binary as `buck2:check`, so a lane # cannot run against a different Buck than the one the check gate proved. buck2UnitTestExec = @@ -449,6 +421,7 @@ let lib.nameValuePair lane.taskName { description = "Execute the bounded ${lane.packageName} unit-test lane under Buck"; after = [ "mr:apply" ] ++ lib.optional (lane ? unboundedTaskName) lane.unboundedTaskName; + # trace-audit-allow: buck2UnitTestExec returns a trace.exec-wrapped command. exec = buck2UnitTestExec { name = lane.taskName; targets = [ lane.target ]; @@ -628,6 +601,38 @@ let printf "%s\n" "$workspace_root" } ''; + buck2AggregateExec = + taskName: target: + trace.exec taskName '' + set -euo pipefail + root="''${DEVENV_ROOT:-$PWD}" + export PATH=${lib.makeBinPath [ pkgs.watchman ]} + cd "$root" + exec "$BUCK2_BIN" build ${lib.escapeShellArg target} + ''; + editorViewExec = + mode: + trace.exec "buck2:editor:${mode}" '' + set -euo pipefail + ${composedWorkspaceRootPredicate} + root="''${DEVENV_ROOT:-$PWD}" + workspace_root="$(composed_workspace_root "$root")" || { + identity_status=$? + echo "buck2:editor:${mode} requires a composed megarepo workspace" >&2 + exit "$identity_status" + } + exec ${pkgs.bun}/bin/bun "$root/scripts/editor-view-authority.ts" ${mode} \ + --repo-root "$root" \ + --workspace-root "$workspace_root" \ + --cell effect_utils \ + --buck2 "$workspace_root/.megarepo/bin/buck2" \ + --git ${pkgs.git}/bin/git \ + --output "$root/.devenv/editor-workspace-authority.json" \ + --publisher "$root/packages/@overeng/buck2-tools/src/editor-view.ts" \ + --cp ${pkgs.coreutils}/bin/cp \ + --mv ${pkgs.coreutils}/bin/mv \ + --snapshot-retention 3 + ''; in { imports = [ @@ -663,9 +668,7 @@ in "mr:lock-sync-check" "mr:source-policy-check" "nix:flake:check" - "pnpm:install" "test:run" - "ts:check:strict" "weaver:check" "weaver:diff" "weaver:version-smoke" @@ -680,25 +683,21 @@ in inputs.playwright.devenvModules.default # Shared task modules taskModules.genie - (taskModules.ts { tsBinPkg = effectTsgo; }) (taskModules.megarepo { mrPkg = mrCli; }) (taskModules.lint-nix { }) + # No repository JavaScript package is source-built by Nix anymore. Import + # the empty module contract to retain repository-wide flake validation. + (taskModules.nix-cli { cliPackages = [ ]; }) (taskModules.check { extraChecks = [ "devenv:trace-audit" "workspace:check" "lint:nix" ]; - # Root `tsc` no longer owns the admitted packages, so the fast lane runs - # its incremental form while `check:all` gets the forced one below. - extraQuickChecks = [ "ts:check" ]; checkQuickTypecheckTask = "buck2:check"; checkAllTypecheckTask = "buck2:check"; }) (taskModules.devenv-eval-input-budget { }) - # Root `tsc` remains the sole producer for the projects no Buck target owns. - # `extraChecks` feeds both gates, so the forced run is wired here instead. - { tasks."check:all".after = [ "ts:check:strict" ]; } (taskModules.weaver { }) # Wire the additive weaver gate into `check:all` only (not `check:quick`, which stays fast): # `after` list options merge across modules, so this appends without redefining check:all. @@ -724,23 +723,25 @@ in # unlike the deterministic check/diff runs, this is a subprocess e2e (spawns otelite, binds an # ephemeral port, depends on export-flush timing), so it lives in CI rather than gating every # local `check:all` on capture reliability. - (taskModules.weaver-live-check { }) + (taskModules.weaver-live-check { installTask = "buck2:editor:publish"; }) # Version-pin consistency smoke (SC-DQ4): catches weaver/semconv pin drift the content # gate (weaver:check) silently degrades past (a bumped version with a stale FOD hash). (taskModules.weaver-version-smoke { }) { tasks."check:all".after = [ "weaver:version-smoke" ]; } (taskModules.clean { packages = allPackages; }) - # Repo-root pnpm install task - # NOTE: Using pnpm temporarily. See: context/workarounds/bun-issues.md + # Pnpm remains only as a lockfile authoring tool. It cannot materialize a + # workspace dependency graph or publish node_modules. (taskModules.pnpm { packages = allPackages; inherit pnpmPkg; + materialize = false; }) # Source-side Vitest is now only what Buck does not execute: packages outside the Buck # test registry and each admitted lane's exact excluded files. Retained JSON therefore # exists exactly where the baseline gate still needs a source report. (taskModules.test-playwright { playwrightPkg = inputs.playwright.packages.${currentSystem}.playwright; + installTask = "buck2:editor:publish"; packages = [ { path = "packages/@overeng/utils"; @@ -753,6 +754,7 @@ in ]; }) (taskModules.test { + installTask = "buck2:editor:publish"; packages = sourceTestPackages; extraTests = [ "devenv-modules:test" @@ -764,6 +766,7 @@ in # Per-lane Buck `test:` tasks, each pulling in its unbounded complement. { tasks = buck2TestLaneTasks; } (taskModules.storybook { + installTask = "buck2:editor:publish"; packages = packagesWithStorybook; }) (taskModules.netlify { @@ -798,9 +801,8 @@ in ++ genieExtraInputGlobs; genieCoverageDirs = [ "packages" ]; # Type-aware linting for typescript/no-deprecated rule - tsconfig = "tsconfig.check.json"; - # The type-aware rules resolve Buck-authoritative packages through their - # published `dist` declarations, so the lane waits for the materializer. + tsconfig = "tsconfig.lint.json"; + # Type-aware lint consumes the declaration products Buck publishes. tsconfigAfterTasks = [ "buck2:typescript:materialize-dist" ]; # Warning cleanup is complete: every oxlint rule is at zero repo-wide # (swept + key rules promoted to error; non-API surfaces exempted by @@ -821,25 +823,16 @@ in # Reuse the Genie semantic-input SSOT in the cheap Git-index outer # fingerprint so a warm shell cannot bypass projection invalidation. extraFingerprintGlobs = genieExtraInputGlobs; - # Keep shell entry resilient (R12): optional tasks run via @complete. - # Ordering ensures source CLIs have deps before use. - optionalTasks = [ - "pnpm:install" - "genie:run" - "mr:apply" - ]; + # Run the one ordered mutating entrypoint. Its internal task sequence + # preserves generator/freshness/composition/publication happens-before. + optionalTasks = [ "buck2:editor:materialize" ]; completionsCliNames = [ "genie" "mr" ]; }) - # Nix CLI build and hash management - (taskModules.nix-cli { cliPackages = nixCliPackages; }) (taskModules.secretspec { }) - # Local task: Validate allPackages matches filesystem packages (effect-utils specific) - ./nix/devenv-modules/tasks/local/workspace-check.nix taskModules.devenv-module-tests - taskModules.asset-import-type-reference # Notion integration tests (requires NOTION_API_TOKEN) ./nix/devenv-modules/tasks/local/notion-integration-test.nix # Restate integration tests (native restate-server via RESTATE_SERVER_BIN) @@ -850,13 +843,73 @@ in # Genie product, which is also what downstream consumers set here. effectUtils.genie.package = genieCli; - # Design-time generators import the workspace dependency graph. The packaged - # CLI is self-contained, but the generator sources it loads still require - # pnpm's package links. - tasks."genie:run".after = [ "pnpm:install" ]; - tasks."genie:check".after = [ "pnpm:install" ]; - tasks."lint:check:genie".after = [ "pnpm:install" ]; - tasks."genie:watch".after = [ "pnpm:install" ]; + # The packaged Genie CLI is self-contained; generator sources resolve their + # external imports through the committed-graph bootstrap editor views. This + # stage-zero publication cannot report governed Buck evidence: genie:check + # must first prove the graph fresh, then mr:apply and the authoritative + # publisher replay it. + tasks."genie:run".after = [ "buck2:editor:bootstrap" ]; + tasks."genie:check".after = lib.mkForce [ "genie:prepare" ]; + tasks."lint:check:genie".after = [ "buck2:editor:bootstrap" ]; + tasks."genie:watch".after = [ "buck2:editor:bootstrap" ]; + tasks."lint:check:lockfile".description = + lib.mkForce "Verify lockfile and package specifiers through source-side Genie freshness"; + tasks."lint:check:lockfile".after = lib.mkForce [ "genie:check" ]; + tasks."lint:check:lockfile".exec = lib.mkForce ( + trace.exec "lint:check:lockfile" "exec genie --check" + ); + tasks."lint:fix:oxlint".after = [ "buck2:editor:publish" ]; + tasks."devenv-modules:test".after = lib.mkForce [ "buck2:editor:publish" ]; + tasks."test:restate-integration".after = lib.mkForce [ "buck2:editor:publish" ]; + tasks."test:notion-integration:notion-effect-client".after = lib.mkForce [ "buck2:editor:publish" ]; + tasks."test:notion-integration:notion-cli".after = lib.mkForce [ "buck2:editor:publish" ]; + tasks."test:notion-integration:notion-datasource-sync".after = lib.mkForce [ + "buck2:editor:publish" + ]; + tasks."test:notion-integration:notion-md".after = lib.mkForce [ "buck2:editor:publish" ]; + tasks."test:notion-integration:notion-react".after = lib.mkForce [ "buck2:editor:publish" ]; + tasks."weaver:live-check".after = lib.mkForce [ "buck2:editor:publish" ]; + tasks."test:pty-effect:unbounded".env = { + NODE_PTY_NATIVE_PACKAGE = "${nodePtyNative}/node_modules/node-pty"; + NODE_OPTIONS = "--import=${./. + "/packages/@overeng/pty-effect/test/node-pty-native-hook.ts"}"; + }; + + # Read-only formatting and linting are Buck actions over the exact generated + # source manifest. Mutation remains source-side under lint:fix. + tasks."lint:check:format".after = lib.mkForce [ "mr:apply" ]; + tasks."lint:check:format".exec = lib.mkForce (buck2BuildExec { + name = "lint:check:format"; + targets = [ "effect_utils//buck2/static:check_format" ]; + }); + tasks."lint:check:oxlint".after = lib.mkForce [ "mr:apply" ]; + tasks."lint:check:oxlint".exec = lib.mkForce (buck2BuildExec { + name = "lint:check:oxlint"; + targets = [ "effect_utils//buck2/static:check_lint" ]; + }); + tasks."lint:check:asset-import-needs-type-reference" = { + after = [ "mr:apply" ]; + description = "Require travelling type references for compiled asset imports through Buck"; + # trace-audit-allow: buck2BuildExec returns a trace.exec-wrapped command. + exec = buck2BuildExec { + name = "lint:check:asset-import-needs-type-reference"; + targets = [ "effect_utils//buck2/static:check_policy" ]; + }; + }; + tasks."lint:check".after = lib.mkAfter [ "lint:check:asset-import-needs-type-reference" ]; + tasks."lint:check:genie:coverage".after = lib.mkForce [ "mr:apply" ]; + tasks."lint:check:genie:coverage".exec = lib.mkForce (buck2BuildExec { + name = "lint:check:genie:coverage"; + targets = [ "effect_utils//buck2/static:check_policy" ]; + }); + tasks."workspace:check" = { + after = [ "mr:apply" ]; + description = "Validate generated workspace package inventory through Buck"; + # trace-audit-allow: buck2BuildExec returns a trace.exec-wrapped command. + exec = buck2BuildExec { + name = "workspace:check"; + targets = [ "effect_utils//buck2/static:check_policy" ]; + }; + }; # Non-`.genie.ts` sources share one list with the lint freshness scheduler. effectUtils.genie.extraInputGlobs = genieExtraInputGlobs; @@ -885,8 +938,8 @@ in ghCiUtilsCli tuiStoriesCli # Rust toolchain for the standalone Rust crates. - # Nix builds use pkgs.rustPlatform; these give local dev + the cargo CI lane - # cargo/clippy/rustfmt/rust-analyzer matching nixpkgs' stable rust. + # Stage-zero Nix providers use pkgs.rustPlatform; local validation keeps + # cargo/clippy/rustfmt/rust-analyzer aligned with nixpkgs' stable Rust. pkgs.cargo pkgs.rustc pkgs.clippy @@ -909,29 +962,22 @@ in env.MR_COMPOSITION_GIT_BIN = "${pkgs.git}/bin/git"; env.MR_COMPOSITION_WATCHMAN_BIN = "${pkgs.watchman}/bin/watchman"; env.MR_CAPABILITY_NIX_BIN = "${pkgs.nix}/bin/nix"; + env.MR_CAPABILITY_PROJECTION = "${buck2Capabilities}"; env.MR_CAPABILITY_MV_BIN = "${pkgs.coreutils}/bin/mv"; # restate-server binary path for restate-effect integration tests (test/test-utils.ts # reads RESTATE_SERVER_BIN to locate the native server, else falls back to $PATH). env.RESTATE_SERVER_BIN = "${restate}/bin/restate-server"; - # Genie and mr run from their packaged products, whose dependencies are baked - # into the store path, so neither waits on a repository pnpm projection any - # more. What survives is the real constraint: the composed-root mutators must - # not run concurrently with each other. + # Genie and mr run from packaged products, but the generated projection still defines + # the graph mr composes. Generation freshness is therefore a source-side stage-zero + # prerequisite: a stale graph must fail before reconciliation can publish it to Buck. + # The composed-root mutators also remain serialized behind mr:setup. tasks."mr:setup".after = [ "mr:bootstrap" ]; - tasks."mr:apply".after = [ "mr:setup" ]; - - # The projects root `tsc` still owns resolve their Buck-authoritative - # dependencies through published `dist` declarations, so the root project - # graph runs after the materializer that publishes them. `after` list options - # merge across modules, so these edges are additive and the shared `ts` module - # stays free of repository-specific Buck task names. `ts:check:strict` - # inherits the merged `ts:check` graph and needs no edge of its own. - tasks."ts:check".after = [ "buck2:typescript:materialize-dist" ]; - tasks."ts:build".after = [ "buck2:typescript:materialize-dist" ]; - tasks."ts:emit".after = [ "buck2:typescript:materialize-dist" ]; - tasks."ts:build-watch".after = [ "buck2:typescript:materialize-dist" ]; + tasks."mr:apply".after = [ + "genie:check" + "mr:setup" + ]; # buck2-tools executes inside pinned Bun actions and exercises Bun.YAML/Bun.which. # Keep its package gate on that runtime rather than Vitest's Node process. @@ -955,7 +1001,7 @@ in # Bun: the pnpm-lock projection it imports reads Bun.YAML. tasks."genie:buck2:test" = { description = "Run the Buck2 genie projection and staged-runtime guards under pinned Bun"; - after = [ "pnpm:install" ]; + after = [ "buck2:editor:publish" ]; exec = trace.exec "genie:buck2:test" '' set -euo pipefail cd "''${DEVENV_ROOT:-$PWD}" @@ -970,24 +1016,11 @@ in ]; }; - # NOTE (decision 0004): there is deliberately NO `genie:bootstrap`-before-`pnpm:install` edge. - # An earlier form wired `pnpm:install.after = [ "genie:bootstrap" ]` so install would run - # `genie --phase bootstrap` first. Verified during implementation that this does NOT arbitrate - # bootstrap-safety: the source-mode `genie` on PATH needs `node_modules` (it cold-guarded to a - # no-op on a fresh clone), and committed outputs (T01) mean install succeeds with the on-disk - # `package.json` regardless — so the edge enforced nothing while adding cost to every warm install - # and a new failure mode. Bootstrap-safety is instead demonstrated empirically by - # `bootstrap:cold-proof` (R32, below), with `bootstrap-closure:check` as fast local feedback. - - # bootstrap:cold-proof (R32) — the EMPIRICAL bootstrap-safety authority. In a fresh, no-node_modules - # tree of the committed source it runs the self-contained packaged Genie CLI - # (`.#genie`, deps baked into the store) with `--phase bootstrap`, then - # `pnpm install --frozen-lockfile`, asserting both succeed. - # This exercises the exact pre-install path and turns bootstrap-safety from asserted into - # demonstrated. Heavy (nix build + full install) so it is a dedicated task/CI lane, NOT in - # `check:all`. Set GENIE_COLD_PROOF_BIN to reuse an already-built genie and skip the nix build. + # Empirical authority for the minimal generator phase that must run before + # any dependency view exists. The design-time source closure is proven by + # buck2:editor:bootstrap followed by genie:check. tasks."bootstrap:cold-proof" = { - description = "Prove bootstrap-phase genie + pnpm install run cold (no node_modules) — R32 authority"; + description = "Prove the marked bootstrap Genie generators run without node_modules"; exec = trace.exec "bootstrap:cold-proof" '' set -euo pipefail root="''${DEVENV_ROOT:-$PWD}" @@ -995,34 +1028,8 @@ in ''; }; - tasks."pnpm:link-native-node-packages" = { - after = [ "pnpm:install" ]; - description = "Link Nix-built native Node packages into the pnpm projection"; - exec = trace.exec "pnpm:link-native-node-packages" '' - set -euo pipefail - source ${lib.escapeShellArg pnpmTaskHelpersScript} - - link_native_package() { - local package_name="$1" - local package_path="$2" - local rel_path="$package_name" - local search_roots=(node_modules) - - if [[ "$package_name" == @*/* ]]; then - rel_path="$(dirname "$package_name")/$(basename "$package_name")" - fi - - find "''${search_roots[@]}" \ - -path "*/node_modules/$rel_path" \ - -exec sh -c 'package_path="$1"; shift; for target do rm -rf "$target"; ln -s "$package_path" "$target"; done' sh "$package_path" {} + - } - - link_native_package "node-pty" "${nodePtyNative}/node_modules/node-pty" - ''; - }; - tasks."test:megarepo-cold-gc" = { - after = [ "pnpm:install" ]; + after = [ "buck2:editor:publish" ]; description = "Run isolated megarepo cold-GC integration tests"; cwd = "packages/@overeng/megarepo"; exec = trace.exec "test:megarepo-cold-gc" '' @@ -1038,12 +1045,13 @@ in }; tasks."bundle:smoke" = { - after = [ "pnpm:install" ]; - description = "Bundle representative public entries with Vite/Rollup dependency resolution"; - exec = trace.exec "bundle:smoke" '' - set -euo pipefail - DEVENV_TASK_PASSTHROUGH=1 pnpm --dir packages/@overeng/pty-effect run bundle:smoke - ''; + after = [ "mr:apply" ]; + description = "Bundle representative public entries through Buck with Vite/Rollup"; + # trace-audit-allow: buck2UnitTestExec returns a trace.exec-wrapped command. + exec = buck2UnitTestExec { + name = "bundle:smoke"; + targets = [ "effect_utils//packages/@overeng/pty-effect:bundle_smoke" ]; + }; }; tasks."gh:apply-settings" = { @@ -1072,13 +1080,11 @@ in # silently turns the whole audit vacuous (it always exits 0) — the exact # failure this rewrite fixes. # - # A few raw exec/status lines are legitimately allowed and are annotated - # with a `trace-audit-allow` marker comment IMMEDIATELY ABOVE the line: - # - the raw string is an argument passed INTO trace.* a few lines below - # (restate integration test, ts:emit). - # A deliberately-untraced task would also qualify, but there are currently - # none: every thin `ci-tools` delegation task (netlify/vercel deploys, - # workflow-report) routes through trace.exec for a task span. + # Raw exec/status lines can be allowed only when they are annotated with + # a `trace-audit-allow` marker comment IMMEDIATELY ABOVE the line. + # There are currently no such exceptions: every thin `ci-tools` + # delegation task (netlify/vercel deploys, workflow-report) routes through + # trace.exec for a task span. # The marker is matched in a 2-line window (the line plus the one above), # so this stays robust to line shifts — no fragile file:line pins. marker='trace-audit-allow' @@ -1120,14 +1126,13 @@ in }; tasks."cargo:check" = { - description = "Validate the shared Cargo workspace, then build, test, lint, and format-check each member"; + description = "Validate the shared Cargo workspace, then test, lint, and format-check each member"; after = [ "cargo:test:buck2-foundation" ]; exec = trace.exec "cargo:check" '' set -euo pipefail ${pkgs.bash}/bin/bash rust/workspace-contract.test.sh "$PWD" ( cd rust - cargo build --release --locked --workspace cargo test --locked --workspace --exclude 'buck2-*' cargo clippy --locked --workspace --all-targets -- -D warnings cargo fmt --all --check @@ -1171,7 +1176,7 @@ in tasks."buck2:nix-bridge:check" = { description = "Check the strict build-product contract and fail-closed artifact importer"; - after = [ "mr:apply" ]; + after = lib.mkForce [ "genie:check" ]; exec = trace.exec "buck2:nix-bridge:check" '' set -euo pipefail ${pkgs.bash}/bin/bash nix/workspace-tools/lib/tests/buck2-build-product-contract.sh "$PWD" @@ -1179,119 +1184,69 @@ in ''; }; - tasks."buck2:editor-authority" = { - description = "Derive exact whole-workspace editor dependency authority from semantic and Buck ownership"; - # Buck analysis of //buck2/toolchains reads the `.buck2/capabilities` - # projection, so every task that invokes Buck must be ordered after it. - after = [ "mr:apply" ]; - exec = trace.exec "buck2:editor-authority" '' - set -euo pipefail - root="''${DEVENV_ROOT:-$PWD}" - workspace_root="$(${pkgs.coreutils}/bin/realpath "$root/../..")" - buck="$workspace_root/.megarepo/bin/buck2" - ${pkgs.bun}/bin/bun "$root/scripts/editor-view-authority.ts" \ - --repo-root "$root" \ - --workspace-root "$workspace_root" \ - --cell effect_utils \ - --buck2 "$buck" \ - --git ${pkgs.git}/bin/git \ - --output "$root/.devenv/editor-workspace-authority.json" - ''; + tasks."buck2:editor:bootstrap" = { + description = "Bootstrap source-generator dependencies from the committed Buck graph"; + after = [ "mr:setup" ]; + # trace-audit-allow: editorViewExec returns a trace.exec-wrapped command. + exec = editorViewExec "bootstrap"; }; - tasks."buck2:tui-core:publish-editor" = { - description = "Publish the admitted Buck tui-core node_modules tree to the scoped editor view"; - after = [ "buck2:editor-authority" ]; - exec = trace.exec "buck2:tui-core:publish-editor" '' + # Authoring and declaration publication need generated projections to be + # updated before freshness is checked, but standalone genie:check must remain + # mutation-free. Keep that mutating sequence in one explicit entrypoint + # rather than adding global edges between genie:run and genie:check. + tasks."buck2:editor:materialize" = { + description = "Regenerate, freshness-check, recompose, and publish every editor dependency view in order"; + exec = trace.exec "buck2:editor:materialize" '' set -euo pipefail - root="''${DEVENV_ROOT:-$PWD}" - authority="$root/.devenv/editor-workspace-authority.json" - scratch="$(${pkgs.coreutils}/bin/mktemp -d "$root/.devenv/editor-publish-inputs.XXXXXX")" - cleanup_editor_publish() { - status=$? - ${pkgs.coreutils}/bin/rm -rf -- "$scratch" || status=$? - trap - EXIT - exit "$status" - } - trap cleanup_editor_publish EXIT - workspace_root="$(${pkgs.coreutils}/bin/realpath "$root/../..")" - buck="$workspace_root/.megarepo/bin/buck2" - ( - cd "$workspace_root" - "$buck" build effect_utils//packages/@overeng/tui-core:editor_inputs --out "$scratch/editor_inputs" - "$buck" build effect_utils//packages/@overeng/tui-core:node_modules --out "$scratch/node_modules" - ) - ${pkgs.bun}/bin/bun "$root/packages/@overeng/buck2-tools/src/editor-view.ts" publish \ - --repo-root "$root" \ - --package packages/@overeng/tui-core \ - --cell tui-core \ - --target //packages/@overeng/tui-core:editor_inputs \ - --editor-inputs "$scratch/editor_inputs" \ - --node-modules "$scratch/node_modules" \ - --cp ${pkgs.coreutils}/bin/cp \ - --workspace-authority "$authority" \ - --consumer-cache "$root/.devenv/vite-cache/tui-core" \ - --snapshot-retention 3 \ - --mv ${pkgs.coreutils}/bin/mv + export DEVENV_TUI=false + devenv tasks run mr:setup + devenv tasks run buck2:editor:bootstrap --mode single + devenv tasks run genie:run --mode single + devenv tasks run genie:check --mode single + devenv tasks run mr:apply --mode single + devenv tasks run buck2:editor:publish --mode single ''; }; - tasks."buck2:tui-core:check-editor" = { - description = "Check the scoped tui-core editor view against current admitted Buck outputs"; - after = [ "buck2:editor-authority" ]; - exec = trace.exec "buck2:tui-core:check-editor" '' - set -euo pipefail - root="''${DEVENV_ROOT:-$PWD}" - authority="$root/.devenv/editor-workspace-authority.json" - scratch="$(${pkgs.coreutils}/bin/mktemp -d "$root/.devenv/editor-check-inputs.XXXXXX")" - cleanup_editor_check() { - status=$? - ${pkgs.coreutils}/bin/rm -rf -- "$scratch" || status=$? - trap - EXIT - exit "$status" - } - trap cleanup_editor_check EXIT - workspace_root="$(${pkgs.coreutils}/bin/realpath "$root/../..")" - buck="$workspace_root/.megarepo/bin/buck2" - ( - cd "$workspace_root" - "$buck" build effect_utils//packages/@overeng/tui-core:editor_inputs --out "$scratch/editor_inputs" - "$buck" build effect_utils//packages/@overeng/tui-core:node_modules --out "$scratch/node_modules" - ) - ${pkgs.bun}/bin/bun "$root/packages/@overeng/buck2-tools/src/editor-view.ts" check \ - --repo-root "$root" \ - --package packages/@overeng/tui-core \ - --cell tui-core \ - --target //packages/@overeng/tui-core:editor_inputs \ - --editor-inputs "$scratch/editor_inputs" \ - --node-modules "$scratch/node_modules" \ - --cp ${pkgs.coreutils}/bin/cp \ - --workspace-authority "$authority" \ - --consumer-cache "$root/.devenv/vite-cache/tui-core" \ - --snapshot-retention 3 \ - --mv ${pkgs.coreutils}/bin/mv - ''; + tasks."buck2:editor:authority" = { + description = "Prove complete Buck ownership of every workspace editor dependency view"; + after = [ "mr:apply" ]; + # trace-audit-allow: editorViewExec returns a trace.exec-wrapped command. + exec = editorViewExec "authority"; }; - tasks."buck2:tui-core:recover-editor-lock" = { - description = "Recover the scoped tui-core editor publication lock with its exact owner token"; - exec = trace.exec "buck2:tui-core:recover-editor-lock" '' + tasks."buck2:editor:publish" = { + description = "Atomically publish every Buck-owned workspace editor dependency view"; + after = [ "mr:apply" ]; + # trace-audit-allow: editorViewExec returns a trace.exec-wrapped command. + exec = editorViewExec "publish"; + }; + + tasks."buck2:editor:check" = { + description = "Fail when any published workspace editor dependency view is stale"; + after = [ "mr:apply" ]; + # trace-audit-allow: editorViewExec returns a trace.exec-wrapped command. + exec = editorViewExec "check"; + }; + + tasks."buck2:editor:recover-lock" = { + description = "Recover the shared editor publication lock with its exact owner token"; + exec = trace.exec "buck2:editor:recover-lock" '' set -euo pipefail root="''${DEVENV_ROOT:-$PWD}" + package="''${EDITOR_VIEW_PACKAGE:?set EDITOR_VIEW_PACKAGE to a workspace package path}" token="''${EDITOR_VIEW_LOCK_TOKEN:?set EDITOR_VIEW_LOCK_TOKEN to the owner token printed by publish}" ${pkgs.bun}/bin/bun "$root/packages/@overeng/buck2-tools/src/editor-view.ts" recover-lock \ --repo-root "$root" \ - --package packages/@overeng/tui-core \ + --package "$package" \ --token "$token" ''; }; tasks."buck2:typescript:materialize-dist" = { description = "Atomically materialize all Buck-owned TypeScript declarations"; - after = [ - "mr:apply" - "genie:run" - ]; + after = [ "buck2:editor:materialize" ]; exec = trace.exec "buck2:typescript:materialize-dist" '' set -euo pipefail ${composedWorkspaceRootPredicate} @@ -1302,17 +1257,13 @@ in pkgs.watchman ] } - if workspace_root="$(composed_workspace_root "$root")"; then - export TYPESCRIPT_DIST_MODE=publish - export WORKSPACE_ROOT="$workspace_root" - export BUCK2_BIN="$WORKSPACE_ROOT/.megarepo/bin/buck2" - else + workspace_root="$(composed_workspace_root "$root")" || { identity_status=$? - [ "$identity_status" -eq 1 ] || exit "$identity_status" - export TYPESCRIPT_DIST_MODE=check - export TSGO_BIN=${effectTsgo}/bin/tsgo - export DIFF_BIN=${pkgs.diffutils}/bin/diff - fi + echo "buck2:typescript:materialize-dist requires a composed megarepo workspace" >&2 + exit "$identity_status" + } + export WORKSPACE_ROOT="$workspace_root" + export BUCK2_BIN="$WORKSPACE_ROOT/.megarepo/bin/buck2" exec ${pkgs.bun}/bin/bun "$root/genie/buck2/typescript-authority-runtime.ts" \ materialize-dist "$root" ${pkgs.bash}/bin/bash ''; @@ -1330,10 +1281,22 @@ in ''; }; + tasks."check:buck2-producer-overlap" = { + description = "Reject duplicate Buck and legacy TypeScript producers"; + after = [ "genie:check" ]; + exec = trace.exec "check:buck2-producer-overlap" '' + set -euo pipefail + root="''${DEVENV_ROOT:-$PWD}" + exec ${pkgs.bun}/bin/bun "$root/genie/buck2/producer-overlap.ts" check \ + "$root/.devenv/gc/task-config-devenv-config-task-config" + ''; + }; + + # The provider audit remains separate because it validates the composed + # toolchain boundary rather than producing an admitted repository artifact. tasks."buck2:check" = { description = "Build every admitted TypeScript check, declared test lane, and the archive/product Buck2 surface"; after = [ - "mr:apply" "buck2:nix-bridge:check" "buck2:task-guards:check" "buck2:rust-deps:check" @@ -1341,36 +1304,49 @@ in exec = trace.exec "buck2:check" '' set -euo pipefail root="''${DEVENV_ROOT:-$PWD}" - export PATH=${ - lib.makeBinPath [ - pkgs.coreutils - pkgs.watchman - ] - } - workspace_root="$(${pkgs.coreutils}/bin/realpath "$root/../..")" - buck="$workspace_root/.megarepo/bin/buck2" - "$buck" audit providers \ - --target-platforms effect_utils//buck2/platforms:host_platform \ - effect_utils//buck2/toolchains:cross_cell_provider_identity \ - effect_utils//buck2/toolchains:cross_cell_product_identity - exec ${pkgs.bun}/bin/bun "$root/genie/buck2/typescript-authority-runtime.ts" \ - build "$buck" + export PATH=${lib.makeBinPath [ pkgs.watchman ]} + cd "$root" + exec "$BUCK2_BIN" audit providers \ + --target-platforms //buck2/platforms:host_platform \ + //buck2/toolchains:cross_cell_provider_identity \ + //buck2/toolchains:cross_cell_product_identity ''; }; + tasks."buck2:quick" = { + description = "Build the admitted quick Buck aggregate"; + after = [ "buck2:check" ]; + # trace-audit-allow: buck2AggregateExec returns a trace.exec-wrapped command. + exec = buck2AggregateExec "buck2:quick" "//:quick"; + }; + + tasks."buck2:all" = { + description = "Build the complete admitted Buck aggregate"; + after = [ "buck2:check" ]; + # trace-audit-allow: buck2AggregateExec returns a trace.exec-wrapped command. + exec = buck2AggregateExec "buck2:all" "//:all"; + }; + + tasks."check:quick".after = [ + "buck2:quick" + "check:buck2-producer-overlap" + ]; + # One Buck invocation executes every admitted bounded lane. This is what `test:run` waits on; # the per-lane `test:` tasks (imported above) exist for standalone use and are not # part of that graph, so no suite is scheduled twice. tasks."test:buck2:unit" = { description = "Execute every admitted bounded unit-test lane under Buck"; after = [ "mr:apply" ]; + # trace-audit-allow: buck2UnitTestExec returns a trace.exec-wrapped command. exec = buck2UnitTestExec { name = "test:buck2:unit"; targets = map (lane: lane.target) buck2TestLanes; }; }; - tasks."check:all".after = [ + "buck2:all" + "check:buck2-producer-overlap" "cargo:check" "dependency-materialization:evidence:check" ]; @@ -1409,6 +1385,16 @@ in enterShell = '' export WORKSPACE_ROOT="$PWD" export PATH="$WORKSPACE_ROOT/node_modules/.bin:$PATH" + # Buck2 expands the cache header in the daemon; keep the optional credential + # defined so unauthenticated cache reads work when SecretSpec is not active. + export BUCK2_REMOTE_CACHE_BASIC_AUTH="''${BUCK2_REMOTE_CACHE_BASIC_AUTH:-}" + capability_parent="$WORKSPACE_ROOT/.buck2" + capability_link="$capability_parent/capabilities" + ${pkgs.coreutils}/bin/mkdir -p "$capability_parent" + if [ -e "$capability_link" ] && [ ! -L "$capability_link" ]; then + ${pkgs.coreutils}/bin/rm -rf -- "$capability_link" + fi + ${pkgs.coreutils}/bin/ln -sfnT ${buck2Capabilities} "$capability_link" ${cliBuildStamp.shellHook} ''; diff --git a/flake.nix b/flake.nix index 6efd22c3ad..2f2408a7d5 100644 --- a/flake.nix +++ b/flake.nix @@ -38,34 +38,19 @@ system: let pkgs = import nixpkgs { inherit system; }; + rootPath = self.outPath; mkBunCli = import ./nix/workspace-tools/lib/mk-bun-cli.nix { inherit pkgs; }; cliBuildStamp = import ./nix/workspace-tools/lib/cli-build-stamp.nix { inherit pkgs; }; mkPnpmCliSupport = import ./nix/workspace-tools/lib/mk-pnpm-cli-support.nix { inherit pkgs; }; - rootPath = self.outPath; - oxlintNpm = import ./nix/oxlint-npm.nix { - inherit pkgs; - bun = pkgs.bun; - src = self; - }; nodePtyNative = import ./nix/node-pty-native.nix { inherit pkgs; }; providerCliPackages = { vercel-cli = import ./nix/provider-clis/vercel-cli { inherit pkgs; }; netlify-cli = import ./nix/provider-clis/netlify-cli { inherit pkgs; }; }; - # Rust packages (otelite, otel-scrape) built via - # rustPlatform.buildRustPackage, separate from the Bun CLIs. otelite (a - # local OTLP capture tool) was effect-utils' first Rust package. - otelite = import (rootPath + "/packages/@overeng/otelite/nix/build.nix") { - inherit pkgs; - }; - otel-scrape = import (rootPath + "/packages/@overeng/otel-scrape/nix/build.nix") { - inherit - pkgs - gitRev - commitTs - dirty - ; - }; + # Buck is the sole producer for shipped Rust CLIs. Nix imports the exact + # reviewed per-tuple release assets and revalidates their descriptors, + # payloads, native runtime contracts, and entrypoints. + nativeProductPackages = (import ./nix/buck2-native-products { inherit pkgs; }).products; buck2 = import ./nix/buck2.nix { inherit pkgs; }; buck2-go = import ./nix/go.nix { inherit pkgs; }; buck2-stage0-tools = import ./nix/buck2-stage0-tools.nix { inherit pkgs; }; @@ -79,6 +64,50 @@ # unadmitted gh-ci-utils CLI keeps its source-built Nix package until a # later authority transfer explicitly admits it. trackedBuck2Products = import ./nix/buck2-products { inherit pkgs; }; + oxlintNpm = import ./nix/oxlint-npm.nix { + inherit pkgs; + bun = pkgs.bun; + products = trackedBuck2Products.products; + }; + capabilityPackages = { + inherit buck2; + bun = pkgs.bun; + buck2-node = pkgs.writeShellScriptBin "node" '' + exec ${pkgs.nodejs_24 or pkgs.nodejs}/bin/node "$@" + ''; + inherit buck2-go; + buck2-python-bootstrap = pkgs.writeShellScriptBin "python3" '' + exec ${pkgs.python3}/bin/python3 "$@" + ''; + buck2-archive-tool = buck2-stage0-tools.archive-tool; + buck2-product = buck2-stage0-tools.product; + buck2-coreutils = pkgs.writeShellScriptBin "readlink" '' + exec ${pkgs.coreutils}/bin/readlink "$@" + ''; + buck2-rust-compiler = buck2-rust-toolchain-capability.packages.rust-compiler; + buck2-rust-rustdoc = buck2-rust-toolchain-capability.packages.rust-rustdoc; + buck2-rust-clippy-driver = buck2-rust-toolchain-capability.packages.rust-clippy-driver; + buck2-rust-c-compiler = buck2-rust-toolchain-capability.packages.rust-c-compiler; + buck2-rust-cxx-compiler = buck2-rust-toolchain-capability.packages.rust-cxx-compiler; + buck2-rust-linker = buck2-rust-toolchain-capability.packages.rust-linker; + buck2-rust-archiver = buck2-rust-toolchain-capability.packages.rust-archiver; + buck2-rust-dwp = buck2-rust-toolchain-capability.packages.rust-dwp; + buck2-rust-nm = buck2-rust-toolchain-capability.packages.rust-nm; + buck2-rust-objcopy = buck2-rust-toolchain-capability.packages.rust-objcopy; + buck2-rust-objdump = buck2-rust-toolchain-capability.packages.rust-objdump; + buck2-rust-ranlib = buck2-rust-toolchain-capability.packages.rust-ranlib; + buck2-rust-strip = buck2-rust-toolchain-capability.packages.rust-strip; + buck2-rust-shell = buck2-rust-toolchain-capability.packages.rust-shell; + effect-tsgo = tsgo.packages.${system}.effect-tsgo; + oxfmt = pkgs.oxfmt; + oxlint-with-plugins = import ./nix/oxlint-with-plugins.nix { + inherit pkgs oxlintNpm; + }; + }; + buck2Capabilities = import ./nix/buck2-capabilities.nix { + inherit pkgs capabilityPackages; + src = rootPath; + }; buck2ProductCandidates = import ./nix/workspace-tools/lib/buck2-product-candidates.nix { inherit pkgs @@ -88,6 +117,7 @@ ; products = trackedBuck2Products.products; typeProofCompilerBin = "${tsgo.packages.${system}.tsgo}/bin/tsgo"; + capabilityProjection = buck2Capabilities; }; ghCiUtils = import (rootPath + "/packages/@overeng/gh-ci-utils/nix/build.nix") { inherit @@ -110,75 +140,26 @@ }; }); }; + in { packages = cliPackages // providerCliPackages + // nativeProductPackages + // capabilityPackages // { - inherit - buck2 - otelite - otel-scrape - ; - # Hub toolchain authority realization: the exact Bun every Buck JS/TS action uses. - bun = pkgs.bun; - # Hub toolchain authority realization: the exact Node every Buck Vitest lane - # that exercises Node built-ins runs on. - buck2-node = pkgs.writeShellScriptBin "node" '' - exec ${pkgs.nodejs_24 or pkgs.nodejs}/bin/node "$@" - ''; - # Hub toolchain authority realization: the exact Go distribution every - # Buck Go action compiles with — the OFFICIAL release archive, not - # `pkgs.go`, whose patched stdlib puts three absolute store paths into - # every product it compiles (decision 0029, `nix/go.nix`). `bin/go` is a - # real file in that archive, so the resolver's realpath lands on - # /nix/store//bin/go and no wrapper is needed. - inherit buck2-go; - # Hub toolchain authority realization: prelude's bootstrap interpreter. - buck2-python-bootstrap = pkgs.writeShellScriptBin "python3" '' - exec ${pkgs.python3}/bin/python3 "$@" - ''; - buck2-archive-tool = buck2-stage0-tools.archive-tool; - buck2-product = buck2-stage0-tools.product; - # Composition-wrapper capability realization for the - # `gnu/coreutils/v9` readlink executable. Keep a real executable - # file at this path so capability resolution can attest it. - buck2-coreutils = pkgs.writeShellScriptBin "readlink" '' - exec ${pkgs.coreutils}/bin/readlink "$@" - ''; - buck2-rust-compiler = buck2-rust-toolchain-capability.packages.rust-compiler; - buck2-rust-rustdoc = buck2-rust-toolchain-capability.packages.rust-rustdoc; - buck2-rust-clippy-driver = buck2-rust-toolchain-capability.packages.rust-clippy-driver; - buck2-rust-c-compiler = buck2-rust-toolchain-capability.packages.rust-c-compiler; - buck2-rust-cxx-compiler = buck2-rust-toolchain-capability.packages.rust-cxx-compiler; - buck2-rust-linker = buck2-rust-toolchain-capability.packages.rust-linker; - buck2-rust-archiver = buck2-rust-toolchain-capability.packages.rust-archiver; - buck2-rust-dwp = buck2-rust-toolchain-capability.packages.rust-dwp; - buck2-rust-nm = buck2-rust-toolchain-capability.packages.rust-nm; - buck2-rust-objcopy = buck2-rust-toolchain-capability.packages.rust-objcopy; - buck2-rust-objdump = buck2-rust-toolchain-capability.packages.rust-objdump; - buck2-rust-ranlib = buck2-rust-toolchain-capability.packages.rust-ranlib; - buck2-rust-strip = buck2-rust-toolchain-capability.packages.rust-strip; - buck2-rust-shell = buck2-rust-toolchain-capability.packages.rust-shell; + buck2-capabilities = buck2Capabilities; cli-build-stamp = cliBuildStamp.package; - effect-tsgo = tsgo.packages.${system}.effect-tsgo; gh-ci-utils = ghCiUtils; gh-ci-utils-dirty = ghCiUtilsDirty; "gh-ci-utils-pnpm-deps" = ghCiUtils.passthru.depsBuildsByInstallRoot.root; - # The oxlint plugin bundle keeps its pnpm FOD as first-class outputs: - # `nix/oxlint-npm.nix` needs the pnpm-built plugin bundle, which the - # `oxc-config` JavaScript product does not replace. The bundle exposes - # Evergreen producer metadata; its raw FOD remains directly addressable. - # The `oxc-config` package itself is merged in from `cliPackages`. - "oxc-config-plugin" = oxlintNpm.pluginBundle; - "oxc-config-plugin-pnpm-deps" = oxlintNpm.pluginBundle.passthru.depsBuildsByInstallRoot.root; - # npm oxlint with NAPI bindings + pre-bundled @overeng/oxc-config plugin + # Static-check executables projected as Buck capabilities. Nix realizes + # third-party tools; Buck owns source inputs and check execution. + oxfmt = pkgs.oxfmt; + # npm oxlint with NAPI bindings. Its two JavaScript plugins are + # immutable Buck module products imported from the tracked manifest. oxlint-npm = oxlintNpm; - # oxlint-npm wrapped with automatic @overeng/oxc-config plugin injection - oxlint-with-plugins = import ./nix/oxlint-with-plugins.nix { - inherit pkgs oxlintNpm; - }; node-pty-native = nodePtyNative; } // pkgs.lib.optionalAttrs (system == "x86_64-linux") { @@ -197,11 +178,21 @@ gh-ci-utils = ghCiUtilsDirty.outPath; }; - apps.update-bun-hashes = flake-utils.lib.mkApp { - drv = import ./nix/workspace-tools/lib/update-bun-hashes.nix { inherit pkgs; }; + apps = { + update-bun-hashes = flake-utils.lib.mkApp { + drv = import ./nix/workspace-tools/lib/update-bun-hashes.nix { inherit pkgs; }; + }; + } + // pkgs.lib.optionalAttrs (nativeProductPackages ? otelite) { + otelite = flake-utils.lib.mkApp { + drv = nativeProductPackages.otelite; + exePath = "/bin/otelite"; + }; + otel-scrape = flake-utils.lib.mkApp { + drv = nativeProductPackages.otel-scrape; + exePath = "/bin/otel-scrape"; + }; }; - apps.otelite = flake-utils.lib.mkApp { drv = otelite; }; - apps.otel-scrape = flake-utils.lib.mkApp { drv = otel-scrape; }; } ) // { @@ -312,21 +303,20 @@ // args ); - # npm oxlint with NAPI bindings for JavaScript plugin support. - # When `src` is provided (the effect-utils source), the @overeng/oxc-config - # plugin is bundled alongside and exposed via passthru.pluginPath. - # Usage: effectUtils.lib.mkOxlintNpm { inherit pkgs; bun = pkgs.bun; src = inputs.effect-utils; } + # npm oxlint with NAPI bindings plus the two tracked immutable + # @overeng/oxc-config JavaScript plugin products. + # Usage: effectUtils.lib.mkOxlintNpm { inherit pkgs; bun = pkgs.bun; } lib.mkOxlintNpm = { pkgs, bun, - src ? null, + products ? (import ./nix/buck2-products { inherit pkgs; }).products, }: - import ./nix/oxlint-npm.nix { inherit pkgs bun src; }; + import ./nix/oxlint-npm.nix { inherit pkgs bun products; }; - # oxlint wrapper that auto-injects the @overeng/oxc-config plugin when - # the project config contains overeng/* rules. Falls through to plain - # oxlint-npm otherwise. + # oxlint wrapper that substitutes the overeng and @stylexjs configured + # entries with their separate tracked module paths. Projects without + # either namespace pass through to plain oxlint-npm. # Usage: effectUtils.lib.mkOxlintWithPlugins { inherit pkgs; oxlintNpm = effectUtils.packages.\${system}.oxlint-npm; } lib.mkOxlintWithPlugins = { diff --git a/genie/buck2/buck2-runtime-closure.unit.test.ts b/genie/buck2/buck2-runtime-closure.unit.test.ts index 9dbcf0d863..4e978c9b28 100644 --- a/genie/buck2/buck2-runtime-closure.unit.test.ts +++ b/genie/buck2/buck2-runtime-closure.unit.test.ts @@ -47,7 +47,7 @@ const importClosure = (entry: string): readonly string[] => { return [...seen].toSorted() } -const rootBuck = readFileSync('BUCK', 'utf8') +const buck2ToolsBuck = readFileSync('packages/@overeng/buck2-tools/BUCK', 'utf8') describe('staged Buck runtime closure', () => { it.each(buck2StagedRuntimes.map((runtime) => [runtime.label, runtime] as const))( @@ -64,17 +64,17 @@ describe('staged Buck runtime closure', () => { )('%s is staged as one file and therefore imports nothing relative', (_label, runtime) => { expect(runtime.modules).toEqual([runtime.entry]) expect(relativeSpecifiers(readFileSync(runtime.entry, 'utf8'))).toEqual([]) - expect(rootBuck).toContain(` src = "${runtime.entry}",`) + expect(buck2ToolsBuck).toContain(` src = "src/${stagedModuleName(runtime.entry)}",`) }) - it('declares every filegroup-staged module in the root Buck package', () => { + it('declares every filegroup-staged module in the buck2-tools package', () => { for (const runtime of buck2StagedRuntimes.filter((entry) => entry.staging === 'filegroup')) { - const name = runtime.label.slice('//:'.length) - const block = rootBuck.split(`name = "${name}",`)[1]?.split(')')[0] ?? '' + const name = runtime.label.slice(runtime.label.lastIndexOf(':') + 1) + const block = buck2ToolsBuck.split(`name = "${name}",`)[1]?.split(')')[0] ?? '' expect(block, `no filegroup block for ${runtime.label}`).not.toBe('') const declared = [...block.matchAll(/"([^"]+)":\s*"([^"]+)"/gu)].map((match) => ({ staged: match[1], - source: match[2], + source: `packages/@overeng/buck2-tools/${match[2] ?? ''}`, })) expect(declared.map(({ source }) => source).toSorted()).toEqual( [...runtime.modules].toSorted(), diff --git a/genie/buck2/javascript-candidates.unit.test.ts b/genie/buck2/javascript-candidates.unit.test.ts index 6d179a728b..84291c6e65 100644 --- a/genie/buck2/javascript-candidates.unit.test.ts +++ b/genie/buck2/javascript-candidates.unit.test.ts @@ -3,6 +3,7 @@ import process from 'node:process' import { describe, expect, it } from 'vitest' import type { GenieContext } from '../../packages/@overeng/genie/src/runtime/core.ts' +import releaseTargetsProjection from '../../nix/buck2-products/targets.json.genie.ts' import { withJavaScriptCandidates } from './javascript-candidates.ts' import { javaScriptProductPublications, @@ -78,6 +79,13 @@ const expectedPublications = [ productName: 'oxc-config', runtimeKind: 'node', }, + { + label: '//packages/@overeng/oxc-config:oxc-config-stylex-upstream-plugin-candidate', + module: 'oxc-config-stylex-upstream-plugin.js', + productKind: 'module', + productName: 'oxc-config-stylex-upstream-plugin', + runtimeKind: 'node', + }, { label: '//packages/@overeng/tui-stories:tui-stories-candidate', module: 'tui-stories.js', @@ -94,9 +102,9 @@ const expectUnique = (values: readonly string[]): void => { } describe('JavaScript product registry', () => { - it('declares the ten exact publication labels and product contracts', () => { + it('declares the eleven exact publication labels and product contracts', () => { expect(javaScriptProductPublications).toEqual(expectedPublications) - expect(javaScriptProductPublications).toHaveLength(10) + expect(javaScriptProductPublications).toHaveLength(11) }) it('keeps every publication identity and package-local target unique', () => { @@ -117,13 +125,57 @@ describe('JavaScript product registry', () => { } }) - it('keeps product package admissions editor non-consumers with targets clear of authority', () => { + it('declares the two oxc-config plugin entry points as separate products', () => { + expect(javaScriptProductsFor('packages/@overeng/oxc-config')).toEqual([ + expect.objectContaining({ + entrypoint: 'src/mod.ts', + productName: 'oxc-config', + }), + expect.objectContaining({ + entrypoint: 'src/stylex-upstream-plugin.ts', + productName: 'oxc-config-stylex-upstream-plugin', + }), + ]) + }) + + it('projects the registry into the fingerprinted release target inventory', () => { + const inventory = JSON.parse(releaseTargetsProjection.stringify(genieContext)) as { + products: Array<{ name: string; target: string }> + provenance: { + fingerprint: string + generator: string + regenerationCommand: string + semanticInputs: string[] + source: string + } + schemaVersion: number + } + + expect(inventory).toEqual({ + products: expectedPublications.map(({ label, productName }) => ({ + name: productName, + target: `effect_utils${label}`, + })), + provenance: { + fingerprint: expect.stringMatching(/^sha256:[0-9a-f]{64}$/), + generator: 'effect-utils/genie/buck2-javascript-release-targets', + regenerationCommand: 'devenv tasks run genie:run', + semanticInputs: [ + 'genie/buck2/javascript-product-registry.ts', + 'nix/buck2-products/targets.json.genie.ts', + ], + source: 'nix/buck2-products/targets.json.genie.ts', + }, + schemaVersion: 1, + }) + }) + + it('keeps product targets clear of TypeScript authority targets', () => { const admissions = Object.values(buck2TypeScriptAdmissions) const authorityTargetNames: Record = { typecheck: true, dist: true } for (const packagePath of productPackagePaths) { const admission = admissions.find((candidate) => candidate.packagePath === packagePath) expect(admission, `missing TypeScript admission for ${packagePath}`).toBeDefined() - expect(admission?.editorViewConsumer).toBe(false) for (const product of javaScriptProductsFor( packagePath as keyof typeof javaScriptProductRegistry, )) { diff --git a/genie/buck2/javascript-package-projection.unit.test.ts b/genie/buck2/javascript-package-projection.unit.test.ts index 89485536a7..31fcd974a5 100644 --- a/genie/buck2/javascript-package-projection.unit.test.ts +++ b/genie/buck2/javascript-package-projection.unit.test.ts @@ -31,3 +31,48 @@ describe('buck2/javascript.bzl test cache participation', () => { ) }) }) + +describe('portable JavaScript product cache policy', () => { + const packageTools = readFileSync('buck2/package_tools.bzl', 'utf8') + const productRules = readFileSync('buck2/products/defs.bzl', 'utf8') + + it('admits deterministic local product actions under the root shared-cache policy', () => { + for (const source of [packageTools, productRules]) { + expect(source).toContain( + 'load("//buck2/platforms:defs.bzl",', + ) + expect(source).toContain('"root_allow_cache_uploads"') + expect(source).toContain('"root_remote_cache_enabled"') + expect(source).toContain( + 'allow_cache_upload = root_remote_cache_enabled() and root_allow_cache_uploads(),', + ) + } + expect(packageTools).toContain( + 'default_target_platform = "//buck2/platforms:javascript_portable",', + ) + }) + + it('keeps every result-affecting tool and product artifact in the action command line', () => { + expect(packageTools).toContain(`toolchain.executable, + _runner(ctx), + "bundle", + toolchain.executable, + package_tree.tree,`) + expect(packageTools).toContain('"--platform-gated-manifest",') + expect(packageTools).toContain('gated.manifest,') + expect(packageTools).toContain('args.add(cmd_args(hidden = package_tree.read_roots))') + expect(productRules).toContain(`toolchain.executable, + _runner(ctx), + "product-descriptor",`) + expect(productRules).toContain(`"--module-descriptor", + module.descriptor,`) + }) + + it('retains the non-product package check and build cache exceptions', () => { + for (const category of ['package_bin_check', 'package_bin_build']) { + expect(packageTools).toContain(`category = "${category}", + local_only = True, + allow_cache_upload = False,`) + } + }) +}) diff --git a/genie/buck2/javascript-product-registry.ts b/genie/buck2/javascript-product-registry.ts index 68ac2e6e79..9d79b1d8d6 100644 --- a/genie/buck2/javascript-product-registry.ts +++ b/genie/buck2/javascript-product-registry.ts @@ -38,6 +38,7 @@ export const javaScriptProductRegistry = { }, { entrypoint: 'bin/bootstrap-closure-check.ts', + externalCapabilities: ['typescript-api-server'], kind: 'cli', output: 'genie-bootstrap-closure-check.js', productName: 'genie-bootstrap-closure-check', @@ -107,6 +108,13 @@ export const javaScriptProductRegistry = { productName: 'oxc-config', targetName: 'oxc-config-candidate', }, + { + entrypoint: 'src/stylex-upstream-plugin.ts', + kind: 'module', + output: 'oxc-config-stylex-upstream-plugin.js', + productName: 'oxc-config-stylex-upstream-plugin', + targetName: 'oxc-config-stylex-upstream-plugin-candidate', + }, ], 'packages/@overeng/tui-stories': [ { diff --git a/genie/buck2/operation-dispositions.ts b/genie/buck2/operation-dispositions.ts new file mode 100644 index 0000000000..f927fef045 --- /dev/null +++ b/genie/buck2/operation-dispositions.ts @@ -0,0 +1,64 @@ +import { CI_JOB_NAMES, type CIJobName } from '../ci.ts' + +export type BuckAuthorityTranche = 'static' | 'editor' | 'rust' | 'consumer' + +export type OperationDisposition = + | 'buck-owned' + | `buck-pending:${BuckAuthorityTranche}` + | `outside-by-policy:${string}` + +export const developerOperationDispositions = { + 'buck2:check': 'buck-owned', + 'buck2:editor:publish': 'outside-by-policy:workspace-publication', + 'buck2:typescript:materialize-dist': 'outside-by-policy:workspace-publication', + 'check:all': 'outside-by-policy:cross-boundary-aggregate', + 'check:quick': 'outside-by-policy:cross-boundary-aggregate', + 'genie:check': 'outside-by-policy:stage-zero-bootstrap-freshness', + 'genie:run': 'outside-by-policy:authoring-mutation', + 'genie:watch': 'outside-by-policy:long-lived-watcher', + 'lint:check': 'outside-by-policy:includes-stage-zero-freshness', + 'lint:fix': 'outside-by-policy:authoring-mutation', + 'test:': 'outside-by-policy:aggregate-includes-policy-excluded-tests', + 'test:genie': 'outside-by-policy:aggregate-includes-policy-excluded-tests', + 'test:integration': 'outside-by-policy:secret-service-integration', + 'test:run': 'outside-by-policy:aggregate-includes-policy-excluded-tests', + 'test:utils': 'outside-by-policy:aggregate-includes-policy-excluded-tests', + 'test:watch': 'outside-by-policy:long-lived-watcher', +} as const satisfies Record + +export type DeveloperOperation = keyof typeof developerOperationDispositions + +export const ciOperationDispositions = { + 'bootstrap-cold-proof': 'outside-by-policy:bootstrap-integration', + 'bundle-smoke': 'buck-owned', + cargo: 'outside-by-policy:aggregate-includes-rust-quality-gates', + 'ci-measurements-report': 'outside-by-policy:ci-control-plane', + 'default-ref-policy': 'outside-by-policy:pre-composition-trust-gate', + 'deploy-storybooks': 'outside-by-policy:live-deployment', + 'devenv-perf': 'outside-by-policy:operator-benchmark', + lint: 'outside-by-policy:includes-stage-zero-freshness', + 'nix-closure-sizes': 'outside-by-policy:nix-realization', + 'notify-alignment': 'outside-by-policy:ci-control-plane', + 'pnpm-builder-contract': 'outside-by-policy:nix-builder-contract', + 'pnpm-regression': 'outside-by-policy:nix-builder-contract', + 'source-shape': 'outside-by-policy:ci-measurement-with-run-timestamp', + test: 'outside-by-policy:aggregate-includes-policy-excluded-tests', + 'test-integration-notion': 'outside-by-policy:secret-service-integration', + 'test-integration-restate': 'outside-by-policy:service-integration', + 'test-live-deploy-ci-tools': 'outside-by-policy:live-deployment', + 'test-megarepo-cold-gc': 'outside-by-policy:filesystem-integration', + 'test-playwright-tui-react': 'outside-by-policy:browser-integration', + 'test-playwright-utils': 'outside-by-policy:browser-integration', + typecheck: 'buck-owned', + weaver: 'outside-by-policy:aggregate-includes-change-relative-and-live-integration', +} as const satisfies Record + +export const operationDispositionProjection = { + developerOperations: Object.entries(developerOperationDispositions).map( + ([operation, disposition]) => ({ operation, disposition }), + ), + ciOperations: CI_JOB_NAMES.map((operation) => ({ + operation, + disposition: ciOperationDispositions[operation], + })), +} as const diff --git a/genie/buck2/operation-dispositions.unit.test.ts b/genie/buck2/operation-dispositions.unit.test.ts new file mode 100644 index 0000000000..d693960781 --- /dev/null +++ b/genie/buck2/operation-dispositions.unit.test.ts @@ -0,0 +1,54 @@ +import { readFileSync } from 'node:fs' +import process from 'node:process' + +import { describe, expect, it } from 'vitest' + +import dispositionArtifact from '../../buck2-operation-dispositions.json.genie.ts' +import { CI_JOB_NAMES } from '../ci.ts' +import { + ciOperationDispositions, + developerOperationDispositions, + operationDispositionProjection, +} from './operation-dispositions.ts' + +const sort = (values: Iterable) => [...values].sort((left, right) => left.localeCompare(right)) + +const documentedDeveloperOperations = () => { + const operations = new Set() + for (const path of ['AGENTS.md', 'README.md']) { + const source = readFileSync(path, 'utf8') + for (const match of source.matchAll(/devenv tasks run ([^\s`]+)/g)) { + const operation = match[1] + if (operation !== '') operations.add(operation) + } + } + return sort(operations) +} + +describe('Buck operation disposition coverage', () => { + it('classifies every documented public developer operation exactly once', () => { + expect(sort(Object.keys(developerOperationDispositions))).toEqual(documentedDeveloperOperations()) + }) + + it('classifies every generated CI job exactly once', () => { + expect(sort(Object.keys(ciOperationDispositions))).toEqual(sort(CI_JOB_NAMES)) + }) + + it('uses only actionable or explicit policy dispositions', () => { + for (const disposition of [ + ...Object.values(developerOperationDispositions), + ...Object.values(ciOperationDispositions), + ]) { + expect(disposition).toMatch( + /^(?:buck-owned|buck-pending:(?:static|editor|rust|consumer)|outside-by-policy:[a-z0-9-]+)$/, + ) + } + }) + + it('projects the source registry without a second classification table', () => { + expect(JSON.parse(dispositionArtifact.stringify({ cwd: process.cwd(), location: '' }))).toEqual({ + schemaVersion: 1, + ...operationDispositionProjection, + }) + }) +}) diff --git a/genie/buck2/producer-overlap.ts b/genie/buck2/producer-overlap.ts new file mode 100644 index 0000000000..8198419c82 --- /dev/null +++ b/genie/buck2/producer-overlap.ts @@ -0,0 +1,126 @@ +import { readFileSync } from 'node:fs' +import process from 'node:process' + +import { + authoritativeBuck2TypeScriptDeclarations, + authoritativeBuck2TypeScriptProjects, + type AuthoritativeBuck2TypeScriptDeclaration, + type AuthoritativeBuck2TypeScriptProject, +} from './typescript-admissions.ts' + +export type ProducerOperation = 'dist' | 'typecheck' + +export type ProducerOverlapAllowance = { + readonly ledgerRow: `effect-utils/${ProducerOperation}/${string}` + readonly operation: ProducerOperation + readonly packagePath: string +} + +export type ProducerOverlap = { + readonly operation: ProducerOperation + readonly packagePath: string + readonly producers: readonly [buck: string, legacy: string] +} + +/** Lower stack members retired every prior allowance with the root TypeScript solution. */ +export const producerOverlapAllowlist: readonly ProducerOverlapAllowance[] = [] + +const overlapKey = ({ + operation, + packagePath, +}: Pick): string => `${operation}:${packagePath}` + +export const findProducerOverlaps = ({ + projects, + declarations, + allowances, + devenvTaskNames, +}: { + readonly projects: readonly AuthoritativeBuck2TypeScriptProject[] + readonly declarations: readonly AuthoritativeBuck2TypeScriptDeclaration[] + readonly allowances: readonly ProducerOverlapAllowance[] + readonly devenvTaskNames: readonly string[] +}): readonly ProducerOverlap[] => { + const taskNames = new Set(devenvTaskNames) + const overlaps: ProducerOverlap[] = [] + + if (taskNames.has('ts:check')) { + overlaps.push( + ...projects.map( + (project): ProducerOverlap => ({ + operation: 'typecheck', + packagePath: project.packagePath, + producers: [`Buck ${project.typecheckTarget}`, 'devenv ts:check'], + }), + ), + ) + } + if (taskNames.has('ts:emit')) { + overlaps.push( + ...declarations.map( + (declaration): ProducerOverlap => ({ + operation: 'dist', + packagePath: declaration.packagePath, + producers: [`Buck ${declaration.distTarget}`, 'devenv ts:emit'], + }), + ), + ) + } + + const overlapKeys = new Set(overlaps.map(overlapKey)) + const staleAllowances = allowances.filter( + (allowance) => overlapKeys.has(overlapKey(allowance)) === false, + ) + if (staleAllowances.length > 0) { + throw new Error( + `stale Buck producer overlap allowances: ${staleAllowances.map(({ ledgerRow }) => ledgerRow).join(', ')}`, + ) + } + + const allowedKeys = new Set(allowances.map(overlapKey)) + return overlaps.filter((overlap) => allowedKeys.has(overlapKey(overlap)) === false) +} + +const taskNamesFromDocument = (document: unknown): readonly string[] => { + if (Array.isArray(document)) { + return document.flatMap((task) => + task !== null && typeof task === 'object' && 'name' in task && typeof task.name === 'string' + ? [task.name] + : [], + ) + } + if (document === null || typeof document !== 'object') return [] + const tasks = 'tasks' in document ? document.tasks : document + if (Array.isArray(tasks)) return taskNamesFromDocument(tasks) + if (tasks === null || typeof tasks !== 'object') return [] + return Object.entries(tasks).flatMap(([key, task]) => + task !== null && typeof task === 'object' && 'name' in task && typeof task.name === 'string' + ? [task.name] + : [key], + ) +} + +const main = (): number => { + const [operation, taskDocumentPath, ...unexpected] = process.argv.slice(2) + if (operation !== 'check' || taskDocumentPath === undefined || unexpected.length > 0) { + console.error('usage: producer-overlap.ts check ') + return 2 + } + + const taskDocument: unknown = JSON.parse(readFileSync(taskDocumentPath, 'utf8')) + const overlaps = findProducerOverlaps({ + projects: authoritativeBuck2TypeScriptProjects, + declarations: authoritativeBuck2TypeScriptDeclarations, + allowances: producerOverlapAllowlist, + devenvTaskNames: taskNamesFromDocument(taskDocument), + }) + if (overlaps.length === 0) return 0 + for (const overlap of overlaps) { + console.error( + `${overlap.packagePath} ${overlap.operation} has overlapping producers: ${overlap.producers.join(', ')}`, + ) + } + return 1 +} + +if (import.meta.main === true) process.exit(main()) diff --git a/genie/buck2/producer-overlap.unit.test.ts b/genie/buck2/producer-overlap.unit.test.ts new file mode 100644 index 0000000000..55b8248960 --- /dev/null +++ b/genie/buck2/producer-overlap.unit.test.ts @@ -0,0 +1,77 @@ +import { describe, expect, it } from 'vitest' + +import { findProducerOverlaps, type ProducerOverlapAllowance } from './producer-overlap.ts' +import type { + AuthoritativeBuck2TypeScriptDeclaration, + AuthoritativeBuck2TypeScriptProject, +} from './typescript-admissions.ts' + +const project = { + packagePath: 'packages/@example/widget', + projectPath: 'packages/@example/widget', + projectFile: 'tsconfig.json', + typecheckTarget: '//packages/@example/widget:typecheck', +} as const satisfies AuthoritativeBuck2TypeScriptProject +const declaration = { + ...project, + declarationEntrypoint: 'src/mod.d.ts', + distTarget: '//packages/@example/widget:dist', + testTargets: [], +} as const satisfies AuthoritativeBuck2TypeScriptDeclaration + +const allAllowances = [ + { + ledgerRow: 'effect-utils/typecheck/widget', + operation: 'typecheck', + packagePath: project.packagePath, + }, + { + ledgerRow: 'effect-utils/dist/widget', + operation: 'dist', + packagePath: project.packagePath, + }, +] as const satisfies readonly ProducerOverlapAllowance[] + +describe('Buck producer overlap guard', () => { + it('fails an overlap outside the transitional allowlist', () => { + expect( + findProducerOverlaps({ + projects: [project], + declarations: [declaration], + allowances: [], + devenvTaskNames: ['ts:check', 'ts:emit'], + }), + ).toEqual([ + { + operation: 'typecheck', + packagePath: project.packagePath, + producers: ['Buck //packages/@example/widget:typecheck', 'devenv ts:check'], + }, + { + operation: 'dist', + packagePath: project.packagePath, + producers: ['Buck //packages/@example/widget:dist', 'devenv ts:emit'], + }, + ]) + }) + + it('passes known overlaps and rejects stale ledger allowances', () => { + expect( + findProducerOverlaps({ + projects: [project], + declarations: [declaration], + allowances: allAllowances, + devenvTaskNames: ['ts:check', 'ts:emit'], + }), + ).toEqual([]) + + expect(() => + findProducerOverlaps({ + projects: [project], + declarations: [declaration], + allowances: allAllowances, + devenvTaskNames: [], + }), + ).toThrow('stale Buck producer overlap allowances') + }) +}) diff --git a/genie/buck2/root-aggregate-projection.ts b/genie/buck2/root-aggregate-projection.ts new file mode 100644 index 0000000000..c38f01b0f1 --- /dev/null +++ b/genie/buck2/root-aggregate-projection.ts @@ -0,0 +1,94 @@ +import { + createGenieOutput, + type GenieOutput, +} from '../../packages/@overeng/genie/src/runtime/core.ts' +import { buck2SemanticFingerprint } from './mod.ts' +import { + authoritativeBuck2TypeScriptDeclarations, + authoritativeBuck2TypeScriptProjects, + buck2TypeScriptTestTargets, +} from './typescript-admissions.ts' + +const regenerationCommand = 'devenv tasks run genie:run' as const + +export type RootBuckAggregatePlan = { + readonly quick: readonly string[] + readonly all: readonly string[] +} +const fullAuthorityTargets = [ + '//buck2/toolchains:archive_tool', + '//buck2/toolchains:product_tool', +] as const + +export const planRootBuckAggregates = ({ + typecheckTargets = authoritativeBuck2TypeScriptProjects.map((project) => project.typecheckTarget), + distTargets = authoritativeBuck2TypeScriptDeclarations.map( + (declaration) => declaration.distTarget, + ), + testTargets = buck2TypeScriptTestTargets, +}: { + readonly typecheckTargets?: readonly string[] + readonly distTargets?: readonly string[] + readonly testTargets?: readonly string[] +} = {}): RootBuckAggregatePlan => ({ + quick: typecheckTargets, + all: [':quick', ...distTargets, ...testTargets, ...fullAuthorityTargets], +}) + +const renderFilegroup = ({ name, srcs }: { name: string; srcs: readonly string[] }): string => + [ + 'filegroup(', + ` name = ${JSON.stringify(name)},`, + ' srcs = {', + ...srcs.map( + (target, index) => ` ${JSON.stringify(index.toString().padStart(3, '0'))}: ${JSON.stringify(target)},`, + ), + ' },', + ' visibility = ["PUBLIC"],', + ')', + ].join('\n') + +const rootBuckBase = + 'load("//buck2:editor_view.bzl", "editor_view_inputs")\nload("@prelude//toolchains:genrule.bzl", "system_genrule_toolchain")\nload("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set")\n\n# Conventional prelude toolchain targets, owned by the platform hub.\n#\n# The composition root sets `[cell_aliases] toolchains = `\n# (`composition/root/composition-root.ts`), so prelude\'s conventional\n# `toolchains//:` spelling resolves into *this* package for every member cell in the\n# composed workspace. Prelude rules used by any member therefore find exactly one instance\n# of each conventional toolchain, and it is the hub\'s capability-backed one. Keeping them\n# here preserves `05-composition/spec.md:51-56` ("the root carries no synthetic toolchains\n# or `none` cell").\ntoolchain_alias(\n name = "rust",\n actual = "//buck2/toolchains:rust",\n visibility = ["PUBLIC"],\n)\n\ntoolchain_alias(\n name = "cxx",\n actual = "//buck2/toolchains:cxx",\n visibility = ["PUBLIC"],\n)\n\ntoolchain_alias(\n name = "go_bootstrap",\n actual = "//buck2/toolchains:go_bootstrap",\n visibility = ["PUBLIC"],\n)\n\ntoolchain_alias(\n name = "python_bootstrap",\n actual = "//buck2/toolchains:python_bootstrap",\n visibility = ["PUBLIC"],\n)\n\n# Prelude\'s genrule toolchain carries no executable at all (`zip_scrubber = None`,\n# `@prelude//:genrule_toolchain.bzl`), so there is nothing to pin and nothing to project:\n# the upstream instance is already hermetic.\nsystem_genrule_toolchain(\n name = "genrule",\n visibility = ["PUBLIC"],\n)\n\nexport_file(\n name = "package.json",\n src = "package.json",\n visibility = ["PUBLIC"],\n)\n\nalias(\n name = "node_modules",\n actual = "//packages/@overeng/genie:node_modules",\n visibility = ["PUBLIC"],\n)\n\nalias(\n name = "editor_inputs",\n actual = ":node_modules",\n visibility = ["PUBLIC"],\n)\n\nalias(\n name = "root_editor_package_tree",\n actual = "//packages/@overeng/genie:package_tree",\n visibility = ["PUBLIC"],\n)\n\neditor_view_inputs(\n name = "editor_view_inputs",\n editor_inputs = ":editor_inputs",\n package_tree = ":root_editor_package_tree",\n visibility = ["PUBLIC"],\n)\nstatic_source_set(\n name = "static_sources",\n prefix = "",\n srcs = glob(\n [\n root + "/" + pattern\n for root in ["context", "packages", "scripts"]\n for pattern in STATIC_SOURCE_GLOBS\n ],\n exclude = [\n root + "/" + pattern\n for root in ["context", "packages", "scripts"]\n for pattern in STATIC_SOURCE_EXCLUDES\n ],\n ) + [\n ".oxfmtrc.json",\n ".oxlintrc.json",\n "devenv.lock",\n "devenv.yaml",\n "flake.lock",\n "flake.nix",\n "megarepo.kdl",\n "megarepo.lock",\n "tsconfig.lint.json",\n ],\n visibility = ["PUBLIC"],\n)\n\n\n# Workspace patches are declared inputs to the generated pnpm extraction actions.\nexport_file(\n name = "patches/@myobie__pty@0.10.0.patch",\n src = "patches/@myobie__pty@0.10.0.patch",\n visibility = ["PUBLIC"],\n)' + +export const rootBuckAggregateProjection = (): GenieOutput => { + const data = planRootBuckAggregates() + const packageInputs = [ + ...new Set( + authoritativeBuck2TypeScriptProjects.map((project) => `${project.packagePath}/BUCK.genie.ts`), + ), + ].toSorted() + const semanticInputs = [ + 'BUCK.genie.ts', + 'genie/buck2/mod.ts', + 'genie/buck2/root-aggregate-projection.ts', + 'genie/buck2/typescript-admissions.ts', + ...packageInputs, + ] + const fingerprint = buck2SemanticFingerprint({ + generator: 'effect-utils/genie/buck2-root-aggregate-projection', + schemaVersion: 1, + semanticData: data, + }) + + return createGenieOutput({ + data, + stringify: () => + [ + '# Projection source: BUCK.genie.ts', + '# Projection schema version: 1', + '# Projection generator: effect-utils/genie/buck2-root-aggregate-projection', + `# Semantic fingerprint: ${fingerprint}`, + `# Semantic inputs: ${semanticInputs.join(', ')}`, + `# Regenerate: ${regenerationCommand}`, + '', + rootBuckBase, + '', + '# Scoped repository checks derived from the TypeScript admission registry.', + renderFilegroup({ name: 'quick', srcs: data.quick }), + '', + renderFilegroup({ name: 'all', srcs: data.all }), + '', + ].join('\n'), + }) +} diff --git a/genie/buck2/root-aggregate-projection.unit.test.ts b/genie/buck2/root-aggregate-projection.unit.test.ts new file mode 100644 index 0000000000..63dc06077c --- /dev/null +++ b/genie/buck2/root-aggregate-projection.unit.test.ts @@ -0,0 +1,42 @@ +import { describe, expect, it } from 'vitest' + +import { planRootBuckAggregates, rootBuckAggregateProjection } from './root-aggregate-projection.ts' +import { authoritativeBuck2TypeScriptProjects } from './typescript-admissions.ts' + +describe('root Buck aggregate projection', () => { + it('derives quick and all from the authoritative target sets', () => { + expect( + planRootBuckAggregates({ + typecheckTargets: ['//packages/@example/alpha:typecheck'], + distTargets: ['//packages/@example/alpha:dist'], + testTargets: ['//packages/@example/alpha:test'], + }), + ).toEqual({ + quick: ['//packages/@example/alpha:typecheck'], + all: [ + ':quick', + '//packages/@example/alpha:dist', + '//packages/@example/alpha:test', + '//buck2/toolchains:archive_tool', + '//buck2/toolchains:product_tool', + ], + }) + }) + + it('renders the stack-head root targets and registry aggregates together', () => { + const output = rootBuckAggregateProjection().stringify({ cwd: '/repo', location: '' }) + + expect(output).toContain('name = "editor_view_inputs"') + expect(output).toContain('name = "static_sources"') + expect(output).toContain('name = "quick"') + expect(output).toContain('name = "all"') + expect(output).toContain('"000": "//context/effect/socket:typecheck"') + expect(output).not.toContain('srcs = [') + }) + + it('keeps the production quick target set equal to the admission registry', () => { + expect(planRootBuckAggregates().quick).toEqual( + authoritativeBuck2TypeScriptProjects.map((project) => project.typecheckTarget), + ) + }) +}) diff --git a/genie/buck2/runtime-modules.ts b/genie/buck2/runtime-modules.ts index df636eb958..d1977afffd 100644 --- a/genie/buck2/runtime-modules.ts +++ b/genie/buck2/runtime-modules.ts @@ -1,3 +1,8 @@ +import { + createGenieOutput, + type GenieOutput, +} from '../../packages/@overeng/genie/src/runtime/core.ts' + /** * Declared module sets for the TypeScript sources Buck stages into actions. * @@ -17,26 +22,24 @@ export type Buck2StagedRuntime = { readonly entry: string /** Complete relative-import closure of `entry`, repository-relative. */ readonly modules: readonly string[] - /** - * How the label stages the modules. `filegroup` co-locates a closure of more - * than one module; `export_file` stages exactly one file on its own and can - * therefore only carry a runner with no relative imports. - */ + /** Multi-file closures use a filegroup; standalone modules use export_file. */ readonly staging: 'export_file' | 'filegroup' } -const runnerSource = (name: string): string => `packages/@overeng/buck2-tools/src/${name}` +const buck2ToolsPackagePath = 'packages/@overeng/buck2-tools' +const buck2ToolsLabel = (name: string): string => `//${buck2ToolsPackagePath}:${name}` +const runnerSource = (name: string): string => `${buck2ToolsPackagePath}/src/${name}` -/** Every TypeScript runner Buck executes, and the sources staged with it. */ +/** Every TypeScript runner Buck executes, owned by the package containing its source. */ export const buck2StagedRuntimes = [ { - label: '//:package_tree_runtime', + label: buck2ToolsLabel('package_tree_runtime'), entry: runnerSource('package-tree.ts'), modules: [runnerSource('package-tree.ts'), runnerSource('real-path.ts')], staging: 'filegroup', }, { - label: '//:package_command_runtime', + label: buck2ToolsLabel('package_command_runtime'), entry: runnerSource('package-command-runner.ts'), modules: [ runnerSource('package-command-runner.ts'), @@ -46,23 +49,17 @@ export const buck2StagedRuntimes = [ staging: 'filegroup', }, { - label: '//:javascript_action_runtime', + label: buck2ToolsLabel('javascript_action_runtime'), entry: runnerSource('javascript-runner.ts'), modules: [runnerSource('javascript-runner.ts'), runnerSource('typescript-runner.ts')], staging: 'filegroup', }, { - label: '//:packages/@overeng/buck2-tools/src/typescript-runner.ts', + label: buck2ToolsLabel('typescript-runner.ts'), entry: runnerSource('typescript-runner.ts'), modules: [runnerSource('typescript-runner.ts')], staging: 'export_file', }, - { - label: '//:packages/@overeng/buck2-tools/src/owned-files.ts', - entry: runnerSource('owned-files.ts'), - modules: [runnerSource('owned-files.ts')], - staging: 'export_file', - }, ] as const satisfies readonly Buck2StagedRuntime[] /** The package-tree runner, which the generated package projections point at. */ @@ -77,3 +74,43 @@ export const stagedModuleName = (module: string): string => { if (name === '') throw new Error(`Runtime module has no file name: ${module}`) return name } + +const packageRelativeSource = (module: string): string => { + const prefix = `${buck2ToolsPackagePath}/` + if (module.startsWith(prefix) === false) { + throw new Error(`Buck2 tools runtime source is outside its package: ${module}`) + } + return module.slice(prefix.length) +} + +const renderRuntime = (runtime: Buck2StagedRuntime): string => { + const name = runtime.label.slice(runtime.label.lastIndexOf(':') + 1) + if (runtime.staging === 'export_file') { + return `export_file( + name = ${JSON.stringify(name)}, + src = ${JSON.stringify(packageRelativeSource(runtime.entry))}, + visibility = ["PUBLIC"], +)` + } + const sources = runtime.modules + .map( + (module) => + ` ${JSON.stringify(stagedModuleName(module))}: ${JSON.stringify(packageRelativeSource(module))},`, + ) + .join('\n') + return `filegroup( + name = ${JSON.stringify(name)}, + srcs = { +${sources} + }, + visibility = ["PUBLIC"], +)` +} + +/** Appends the package-owned staged runner targets to its TypeScript projection. */ +export const withBuck2ToolsRuntimes = (projection: GenieOutput): GenieOutput => + createGenieOutput({ + ...projection, + stringify: (context) => + `${projection.stringify(context)}\n${buck2StagedRuntimes.map(renderRuntime).join('\n\n')}\n`, + }) diff --git a/genie/buck2/typescript-admissions.ts b/genie/buck2/typescript-admissions.ts index 48b8c2b56a..688e4afb58 100644 --- a/genie/buck2/typescript-admissions.ts +++ b/genie/buck2/typescript-admissions.ts @@ -1,4 +1,8 @@ +import { pnpmWorkspaceMemberPaths } from '../packages.ts' +import { buck2TypeScriptAdmission as effectSocketAdmission } from '../../context/effect/socket/BUCK.genie.ts' +import { buck2TypeScriptAdmission as opentuiAdmission } from '../../context/opentui/BUCK.genie.ts' import { buck2TypeScriptAdmission as agentSessionIngestAdmission } from '../../packages/@overeng/agent-session-ingest/BUCK.genie.ts' +import { buck2TypeScriptAdmission as buck2ToolsAdmission } from '../../packages/@overeng/buck2-tools/BUCK.genie.ts' import { buck2TypeScriptAdmission as ciToolsAdmission } from '../../packages/@overeng/ci-tools/BUCK.genie.ts' import { buck2TypeScriptAdmission as contentAddressAdmission } from '../../packages/@overeng/content-address/BUCK.genie.ts' import { buck2TypeScriptAdmission as effectAiClaudeCliAdmission } from '../../packages/@overeng/effect-ai-claude-cli/BUCK.genie.ts' @@ -6,8 +10,11 @@ import { buck2TypeScriptAdmission as effectDistributedLockAdmission } from '../. import { buck2TypeScriptAdmission as effectPathAdmission } from '../../packages/@overeng/effect-path/BUCK.genie.ts' import { buck2TypeScriptAdmission as effectReactAdmission } from '../../packages/@overeng/effect-react/BUCK.genie.ts' import { buck2TypeScriptAdmission as effectRpcTanstackAdmission } from '../../packages/@overeng/effect-rpc-tanstack/BUCK.genie.ts' +import { buck2TypeScriptAdmission as effectRpcTanstackBasicAdmission } from '../../packages/@overeng/effect-rpc-tanstack/examples/basic/BUCK.genie.ts' +import { buck2TypeScriptAdmission as effectSchemaFormAriaAdmission } from '../../packages/@overeng/effect-schema-form-aria/BUCK.genie.ts' import { buck2TypeScriptAdmission as effectSchemaFormAdmission } from '../../packages/@overeng/effect-schema-form/BUCK.genie.ts' import { buck2TypeScriptAdmission as genieAdmission } from '../../packages/@overeng/genie/BUCK.genie.ts' +import { buck2TypeScriptAdmission as ghCiUtilsAdmission } from '../../packages/@overeng/gh-ci-utils/BUCK.genie.ts' import { buck2TypeScriptAdmission as kdlEffectAdmission } from '../../packages/@overeng/kdl-effect/BUCK.genie.ts' import { buck2TypeScriptAdmission as kdlAdmission } from '../../packages/@overeng/kdl/BUCK.genie.ts' import { buck2TypeScriptAdmission as megarepoAdmission } from '../../packages/@overeng/megarepo/BUCK.genie.ts' @@ -36,33 +43,38 @@ import { discoverCollectableTestModules, } from './typescript-package-projection.ts' import type { - Buck2TypeScriptAuthorityMetadata, Buck2TypeScriptPackageProjection, Buck2TypeScriptPackageTestTarget, + Buck2TypeScriptProjectAuthorityMetadata, } from './typescript-package-projection.ts' -export type { Buck2TypeScriptAuthorityMetadata } from './typescript-package-projection.ts' +export type { Buck2TypeScriptProjectAuthorityMetadata } from './typescript-package-projection.ts' const compareAuthorityStrings = (left: string, right: string): number => left < right ? -1 : left > right ? 1 : 0 -/** Buck TypeScript projection input plus editor publication and optional authority admission. */ -export type Buck2TypeScriptAdmission = Buck2TypeScriptPackageProjection & { - readonly editorViewConsumer: boolean - readonly authority?: Buck2TypeScriptAuthorityMetadata -} +/** Buck TypeScript projection input. Every admitted workspace package receives an editor view. */ +export type Buck2TypeScriptAdmission = Buck2TypeScriptPackageProjection -/** Derived command and manifest data for a Buck-authoritative TypeScript package. */ -export type AuthoritativeBuck2TypeScriptAdmission = Buck2TypeScriptAuthorityMetadata & { +/** Derived command and root-project data for every Buck-authoritative TypeScript project. */ +export type AuthoritativeBuck2TypeScriptProject = Buck2TypeScriptProjectAuthorityMetadata & { readonly packagePath: string - readonly sourceRoots: readonly string[] - readonly typecheckTarget: `//${string}:typecheck` + readonly projectPath: string + readonly typecheckTarget: `//${string}:${string}` +} + +/** Declaration-producing subset consumed by the dist publisher and member manifest. */ +export type AuthoritativeBuck2TypeScriptDeclaration = AuthoritativeBuck2TypeScriptProject & { + readonly declarationEntrypoint: string readonly distTarget: `//${string}:dist` } /** Semantic registry for every package admitted to the Buck TypeScript projection. */ export const buck2TypeScriptAdmissions = { + effectSocket: effectSocketAdmission, + opentui: opentuiAdmission, agentSessionIngest: agentSessionIngestAdmission, + buck2Tools: buck2ToolsAdmission, ciTools: ciToolsAdmission, contentAddress: contentAddressAdmission, effectAiClaudeCli: effectAiClaudeCliAdmission, @@ -70,8 +82,11 @@ export const buck2TypeScriptAdmissions = { effectPath: effectPathAdmission, effectReact: effectReactAdmission, effectRpcTanstack: effectRpcTanstackAdmission, + effectRpcTanstackBasic: effectRpcTanstackBasicAdmission, effectSchemaForm: effectSchemaFormAdmission, + effectSchemaFormAria: effectSchemaFormAriaAdmission, genie: genieAdmission, + ghCiUtils: ghCiUtilsAdmission, kdl: kdlAdmission, kdlEffect: kdlEffectAdmission, megarepo: megarepoAdmission, @@ -97,39 +112,55 @@ export const buck2TypeScriptAdmissions = { utilsDev: utilsDevAdmission, } as const satisfies Record -/** Derives labels rather than duplicating them in package-local authority metadata. */ +/** Derives labels and project identity rather than duplicating them in package-local metadata. */ export const deriveBuck2TypeScriptAuthority = ({ authority, packagePath, - sourceRoots, -}: Buck2TypeScriptAdmission & { - readonly authority: Buck2TypeScriptAuthorityMetadata -}): AuthoritativeBuck2TypeScriptAdmission => ({ - declarationEntrypoint: authority.declarationEntrypoint, - distTarget: `//${packagePath}:dist`, - packagePath, - projectFile: authority.projectFile, - sourceRoots, - typecheckTarget: `//${packagePath}:typecheck`, -}) +}: Pick & { + readonly authority: Buck2TypeScriptProjectAuthorityMetadata +}): AuthoritativeBuck2TypeScriptProject => { + const projectPath = authority.projectPath ?? packagePath + const typecheckTargetName = + authority.typecheckTargetName ?? (projectPath === packagePath ? 'typecheck' : undefined) + if (typecheckTargetName === undefined) { + throw new Error(`Additional TypeScript project ${projectPath} must name its typecheck target`) + } + return { + ...authority, + packagePath, + projectPath, + typecheckTarget: `//${packagePath}:${typecheckTargetName}`, + } +} -/** Registry-ordered packages whose TypeScript checking and declarations are Buck-owned. */ -export const authoritativeBuck2TypeScriptAdmissions = Object.values( - buck2TypeScriptAdmissions, -).flatMap( - (admission: Buck2TypeScriptAdmission): readonly AuthoritativeBuck2TypeScriptAdmission[] => - admission.authority === undefined +/** Registry-ordered root projects whose TypeScript checking is Buck-owned. */ +export const authoritativeBuck2TypeScriptProjects: readonly AuthoritativeBuck2TypeScriptProject[] = + Object.values(buck2TypeScriptAdmissions).flatMap( + (admission: Buck2TypeScriptAdmission): readonly AuthoritativeBuck2TypeScriptProject[] => + admission.authorities.map((authority) => + deriveBuck2TypeScriptAuthority({ + authority, + packagePath: admission.packagePath, + }), + ), + ) + +/** Projects whose authority includes one published declaration surface. */ +export const authoritativeBuck2TypeScriptDeclarations: readonly AuthoritativeBuck2TypeScriptDeclaration[] = + authoritativeBuck2TypeScriptProjects.flatMap((project) => + project.declarationEntrypoint === undefined ? [] : [ - deriveBuck2TypeScriptAuthority({ - ...admission, - authority: admission.authority, - }), + { + ...project, + declarationEntrypoint: project.declarationEntrypoint, + distTarget: `//${project.packagePath}:dist`, + }, ], -) + ) -/** Dist overlays derived from the same package-local authority declarations. */ -export const buck2TypeScriptDistOverlays = authoritativeBuck2TypeScriptAdmissions +/** Dist overlays derived from the declaration-producing project subset. */ +export const buck2TypeScriptDistOverlays = authoritativeBuck2TypeScriptDeclarations .map(({ distTarget, packagePath }) => ({ target: distTarget, destination: `${packagePath}/dist`, @@ -292,10 +323,6 @@ export const buck2TestLanes: readonly Buck2TestLane[] = Object.values(buck2TypeS ) }) .toSorted((left, right) => compareAuthorityStrings(left.target, right.target)) -const testLanePackagePaths = buck2TestLanes.map(({ packagePath }) => packagePath) -if (new Set(testLanePackagePaths).size !== testLanePackagePaths.length) { - throw new Error('Buck test authority does not yet support more than one lane per package') -} for (const parent of buck2TestLanes) { const child = buck2TestLanes.find( (candidate) => @@ -329,8 +356,20 @@ export const buck2TypeScriptTestCollectionTargets: readonly string[] = buck2Test ({ collectionTarget }) => (collectionTarget === undefined ? [] : [collectionTarget]), ) -/** Byte-sorted package paths whose editor dependency surface is currently admitted. */ +/** Byte-sorted package paths whose Buck dependency trees publish editor views. */ export const editorViewConsumerPackagePaths = Object.values(buck2TypeScriptAdmissions) - .filter((admission) => admission.editorViewConsumer === true) .map((admission) => admission.packagePath) .toSorted(compareAuthorityStrings) +const editorViewPackageSet = new Set(editorViewConsumerPackagePaths) +const workspacePackageSet = new Set(pnpmWorkspaceMemberPaths) +const missingEditorViews = pnpmWorkspaceMemberPaths.filter( + (packagePath) => editorViewPackageSet.has(packagePath) === false, +) +const nonWorkspaceEditorViews = editorViewConsumerPackagePaths.filter( + (packagePath) => workspacePackageSet.has(packagePath) === false, +) +if (missingEditorViews.length > 0 || nonWorkspaceEditorViews.length > 0) { + throw new Error( + `Editor view authority must cover every pnpm workspace package exactly once: missing=${JSON.stringify(missingEditorViews)} extra=${JSON.stringify(nonWorkspaceEditorViews)}`, + ) +} diff --git a/genie/buck2/typescript-admissions.unit.test.ts b/genie/buck2/typescript-admissions.unit.test.ts index a712532a62..ddb081b417 100644 --- a/genie/buck2/typescript-admissions.unit.test.ts +++ b/genie/buck2/typescript-admissions.unit.test.ts @@ -6,14 +6,10 @@ import { describe, expect, it } from 'vitest' import buckMemberManifest from '../../buck2-member.json.genie.ts' import buck2TestAuthority from '../../buck2-test-authority.json.genie.ts' import { decodeBuckMemberManifestJson } from '../../packages/@overeng/megarepo/src/buck2-manifest.ts' +import { rootTsconfigProjects } from '../tsconfig-projects.ts' import { - isRootTsconfigCheckProject, - isRootTsconfigEmitProject, - rootTsconfigProjects, - rootWorkspaceTsconfigProjects, -} from '../tsconfig-projects.ts' -import { - authoritativeBuck2TypeScriptAdmissions, + authoritativeBuck2TypeScriptDeclarations, + authoritativeBuck2TypeScriptProjects, buck2TestLanes, buck2TypeScriptAdmissions, buck2TypeScriptDistOverlays, @@ -25,69 +21,36 @@ import { } from './typescript-admissions.ts' describe('Buck2 TypeScript authority derivation', () => { - it('derives authority only from package-local declarations in registry order', () => { + it('derives every project only from package-local declarations in registry order', () => { const packageLocalAuthorities = Object.values(buck2TypeScriptAdmissions).flatMap( (admission: Buck2TypeScriptAdmission) => - admission.authority === undefined - ? [] - : [ - deriveBuck2TypeScriptAuthority({ - ...admission, - authority: admission.authority, - }), - ], + (admission.authorities ?? []).map((authority) => + deriveBuck2TypeScriptAuthority({ + authority, + packagePath: admission.packagePath, + sourceRoots: admission.sourceRoots, + }), + ), ) - expect(authoritativeBuck2TypeScriptAdmissions).toEqual(packageLocalAuthorities) + expect(authoritativeBuck2TypeScriptProjects).toEqual(packageLocalAuthorities) + expect(authoritativeBuck2TypeScriptProjects).toHaveLength(40) }) - it('excludes every Buck-authoritative project from the root TypeScript solution', () => { - const authoritativePackagePaths = authoritativeBuck2TypeScriptAdmissions.map( - ({ packagePath }) => packagePath, - ) + it('gives every root TypeScript project one Buck typecheck target', () => { + const authoritativeProjectPaths = authoritativeBuck2TypeScriptProjects + .map(({ projectPath }) => projectPath) + .toSorted((left, right) => Buffer.from(left).compare(Buffer.from(right))) + const rootProjectPaths = rootTsconfigProjects + .map(({ path }) => path) + .toSorted((left, right) => Buffer.from(left).compare(Buffer.from(right))) - expect( - rootWorkspaceTsconfigProjects - .filter((project) => isRootTsconfigCheckProject(project) === false) - .map(({ path }) => path) - .toSorted((left, right) => Buffer.from(left).compare(Buffer.from(right))), - ).toEqual( - authoritativePackagePaths.toSorted((left, right) => - Buffer.from(left).compare(Buffer.from(right)), - ), - ) + expect(authoritativeProjectPaths).toEqual(rootProjectPaths) }) - it('leaves exactly the projects no Buck target owns to root tsc', () => { - // The generated solutions sort by path, so assert on that same order. - const rootMembers = (predicate: (project: RootTsconfigProject) => boolean): readonly string[] => - rootTsconfigProjects - .filter(predicate) - .map(({ path }) => path) - .toSorted((left, right) => left.localeCompare(right)) - - // Checking and emitting are one decision: a project Buck typechecks also - // owns its declarations, so the two root filters must select the same set. - expect(rootMembers(isRootTsconfigCheckProject)).toEqual(rootMembers(isRootTsconfigEmitProject)) - - expect(rootMembers(isRootTsconfigCheckProject)).toEqual([ - 'context/effect/socket', - 'context/opentui', - 'packages/@overeng/buck2-tools', - 'packages/@overeng/effect-rpc-tanstack/examples/basic', - 'packages/@overeng/effect-schema-form-aria', - 'packages/@overeng/genie', - 'packages/@overeng/gh-ci-utils', - 'packages/@overeng/kdl-effect', - 'packages/@overeng/megarepo', - 'packages/@overeng/react-inspector/tsconfig.strict-consumer.json', - 'packages/@overeng/tui-stories', - ]) - }) - - it('derives manifest overlays and root TypeScript authority from the same entries', () => { + it('derives declaration overlays and project authorities from the same entries', () => { expect(buck2TypeScriptDistOverlays).toEqual( - authoritativeBuck2TypeScriptAdmissions + authoritativeBuck2TypeScriptDeclarations .map(({ distTarget, packagePath }) => ({ destination: `${packagePath}/dist`, target: distTarget, @@ -103,27 +66,35 @@ describe('Buck2 TypeScript authority derivation', () => { expect(projectedManifest.distOverlays).toEqual(buck2TypeScriptDistOverlays) expect( - rootWorkspaceTsconfigProjects - .flatMap(({ buck2Authority, path }) => - buck2Authority === undefined ? [] : [{ buck2Authority, path }], - ) + rootTsconfigProjects + .map(({ buck2Authority, path }) => ({ buck2Authority, path })) .toSorted((left, right) => Buffer.from(left.path).compare(Buffer.from(right.path))), ).toEqual( - authoritativeBuck2TypeScriptAdmissions - .filter(({ packagePath }) => - rootWorkspaceTsconfigProjects.some(({ path }) => path === packagePath), - ) - .map(({ distTarget, packagePath, typecheckTarget }) => ({ + authoritativeBuck2TypeScriptProjects + .map(({ declarationEntrypoint, packagePath, projectPath, typecheckTarget }) => ({ buck2Authority: { _tag: 'Buck2TypeScriptAuthority', - emitTarget: distTarget, typecheckTarget, + ...(declarationEntrypoint === undefined ? {} : { emitTarget: `//${packagePath}:dist` }), }, - path: packagePath, + path: projectPath, })) .toSorted((left, right) => Buffer.from(left.path).compare(Buffer.from(right.path))), ) }) + + it('represents the React Inspector strict consumer as an independent project', () => { + expect( + authoritativeBuck2TypeScriptProjects.find( + ({ projectPath }) => + projectPath === 'packages/@overeng/react-inspector/tsconfig.strict-consumer.json', + ), + ).toMatchObject({ + packagePath: 'packages/@overeng/react-inspector', + projectFile: 'tsconfig.strict-consumer.json', + typecheckTarget: '//packages/@overeng/react-inspector:strict_consumer_typecheck', + }) + }) }) describe('Buck2 test lane registry', () => { @@ -136,7 +107,7 @@ describe('Buck2 test lane registry', () => { expect(buck2TestLanes.length).toBe(declaredLanes.length) // The lanes that exist today. A registry that silently shrinks moves tests out of the // gate without anyone deciding to, so the floor is asserted rather than described. - expect(buck2TestLanes.length).toBeGreaterThanOrEqual(32) + expect(buck2TestLanes.length).toBeGreaterThanOrEqual(34) expect(new Set(buck2TestLanes.map(({ target }) => target)).size).toBe(buck2TestLanes.length) expect(new Set(buck2TestLanes.map(({ taskName }) => taskName)).size).toBe(buck2TestLanes.length) }) @@ -190,8 +161,7 @@ describe('Buck2 test lane registry', () => { 'src/browser/__tests__/BroadcastLogger.pw.test.ts', ) - // A named lane still derives an addressable task, but the published authority rejects - // multiple lanes for one package until overlap semantics exist. + // Named lanes derive distinct addressable tasks without making package identity unique. expect( deriveBuck2TestLane({ packagePath: 'packages/@example/widget', @@ -212,6 +182,42 @@ describe('Buck2 test lane registry', () => { unboundedAfter: [], unboundedFiles: [], }) + expect( + buck2TestLanes + .filter(({ packagePath }) => packagePath === 'packages/@overeng/pty-effect') + .map(({ taskName, target }) => ({ taskName, target })), + ).toEqual([ + { + taskName: 'test:pty-effect:bundle_smoke', + target: 'effect_utils//packages/@overeng/pty-effect:bundle_smoke', + }, + { + taskName: 'test:pty-effect', + target: 'effect_utils//packages/@overeng/pty-effect:test', + }, + ]) + }) + + it('keeps effect-schema-form-aria out of the source-side fallback partition', () => { + const lane = buck2TestLanes.find( + ({ packagePath }) => packagePath === 'packages/@overeng/effect-schema-form-aria', + ) + + expect(lane).toEqual({ + collectionTarget: + 'effect_utils//packages/@overeng/effect-schema-form-aria:test_collect', + excludes: [], + packageName: 'effect-schema-form-aria', + packagePath: 'packages/@overeng/effect-schema-form-aria', + runner: 'vitest', + selectedTestFiles: ['src/mod.unit.test.tsx'], + sourceOwners: {}, + target: 'effect_utils//packages/@overeng/effect-schema-form-aria:test', + taskName: 'test:effect-schema-form-aria', + testFiles: ['src/mod.unit.test.tsx'], + unboundedAfter: [], + unboundedFiles: [], + }) }) it('publishes the derived registry verbatim as the generated bridge', () => { diff --git a/genie/buck2/typescript-authority-runtime.ts b/genie/buck2/typescript-authority-runtime.ts index a0f774a8d1..46b332def8 100644 --- a/genie/buck2/typescript-authority-runtime.ts +++ b/genie/buck2/typescript-authority-runtime.ts @@ -2,12 +2,13 @@ import { spawn } from 'node:child_process' import process from 'node:process' import { - authoritativeBuck2TypeScriptAdmissions, + authoritativeBuck2TypeScriptDeclarations, + authoritativeBuck2TypeScriptProjects, buck2TypeScriptTestCollectionTargets, buck2TypeScriptTestTargets, - type AuthoritativeBuck2TypeScriptAdmission, + type AuthoritativeBuck2TypeScriptDeclaration, + type AuthoritativeBuck2TypeScriptProject, } from './typescript-admissions.ts' -import { buck2TypeScriptDeclarationSources } from './typescript-package-projection.ts' /** Executable followed by its exact ordered argument vector. */ export type CommandArgv = [executable: string, ...args: string[]] @@ -39,65 +40,47 @@ export type CommandRuntime = { }) => void } -/** - * Resolves the handwritten declarations a package publishes verbatim. - * - * Injectable so planning stays testable without a package tree on disk; the - * default is the same census the Buck projection renders into - * `declaration_sources`, which is what keeps copy and comparison from drifting. - */ -export type DeclarationSourceResolver = (options: { - readonly packagePath: string - readonly sourceRoots: readonly string[] -}) => readonly string[] - -/** Plans the existing declaration materializer invocation for every authoritative package. */ +/** Plans one declaration publisher invocation for every emitting authoritative project. */ export const planTypeScriptDistMaterialization = ({ - admissions = authoritativeBuck2TypeScriptAdmissions, + admissions = authoritativeBuck2TypeScriptDeclarations, bashBin, - declarationSources, root, }: { - readonly admissions?: readonly AuthoritativeBuck2TypeScriptAdmission[] + readonly admissions?: readonly AuthoritativeBuck2TypeScriptDeclaration[] readonly bashBin: string - readonly declarationSources?: DeclarationSourceResolver readonly root: string -}): readonly CommandArgv[] => { - const resolveDeclarationSources: DeclarationSourceResolver = - declarationSources ?? - (({ packagePath, sourceRoots }) => - buck2TypeScriptDeclarationSources({ packagePath, repoRoot: root, sourceRoots })) - return admissions.map( - ({ declarationEntrypoint, distTarget, packagePath, projectFile, sourceRoots }): CommandArgv => [ +}): readonly CommandArgv[] => + admissions.map( + ({ declarationEntrypoint, distTarget, packagePath }): CommandArgv => [ bashBin, `${root}/scripts/typescript-materialize-dist.sh`, root, packagePath, qualifyEffectUtilsLabel(distTarget), declarationEntrypoint, - projectFile, - ...resolveDeclarationSources({ packagePath, sourceRoots }), ], ) -} /** * Plans the single Buck build used by buck2:check, preserving target order. * - * Every declared lane contributes both its execution target and its inventory target. The - * inventory is what the source-side bounded task reads, so an inventory that stops - * analysing has to fail the check rather than quietly fall back to a source-side census. + * Every declared test lane contributes both its execution target and its inventory target. The + * static aggregate is included here as another governed authority surface rather than a parallel + * source-side producer. */ -export const planBuck2TypeScriptBuild = ({ - admissions = authoritativeBuck2TypeScriptAdmissions, +export const planBuck2AuthorityBuild = ({ + admissions = authoritativeBuck2TypeScriptProjects, buck2Bin, collectionTargets = buck2TypeScriptTestCollectionTargets, + staticTargets = ['effect_utils//buck2/static:check'], testTargets = buck2TypeScriptTestTargets, }: { - readonly admissions?: readonly AuthoritativeBuck2TypeScriptAdmission[] + readonly admissions?: readonly AuthoritativeBuck2TypeScriptProject[] readonly buck2Bin: string /** Fully qualified inventory labels. */ readonly collectionTargets?: readonly string[] + /** Fully qualified static-operation labels. */ + readonly staticTargets?: readonly string[] /** Fully qualified execution labels. */ readonly testTargets?: readonly string[] }): CommandArgv => [ @@ -106,6 +89,7 @@ export const planBuck2TypeScriptBuild = ({ ...admissions.map(({ typecheckTarget }) => qualifyEffectUtilsLabel(typecheckTarget)), ...testTargets, ...collectionTargets, + ...staticTargets, 'effect_utils//buck2/toolchains:archive_tool', 'effect_utils//buck2/toolchains:product_tool', '--local-only', @@ -186,7 +170,7 @@ const main = async (): Promise => { unexpectedArguments.length === 0 ) { return executeCommandPlan({ - commands: [planBuck2TypeScriptBuild({ buck2Bin: firstArgument })], + commands: [planBuck2AuthorityBuild({ buck2Bin: firstArgument })], }) } console.error( diff --git a/genie/buck2/typescript-authority-runtime.unit.test.ts b/genie/buck2/typescript-authority-runtime.unit.test.ts index 23a73ffb56..14c3c9f2e5 100644 --- a/genie/buck2/typescript-authority-runtime.unit.test.ts +++ b/genie/buck2/typescript-authority-runtime.unit.test.ts @@ -1,44 +1,32 @@ -import { existsSync } from 'node:fs' -import path from 'node:path' -import { fileURLToPath } from 'node:url' - import { describe, expect, it } from 'vitest' import { - authoritativeBuck2TypeScriptAdmissions, + authoritativeBuck2TypeScriptDeclarations, + authoritativeBuck2TypeScriptProjects, buck2TypeScriptTestCollectionTargets, buck2TypeScriptTestTargets, - type AuthoritativeBuck2TypeScriptAdmission, + type AuthoritativeBuck2TypeScriptDeclaration, } from './typescript-admissions.ts' import { type CommandArgv, type CommandOutcome, type CommandRuntime, - type DeclarationSourceResolver, executeCommandPlan, type ForwardedSignal, - planBuck2TypeScriptBuild, + planBuck2AuthorityBuild, planTypeScriptDistMaterialization, } from './typescript-authority-runtime.ts' -const repositoryRoot = fileURLToPath(new URL('../../', import.meta.url)) - const fixtureAdmissions = [ { declarationEntrypoint: 'types/index.d.ts', distTarget: '//packages/@example/widget:dist', packagePath: 'packages/@example/widget', projectFile: 'tsconfig.buck.json', - sourceRoots: ['src'], + projectPath: 'packages/@example/widget', typecheckTarget: '//packages/@example/widget:typecheck', }, -] as const satisfies readonly AuthoritativeBuck2TypeScriptAdmission[] - -const fixtureDeclarationSources: DeclarationSourceResolver = ({ packagePath, sourceRoots }) => { - expect(packagePath).toBe('packages/@example/widget') - expect(sourceRoots).toEqual(['src']) - return ['src/vendor.d.ts'] -} +] as const satisfies readonly AuthoritativeBuck2TypeScriptDeclaration[] type SpawnedCommand = { readonly command: CommandArgv @@ -94,7 +82,6 @@ describe('Buck2 TypeScript authority runtime planning', () => { planTypeScriptDistMaterialization({ admissions: fixtureAdmissions, bashBin: '/nix/store/bash/bin/bash', - declarationSources: fixtureDeclarationSources, root: '/repo', }), ).toEqual([ @@ -105,24 +92,11 @@ describe('Buck2 TypeScript authority runtime planning', () => { 'packages/@example/widget', 'effect_utils//packages/@example/widget:dist', 'types/index.d.ts', - 'tsconfig.buck.json', - 'src/vendor.d.ts', ], ]) - // A package without handwritten declarations passes none: the materializer - // must not receive a placeholder path it would then fail to copy. - expect( - planTypeScriptDistMaterialization({ - admissions: fixtureAdmissions, - bashBin: '/nix/store/bash/bin/bash', - declarationSources: () => [], - root: '/repo', - })[0]?.length, - ).toBe(7) - expect( - planBuck2TypeScriptBuild({ + planBuck2AuthorityBuild({ admissions: fixtureAdmissions, buck2Bin: '/workspace/.megarepo/bin/buck2', collectionTargets: ['effect_utils//packages/@example/widget:test_collect'], @@ -134,6 +108,7 @@ describe('Buck2 TypeScript authority runtime planning', () => { 'effect_utils//packages/@example/widget:typecheck', 'effect_utils//packages/@example/widget:test', 'effect_utils//packages/@example/widget:test_collect', + 'effect_utils//buck2/static:check', 'effect_utils//buck2/toolchains:archive_tool', 'effect_utils//buck2/toolchains:product_tool', '--local-only', @@ -142,7 +117,7 @@ describe('Buck2 TypeScript authority runtime planning', () => { // A package with no declared lane adds nothing: the gate must not invent a // target name for it, execution or inventory. expect( - planBuck2TypeScriptBuild({ + planBuck2AuthorityBuild({ admissions: fixtureAdmissions, buck2Bin: '/workspace/.megarepo/bin/buck2', collectionTargets: [], @@ -152,6 +127,7 @@ describe('Buck2 TypeScript authority runtime planning', () => { '/workspace/.megarepo/bin/buck2', 'build', 'effect_utils//packages/@example/widget:typecheck', + 'effect_utils//buck2/static:check', 'effect_utils//buck2/toolchains:archive_tool', 'effect_utils//buck2/toolchains:product_tool', '--local-only', @@ -162,32 +138,30 @@ describe('Buck2 TypeScript authority runtime planning', () => { expect( planTypeScriptDistMaterialization({ bashBin: '/nix/store/bash/bin/bash', - declarationSources: ({ packagePath }) => [`${packagePath}/probe.d.ts`], root: '/repo', }), ).toEqual( - authoritativeBuck2TypeScriptAdmissions.map( - ({ declarationEntrypoint, distTarget, packagePath, projectFile }) => [ + authoritativeBuck2TypeScriptDeclarations.map( + ({ declarationEntrypoint, distTarget, packagePath }) => [ '/nix/store/bash/bin/bash', '/repo/scripts/typescript-materialize-dist.sh', '/repo', packagePath, `effect_utils${distTarget}`, declarationEntrypoint, - projectFile, - `${packagePath}/probe.d.ts`, ], ), ) - expect(planBuck2TypeScriptBuild({ buck2Bin: '/workspace/.megarepo/bin/buck2' })).toEqual([ + expect(planBuck2AuthorityBuild({ buck2Bin: '/workspace/.megarepo/bin/buck2' })).toEqual([ '/workspace/.megarepo/bin/buck2', 'build', - ...authoritativeBuck2TypeScriptAdmissions.map( + ...authoritativeBuck2TypeScriptProjects.map( ({ typecheckTarget }) => `effect_utils${typecheckTarget}`, ), ...buck2TypeScriptTestTargets, ...buck2TypeScriptTestCollectionTargets, + 'effect_utils//buck2/static:check', 'effect_utils//buck2/toolchains:archive_tool', 'effect_utils//buck2/toolchains:product_tool', '--local-only', @@ -200,39 +174,19 @@ describe('Buck2 TypeScript authority runtime planning', () => { expect(buck2TypeScriptTestTargets.every((target) => target.startsWith('effect_utils//'))).toBe( true, ) - expect(buck2TypeScriptTestTargets.every((target) => target.endsWith(':test'))).toBe(true) + expect( + buck2TypeScriptTestTargets.every((target) => + /^effect_utils\/\/[^:]+:[a-z][a-z0-9_]*$/.test(target), + ), + ).toBe(true) expect(buck2TypeScriptTestCollectionTargets.length).toBe(buck2TypeScriptTestTargets.length) expect( - buck2TypeScriptTestCollectionTargets.every((target) => target.endsWith(':test_collect')), + buck2TypeScriptTestCollectionTargets.every( + (target, index) => target === `${buck2TypeScriptTestTargets[index]}_collect`, + ), ).toBe(true) }) - it('derives handwritten declaration arguments from the registry census by default', () => { - const commands = planTypeScriptDistMaterialization({ - bashBin: '/nix/store/bash/bin/bash', - root: repositoryRoot, - }) - const declarationArguments = commands.map((command) => ({ - packagePath: command[3], - sources: command.slice(7), - })) - - // The materializer copies these paths out of the package tree, so every one - // has to be a package-relative declaration that actually exists. Anything - // else would fail the copy or, worse, read as staleness against the dist. - for (const { packagePath, sources } of declarationArguments) { - for (const source of sources) { - expect(source.endsWith('.d.ts'), `${packagePath}: ${source}`).toBe(true) - expect(path.isAbsolute(source)).toBe(false) - expect(existsSync(path.join(repositoryRoot, packagePath ?? '', source))).toBe(true) - } - } - - // At least one admitted package publishes handwritten declarations; without - // that the detached comparison would prove nothing about the copy path. - expect(declarationArguments.some(({ sources }) => sources.length > 0)).toBe(true) - }) - it('forwards task signals to the active child and propagates its signal outcome', async () => { const { emitSignal, runtime, signalListeners, spawnedCommands } = makeCommandRuntime() const execution = executeCommandPlan({ diff --git a/genie/buck2/typescript-package-projection.ts b/genie/buck2/typescript-package-projection.ts index ddf5ba13ed..de7e645891 100644 --- a/genie/buck2/typescript-package-projection.ts +++ b/genie/buck2/typescript-package-projection.ts @@ -6,6 +6,7 @@ import { createGenieOutput, type GenieOutput, } from '../../packages/@overeng/genie/src/runtime/core.ts' +import { pnpmWorkspaceMemberPaths } from '../packages.ts' import { buck2SemanticFingerprint, renderBuck2Visibility } from './mod.ts' import { javaScriptActionRuntime, packageTreeRuntime, stagedModuleName } from './runtime-modules.ts' @@ -68,6 +69,7 @@ const snapshotBaselineFor = (testModule: string): string => const commonSemanticInputs = [ 'buck2/dependencies/BUCK.genie.ts', + 'buck2/static_checks.bzl', 'buck2/dependencies/pnpm-lock.sha256.json.genie.ts', 'genie/buck2/mod.ts', 'genie/buck2/typescript-package-projection.ts', @@ -89,7 +91,7 @@ const safeSourceSegment = (segment: string): boolean => segment !== '..' && segment.includes('/') === false && segment.includes('\\') === false && - /^[A-Za-z0-9._@+-]+$/.test(segment) + /^[A-Za-z0-9._@+$-]+$/.test(segment) const discoverPackageFiles = ({ packagePath, @@ -179,29 +181,6 @@ const discoverPackageSources = ({ /** The one rule for which declarations are published verbatim instead of compiled. */ const isHandwrittenDeclaration = (relativePath: string): boolean => relativePath.endsWith('.d.ts') -/** - * Handwritten declarations a package publishes verbatim into its `dist`. - * - * The emit action copies these instead of compiling them, so the detached - * materializer has to stage the identical set before it compares a published - * `dist`. Both the projection and that materializer derive the set here; - * restating the rule is how every copied declaration used to read as staleness. - */ -export const buck2TypeScriptDeclarationSources = ({ - packagePath, - repoRoot, - sourceRoots, -}: { - readonly packagePath: string - readonly repoRoot?: string - readonly sourceRoots: readonly string[] -}): readonly string[] => - discoverPackageSources({ - packagePath, - ...(repoRoot === undefined ? {} : { repoRoot }), - sourceRoots, - }).filter(isHandwrittenDeclaration) - const starlarkString = (value: string): string => JSON.stringify(value) const renderMap = ({ @@ -667,9 +646,17 @@ export type Buck2WorkspaceSibling = { readonly sourceRoots?: readonly string[] } -export type Buck2TypeScriptAuthorityMetadata = { - readonly declarationEntrypoint: string +export type Buck2TypeScriptProjectAuthorityMetadata = { + /** Repository project identity; defaults to the package path for its primary project. */ + readonly projectPath?: string + /** Package-relative tsconfig consumed by this project's typecheck action. */ readonly projectFile: string + /** Package-local typecheck target; defaults to `typecheck` for the primary project. */ + readonly typecheckTargetName?: string + /** Required only when this project publishes declarations through the package `dist` target. */ + readonly declarationEntrypoint?: string + /** Package-relative compiler inputs outside the declared source roots. */ + readonly projectInputs?: readonly string[] } export type Buck2TypeScriptPackageProjection = { @@ -679,7 +666,11 @@ export type Buck2TypeScriptPackageProjection = { readonly projectionSource: string readonly sourceRoots: readonly string[] readonly workspaceSiblings?: readonly Buck2WorkspaceSibling[] - readonly authority?: Buck2TypeScriptAuthorityMetadata + /** Project-level authority declarations; one package may own more than one root project. */ + readonly authorities: readonly [ + Buck2TypeScriptProjectAuthorityMetadata, + ...Buck2TypeScriptProjectAuthorityMetadata[], + ] readonly tests?: Buck2TypeScriptPackageTests readonly testDataRoots?: readonly Buck2TypeScriptPackageTestDataRoot[] } @@ -691,14 +682,67 @@ export const buck2TypeScriptPackageProjection = ({ projectionSource, sourceRoots, workspaceSiblings = [], - authority, + authorities, tests, testDataRoots = [], }: Buck2TypeScriptPackageProjection): GenieOutput => { - const projectFile = authority?.projectFile ?? 'tsconfig.json' - if (safeSourceSegment(projectFile) === false) { - throw new Error(`Unsafe package project file: ${projectFile}`) + const projectAuthorities = authorities.map((authority) => { + const projectPath = authority.projectPath ?? packagePath + if (projectPath !== packagePath && projectPath.startsWith(`${packagePath}/`) === false) { + throw new Error(`TypeScript authority project is outside its package: ${projectPath}`) + } + if (safeSourceSegment(authority.projectFile) === false) { + throw new Error(`Unsafe package project file: ${authority.projectFile}`) + } + const typecheckTargetName = + authority.typecheckTargetName ?? (projectPath === packagePath ? 'typecheck' : undefined) + if (typecheckTargetName === undefined) { + throw new Error(`Additional TypeScript project ${projectPath} must name its typecheck target`) + } + if (testTargetNamePattern.test(typecheckTargetName) === false) { + throw new Error(`Unsafe TypeScript typecheck target name: ${typecheckTargetName}`) + } + if (authority.declarationEntrypoint !== undefined && projectPath !== packagePath) { + throw new Error(`Only the primary package project may publish declarations: ${projectPath}`) + } + const projectInputs = [...(authority.projectInputs ?? [])] + .map((value) => requireRelativeTestPath({ field: 'TypeScript project input', value })) + .toSorted((left, right) => compareStrings({ left, right })) + for (const projectInput of projectInputs) { + if (admitSourceExtension(projectInput) === false) { + throw new Error(`TypeScript project input has an unsupported extension: ${projectInput}`) + } + if (existsSync(path.join(process.cwd(), packagePath, projectInput)) === false) { + throw new Error(`TypeScript project input does not exist: ${packagePath}/${projectInput}`) + } + } + return { ...authority, projectInputs, projectPath, typecheckTargetName } + }) + const primaryProjects = projectAuthorities.filter( + ({ projectPath }) => projectPath === packagePath, + ) + if (primaryProjects.length !== 1) { + throw new Error(`${packagePath} must declare exactly one primary TypeScript authority project`) + } + const projectPaths = projectAuthorities.map(({ projectPath }) => projectPath) + const targetNames = projectAuthorities.map(({ typecheckTargetName }) => typecheckTargetName) + if (new Set(projectPaths).size !== projectPaths.length) { + throw new Error(`Duplicate TypeScript authority project path in ${packagePath}`) + } + if (new Set(targetNames).size !== targetNames.length) { + throw new Error(`Duplicate TypeScript typecheck target in ${packagePath}`) + } + if ( + projectAuthorities.filter(({ declarationEntrypoint }) => declarationEntrypoint !== undefined) + .length > 1 + ) { + throw new Error(`${packagePath} declares more than one TypeScript declaration publisher`) + } + const primaryAuthority = primaryProjects[0] + if (primaryAuthority === undefined) { + throw new Error(`${packagePath} has no primary TypeScript authority project`) } + const projectFile = primaryAuthority.projectFile // One walk, two trees: the compile tree takes the TypeScript sources that emit, // typecheck and materialization own, while the test tree also takes the modules the // runners collect (`.jsx` specs) and the snapshot baselines those modules read back. @@ -708,7 +752,12 @@ export const buck2TypeScriptPackageProjection = ({ admit: (relativePath) => admitSourceExtension(relativePath) === true || isCollectableTestModule(relativePath) === true, }) - const packageSources = censusFiles.filter(admitSourceExtension) + const packageSources = [ + ...new Set([ + ...censusFiles.filter(admitSourceExtension), + ...projectAuthorities.flatMap(({ projectInputs }) => projectInputs), + ]), + ].toSorted((left, right) => compareStrings({ left, right })) if (packageSources.length === 0) { throw new Error('Package source census found no TypeScript inputs') } @@ -758,6 +807,26 @@ export const buck2TypeScriptPackageProjection = ({ throw new Error(`Duplicate test target names for ${packageName}: ${names.join(', ')}`) } } + const reservedTargetNames = new Set([ + 'dist', + 'editor_inputs', + 'editor_view_inputs', + 'node_modules', + 'package.json', + 'package_tree', + 'static_sources', + 'test_package_tree', + ...testTargets.flatMap(({ collectName, name }) => + collectName === undefined ? [name] : [name, collectName], + ), + ]) + for (const typecheckTargetName of targetNames) { + if (reservedTargetNames.has(typecheckTargetName)) { + throw new Error( + `TypeScript target ${typecheckTargetName} collides with generated Buck target in ${packagePath}`, + ) + } + } // Every lane runs inside the test package tree, so the config it loads and the files that // config loads have to be staged: they live beside `package.json`, outside every source root. const testConfigEntries = [ @@ -789,8 +858,15 @@ export const buck2TypeScriptPackageProjection = ({ emptyCensusMessage: `Test data census found no ${dataRoot.extensions.join(', ')} inputs under ${packagePath}/${dataRoot.root}`, }) }) - const projectFileEntries: readonly (readonly [string, string])[] = - projectFile === 'tsconfig.json' ? [] : [[projectFile, projectFile]] + const projectFileEntries: readonly (readonly [string, string])[] = [ + ...new Set( + projectAuthorities + .map(({ projectFile: authorityProjectFile }) => authorityProjectFile) + .filter((authorityProjectFile) => authorityProjectFile !== 'tsconfig.json'), + ), + ] + .toSorted((left, right) => compareStrings({ left, right })) + .map((authorityProjectFile) => [authorityProjectFile, authorityProjectFile] as const) const identityEntries = (files: readonly string[]): readonly (readonly [string, string])[] => files.map((file) => [file, file] as const) // The compile tree: typecheck, emit and the editor read it, so it carries the TypeScript @@ -866,12 +942,22 @@ export const buck2TypeScriptPackageProjection = ({ sibling.packageTreeTarget, ]) .toSorted(([left], [right]) => compareStrings({ left, right })) + const staticSourceExcludes = pnpmWorkspaceMemberPaths + .filter((candidate) => candidate.startsWith(`${packagePath}/`)) + .map((candidate) => `${path.posix.relative(packagePath, candidate)}/**`) + .toSorted((left, right) => compareStrings({ left, right })) const semanticInputs = [ ...commonSemanticInputs, + 'genie/packages.ts', projectionSource, `${packagePath}/package.json.genie.ts`, `${packagePath}/tsconfig.json.genie.ts`, - ...(projectFile === 'tsconfig.json' ? [] : [`${packagePath}/${projectFile}.genie.ts`]), + ...projectFileEntries.map( + ([authorityProjectFile]) => `${packagePath}/${authorityProjectFile}.genie.ts`, + ), + ...projectAuthorities.flatMap(({ projectInputs }) => + projectInputs.map((projectInput) => `${packagePath}/${projectInput}`), + ), ...sourceRoots.flatMap((sourceRoot) => sourceExtensions.map((extension) => `${packagePath}/${sourceRoot}/**/*${extension}`), ), @@ -911,8 +997,9 @@ export const buck2TypeScriptPackageProjection = ({ declarationSources, packageTreeRuntime: packageTreeRuntime.label, packageTreeRuntimeEntry: runtimeEntry, - projectFile, + projectAuthorities, sourceRoots, + staticSourceExcludes, testDataFiles, testDataRoots, testPackageFiles: testPackageFileEntries.map(([destination]) => destination), @@ -922,14 +1009,66 @@ export const buck2TypeScriptPackageProjection = ({ } const fingerprint = buck2SemanticFingerprint({ generator: 'effect-utils/genie/buck2-typescript-package-projection', - schemaVersion: 8, + schemaVersion: 11, semanticData: data, }) + const renderTypecheckTarget = ({ + name, + targetProjectFile, + }: { + readonly name: string + readonly targetProjectFile: string + }): readonly string[] => [ + 'tsgo_typecheck(', + ` name = ${starlarkString(name)},`, + ' package_tree = ":package_tree",', + ...(targetProjectFile === 'tsconfig.json' + ? [] + : [` project = ${starlarkString(targetProjectFile)},`]), + renderBuck2Visibility({ visibility }), + ')', + '', + ] + const renderDistTarget = ({ + declarationEntrypoint, + targetProjectFile, + }: { + readonly declarationEntrypoint: string + readonly targetProjectFile: string + }): readonly string[] => [ + 'tsgo_emit(', + ' name = "dist",', + ' package_tree = ":package_tree",', + ...renderMap({ + name: 'declaration_sources', + entries: declarationSources.map((source) => [source, source]), + }), + ...(targetProjectFile === 'tsconfig.json' + ? [] + : [` project = ${starlarkString(targetProjectFile)},`]), + ` declaration_entrypoint = ${starlarkString(declarationEntrypoint)},`, + renderBuck2Visibility({ visibility }), + ')', + '', + ] + const typeScriptTargetLines = projectAuthorities.flatMap((authority) => [ + ...renderTypecheckTarget({ + name: authority.typecheckTargetName, + targetProjectFile: authority.projectFile, + }), + ...(authority.declarationEntrypoint === undefined + ? [] + : renderDistTarget({ + declarationEntrypoint: authority.declarationEntrypoint, + targetProjectFile: authority.projectFile, + })), + ]) + const stringify = (): string => { const lines = [ `# Projection source: ${projectionSource}`, - '# Projection schema version: 8', + '# Projection schema version: 11', '# Projection generator: effect-utils/genie/buck2-typescript-package-projection', `# Semantic fingerprint: ${fingerprint}`, `# Semantic inputs: ${semanticInputs.join(', ')}`, @@ -937,6 +1076,7 @@ export const buck2TypeScriptPackageProjection = ({ '', 'load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view")', 'load("//buck2:editor_view.bzl", "editor_view_inputs")', + 'load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set")', ...(testTargets.length === 0 ? [] : [ @@ -947,7 +1087,16 @@ export const buck2TypeScriptPackageProjection = ({ .map((rule) => starlarkString(rule)) .join(', ')})`, ]), - 'load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck")', + `load("//buck2:typescript.bzl", ${[ + ...(projectAuthorities.some( + ({ declarationEntrypoint }) => declarationEntrypoint !== undefined, + ) + ? ['tsgo_emit'] + : []), + 'tsgo_typecheck', + ] + .map((rule) => starlarkString(rule)) + .join(', ')})`, '', 'export_file(', ' name = "package.json",', @@ -959,6 +1108,14 @@ export const buck2TypeScriptPackageProjection = ({ ...packageSources.map((source) => ` ${starlarkString(source)},`), '])', '', + 'static_source_set(', + ' name = "static_sources",', + ' node_modules = ":node_modules",', + ` prefix = ${starlarkString(packagePath)},`, + ` srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES${staticSourceExcludes.length === 0 ? '' : ` + ${JSON.stringify(staticSourceExcludes)}`}),`, + renderBuck2Visibility({ visibility }), + ')', + '', 'alias(', ' name = "node_modules",', ` actual = ${starlarkString(dependencyView)},`, @@ -1011,27 +1168,7 @@ export const buck2TypeScriptPackageProjection = ({ renderBuck2Visibility({ visibility }), ')', '', - 'tsgo_typecheck(', - ' name = "typecheck",', - ' package_tree = ":package_tree",', - ...(projectFile === 'tsconfig.json' ? [] : [` project = ${starlarkString(projectFile)},`]), - renderBuck2Visibility({ visibility }), - ')', - '', - 'tsgo_emit(', - ' name = "dist",', - ' package_tree = ":package_tree",', - ...renderMap({ - name: 'declaration_sources', - entries: declarationSources.map((source) => [source, source]), - }), - ...(projectFile === 'tsconfig.json' ? [] : [` project = ${starlarkString(projectFile)},`]), - ...(authority === undefined - ? [] - : [` declaration_entrypoint = ${starlarkString(authority.declarationEntrypoint)},`]), - renderBuck2Visibility({ visibility }), - ')', - '', + ...typeScriptTargetLines, ...testTargets.flatMap((target) => target.lines), ] return lines.join('\n') diff --git a/genie/buck2/typescript-package-projection.unit.test.ts b/genie/buck2/typescript-package-projection.unit.test.ts index 64489f7371..c6d5a422f3 100644 --- a/genie/buck2/typescript-package-projection.unit.test.ts +++ b/genie/buck2/typescript-package-projection.unit.test.ts @@ -6,40 +6,7 @@ import { describe, expect, it } from 'vitest' import ciWorkflow from '../../.github/workflows/ci.yml.genie.ts' import dependencyBuck from '../../buck2/dependencies/BUCK.genie.ts' -import agentSessionIngestBuck from '../../packages/@overeng/agent-session-ingest/BUCK.genie.ts' -import ciToolsBuck from '../../packages/@overeng/ci-tools/BUCK.genie.ts' -import contentAddressBuck from '../../packages/@overeng/content-address/BUCK.genie.ts' -import effectAiClaudeCliBuck from '../../packages/@overeng/effect-ai-claude-cli/BUCK.genie.ts' -import effectDistributedLockBuck from '../../packages/@overeng/effect-distributed-lock/BUCK.genie.ts' -import effectPathBuck from '../../packages/@overeng/effect-path/BUCK.genie.ts' -import effectReactBuck from '../../packages/@overeng/effect-react/BUCK.genie.ts' -import effectRpcTanstackBuck from '../../packages/@overeng/effect-rpc-tanstack/BUCK.genie.ts' -import effectSchemaFormBuck from '../../packages/@overeng/effect-schema-form/BUCK.genie.ts' -import genieBuck from '../../packages/@overeng/genie/BUCK.genie.ts' import type { GenieContext } from '../../packages/@overeng/genie/src/runtime/core.ts' -import kdlEffectBuck from '../../packages/@overeng/kdl-effect/BUCK.genie.ts' -import kdlBuck from '../../packages/@overeng/kdl/BUCK.genie.ts' -import megarepoBuck from '../../packages/@overeng/megarepo/BUCK.genie.ts' -import notionCliBuck from '../../packages/@overeng/notion-cli/BUCK.genie.ts' -import notionCoreBuck from '../../packages/@overeng/notion-core/BUCK.genie.ts' -import notionDatasourceSyncBuck from '../../packages/@overeng/notion-datasource-sync/BUCK.genie.ts' -import notionEffectClientBuck from '../../packages/@overeng/notion-effect-client/BUCK.genie.ts' -import notionEffectSchemaBuck from '../../packages/@overeng/notion-effect-schema/BUCK.genie.ts' -import notionMdBuck from '../../packages/@overeng/notion-md/BUCK.genie.ts' -import notionPropertyWriteBuck from '../../packages/@overeng/notion-property-write/BUCK.genie.ts' -import notionReactBuck from '../../packages/@overeng/notion-react/BUCK.genie.ts' -import npmReleaseBuck from '../../packages/@overeng/npm-release/BUCK.genie.ts' -import otelContractBuck from '../../packages/@overeng/otel-contract/BUCK.genie.ts' -import oxcConfigBuck from '../../packages/@overeng/oxc-config/BUCK.genie.ts' -import ptyEffectBuck from '../../packages/@overeng/pty-effect/BUCK.genie.ts' -import reactInspectorBuck from '../../packages/@overeng/react-inspector/BUCK.genie.ts' -import restateEffectBuck from '../../packages/@overeng/restate-effect/BUCK.genie.ts' -import stylexTokensBuck from '../../packages/@overeng/stylex-tokens/BUCK.genie.ts' -import tuiCoreBuck from '../../packages/@overeng/tui-core/BUCK.genie.ts' -import tuiReactBuck from '../../packages/@overeng/tui-react/BUCK.genie.ts' -import tuiStoriesBuck from '../../packages/@overeng/tui-stories/BUCK.genie.ts' -import utilsDevBuck from '../../packages/@overeng/utils-dev/BUCK.genie.ts' -import utilsBuck from '../../packages/@overeng/utils/BUCK.genie.ts' import { buck2TestLanes, buck2TypeScriptAdmissions, @@ -51,42 +18,14 @@ import { } from './typescript-package-projection.ts' const genieContext: GenieContext = { cwd: process.cwd(), location: '' } +const buck2ToolsBuck = readFileSync('packages/@overeng/buck2-tools/BUCK', 'utf8') -const outputsByAdmission = { - agentSessionIngest: agentSessionIngestBuck.stringify(genieContext), - ciTools: ciToolsBuck.stringify(genieContext), - contentAddress: contentAddressBuck.stringify(genieContext), - effectAiClaudeCli: effectAiClaudeCliBuck.stringify(genieContext), - effectDistributedLock: effectDistributedLockBuck.stringify(genieContext), - effectPath: effectPathBuck.stringify(genieContext), - effectReact: effectReactBuck.stringify(genieContext), - effectRpcTanstack: effectRpcTanstackBuck.stringify(genieContext), - effectSchemaForm: effectSchemaFormBuck.stringify(genieContext), - genie: genieBuck.stringify(genieContext), - kdl: kdlBuck.stringify(genieContext), - kdlEffect: kdlEffectBuck.stringify(genieContext), - megarepo: megarepoBuck.stringify(genieContext), - notionCli: notionCliBuck.stringify(genieContext), - notionCore: notionCoreBuck.stringify(genieContext), - notionDatasourceSync: notionDatasourceSyncBuck.stringify(genieContext), - notionEffectClient: notionEffectClientBuck.stringify(genieContext), - notionEffectSchema: notionEffectSchemaBuck.stringify(genieContext), - notionMd: notionMdBuck.stringify(genieContext), - notionPropertyWrite: notionPropertyWriteBuck.stringify(genieContext), - notionReact: notionReactBuck.stringify(genieContext), - npmRelease: npmReleaseBuck.stringify(genieContext), - otelContract: otelContractBuck.stringify(genieContext), - oxcConfig: oxcConfigBuck.stringify(genieContext), - ptyEffect: ptyEffectBuck.stringify(genieContext), - reactInspector: reactInspectorBuck.stringify(genieContext), - restateEffect: restateEffectBuck.stringify(genieContext), - stylexTokens: stylexTokensBuck.stringify(genieContext), - tuiCore: tuiCoreBuck.stringify(genieContext), - tuiReact: tuiReactBuck.stringify(genieContext), - tuiStories: tuiStoriesBuck.stringify(genieContext), - utils: utilsBuck.stringify(genieContext), - utilsDev: utilsDevBuck.stringify(genieContext), -} as const satisfies Record +const outputsByAdmission = Object.fromEntries( + Object.entries(buck2TypeScriptAdmissions).map(([name, admission]) => [ + name, + readFileSync(path.join(admission.packagePath, 'BUCK'), 'utf8'), + ]), +) as Record const admittedPackages = Object.entries(buck2TypeScriptAdmissions).map(([key, admission]) => ({ output: outputsByAdmission[key as keyof typeof outputsByAdmission], @@ -173,9 +112,20 @@ const retiredProviderTerms = [ ] as const describe('declared-closure package projection', () => { - it('admits only explicitly marked packages to editor publication', () => { - expect(editorViewConsumerPackagePaths).toEqual(['packages/@overeng/tui-core']) - expect(buck2TypeScriptAdmissions.tuiReact.editorViewConsumer).toBe(false) + it('publishes editor views for the complete workspace package registry', () => { + expect(editorViewConsumerPackagePaths).toHaveLength(39) + expect(editorViewConsumerPackagePaths).toEqual( + Object.values(buck2TypeScriptAdmissions) + .map((admission) => admission.packagePath) + .toSorted(), + ) + }) + + it('assigns nested workspace static sources to their nearest package boundary', () => { + expect(outputsByAdmission.effectRpcTanstack).toContain( + 'exclude = STATIC_SOURCE_EXCLUDES + ["examples/basic/**"]', + ) + expect(outputsByAdmission.effectRpcTanstackBasic).toContain('exclude = STATIC_SOURCE_EXCLUDES)') }) it('wires each admitted package only to its normalized dependency view', () => { @@ -184,7 +134,9 @@ describe('declared-closure package projection', () => { expect(admitted.output).toContain(` dependency_view = "${admitted.dependencyView}",`) expect(admitted.output).toContain(' actual = ":node_modules",') expect(admitted.output).not.toContain('//buck2/dependencies:importer_') - expect(admitted.output).toContain(' runtime = "//:package_tree_runtime",') + expect(admitted.output).toContain( + ' runtime = "//packages/@overeng/buck2-tools:package_tree_runtime",', + ) expect(admitted.output).toContain(' runtime_entry = "package-tree.ts",') expect(admitted.output).toContain('load("//buck2:editor_view.bzl", "editor_view_inputs")') expect(admitted.output).toContain(editorViewTarget) @@ -228,8 +180,8 @@ describe('declared-closure package projection', () => { `${packagePath}/`, ) } - expect(rootBuck).toContain('name = "package_tree_runtime",') - expect(rootBuck).toContain('packages/@overeng/buck2-tools/src/package-tree.ts') + expect(rootBuck).not.toContain('name = "package_tree_runtime",') + expect(buck2ToolsBuck).toContain('name = "package_tree_runtime",') for (const admitted of admittedPackages) { for (const packagePath of admittedPackages.map(({ packagePath }) => packagePath)) { expect( @@ -251,15 +203,61 @@ describe('declared-closure package projection', () => { it('projects package-specific declaration entrypoints for authoritative emits', () => { const output = buck2TypeScriptPackageProjection({ ...buck2TypeScriptAdmissions.stylexTokens, - authority: { - declarationEntrypoint: 'src/tokens.stylex.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [ + { + declarationEntrypoint: 'src/tokens.stylex.d.ts', + projectFile: 'tsconfig.json', + }, + ], }).stringify(genieContext) expect(output).toContain(' declaration_entrypoint = "src/tokens.stylex.d.ts",') }) + it('projects an additional no-emit project under its own typecheck target', () => { + const output = outputsByAdmission.reactInspector + + expect(output).toContain(' name = "strict_consumer_typecheck",') + expect(output).toContain(' project = "tsconfig.strict-consumer.json",') + expect(output.split(' name = "dist",')).toHaveLength(2) + }) + + it('refuses an unnamed additional authority project', () => { + expect(() => + buck2TypeScriptPackageProjection({ + ...buck2TypeScriptAdmissions.reactInspector, + authorities: [ + { + declarationEntrypoint: 'src/index.d.ts', + projectFile: 'tsconfig.json', + }, + { + projectFile: 'tsconfig.strict-consumer.json', + projectPath: 'packages/@overeng/react-inspector/tsconfig.strict-consumer.json', + }, + ], + }).stringify(genieContext), + ).toThrow('must name its typecheck target') + }) + + it.each(['dist', 'package_tree', 'test', 'test_collect'])( + 'refuses a typecheck target that collides with generated target %s', + (typecheckTargetName) => { + expect(() => + buck2TypeScriptPackageProjection({ + ...buck2TypeScriptAdmissions.kdl, + authorities: [ + { + declarationEntrypoint: 'src/mod.d.ts', + projectFile: 'tsconfig.json', + typecheckTargetName, + }, + ], + }).stringify(genieContext), + ).toThrow('collides with generated Buck target') + }, + ) + it('projects only package-local handwritten declarations into emit inputs', () => { expect(outputsByAdmission.tuiReact).toContain( ' "src/storybook/asset-modules.d.ts": "src/storybook/asset-modules.d.ts",', @@ -281,12 +279,15 @@ describe('same-cell label projection', () => { for (const admitted of admittedPackages) { expect(admitted.output).not.toMatch(/@?effect_utils\/\//u) expect(admitted.output).toContain('load("//buck2:materialization.bzl"') + expect(admitted.output).toContain('load("//buck2:static_checks.bzl"') + expect(admitted.output).toContain(' name = "static_sources",') expect(admitted.output).toContain('//buck2/dependencies:view_') - expect(admitted.output).toContain('//:package_tree_runtime') + expect(admitted.output).toContain('//packages/@overeng/buck2-tools:package_tree_runtime') } const hubSources = [ 'buck2/materialization.bzl', + 'buck2/static_checks.bzl', 'buck2/platforms/defs.bzl', 'buck2/products/defs.bzl', 'buck2/toolchains/configured.bzl', @@ -300,6 +301,7 @@ describe('declared test lanes', () => { // Spelled out rather than spread-with-undefined: `exactOptionalPropertyTypes` makes an // explicit `tests: undefined` a different type from an absent lane declaration. const kdlAdmissionWithoutTests: Buck2TypeScriptPackageProjection = { + authorities: buck2TypeScriptAdmissions.kdl.authorities, dependencyImporter: buck2TypeScriptAdmissions.kdl.dependencyImporter, packageName: buck2TypeScriptAdmissions.kdl.packageName, packagePath: buck2TypeScriptAdmissions.kdl.packagePath, @@ -576,16 +578,17 @@ describe('declared test lanes', () => { tests: [{ name: 'test', runner: 'vitest', timeoutMs: 60_000 }], }).stringify(genieContext) - expect(outputsByAdmission.kdl).toContain('# Projection schema version: 8') + expect(outputsByAdmission.kdl).toContain('# Projection schema version: 11') expect(fingerprintOf(outputsByAdmission.kdl)).not.toBe(fingerprintOf(withoutTests)) expect(fingerprintOf(outputsByAdmission.kdl)).not.toBe(fingerprintOf(withLongerTimeout)) }) it('names the JavaScript action runtime as the runner every lane executes', () => { const rules = readFileSync('buck2/javascript.bzl', 'utf8') - expect(rules).not.toContain('//packages/@overeng/buck2-tools:javascript_action_runtime') - expect(rules.split('default = "//:javascript_action_runtime",')).toHaveLength(3) - expect(readFileSync('BUCK', 'utf8')).toContain(' name = "javascript_action_runtime",') + expect( + rules.split('default = "//packages/@overeng/buck2-tools:javascript_action_runtime",'), + ).toHaveLength(3) + expect(buck2ToolsBuck).toContain(' name = "javascript_action_runtime",') }) }) @@ -701,6 +704,38 @@ describe('derived test collection targets', () => { } }) + it('projects the effect-schema-form-aria census as one wholly bounded JSX lane', () => { + const admitted = admittedTestLanes.find( + ({ packagePath }) => packagePath === 'packages/@overeng/effect-schema-form-aria', + ) + expect(admitted).toBeDefined() + const census = admitted === undefined ? [] : collectableTestModulesOf(admitted) + const lane = buck2TestLanes.find( + ({ packagePath }) => packagePath === 'packages/@overeng/effect-schema-form-aria', + ) + + expect(census).toEqual(['src/mod.unit.test.tsx']) + expect(lane?.selectedTestFiles).toEqual(census) + expect(lane?.excludes).toEqual([]) + expect(lane?.sourceOwners).toEqual({}) + expect(lane?.unboundedFiles).toEqual([]) + expect(lane?.unboundedTaskName).toBeUndefined() + expect(admitted?.output).toContain( + [ + 'vitest_test(', + ' name = "test",', + ' package_tree = ":test_package_tree",', + ].join('\n'), + ) + expect(admitted?.output).toContain( + [ + 'vitest_collect(', + ' name = "test_collect",', + ' package_tree = ":test_package_tree",', + ].join('\n'), + ) + }) + it('keeps the JSX census inside the partition it stages', () => { const reactInspector = admittedTestLanes.find( (lane) => lane.packagePath === 'packages/@overeng/react-inspector', diff --git a/genie/ci-scripts/bootstrap-cold-proof.sh b/genie/ci-scripts/bootstrap-cold-proof.sh index 53806866dd..1440e75eec 100755 --- a/genie/ci-scripts/bootstrap-cold-proof.sh +++ b/genie/ci-scripts/bootstrap-cold-proof.sh @@ -1,10 +1,10 @@ #!/usr/bin/env bash # -# bootstrap:cold-proof (R32) — EMPIRICAL bootstrap-safety proof. +# bootstrap:cold-proof (R32) — empirical bootstrap-generator safety proof. # -# Demonstrates (not merely asserts) that the bootstrap-phase generators run BEFORE install in a -# fresh, no-`node_modules` environment and produce a state `pnpm install` accepts. This is the -# authority for the bootstrap contract; `bootstrap-closure:check` (static) is fast local feedback. +# Demonstrates that the bootstrap-phase generators run in a fresh, +# no-`node_modules` environment. This is the authority for the bootstrap +# contract; `bootstrap-closure:check` is its fast static pre-check. # # Mechanism: # 1. Realize the packaged Genie CLI (`.#genie`) — a wrapper over the reviewed, @@ -12,20 +12,17 @@ # it needs no `node_modules` to run. (Override with # GENIE_COLD_PROOF_BIN=/path/to/genie to reuse an already-built product and # skip the Nix build.) -# 2. Materialize a `node_modules`-free tree of the COMMITTED repo source via `git archive HEAD` -# into a temp dir OUTSIDE the repo (so bun/pnpm cannot walk up into the repo's node_modules). -# 3. Run `genie --phase bootstrap` COLD in that tree. Success proves every bootstrap generator's -# transitive runtime closure is importable pre-install (a reach into `effect`/`@effect/*`/ -# `@overeng/otel-contract` would throw on import and fail this step). Non-vacuity: assert it -# selected exactly the `// @genie-bootstrap`-marked set (independently counted from the tree). -# 4. Run `pnpm install --frozen-lockfile` in that tree. Success proves the cold-regenerated install -# inputs match the committed lockfile exactly. +# 2. Materialize a `node_modules`-free tree of the committed repo source via +# `git archive HEAD` outside the repo. +# 3. Run `genie --phase bootstrap` cold. Success proves every bootstrap +# generator's transitive runtime closure is importable without a dependency +# view. Non-vacuity asserts the exact `// @genie-bootstrap`-marked set. # # Usage: # genie/ci-scripts/bootstrap-cold-proof.sh # GENIE_COLD_PROOF_BIN=./result/bin/genie genie/ci-scripts/bootstrap-cold-proof.sh # -# Exit 0 iff BOTH the cold `genie --phase bootstrap` and the cold `pnpm install` succeed. +# Exit 0 iff the complete marked bootstrap generator set succeeds cold. set -euo pipefail @@ -145,24 +142,3 @@ if (files.length !== expected) { } console.error(`[cold-proof] cold genie --phase bootstrap OK — ${files.length} generators ran, none errored`) NODE - -# --- 4. Cold `pnpm install --frozen-lockfile` ------------------------------------------------------ -# Mirror the repo's canonical install (see nix/devenv-modules/tasks/lib/effect-utils-install.nix): -# frozen (asserts the cold-regenerated inputs match the committed lockfile), scripts ignored, and -# resolving against the shared/warm pnpm store so the proof is offline-ish and CI-cache-friendly. -store_dir="${PNPM_STORE_DIR:-${PNPM_CONFIG_STORE_DIR:-${repo}/.devenv/pnpm-store-pure-v1}}" -command -v pnpm >/dev/null 2>&1 || fail "pnpm not on PATH (run inside the devenv shell / task)" -log "running pnpm install --frozen-lockfile COLD (store: ${store_dir}) ..." -if ! DEVENV_TASK_PASSTHROUGH=1 pnpm install \ - --force \ - --frozen-lockfile \ - --ignore-scripts \ - --config.store-dir="$store_dir" \ - --dir "$tree" >"${work}/pnpm.log" 2>&1; then - log "cold pnpm install log (tail):" - tail -40 "${work}/pnpm.log" >&2 || true - fail "cold 'pnpm install --frozen-lockfile' failed against the cold-regenerated inputs" -fi -[ -d "${tree}/node_modules" ] || fail "pnpm install reported success but produced no node_modules" - -log "PASS — cold 'genie --phase bootstrap' (${expected} generators) + cold 'pnpm install' both succeeded" diff --git a/genie/ci-scripts/bundle-smoke.ts b/genie/ci-scripts/bundle-smoke.ts deleted file mode 100644 index fe62a2d5fb..0000000000 --- a/genie/ci-scripts/bundle-smoke.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { builtinModules } from 'node:module' -import { createRequire } from 'node:module' -import path from 'node:path' - -type SmokeEntry = { - readonly name: string - readonly entry: string -} - -const builtinSpecifiers = new Set([ - ...builtinModules, - ...builtinModules.map((moduleName) => `node:${moduleName}`), -]) - -const nativePtySpecifiers = new Set(['node-pty', '@homebridge/node-pty-prebuilt-multiarch']) - -type RollupExternal = (id: string) => boolean - -const external: RollupExternal = (id) => { - if (builtinSpecifiers.has(id) === true) return true - if (nativePtySpecifiers.has(id) === true) return true - return id.endsWith('.node') -} - -const smokeEntries: ReadonlyArray = [ - { - name: 'pty-effect', - entry: 'packages/@overeng/pty-effect/src/mod.ts', - }, - { - name: 'pty-effect-client', - entry: 'packages/@overeng/pty-effect/src/client.ts', - }, -] - -const repoRoot = path.resolve(process.cwd(), '..', '..', '..') -const ptyEffectRequire = createRequire( - path.join(repoRoot, 'packages', '@overeng', 'pty-effect', 'package.json'), -) - -const main = async () => { - const { build } = await import(ptyEffectRequire.resolve('vite')) - - await Promise.all( - smokeEntries.map(async (smokeEntry) => { - console.log(`bundle smoke: ${smokeEntry.name}`) - await build({ - root: repoRoot, - configFile: false, - logLevel: 'warn', - ssr: { - noExternal: true, - }, - build: { - emptyOutDir: false, - minify: false, - outDir: path.join(repoRoot, 'tmp', 'bundle-smoke', smokeEntry.name), - ssr: path.join(repoRoot, smokeEntry.entry), - write: false, - rollupOptions: { - external, - output: { - entryFileNames: `${smokeEntry.name}.mjs`, - }, - }, - }, - }) - }), - ) -} - -main().catch((error: unknown) => { - console.error(error) - process.exitCode = 1 -}) diff --git a/genie/ci-scripts/cleanup-effect-utils-composition.sh b/genie/ci-scripts/cleanup-effect-utils-composition.sh index 95d41107f9..de7b093ede 100755 --- a/genie/ci-scripts/cleanup-effect-utils-composition.sh +++ b/genie/ci-scripts/cleanup-effect-utils-composition.sh @@ -83,6 +83,10 @@ backlink_dir="$(cd "$(dirname "$backlink")" && pwd -P)" backlink="$backlink_dir/$(basename "$backlink")" [ "$backlink" = "$owned_worktree/.git" ] +# Composed capabilities can contain Nix-derived directories without owner write +# permission. Restore removal permission only after the ownership checks above. +chmod -R u+w "$workspace_root" + git --git-dir="$bare_repo" worktree remove --force "$owned_worktree" rm -rf -- "$workspace_root" git --git-dir="$bare_repo" update-ref -d "$branch_ref" diff --git a/genie/ci-workflow.ts b/genie/ci-workflow.ts index 9f0fb0cc36..7335a6f0b1 100644 --- a/genie/ci-workflow.ts +++ b/genie/ci-workflow.ts @@ -23,6 +23,7 @@ * ``` */ + import type { GitHubWorkflowArgs } from '../packages/@overeng/genie/src/runtime/mod.ts' import { defaultRefPolicyCheckStep, @@ -34,7 +35,7 @@ import { bashShellDefaults, linuxX64Runner } from './ci-workflow/shared.ts' type GitHubWorkflowJob = GitHubWorkflowArgs['jobs'][string] type GitHubWorkflowStep = GitHubWorkflowJob['steps'][number] -/** Options for wrapping the default-ref policy check in a dedicated CI job. */ +/** Options for wrapping the pre-composition default-ref policy check in a dedicated CI job. */ export type DefaultRefPolicyCheckJobOptions = DefaultRefPolicyCheckStepOptions & { readonly name?: string readonly runsOn?: GitHubWorkflowJob['runs-on'] @@ -45,15 +46,7 @@ export type DefaultRefPolicyCheckJobOptions = DefaultRefPolicyCheckStepOptions & readonly postSteps?: readonly GitHubWorkflowStep[] } -/** - * Dedicated CI job for first-party default-ref policy. - * - * We intentionally keep this out of lint/typecheck/test jobs. Downstream PRs - * often validate against temporary first-party branches while an upstream PR is - * still open, and that should fail in one authority/policy job without hiding - * whether the actual product jobs are green. Before merge, repos must retarget - * those first-party inputs back to their default refs and refresh locks. - */ +/** Keep the trust gate checkout-only: invalid refs must fail before repository code executes. */ export const defaultRefPolicyCheckJob = (opts: DefaultRefPolicyCheckJobOptions = {}) => { const { name, runsOn, env, permissions, defaults, preSteps, postSteps, ...stepOpts } = opts @@ -72,7 +65,6 @@ export const defaultRefPolicyCheckJob = (opts: DefaultRefPolicyCheckJobOptions = ], } satisfies GitHubWorkflowJob } - export { RUNNER_PROFILES, bashShellDefaults, @@ -222,14 +214,12 @@ export { } from './ci-workflow/setup.ts' export { applyMegarepoLockStep, - defaultRefPolicyCheckStep, cacheableMegarepoStore, installMegarepoStep, jobLocalMegarepoStore, restoreMegarepoStoreStep, saveMegarepoStoreStep, syncMegarepoWorkspaceStep, - type DefaultRefPolicyCheckStepOptions, } from './ci-workflow/megarepo.ts' export { fullPullRequestCiEvent, diff --git a/genie/ci-workflow/default-ref-policy-script.ts b/genie/ci-workflow/default-ref-policy-script.ts new file mode 100644 index 0000000000..6941d90907 --- /dev/null +++ b/genie/ci-workflow/default-ref-policy-script.ts @@ -0,0 +1,349 @@ +export const defaultRefPolicyCheckScript = String.raw`const fs = require('node:fs') +const path = require('node:path') +const os = require('node:os') +const cp = require('node:child_process') + +const cwd = process.cwd() +const firstPartyOwners = new Set(JSON.parse(process.env.FIRST_PARTY_OWNERS_JSON).map((owner) => owner.toLowerCase())) +const defaultRef = process.env.DEFAULT_REF || 'main' +const defaultRefs = new Map(Object.entries(JSON.parse(process.env.DEFAULT_REFS_JSON || '{}')).map(([repo, ref]) => [repo.toLowerCase(), ref])) +const verifyReachable = process.env.VERIFY_REACHABLE === '1' +const allowLegacyMemberCommitRefs = process.env.ALLOW_LEGACY_MEMBER_COMMIT_REFS === '1' +const violations = [] + +const repoKey = (repo) => repo.owner.toLowerCase() + '/' + repo.repo.toLowerCase() +const isFirstParty = (repo) => firstPartyOwners.has(repo.owner.toLowerCase()) +const normalizeGitBranchRefs = process.env.NORMALIZE_GIT_BRANCH_REFS === '1' +const normalizeRef = (ref) => normalizeGitBranchRefs && ref.startsWith('refs/heads/') ? ref.slice('refs/heads/'.length) : ref +const expectedRefFor = (repo) => normalizeRef(defaultRefs.get(repoKey(repo)) || defaultRef) +const immutableCommitRef = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/i +const isAllowedLegacyMemberRef = ({ memberName, ref }) => + allowLegacyMemberCommitRefs && + typeof memberName === 'string' && + memberName.endsWith('-legacy') && + immutableCommitRef.test(ref) + +const githubRepoFromUrl = (url) => { + const match = url.match(/github\.com[/:]([^/]+)\/([^/#?]+?)(?:\.git)?(?:[#?].*)?$/) + return match ? { owner: match[1], repo: match[2] } : undefined +} + +const parseGithubLikeRef = (value) => { + const hashIndex = value.indexOf('#') + const baseWithQuery = hashIndex >= 0 ? value.slice(0, hashIndex) : value + const hashRef = hashIndex >= 0 ? value.slice(hashIndex + 1) : undefined + const queryIndex = baseWithQuery.indexOf('?') + const base = queryIndex >= 0 ? baseWithQuery.slice(0, queryIndex) : baseWithQuery + const params = new URLSearchParams(queryIndex >= 0 ? baseWithQuery.slice(queryIndex + 1) : '') + const queryRef = params.get('ref') || undefined + + if (base.startsWith('github:')) { + const parts = base.slice('github:'.length).split('/') + if (parts.length < 2) return undefined + return { + repo: { owner: parts[0], repo: parts[1] }, + ref: hashRef || queryRef || (parts.length > 2 ? parts.slice(2).join('/') : undefined), + } + } + + if (base.startsWith('git+https://github.com/')) { + const repo = githubRepoFromUrl(base.slice('git+'.length)) + return repo ? { repo, ref: hashRef || queryRef } : undefined + } + + if (base.startsWith('git+ssh://git@github.com/')) { + const pathParts = base.slice('git+ssh://git@github.com/'.length).replace(/\.git$/, '').split('/') + return pathParts.length >= 2 + ? { repo: { owner: pathParts[0], repo: pathParts[1] }, ref: hashRef || queryRef } + : undefined + } + + const urlRepo = githubRepoFromUrl(base) + if (urlRepo) return { repo: urlRepo, ref: hashRef || queryRef } + + if (!value.includes('://') && !value.startsWith('./') && !value.startsWith('../') && !value.startsWith('/')) { + const parts = base.split('/') + if (parts.length === 2 && parts[0] && parts[1]) { + return { repo: { owner: parts[0], repo: parts[1] }, ref: hashRef } + } + } + + return undefined +} + +const addRefViolation = ({ file, repo, ref, field, inputName, memberName }) => { + if (!repo || !ref || !isFirstParty(repo)) return + const expectedRef = expectedRefFor(repo) + const normalizedRef = normalizeRef(ref) + if (normalizedRef === expectedRef) return + if (isAllowedLegacyMemberRef({ memberName, ref: normalizedRef })) return + violations.push({ + type: 'ref', + file, + repo: repoKey(repo), + ref: normalizedRef, + expectedRef, + field, + inputName, + memberName, + }) +} + +const readJson = (file) => { + try { + return JSON.parse(fs.readFileSync(file, 'utf8')) + } catch { + return undefined + } +} + +const displayPath = (file) => path.relative(cwd, file) || path.basename(file) +const authorityNames = new Set(['megarepo.kdl', 'megarepo.json', 'megarepo.lock', 'flake.nix', 'flake.lock', 'devenv.yaml', 'devenv.lock']) +const ignoredDirs = new Set(['.git', 'node_modules', 'dist', 'result', '.devenv', '.direnv', '.next', '.storybook-static']) + +const collectAuthorityFiles = (root) => { + const files = [] + const walk = (dir) => { + let entries = [] + try { + entries = fs.readdirSync(dir) + } catch { + return + } + for (const entry of entries) { + const full = path.join(dir, entry) + let stat + try { + stat = fs.statSync(full) + } catch { + continue + } + if (stat.isDirectory()) { + if (ignoredDirs.has(entry)) continue + if (dir === root && entry === 'repos') continue + walk(full) + } else if (stat.isFile() && authorityNames.has(entry)) { + files.push(full) + } + } + } + walk(root) + return files +} + +const extractFlakeNixInputs = (content) => { + const inputs = [] + const directPattern = /(?:inputs\.)?([a-zA-Z0-9_-]+)\.url\s*=\s*"([^"]+)"/g + let match + while ((match = directPattern.exec(content)) !== null) { + inputs.push({ inputName: match[1], url: match[2] }) + } + + const lines = content.split('\n') + let inInputs = false + let inputsIndent = -1 + let currentInputName + let currentInputIndent = -1 + for (const line of lines) { + const trimmed = line.trimStart() + const indent = line.length - trimmed.length + if (trimmed.startsWith('inputs = {')) { + inInputs = true + inputsIndent = indent + currentInputName = undefined + currentInputIndent = -1 + continue + } + if (!inInputs) continue + if (trimmed && indent <= inputsIndent && trimmed.startsWith('};')) { + inInputs = false + currentInputName = undefined + continue + } + if (currentInputName && trimmed === '};' && indent <= currentInputIndent) { + currentInputName = undefined + continue + } + const inputStart = trimmed.match(/^(?:inputs\.)?([a-zA-Z0-9_-]+)\s*=\s*\{\s*$/) + if (inputStart && indent > inputsIndent) { + currentInputName = inputStart[1] + currentInputIndent = indent + continue + } + const urlMatch = trimmed.match(/^url\s*=\s*"([^"]+)"/) + if (currentInputName && urlMatch) inputs.push({ inputName: currentInputName, url: urlMatch[1] }) + } + return inputs +} + +const extractDevenvYamlInputs = (content) => { + const inputs = [] + const lines = content.split('\n') + let inInputs = false + let inputsIndent = -1 + let currentInputName + for (const line of lines) { + const trimmed = line.trimStart() + const indent = line.length - trimmed.length + if (trimmed === 'inputs:' && !inInputs) { + inInputs = true + inputsIndent = indent + currentInputName = undefined + continue + } + if (!inInputs) continue + if (trimmed && indent <= inputsIndent && !trimmed.startsWith('#')) { + inInputs = false + currentInputName = undefined + continue + } + const inputNameMatch = trimmed.match(/^([a-zA-Z0-9_-]+):$/) + if (inputNameMatch && indent > inputsIndent) { + currentInputName = inputNameMatch[1] + continue + } + const urlMatch = trimmed.match(/^url:\s*(.+)$/) + if (currentInputName && urlMatch) { + const raw = urlMatch[1].trim() + const url = (raw.startsWith('"') && raw.endsWith('"')) || (raw.startsWith("'") && raw.endsWith("'")) + ? raw.slice(1, -1) + : raw + inputs.push({ inputName: currentInputName, url }) + } + } + return inputs +} + +const lockInputs = (content) => { + const parsed = readJsonContent(content) + const rootName = parsed && (parsed.root || 'root') + const root = parsed && parsed.nodes && parsed.nodes[rootName] + if (!root || !root.inputs || !parsed.nodes) return [] + return Object.entries(root.inputs).flatMap(([inputName, nodeName]) => { + const node = parsed.nodes[nodeName] + return node ? [{ inputName, original: node.original, locked: node.locked }] : [] + }) +} + +const readJsonContent = (content) => { + try { + return JSON.parse(content) + } catch { + return undefined + } +} + +const repoFromLockSection = (section) => { + if (!section || typeof section !== 'object') return undefined + if (section.type === 'github' && typeof section.owner === 'string' && typeof section.repo === 'string') { + return { owner: section.owner, repo: section.repo } + } + if (section.type === 'git' && typeof section.url === 'string') return githubRepoFromUrl(section.url) + if (typeof section.url === 'string') return parseGithubLikeRef(section.url)?.repo || githubRepoFromUrl(section.url) + return undefined +} + +const refFromLockSection = (section) => { + if (!section || typeof section !== 'object') return undefined + if (typeof section.ref === 'string') return section.ref + if (typeof section.url === 'string') return parseGithubLikeRef(section.url)?.ref + return undefined +} + +const roots = [cwd] +const reposRoot = path.join(cwd, 'repos') +if (fs.existsSync(reposRoot)) { + for (const entry of fs.readdirSync(reposRoot)) { + roots.push(path.join(reposRoot, entry)) + } +} + +for (const root of roots) { + for (const file of collectAuthorityFiles(root)) { + const base = path.basename(file) + const rel = displayPath(file) + const content = fs.readFileSync(file, 'utf8') + + if (base === 'megarepo.kdl') { + for (const line of content.split('\n')) { + const match = line.trim().match(/^([A-Za-z0-9_.-]+)\s+"([^"]+)"/) + if (!match) continue + const parsed = parseGithubLikeRef(match[2]) + addRefViolation({ file: rel, repo: parsed && parsed.repo, ref: parsed && parsed.ref, field: 'members.source', memberName: match[1] }) + } + } else if (base === 'megarepo.lock') { + const parsed = readJson(file) + for (const [memberName, member] of Object.entries((parsed && parsed.members) || {})) { + const repo = typeof member.url === 'string' ? githubRepoFromUrl(member.url) : undefined + addRefViolation({ file: rel, repo, ref: member.ref, field: 'members.ref', memberName }) + } + } else if (base === 'flake.nix') { + for (const input of extractFlakeNixInputs(content)) { + const parsed = parseGithubLikeRef(input.url) + addRefViolation({ file: rel, repo: parsed && parsed.repo, ref: parsed && parsed.ref, field: 'url.ref', inputName: input.inputName }) + } + } else if (base === 'devenv.yaml') { + for (const input of extractDevenvYamlInputs(content)) { + const parsed = parseGithubLikeRef(input.url) + addRefViolation({ file: rel, repo: parsed && parsed.repo, ref: parsed && parsed.ref, field: 'url.ref', inputName: input.inputName }) + } + } else if (base === 'flake.lock' || base === 'devenv.lock') { + for (const input of lockInputs(content)) { + for (const [field, section] of [['original', input.original], ['locked', input.locked]]) { + addRefViolation({ file: rel, repo: repoFromLockSection(section), ref: refFromLockSection(section), field: field + '.ref', inputName: input.inputName }) + } + } + } + } +} + +if (verifyReachable) { + const lock = readJson(path.join(cwd, 'megarepo.lock')) + for (const [memberName, member] of Object.entries((lock && lock.members) || {})) { + const repo = typeof member.url === 'string' ? githubRepoFromUrl(member.url) : undefined + if (!repo || !isFirstParty(repo)) continue + if ( + typeof member.ref === 'string' && + isAllowedLegacyMemberRef({ memberName, ref: normalizeRef(member.ref) }) + ) { + continue + } + const expectedRef = expectedRefFor(repo) + const remote = 'https://github.com/' + repo.owner + '/' + repo.repo + '.git' + const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'default-ref-policy-')) + let ok = false + try { + cp.execFileSync('git', ['-C', tmp, 'init', '-q'], { stdio: 'ignore' }) + cp.execFileSync('git', ['-C', tmp, 'remote', 'add', 'origin', remote], { stdio: 'ignore' }) + cp.execFileSync('git', ['-C', tmp, 'fetch', '-q', '--filter=blob:none', 'origin', 'refs/heads/' + expectedRef + ':refs/remotes/origin/' + expectedRef], { stdio: 'ignore' }) + cp.execFileSync('git', ['-C', tmp, 'cat-file', '-e', member.commit + '^{commit}'], { stdio: 'ignore' }) + cp.execFileSync('git', ['-C', tmp, 'merge-base', '--is-ancestor', member.commit, 'refs/remotes/origin/' + expectedRef], { stdio: 'ignore' }) + ok = true + } catch { + ok = false + } finally { + fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }) + } + if (!ok) { + violations.push({ type: 'reachability', file: 'megarepo.lock', repo: repoKey(repo), rev: member.commit, expectedRef, memberName }) + } + } +} + +if (violations.length === 0) { + console.log('Default ref policy OK') + process.exit(0) +} + +console.error('Default ref policy failed:') +for (const violation of violations) { + if (violation.type === 'reachability') { + console.error(' - ' + violation.file + ': member ' + violation.memberName + ' ' + violation.repo + ' locks ' + violation.rev.slice(0, 12) + " outside '" + violation.expectedRef + "'") + } else { + const name = violation.memberName ? ' member ' + violation.memberName : violation.inputName ? ' input ' + violation.inputName : '' + console.error(' - ' + violation.file + ':' + name + ' ' + violation.repo + " uses ref '" + violation.ref + "' in " + violation.field + "; expected '" + violation.expectedRef + "'") + } +} +console.error('') +console.error('Fix: merge upstream PRs first, retarget first-party inputs back to their default refs, then refresh locks.') +process.exit(1)` diff --git a/genie/ci-workflow/measurements.ts b/genie/ci-workflow/measurements.ts index add1f2a2a7..373925ba07 100644 --- a/genie/ci-workflow/measurements.ts +++ b/genie/ci-workflow/measurements.ts @@ -2893,7 +2893,7 @@ const humanProbe = (row) => { shell_eval_warm: 'Warm shell eval', tasks_list: 'devenv tasks list', processes_help: 'devenv processes --help', - task_pnpm_install: 'pnpm:install', + task_buck2_editor_publish: 'buck2:editor:publish', task_genie_run: 'genie:run', task_check_quick: 'check:quick', task_check_quick_warm: 'Warm cached check:quick', @@ -2974,7 +2974,7 @@ const chartProbe = (row) => { shell_eval_warm: 'Warm shell eval', tasks_list: 'devenv tasks list', processes_help: 'processes --help', - task_pnpm_install: 'pnpm:install', + task_buck2_editor_publish: 'buck2:editor:publish', task_genie_run: 'genie:run', task_check_quick: 'check:quick', task_check_quick_warm: 'Warm cached check:quick', diff --git a/genie/ci-workflow/megarepo.ts b/genie/ci-workflow/megarepo.ts index 33e6a63bde..91a35ff481 100644 --- a/genie/ci-workflow/megarepo.ts +++ b/genie/ci-workflow/megarepo.ts @@ -1,3 +1,4 @@ +import { defaultRefPolicyCheckScript } from './default-ref-policy-script.ts' import { githubTokenEnv, shellSingleQuote } from './shared.ts' /** Ephemeral per-job megarepo store path scoped to the CI run/attempt/job */ @@ -173,357 +174,7 @@ export type DefaultRefPolicyCheckStepOptions = { readonly allowLegacyMemberCommitRefs?: boolean } -const defaultRefPolicyCheckScript = String.raw`const fs = require('node:fs') -const path = require('node:path') -const os = require('node:os') -const cp = require('node:child_process') - -const cwd = process.cwd() -const firstPartyOwners = new Set(JSON.parse(process.env.FIRST_PARTY_OWNERS_JSON).map((owner) => owner.toLowerCase())) -const defaultRef = process.env.DEFAULT_REF || 'main' -const defaultRefs = new Map(Object.entries(JSON.parse(process.env.DEFAULT_REFS_JSON || '{}')).map(([repo, ref]) => [repo.toLowerCase(), ref])) -const verifyReachable = process.env.VERIFY_REACHABLE === '1' -const allowLegacyMemberCommitRefs = process.env.ALLOW_LEGACY_MEMBER_COMMIT_REFS === '1' -const violations = [] - -const repoKey = (repo) => repo.owner.toLowerCase() + '/' + repo.repo.toLowerCase() -const isFirstParty = (repo) => firstPartyOwners.has(repo.owner.toLowerCase()) -const normalizeGitBranchRefs = process.env.NORMALIZE_GIT_BRANCH_REFS === '1' -const normalizeRef = (ref) => normalizeGitBranchRefs && ref.startsWith('refs/heads/') ? ref.slice('refs/heads/'.length) : ref -const expectedRefFor = (repo) => normalizeRef(defaultRefs.get(repoKey(repo)) || defaultRef) -const immutableCommitRef = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/i -const isAllowedLegacyMemberRef = ({ memberName, ref }) => - allowLegacyMemberCommitRefs && - typeof memberName === 'string' && - memberName.endsWith('-legacy') && - immutableCommitRef.test(ref) - -const githubRepoFromUrl = (url) => { - const match = url.match(/github\.com[/:]([^/]+)\/([^/#?]+?)(?:\.git)?(?:[#?].*)?$/) - return match ? { owner: match[1], repo: match[2] } : undefined -} - -const parseGithubLikeRef = (value) => { - const hashIndex = value.indexOf('#') - const baseWithQuery = hashIndex >= 0 ? value.slice(0, hashIndex) : value - const hashRef = hashIndex >= 0 ? value.slice(hashIndex + 1) : undefined - const queryIndex = baseWithQuery.indexOf('?') - const base = queryIndex >= 0 ? baseWithQuery.slice(0, queryIndex) : baseWithQuery - const params = new URLSearchParams(queryIndex >= 0 ? baseWithQuery.slice(queryIndex + 1) : '') - const queryRef = params.get('ref') || undefined - - if (base.startsWith('github:')) { - const parts = base.slice('github:'.length).split('/') - if (parts.length < 2) return undefined - return { - repo: { owner: parts[0], repo: parts[1] }, - ref: hashRef || queryRef || (parts.length > 2 ? parts.slice(2).join('/') : undefined), - } - } - - if (base.startsWith('git+https://github.com/')) { - const repo = githubRepoFromUrl(base.slice('git+'.length)) - return repo ? { repo, ref: hashRef || queryRef } : undefined - } - - if (base.startsWith('git+ssh://git@github.com/')) { - const pathParts = base.slice('git+ssh://git@github.com/'.length).replace(/\.git$/, '').split('/') - return pathParts.length >= 2 - ? { repo: { owner: pathParts[0], repo: pathParts[1] }, ref: hashRef || queryRef } - : undefined - } - - const urlRepo = githubRepoFromUrl(base) - if (urlRepo) return { repo: urlRepo, ref: hashRef || queryRef } - - if (!value.includes('://') && !value.startsWith('./') && !value.startsWith('../') && !value.startsWith('/')) { - const parts = base.split('/') - if (parts.length === 2 && parts[0] && parts[1]) { - return { repo: { owner: parts[0], repo: parts[1] }, ref: hashRef } - } - } - - return undefined -} - -const addRefViolation = ({ file, repo, ref, field, inputName, memberName }) => { - if (!repo || !ref || !isFirstParty(repo)) return - const expectedRef = expectedRefFor(repo) - const normalizedRef = normalizeRef(ref) - if (normalizedRef === expectedRef) return - if (isAllowedLegacyMemberRef({ memberName, ref: normalizedRef })) return - violations.push({ - type: 'ref', - file, - repo: repoKey(repo), - ref: normalizedRef, - expectedRef, - field, - inputName, - memberName, - }) -} - -const readJson = (file) => { - try { - return JSON.parse(fs.readFileSync(file, 'utf8')) - } catch { - return undefined - } -} - -const displayPath = (file) => path.relative(cwd, file) || path.basename(file) -const authorityNames = new Set(['megarepo.kdl', 'megarepo.json', 'megarepo.lock', 'flake.nix', 'flake.lock', 'devenv.yaml', 'devenv.lock']) -const ignoredDirs = new Set(['.git', 'node_modules', 'dist', 'result', '.devenv', '.direnv', '.next', '.storybook-static']) - -const collectAuthorityFiles = (root) => { - const files = [] - const walk = (dir) => { - let entries = [] - try { - entries = fs.readdirSync(dir) - } catch { - return - } - for (const entry of entries) { - const full = path.join(dir, entry) - let stat - try { - stat = fs.statSync(full) - } catch { - continue - } - if (stat.isDirectory()) { - if (ignoredDirs.has(entry)) continue - if (dir === root && entry === 'repos') continue - walk(full) - } else if (stat.isFile() && authorityNames.has(entry)) { - files.push(full) - } - } - } - walk(root) - return files -} - -const extractFlakeNixInputs = (content) => { - const inputs = [] - const directPattern = /(?:inputs\.)?([a-zA-Z0-9_-]+)\.url\s*=\s*"([^"]+)"/g - let match - while ((match = directPattern.exec(content)) !== null) { - inputs.push({ inputName: match[1], url: match[2] }) - } - - const lines = content.split('\n') - let inInputs = false - let inputsIndent = -1 - let currentInputName - let currentInputIndent = -1 - for (const line of lines) { - const trimmed = line.trimStart() - const indent = line.length - trimmed.length - if (trimmed.startsWith('inputs = {')) { - inInputs = true - inputsIndent = indent - currentInputName = undefined - currentInputIndent = -1 - continue - } - if (!inInputs) continue - if (trimmed && indent <= inputsIndent && trimmed.startsWith('};')) { - inInputs = false - currentInputName = undefined - continue - } - if (currentInputName && trimmed === '};' && indent <= currentInputIndent) { - currentInputName = undefined - continue - } - const inputStart = trimmed.match(/^(?:inputs\.)?([a-zA-Z0-9_-]+)\s*=\s*\{\s*$/) - if (inputStart && indent > inputsIndent) { - currentInputName = inputStart[1] - currentInputIndent = indent - continue - } - const urlMatch = trimmed.match(/^url\s*=\s*"([^"]+)"/) - if (currentInputName && urlMatch) inputs.push({ inputName: currentInputName, url: urlMatch[1] }) - } - return inputs -} - -const extractDevenvYamlInputs = (content) => { - const inputs = [] - const lines = content.split('\n') - let inInputs = false - let inputsIndent = -1 - let currentInputName - for (const line of lines) { - const trimmed = line.trimStart() - const indent = line.length - trimmed.length - if (trimmed === 'inputs:' && !inInputs) { - inInputs = true - inputsIndent = indent - currentInputName = undefined - continue - } - if (!inInputs) continue - if (trimmed && indent <= inputsIndent && !trimmed.startsWith('#')) { - inInputs = false - currentInputName = undefined - continue - } - const inputNameMatch = trimmed.match(/^([a-zA-Z0-9_-]+):$/) - if (inputNameMatch && indent > inputsIndent) { - currentInputName = inputNameMatch[1] - continue - } - const urlMatch = trimmed.match(/^url:\s*(.+)$/) - if (currentInputName && urlMatch) { - const raw = urlMatch[1].trim() - const url = (raw.startsWith('"') && raw.endsWith('"')) || (raw.startsWith("'") && raw.endsWith("'")) - ? raw.slice(1, -1) - : raw - inputs.push({ inputName: currentInputName, url }) - } - } - return inputs -} - -const lockInputs = (content) => { - const parsed = readJsonContent(content) - const rootName = parsed && (parsed.root || 'root') - const root = parsed && parsed.nodes && parsed.nodes[rootName] - if (!root || !root.inputs || !parsed.nodes) return [] - return Object.entries(root.inputs).flatMap(([inputName, nodeName]) => { - const node = parsed.nodes[nodeName] - return node ? [{ inputName, original: node.original, locked: node.locked }] : [] - }) -} - -const readJsonContent = (content) => { - try { - return JSON.parse(content) - } catch { - return undefined - } -} - -const repoFromLockSection = (section) => { - if (!section || typeof section !== 'object') return undefined - if (section.type === 'github' && typeof section.owner === 'string' && typeof section.repo === 'string') { - return { owner: section.owner, repo: section.repo } - } - if (section.type === 'git' && typeof section.url === 'string') return githubRepoFromUrl(section.url) - if (typeof section.url === 'string') return parseGithubLikeRef(section.url)?.repo || githubRepoFromUrl(section.url) - return undefined -} - -const refFromLockSection = (section) => { - if (!section || typeof section !== 'object') return undefined - if (typeof section.ref === 'string') return section.ref - if (typeof section.url === 'string') return parseGithubLikeRef(section.url)?.ref - return undefined -} - -const roots = [cwd] -const reposRoot = path.join(cwd, 'repos') -if (fs.existsSync(reposRoot)) { - for (const entry of fs.readdirSync(reposRoot)) { - roots.push(path.join(reposRoot, entry)) - } -} - -for (const root of roots) { - for (const file of collectAuthorityFiles(root)) { - const base = path.basename(file) - const rel = displayPath(file) - const content = fs.readFileSync(file, 'utf8') - - if (base === 'megarepo.kdl') { - for (const line of content.split('\n')) { - const match = line.trim().match(/^([A-Za-z0-9_.-]+)\s+"([^"]+)"/) - if (!match) continue - const parsed = parseGithubLikeRef(match[2]) - addRefViolation({ file: rel, repo: parsed && parsed.repo, ref: parsed && parsed.ref, field: 'members.source', memberName: match[1] }) - } - } else if (base === 'megarepo.lock') { - const parsed = readJson(file) - for (const [memberName, member] of Object.entries((parsed && parsed.members) || {})) { - const repo = typeof member.url === 'string' ? githubRepoFromUrl(member.url) : undefined - addRefViolation({ file: rel, repo, ref: member.ref, field: 'members.ref', memberName }) - } - } else if (base === 'flake.nix') { - for (const input of extractFlakeNixInputs(content)) { - const parsed = parseGithubLikeRef(input.url) - addRefViolation({ file: rel, repo: parsed && parsed.repo, ref: parsed && parsed.ref, field: 'url.ref', inputName: input.inputName }) - } - } else if (base === 'devenv.yaml') { - for (const input of extractDevenvYamlInputs(content)) { - const parsed = parseGithubLikeRef(input.url) - addRefViolation({ file: rel, repo: parsed && parsed.repo, ref: parsed && parsed.ref, field: 'url.ref', inputName: input.inputName }) - } - } else if (base === 'flake.lock' || base === 'devenv.lock') { - for (const input of lockInputs(content)) { - for (const [field, section] of [['original', input.original], ['locked', input.locked]]) { - addRefViolation({ file: rel, repo: repoFromLockSection(section), ref: refFromLockSection(section), field: field + '.ref', inputName: input.inputName }) - } - } - } - } -} - -if (verifyReachable) { - const lock = readJson(path.join(cwd, 'megarepo.lock')) - for (const [memberName, member] of Object.entries((lock && lock.members) || {})) { - const repo = typeof member.url === 'string' ? githubRepoFromUrl(member.url) : undefined - if (!repo || !isFirstParty(repo)) continue - if ( - typeof member.ref === 'string' && - isAllowedLegacyMemberRef({ memberName, ref: normalizeRef(member.ref) }) - ) { - continue - } - const expectedRef = expectedRefFor(repo) - const remote = 'https://github.com/' + repo.owner + '/' + repo.repo + '.git' - const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'default-ref-policy-')) - let ok = false - try { - cp.execFileSync('git', ['-C', tmp, 'init', '-q'], { stdio: 'ignore' }) - cp.execFileSync('git', ['-C', tmp, 'remote', 'add', 'origin', remote], { stdio: 'ignore' }) - cp.execFileSync('git', ['-C', tmp, 'fetch', '-q', '--filter=blob:none', 'origin', 'refs/heads/' + expectedRef + ':refs/remotes/origin/' + expectedRef], { stdio: 'ignore' }) - cp.execFileSync('git', ['-C', tmp, 'cat-file', '-e', member.commit + '^{commit}'], { stdio: 'ignore' }) - cp.execFileSync('git', ['-C', tmp, 'merge-base', '--is-ancestor', member.commit, 'refs/remotes/origin/' + expectedRef], { stdio: 'ignore' }) - ok = true - } catch { - ok = false - } finally { - fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }) - } - if (!ok) { - violations.push({ type: 'reachability', file: 'megarepo.lock', repo: repoKey(repo), rev: member.commit, expectedRef, memberName }) - } - } -} - -if (violations.length === 0) { - console.log('Default ref policy OK') - process.exit(0) -} - -console.error('Default ref policy failed:') -for (const violation of violations) { - if (violation.type === 'reachability') { - console.error(' - ' + violation.file + ': member ' + violation.memberName + ' ' + violation.repo + ' locks ' + violation.rev.slice(0, 12) + " outside '" + violation.expectedRef + "'") - } else { - const name = violation.memberName ? ' member ' + violation.memberName : violation.inputName ? ' input ' + violation.inputName : '' - console.error(' - ' + violation.file + ':' + name + ' ' + violation.repo + " uses ref '" + violation.ref + "' in " + violation.field + "; expected '" + violation.expectedRef + "'") - } -} -console.error('') -console.error('Fix: merge upstream PRs first, retarget first-party inputs back to their default refs, then refresh locks.') -process.exit(1)` - -/** Fail when first-party megarepo/flake/devenv inputs target non-default refs. */ +/** Fail before composition when first-party megarepo/flake/devenv inputs target non-default refs. */ export const defaultRefPolicyCheckStep = (opts: DefaultRefPolicyCheckStepOptions = {}) => ({ name: 'Check first-party default refs', env: { diff --git a/genie/ci.ts b/genie/ci.ts index 037d2722c1..7b09e3ca5e 100644 --- a/genie/ci.ts +++ b/genie/ci.ts @@ -16,17 +16,14 @@ export type RunnerProfile = (typeof RUNNER_PROFILES)[number] /** Core CI job keys used for the typed product-job block in the workflow generator. */ export const CORE_CI_JOB_NAMES = [ - // Split typecheck authority: `buck2:check` for Buck-authoritative packages, `ts:check:strict` - // for the residual root TypeScript solution. This lane runs both, so there is no separate - // `buck2` lane — `buck2:check` would otherwise be paid twice on independent runners. + // Buck owns every TypeScript project and declaration producer. Keep it in the existing + // typecheck lane rather than paying for the same complete authority surface twice. 'typecheck', 'lint', 'test', 'test-playwright-utils', 'test-playwright-tui-react', 'test-megarepo-cold-gc', - 'nix-check', - 'nix-fod-check', 'pnpm-builder-contract', 'pnpm-regression', 'bundle-smoke', @@ -100,7 +97,7 @@ export const REQUIRED_CI_JOB_NAMES = [ ...EXTRA_CI_JOB_NAMES, ] as const satisfies readonly CIJobName[] -const matrixCIJobNames = ['test', 'nix-check', 'nix-fod-check'] as const +const matrixCIJobNames = ['test'] as const /** GitHub status-check context names emitted by a workflow job key. */ export const ciJobCheckContexts = (jobName: CIJobName) => { diff --git a/genie/external.ts b/genie/external.ts index 93252e8253..f8b56ab98b 100644 --- a/genie/external.ts +++ b/genie/external.ts @@ -797,9 +797,8 @@ export const createPatchPostinstall = (args: { basePath: string }) => { * `false`. This switch is the gate: both fields are `true`, so Effect warnings * AND suggestions fail the build exit code (errors always gate regardless). * - * The gate runs through the existing `tsgo --build` over the project graph — no - * extra compiler pass — so it is enforced by `ts:check` / `ts:check:strict` - * (hence `devenv tasks run check:quick` / `devenv tasks run check:all` and the CI `typecheck` lane). + * The gate runs inside every Buck `tsgo_typecheck` target, so `buck2:check` + * enforces it across all 39 projects and the CI `typecheck` lane. * * This is the SHARED base consumed by peer repos: enabling it gates Effect * diagnostics fleet-wide. A repo that is not yet clean can locally override its diff --git a/genie/packages.ts b/genie/packages.ts index 9fb412865d..f1ba7f868d 100644 --- a/genie/packages.ts +++ b/genie/packages.ts @@ -45,6 +45,20 @@ export const internalPackages = [ 'ci-tools', ] as const +/** + * Every pnpm workspace member path, including private packages and non-`@overeng` + * context packages. Keep package-set consumers on this pure registry rather than + * importing package generators, whose values are needed only to render manifests. + */ +export const pnpmWorkspaceMemberPaths = [ + 'context/effect/socket', + 'packages/@overeng/effect-rpc-tanstack/examples/basic', + 'context/opentui', + ...internalPackages.map((name) => `packages/@overeng/${name}` as const), + 'packages/@overeng/npm-release', + 'packages/@overeng/stylex-tokens', +].toSorted() + /** Short name of an internal @overeng/* package. */ export type InternalPackageName = (typeof internalPackages)[number] diff --git a/genie/tsconfig-projects.ts b/genie/tsconfig-projects.ts index 798f7ec9a4..4bffbfddf4 100644 --- a/genie/tsconfig-projects.ts +++ b/genie/tsconfig-projects.ts @@ -41,76 +41,63 @@ import tuiReactTsconfig from '../packages/@overeng/tui-react/tsconfig.json.genie import tuiStoriesTsconfig from '../packages/@overeng/tui-stories/tsconfig.json.genie.ts' import utilsDevTsconfig from '../packages/@overeng/utils-dev/tsconfig.json.genie.ts' import utilsTsconfig from '../packages/@overeng/utils/tsconfig.json.genie.ts' -import { authoritativeBuck2TypeScriptAdmissions } from './buck2/typescript-admissions.ts' +import { authoritativeBuck2TypeScriptProjects } from './buck2/typescript-admissions.ts' -/** The Buck targets that own one root TypeScript project's checking and declarations. */ +/** Buck targets that own one root TypeScript project's checking and optional declarations. */ export type Buck2TypeScriptAuthority = { readonly _tag: 'Buck2TypeScriptAuthority' - readonly typecheckTarget: `//${string}:typecheck` - readonly emitTarget: `//${string}:dist` + readonly typecheckTarget: `//${string}:${string}` + readonly emitTarget?: `//${string}:dist` } export type RootTsconfigProject = { readonly path: string readonly tsconfig: GenieOutput - readonly buck2Authority?: Buck2TypeScriptAuthority + readonly buck2Authority: Buck2TypeScriptAuthority } -type RootTsconfigProjectDefinition = Omit +type RootTsconfigProjectDefinition = Pick /** - * Root solution membership is the complement of Buck authority. + * Authority keyed by project path because one package may own multiple projects. * - * A project whose typecheck and declarations a Buck target owns must not also be - * a member of the root `tsc` solution: two producers of the same `dist` race - * each other, and root `tsc` would recheck inputs Buck already gates. The - * remaining projects stay root-owned and read the Buck-owned declarations that - * `buck2:typescript:materialize-dist` publishes, so root checking is ordered - * after that materialization rather than duplicating it. + * The lookup is also the completeness assertion for the lint project graph: + * every registered root project must have exactly one Buck authority. */ -export const isRootTsconfigCheckProject = (project: RootTsconfigProject): boolean => - project.buck2Authority === undefined - -export const isRootTsconfigEmitProject = (project: RootTsconfigProject): boolean => - project.buck2Authority === undefined - -/** - * Authority keyed by the project path this module names, not by package path. - * - * `rootTsconfigProjects` addresses projects, and a package may contribute more - * than one (`react-inspector` contributes its strict-consumer project). Keying - * on the project path lets one lookup serve both project lists without a second - * registry to keep in step with `authoritativeBuck2TypeScriptAdmissions`. - */ -const buck2AuthoritiesByProjectPath: Readonly> = - Object.fromEntries( - authoritativeBuck2TypeScriptAdmissions.map( - ({ - distTarget, - packagePath, - typecheckTarget, - }): readonly [string, Buck2TypeScriptAuthority] => [ - packagePath, - { - _tag: 'Buck2TypeScriptAuthority', - emitTarget: distTarget, - typecheckTarget, - }, - ], - ), - ) +const buck2AuthoritiesByProjectPath: Readonly> = (() => { + const authorities: Record = {} + for (const { + declarationEntrypoint, + packagePath, + projectPath, + typecheckTarget, + } of authoritativeBuck2TypeScriptProjects) { + if (authorities[projectPath] !== undefined) { + throw new Error(`root TypeScript project has multiple Buck authorities: ${projectPath}`) + } + authorities[projectPath] = { + _tag: 'Buck2TypeScriptAuthority', + typecheckTarget, + ...(declarationEntrypoint === undefined + ? {} + : { emitTarget: `//${packagePath}:dist` as const }), + } + } + return authorities +})() const attachBuck2Authority = ({ path, ...definition -}: RootTsconfigProject): RootTsconfigProject => { +}: RootTsconfigProjectDefinition & { readonly path: string }): RootTsconfigProject => { const buck2Authority = buck2AuthoritiesByProjectPath[path] - return buck2Authority === undefined - ? { path, ...definition } - : { path, ...definition, buck2Authority } + if (buck2Authority === undefined) { + throw new Error(`root TypeScript project has no Buck authority: ${path}`) + } + return { path, ...definition, buck2Authority } } -export const rootWorkspaceTsconfigProjects = (() => { +const rootWorkspaceTsconfigProjects = (() => { const workspaceTsconfigsByPath: Record = { 'context/effect/socket': { tsconfig: effectSocketTsconfig }, 'context/opentui': { tsconfig: opentuiTsconfig }, @@ -188,7 +175,7 @@ export const rootWorkspaceTsconfigProjects = (() => { }) })() -export const extraRootTsconfigProjects = [ +const extraRootTsconfigProjects = [ attachBuck2Authority({ path: 'packages/@overeng/react-inspector/tsconfig.strict-consumer.json', tsconfig: reactInspectorStrictConsumerTsconfig, diff --git a/nix/buck2-capabilities.nix b/nix/buck2-capabilities.nix new file mode 100644 index 0000000000..35e9a5249f --- /dev/null +++ b/nix/buck2-capabilities.nix @@ -0,0 +1,41 @@ +{ + pkgs, + src, + capabilityPackages, +}: + +let + manifest = builtins.fromJSON (builtins.readFile (src + "/buck2-member.json")); + executableCapabilities = builtins.filter (capability: !(capability ? _tag)) manifest.capabilities; + authorityCapabilities = builtins.concatMap ( + capability: if capability._tag or null == "ToolchainAuthority" then capability.provides else [ ] + ) manifest.capabilities; + capabilities = builtins.sort (left: right: left.toolId < right.toolId) ( + executableCapabilities ++ authorityCapabilities + ); + projectionInputs = map ( + capability: + let + package = + if builtins.hasAttr capability.flakePackage capabilityPackages then + builtins.getAttr capability.flakePackage capabilityPackages + else + throw "buck2-capabilities: missing flake package ${capability.flakePackage} for ${capability.toolId}"; + closure = pkgs.closureInfo { rootPaths = [ package ]; }; + in + { + inherit capability; + nixOutputPath = package; + closurePathsFile = "${closure}/store-paths"; + } + ) capabilities; + input = pkgs.writeText "buck2-capability-projection-input.json" (builtins.toJSON projectionInputs); + platform = + if pkgs.stdenv.hostPlatform.isDarwin then "aarch64-macos" else pkgs.stdenv.hostPlatform.system; +in +pkgs.runCommand "buck2-capabilities" { nativeBuildInputs = [ pkgs.bun ]; } '' + bun ${src}/packages/@overeng/megarepo/src/composition/capabilities/capability-projection.ts \ + --input ${input} \ + --output "$out" \ + --platform ${platform} +'' diff --git a/nix/buck2-native-products/default.nix b/nix/buck2-native-products/default.nix new file mode 100644 index 0000000000..592bd0e41f --- /dev/null +++ b/nix/buck2-native-products/default.nix @@ -0,0 +1,202 @@ +{ pkgs }: + +let + lib = pkgs.lib; + contract = import ../workspace-tools/lib/buck2-build-product-contract.nix; + importArtifact = import ../workspace-tools/lib/buck2-artifact-import.nix { inherit pkgs; }; + manifest = builtins.fromJSON (builtins.readFile ./manifest.json); + targets = builtins.fromJSON (builtins.readFile ./targets.json); + repositoryReleaseBase = "https://github.com/overengineeringstudio/effect-utils/releases/download"; + ensure = condition: message: if condition then true else throw "buck2-native-products: ${message}"; + platformKey = platform: "${platform.architecture}-${platform.os}-${platform.abi}"; + targetByName = builtins.listToAttrs ( + map (product: { + inherit (product) name; + value = product.target; + }) targets.products + ); + expectedKeys = builtins.concatMap ( + platform: map (product: "${product.name}/${platformKey platform}") targets.products + ) targets.platforms; + platformKeys = map ( + platform: platformKey (builtins.removeAttrs platform [ "system" ]) + ) targets.platforms; + systems = map (platform: platform.system) targets.platforms; + productNames = map (product: product.name) targets.products; + productTargets = map (product: product.target) targets.products; + checkEntry = + entry: + let + descriptor = contract.verifyDescriptor { + inherit (entry) descriptor; + expectedDescriptorDigest = entry.descriptorSha256; + }; + name = descriptor.name; + platform = descriptor.platform; + key = "${name}/${platformKey platform}"; + release = entry.release; + tagMatch = builtins.match ("buck2-native-product-v1-${name}-${platform.os}-${platform.architecture}-${platform.abi}-([0-9a-f]{64})") release.tag; + payloadDigest = if tagMatch == null then "" else builtins.head tagMatch; + checks = [ + (ensure ( + builtins.attrNames entry == [ + "descriptor" + "descriptorSha256" + "release" + ] + ) "${key} manifest fields are not exact") + (ensure (builtins.hasAttr name targetByName) "${key} is not a declared product") + (ensure ( + descriptor.semanticProvenance.target == targetByName.${name} + ) "${key} target does not match the release declaration") + (ensure (builtins.elem platform ( + map (value: builtins.removeAttrs value [ "system" ]) targets.platforms + )) "${key} platform is not admitted") + (ensure ( + builtins.attrNames release == [ + "hash" + "name" + "tag" + "url" + ] + ) "${key} release fields are not exact") + (ensure (tagMatch != null) "${key} release tag is not content-addressed") + (ensure ( + release.name + == "${payloadDigest}-${name}-${platform.os}-${platform.architecture}-${platform.abi}.tar" + ) "${key} release asset name does not match its tag") + (ensure ( + release.url == "${repositoryReleaseBase}/${release.tag}/${release.name}" + ) "${key} release URL does not match its immutable tag and asset") + (ensure ( + release.hash == descriptor.payload.digest.sri + ) "${key} release hash does not match the descriptor payload") + ]; + in + builtins.deepSeq checks { + inherit (entry) descriptorSha256; + inherit + descriptor + key + platform + release + ; + }; + checkedEntries = map checkEntry manifest.products; + actualKeys = map (entry: entry.key) checkedEntries; + entryByKey = builtins.listToAttrs ( + map (entry: { + name = entry.key; + value = entry; + }) checkedEntries + ); + currentPlatform = lib.findFirst ( + platform: platform.system == pkgs.stdenv.hostPlatform.system + ) null targets.platforms; + productsForPlatform = + platform: + let + key = platformKey (builtins.removeAttrs platform [ "system" ]); + in + builtins.listToAttrs ( + map ( + declaration: + let + entry = entryByKey."${declaration.name}/${key}"; + in + { + inherit (declaration) name; + value = importArtifact { + descriptor = entry.descriptor; + expectedDescriptorDigest = entry.descriptorSha256; + expectedPlatform = entry.platform; + url = entry.release.url; + }; + } + ) targets.products + ); + productsBySystem = builtins.listToAttrs ( + map (platform: { + name = platform.system; + value = productsForPlatform platform; + }) targets.platforms + ); + products = if currentPlatform == null then { } else productsBySystem.${currentPlatform.system}; + topChecks = [ + (ensure ( + builtins.attrNames manifest == [ + "products" + "schema" + ] + ) "manifest fields are not exact") + (ensure ( + builtins.attrNames targets == [ + "platforms" + "products" + "schema" + ] + ) "target inventory fields are not exact") + (ensure ( + manifest.schema == "effect-utils/buck2-native-release-products/v1" + ) "unsupported manifest schema") + (ensure ( + targets.schema == "effect-utils/buck2-native-release-targets/v1" + ) "unsupported target schema") + (ensure (builtins.all ( + platform: + builtins.attrNames platform == [ + "abi" + "architecture" + "os" + "system" + ] + && builtins.all builtins.isString [ + platform.abi + platform.architecture + platform.os + platform.system + ] + ) targets.platforms) "target platforms are malformed") + (ensure (builtins.all ( + product: + builtins.attrNames product == [ + "name" + "target" + ] + && builtins.isString product.name + && builtins.match "^[A-Za-z0-9][A-Za-z0-9._+-]*$" product.name != null + && builtins.isString product.target + && builtins.match "^([A-Za-z0-9_]+)?//.+:.+$" product.target != null + && builtins.match ".*[[:space:]\\[\\]].*" product.target == null + ) targets.products) "target products are malformed") + (ensure ( + builtins.length platformKeys == builtins.length (lib.unique platformKeys) + ) "target platforms contain duplicate native tuples") + (ensure ( + builtins.length systems == builtins.length (lib.unique systems) + ) "target platforms contain duplicate Nix systems") + (ensure ( + builtins.length productNames == builtins.length (lib.unique productNames) + ) "target products contain duplicate names") + (ensure ( + builtins.length productTargets == builtins.length (lib.unique productTargets) + ) "target products contain duplicate labels") + (ensure ( + builtins.length actualKeys == builtins.length expectedKeys + ) "manifest matrix has the wrong size") + (ensure ( + builtins.length actualKeys == builtins.length (lib.unique actualKeys) + ) "manifest matrix contains duplicates") + (ensure ( + lib.sort builtins.lessThan actualKeys == lib.sort builtins.lessThan expectedKeys + ) "manifest does not exactly cover the declared product matrix") + ]; +in +builtins.deepSeq topChecks { + inherit + manifest + products + productsBySystem + targets + ; +} diff --git a/nix/buck2-native-products/manifest.json b/nix/buck2-native-products/manifest.json new file mode 100644 index 0000000000..77933e0b24 --- /dev/null +++ b/nix/buck2-native-products/manifest.json @@ -0,0 +1,505 @@ +{ + "products": [ + { + "descriptor": { + "entrypoints": [ + "bin/otel-scrape" + ], + "name": "otel-scrape", + "payload": { + "digest": { + "algorithm": "sha256", + "sri": "sha256-HZLblFFYtQVPxm+xGQbKHMGiW3cSCDdmRFr3Ag+hKtU=" + }, + "file": "artifact.tar", + "format": "tar", + "sizeBytes": 3197952 + }, + "platform": { + "abi": "darwin", + "architecture": "aarch64", + "os": "darwin" + }, + "runtime": { + "architecture": "arm64", + "dylibs": [ + "/usr/lib/libSystem.B.dylib", + "/usr/lib/libiconv.2.dylib" + ], + "inspectionContract": "mach-o-dynamic/v1", + "installNamePolicy": "system-only/v1", + "kind": "mach-o-dynamic", + "minimumOs": "15.0", + "rpathPolicy": "empty/v1", + "signingPolicy": "adhoc/v1" + }, + "schema": "buck-build-product/v1", + "semanticProvenance": { + "recipe": "cargo-workspace:otel-scrape@0.0.0", + "target": "effect_utils//packages/@overeng/otel-scrape:otel-scrape-product", + "toolchain": "contract=effect-utils/buck2-rust-toolchain/v1;execution_platform=aarch64-macos;target_platform=//buck2/platforms:macos_aarch64;target_triple=aarch64-apple-darwin;rust-archiver=/nix/store/0hkgh95m01v2r58ihyjcb1c9xqpmszan-ar:cc24b301950403b4073f8af51cf7478d7a3b2cd8669129f07b8b4c99a04a9ce2;rust-c-compiler=/nix/store/v50fkq20w63wbciqlb7pv0gda2prd4dq-cc:9653de299fcb51919657a930c78fa368b34cc463a270dedea171e0ade4af4911;rust-dwp=/nix/store/nszs1bddpcxmjyrpm7zc6gg0fxx1w6fz-dwp:5686d95accfd29e4df352f5c95fb21f67361737dc46e5def2594571f21cf55f2;rust-clippy-driver=/nix/store/wpgsb4yh7y3qj2yf1a891azsnfl69pvm-clippy-driver:a4e180ad69aeaea1dc47ba9bf3d91bd345d92a4b72a907a425e6b6162e681898;rust-compiler=/nix/store/7lv5rg7ipf0inlm3y8zvbp4rpwj9m7va-rustc:92794ef4ee732c38e4f18ba1c65127156591363e55abc0a5c8eae492df926f85;rust-cxx-compiler=/nix/store/vvliica9vnwczdb00j984yzv62m8j1cy-c++:acfebf80f5615a5db676e413f53f46fce26f4cf3f2c0c3941992c132b81cc6be;rust-linker=/nix/store/vvliica9vnwczdb00j984yzv62m8j1cy-c++:acfebf80f5615a5db676e413f53f46fce26f4cf3f2c0c3941992c132b81cc6be;rust-rustdoc=/nix/store/vqsn9q8c0v6r8navwrayyi7lr0n8j3cf-rustdoc:6ad6d067abb26c08b5cbe1225a54ab7dac2f8e6642b701034a780f77ebd99fbb;rust-nm=/nix/store/v76i0jncav3i5kiwwg4jz32lq6xb9k7x-nm:a20d5d0c9c81e0f7a7ce96ebaffd35f92a786a8e25e1d0e0416ae579e3510f4e;rust-objcopy=/nix/store/js9zdv0n6wx36mfxa7bf6f4s84kmgmql-objcopy:fc4529d3b99dee3bdc108a7766f5897b2f4cca2f9bfe0bdd45e4ae710d175ab4;rust-objdump=/nix/store/v9n6wgpz098jhw1scc6f972677ai5qw2-objdump:e671abee5dbcaad756d818e8d3d532ba7b3e815e7be65c2098760f4a59019599;rust-ranlib=/nix/store/3b61qrg8l0whl4m0c1mphigq9739qa3f-ranlib:e05990426b541a428d6c12a7e532747f8a1ae3ca25c344004e27b698ca88e0f0;rust-strip=/nix/store/9jp016rpjlwivkg9i7dlwasylpfr4rzw-strip:81a72c6ca46f841cae9739b4468e0dc2f581da7e156155692a060e54a651a5d6;rust-shell=/nix/store/401wfz3g4kmjhi96qq29qbqz4143bwdq-bash-interactive-5.3p15:f055535c334166f2f9c843ec9702bbbc78649a5c8ad6bd7f580ba0f2f0cda4c8" + } + }, + "descriptorSha256": "sha256:fa8edc2f096d35e34a8d6a20ce45b5a21b6e31ad14b9fb57a3a845827fcb4675", + "release": { + "hash": "sha256-HZLblFFYtQVPxm+xGQbKHMGiW3cSCDdmRFr3Ag+hKtU=", + "name": "1d92db945158b5054fc66fb11906ca1cc1a25b7712083766445af7020fa12ad5-otel-scrape-darwin-aarch64-darwin.tar", + "tag": "buck2-native-product-v1-otel-scrape-darwin-aarch64-darwin-1d92db945158b5054fc66fb11906ca1cc1a25b7712083766445af7020fa12ad5", + "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-native-product-v1-otel-scrape-darwin-aarch64-darwin-1d92db945158b5054fc66fb11906ca1cc1a25b7712083766445af7020fa12ad5/1d92db945158b5054fc66fb11906ca1cc1a25b7712083766445af7020fa12ad5-otel-scrape-darwin-aarch64-darwin.tar" + } + }, + { + "descriptor": { + "entrypoints": [ + "bin/otel-scrape" + ], + "name": "otel-scrape", + "payload": { + "digest": { + "algorithm": "sha256", + "sri": "sha256-uhLWWxvsWJmM3P3GJaSRM4hWF3S/QBvgZfbPjDa8N9M=" + }, + "file": "artifact.tar", + "format": "tar", + "sizeBytes": 3346432 + }, + "platform": { + "abi": "glibc", + "architecture": "aarch64", + "os": "linux" + }, + "runtime": { + "elfClass": "ELF64", + "inspectionContract": "elf-dynamic/v1", + "interpreter": "/lib/ld-linux-aarch64.so.1", + "kind": "elf-dynamic", + "machine": "aarch64", + "neededLibraries": [ + "ld-linux-aarch64.so.1", + "libc.so.6", + "libgcc_s.so.1" + ], + "rpathPolicy": "empty/v1", + "symbolVersionFloors": [ + "GCC_3.0", + "GCC_3.3", + "GCC_4.2.0", + "GLIBC_2.17", + "GLIBC_2.18", + "GLIBC_2.25", + "GLIBC_2.28", + "GLIBC_2.29", + "GLIBC_2.30", + "GLIBC_2.32", + "GLIBC_2.33", + "GLIBC_2.34", + "GLIBC_2.39" + ] + }, + "schema": "buck-build-product/v1", + "semanticProvenance": { + "recipe": "cargo-workspace:otel-scrape@0.0.0", + "target": "effect_utils//packages/@overeng/otel-scrape:otel-scrape-product", + "toolchain": "contract=effect-utils/buck2-rust-toolchain/v1;execution_platform=aarch64-linux;target_platform=//buck2/platforms:linux_aarch64;target_triple=aarch64-unknown-linux-gnu;rust-archiver=/nix/store/ywcfnjg8yrm1kvdpnvzswaiwagjyzfyi-ar:52a8164487ad78b2e50595f924432d95383a774cd029a707c09afa308a8414cc;rust-c-compiler=/nix/store/90wgh551c50129idqw8rcbhg30fbkmfd-cc:32e2e11cb267ca46c5130040d750ef5b88bb524dfd0d3da6828ad77a3f8d71d0;rust-dwp=/nix/store/x9h8lnq4jdm9vryamh33vxzba7c70w2q-dwp:ee23610df0e166d7016cac8aea2af5c0966ecfe662edb6980e904b44eda3c47b;rust-clippy-driver=/nix/store/q832j2j7wxb1a8w57w1frs1ivgp0v5qk-clippy-driver:d0cc6eb9f5810e8c8374da1f8343969638f9c7ebbd2ade6f8dd62c6d2aadb576;rust-compiler=/nix/store/vafz21y36qjarcgq6q2r7md3w5mzcyx2-rustc:f5ec8efd6a76ded37fb287df5fc666937e0ef629f1f588e9f425287eab93ff52;rust-cxx-compiler=/nix/store/7wwzzggdgl9m6khd3y3x1c8wqmxy4ifr-c++:fe5d5908fa4fb19bc7e2dac68579431c510921126c6865a3c381ef90eb417c34;rust-linker=/nix/store/7wwzzggdgl9m6khd3y3x1c8wqmxy4ifr-c++:fe5d5908fa4fb19bc7e2dac68579431c510921126c6865a3c381ef90eb417c34;rust-rustdoc=/nix/store/k7wjw07l4rl2jbdw9160ba9cl04scmxh-rustdoc:f3a2a2607aaa2dbfdcb5f2942a148df76bbea36ffabf0f22bd0c7346f221c64f;rust-nm=/nix/store/j2jm7yzby4x0yrry4vwhcp90z0161q1z-nm:54e6d6c83a50e344a34072ddaf4523a5560370c896cdc5efb34b7714b8be3b1a;rust-objcopy=/nix/store/maxzixxf6kwic6ppg0xmgar1can0gy6h-objcopy:160548eeecfb57bdf6fa98db34e7560b8ca4bc105d3ff7cc405caf8f80194c40;rust-objdump=/nix/store/9026lv5vp3z5vn1cp2kf2kpxndmfdblz-objdump:0564ecf687df5aeeff13a31ee79bb6f66a20632c0c7ec7b0be670f0d8a7a2145;rust-ranlib=/nix/store/05d43zybdh9qmsizc653c2y2npfy46d7-ranlib:e2bb73aa022dd0297ec97c4d3fb06e3c72c81d1b2d787ae9533f316e461367c2;rust-strip=/nix/store/9lrkvk74cz5l37xk3axksdlkm7gph6kg-strip:60477c9a7bb2fdb95afe0d79106189484140c286415f81aab480d21c9a45aa89;rust-shell=/nix/store/dgm1mdazv3xkhbmphwv4dwci0bqzs7rp-bash:69f62cbb488003a4023606cab697f52ab5ec14ae20f53aeab30990eea856f423" + } + }, + "descriptorSha256": "sha256:b21cb66a77e47aade75a89196602e475012dbbcd8ef4682a3ace14d2763253c1", + "release": { + "hash": "sha256-uhLWWxvsWJmM3P3GJaSRM4hWF3S/QBvgZfbPjDa8N9M=", + "name": "ba12d65b1bec58998cdcfdc625a4913388561774bf401be065f6cf8c36bc37d3-otel-scrape-linux-aarch64-glibc.tar", + "tag": "buck2-native-product-v1-otel-scrape-linux-aarch64-glibc-ba12d65b1bec58998cdcfdc625a4913388561774bf401be065f6cf8c36bc37d3", + "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-native-product-v1-otel-scrape-linux-aarch64-glibc-ba12d65b1bec58998cdcfdc625a4913388561774bf401be065f6cf8c36bc37d3/ba12d65b1bec58998cdcfdc625a4913388561774bf401be065f6cf8c36bc37d3-otel-scrape-linux-aarch64-glibc.tar" + } + }, + { + "descriptor": { + "entrypoints": [ + "bin/otel-scrape" + ], + "name": "otel-scrape", + "payload": { + "digest": { + "algorithm": "sha256", + "sri": "sha256-B/j+haO2aWA3OxxvP2Wo3zIzclUfhYFEwa/9NGNGjKM=" + }, + "file": "artifact.tar", + "format": "tar", + "sizeBytes": 3288064 + }, + "platform": { + "abi": "glibc", + "architecture": "x86_64", + "os": "linux" + }, + "runtime": { + "elfClass": "ELF64", + "inspectionContract": "elf-dynamic/v1", + "interpreter": "/lib64/ld-linux-x86-64.so.2", + "kind": "elf-dynamic", + "machine": "x86_64", + "neededLibraries": [ + "ld-linux-x86-64.so.2", + "libc.so.6", + "libgcc_s.so.1" + ], + "rpathPolicy": "empty/v1", + "symbolVersionFloors": [ + "GCC_3.0", + "GCC_3.3", + "GCC_4.2.0", + "GLIBC_2.14", + "GLIBC_2.15", + "GLIBC_2.16", + "GLIBC_2.17", + "GLIBC_2.18", + "GLIBC_2.2.5", + "GLIBC_2.25", + "GLIBC_2.28", + "GLIBC_2.29", + "GLIBC_2.3", + "GLIBC_2.3.4", + "GLIBC_2.30", + "GLIBC_2.32", + "GLIBC_2.33", + "GLIBC_2.34", + "GLIBC_2.39", + "GLIBC_2.4", + "GLIBC_2.9" + ] + }, + "schema": "buck-build-product/v1", + "semanticProvenance": { + "recipe": "cargo-workspace:otel-scrape@0.0.0", + "target": "effect_utils//packages/@overeng/otel-scrape:otel-scrape-product", + "toolchain": "contract=effect-utils/buck2-rust-toolchain/v1;execution_platform=x86_64-linux;target_platform=//buck2/platforms:linux_x86_64;target_triple=x86_64-unknown-linux-gnu;rust-archiver=/nix/store/bj1mfdd968knmbl0rcyr35pqjsh78gaq-ar:8ddb61934a99ba087deeea1765e9da0b84ad065121031f469f7bd8ae06621b0a;rust-c-compiler=/nix/store/ndad9i5wnxxrsisb208c1k79dvyvnw2f-cc:ea5cdeff444fa8758c3f54a1ebf9146ecc74745f89b7f1ba532e098ee74838d0;rust-dwp=/nix/store/8v6vlmbjglbv01zasqziwhmypq8iam33-dwp:35dacff2c48037a73807d190fe985c77e3ebc70ba20a4d56d784777b474b28ed;rust-clippy-driver=/nix/store/1x3h3g3lqz79bwb0xz0p7gq80dvjjlsq-clippy-driver:dd0052080a387712d03e59d9cc2369ec8441544a88fd5cb64bd1e6cb9bcf79de;rust-compiler=/nix/store/vk2bw22y8xrpfsqphcmb9v6vwh7085fi-rustc:5670b4ef087187b199a2d9e1c753c1d252e285e7c7225983c5694bd4405f11a7;rust-cxx-compiler=/nix/store/05ifm3sda8qgd534ff188k3zr7399csa-c++:729198fda42f53137ff7c8243c9807b4b8a90fa13e45ce9e5b54552b9e8b4b6a;rust-linker=/nix/store/05ifm3sda8qgd534ff188k3zr7399csa-c++:729198fda42f53137ff7c8243c9807b4b8a90fa13e45ce9e5b54552b9e8b4b6a;rust-rustdoc=/nix/store/0n51s93xixi22ff0g84qf3g1wr2khkcg-rustdoc:395989c0eda19224fff6a4c92a14047c0bacea85803701882ea166b600dc6eca;rust-nm=/nix/store/n0hhhcwc5b3nib41yfpfkappc29x6gx2-nm:4cf271ac874ec9aac9e6674cde28c0b62551a8d01935d808578e942ac2c8a858;rust-objcopy=/nix/store/azd96w4p3v2jzgz0npzdsnlwhscjcvp3-objcopy:3c5c30d6472ccdefcdedbb7883e4041c25fac3ba3f63997d8cc6ff2918c696bb;rust-objdump=/nix/store/blrn7bk4n3hq3b52128p2shcqkdynidx-objdump:d1dee52c9cfdd15ecf00c9647e6c138b155edb4a5117af9ca495f08268fcd9c0;rust-ranlib=/nix/store/fjvfmsym9h9kfh92q6fsiw255fpj1i3w-ranlib:8c2ada015ae830eacfc56cdf890e7f9d6ab982251f8da5bf75a037e6d731958c;rust-strip=/nix/store/vyn08yg3xavyw5jxkvk7y627nprfyz5d-strip:a24d4704f9a8731d0575f8a51bbe74d6cb73a2d3694d9be87d8aa7c613ff9ea0;rust-shell=/nix/store/75b5c1abflninf1dfd57qaxrxihi4030-bash:94c557aa408ebbc50a044a53cbe5fc3878637e257d58fc6e2db370dc2594e515" + } + }, + "descriptorSha256": "sha256:b6a9a1d901b7f550ee71727c23ea0dd28a8de435315082715426c2a165f6b99d", + "release": { + "hash": "sha256-B/j+haO2aWA3OxxvP2Wo3zIzclUfhYFEwa/9NGNGjKM=", + "name": "07f8fe85a3b66960373b1c6f3f65a8df323372551f858144c1affd3463468ca3-otel-scrape-linux-x86_64-glibc.tar", + "tag": "buck2-native-product-v1-otel-scrape-linux-x86_64-glibc-07f8fe85a3b66960373b1c6f3f65a8df323372551f858144c1affd3463468ca3", + "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-native-product-v1-otel-scrape-linux-x86_64-glibc-07f8fe85a3b66960373b1c6f3f65a8df323372551f858144c1affd3463468ca3/07f8fe85a3b66960373b1c6f3f65a8df323372551f858144c1affd3463468ca3-otel-scrape-linux-x86_64-glibc.tar" + } + }, + { + "descriptor": { + "entrypoints": [ + "bin/otelite" + ], + "name": "otelite", + "payload": { + "digest": { + "algorithm": "sha256", + "sri": "sha256-PYScmoG+DGBRixBn8/W3GPtvueTmsknYsWrgOzJF+JY=" + }, + "file": "artifact.tar", + "format": "tar", + "sizeBytes": 19759104 + }, + "platform": { + "abi": "darwin", + "architecture": "aarch64", + "os": "darwin" + }, + "runtime": { + "architecture": "arm64", + "dylibs": [ + "/usr/lib/libSystem.B.dylib", + "/usr/lib/libiconv.2.dylib" + ], + "inspectionContract": "mach-o-dynamic/v1", + "installNamePolicy": "system-only/v1", + "kind": "mach-o-dynamic", + "minimumOs": "15.0", + "rpathPolicy": "empty/v1", + "signingPolicy": "adhoc/v1" + }, + "schema": "buck-build-product/v1", + "semanticProvenance": { + "recipe": "cargo-workspace:otelite@0.0.0", + "target": "effect_utils//packages/@overeng/otelite:otelite-product", + "toolchain": "contract=effect-utils/buck2-rust-toolchain/v1;execution_platform=aarch64-macos;target_platform=//buck2/platforms:macos_aarch64;target_triple=aarch64-apple-darwin;rust-archiver=/nix/store/0hkgh95m01v2r58ihyjcb1c9xqpmszan-ar:cc24b301950403b4073f8af51cf7478d7a3b2cd8669129f07b8b4c99a04a9ce2;rust-c-compiler=/nix/store/v50fkq20w63wbciqlb7pv0gda2prd4dq-cc:9653de299fcb51919657a930c78fa368b34cc463a270dedea171e0ade4af4911;rust-dwp=/nix/store/nszs1bddpcxmjyrpm7zc6gg0fxx1w6fz-dwp:5686d95accfd29e4df352f5c95fb21f67361737dc46e5def2594571f21cf55f2;rust-clippy-driver=/nix/store/wpgsb4yh7y3qj2yf1a891azsnfl69pvm-clippy-driver:a4e180ad69aeaea1dc47ba9bf3d91bd345d92a4b72a907a425e6b6162e681898;rust-compiler=/nix/store/7lv5rg7ipf0inlm3y8zvbp4rpwj9m7va-rustc:92794ef4ee732c38e4f18ba1c65127156591363e55abc0a5c8eae492df926f85;rust-cxx-compiler=/nix/store/vvliica9vnwczdb00j984yzv62m8j1cy-c++:acfebf80f5615a5db676e413f53f46fce26f4cf3f2c0c3941992c132b81cc6be;rust-linker=/nix/store/vvliica9vnwczdb00j984yzv62m8j1cy-c++:acfebf80f5615a5db676e413f53f46fce26f4cf3f2c0c3941992c132b81cc6be;rust-rustdoc=/nix/store/vqsn9q8c0v6r8navwrayyi7lr0n8j3cf-rustdoc:6ad6d067abb26c08b5cbe1225a54ab7dac2f8e6642b701034a780f77ebd99fbb;rust-nm=/nix/store/v76i0jncav3i5kiwwg4jz32lq6xb9k7x-nm:a20d5d0c9c81e0f7a7ce96ebaffd35f92a786a8e25e1d0e0416ae579e3510f4e;rust-objcopy=/nix/store/js9zdv0n6wx36mfxa7bf6f4s84kmgmql-objcopy:fc4529d3b99dee3bdc108a7766f5897b2f4cca2f9bfe0bdd45e4ae710d175ab4;rust-objdump=/nix/store/v9n6wgpz098jhw1scc6f972677ai5qw2-objdump:e671abee5dbcaad756d818e8d3d532ba7b3e815e7be65c2098760f4a59019599;rust-ranlib=/nix/store/3b61qrg8l0whl4m0c1mphigq9739qa3f-ranlib:e05990426b541a428d6c12a7e532747f8a1ae3ca25c344004e27b698ca88e0f0;rust-strip=/nix/store/9jp016rpjlwivkg9i7dlwasylpfr4rzw-strip:81a72c6ca46f841cae9739b4468e0dc2f581da7e156155692a060e54a651a5d6;rust-shell=/nix/store/401wfz3g4kmjhi96qq29qbqz4143bwdq-bash-interactive-5.3p15:f055535c334166f2f9c843ec9702bbbc78649a5c8ad6bd7f580ba0f2f0cda4c8" + } + }, + "descriptorSha256": "sha256:5889e571704e047f8944afde7144d637665a2cc243a1277120ea754106e82c49", + "release": { + "hash": "sha256-PYScmoG+DGBRixBn8/W3GPtvueTmsknYsWrgOzJF+JY=", + "name": "3d849c9a81be0c60518b1067f3f5b718fb6fb9e4e6b249d8b16ae03b3245f896-otelite-darwin-aarch64-darwin.tar", + "tag": "buck2-native-product-v1-otelite-darwin-aarch64-darwin-3d849c9a81be0c60518b1067f3f5b718fb6fb9e4e6b249d8b16ae03b3245f896", + "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-native-product-v1-otelite-darwin-aarch64-darwin-3d849c9a81be0c60518b1067f3f5b718fb6fb9e4e6b249d8b16ae03b3245f896/3d849c9a81be0c60518b1067f3f5b718fb6fb9e4e6b249d8b16ae03b3245f896-otelite-darwin-aarch64-darwin.tar" + } + }, + { + "descriptor": { + "entrypoints": [ + "bin/otelite" + ], + "name": "otelite", + "payload": { + "digest": { + "algorithm": "sha256", + "sri": "sha256-6x/YfI+mj117UsUXjbv9x06biFb7T4mv+/YC6xE8G2U=" + }, + "file": "artifact.tar", + "format": "tar", + "sizeBytes": 17944064 + }, + "platform": { + "abi": "glibc", + "architecture": "aarch64", + "os": "linux" + }, + "runtime": { + "elfClass": "ELF64", + "inspectionContract": "elf-dynamic/v1", + "interpreter": "/lib/ld-linux-aarch64.so.1", + "kind": "elf-dynamic", + "machine": "aarch64", + "neededLibraries": [ + "ld-linux-aarch64.so.1", + "libc.so.6", + "libgcc_s.so.1", + "libm.so.6" + ], + "rpathPolicy": "empty/v1", + "symbolVersionFloors": [ + "GCC_3.0", + "GCC_3.3", + "GCC_4.2.0", + "GLIBC_2.17", + "GLIBC_2.18", + "GLIBC_2.25", + "GLIBC_2.28", + "GLIBC_2.29", + "GLIBC_2.30", + "GLIBC_2.32", + "GLIBC_2.33", + "GLIBC_2.34", + "GLIBC_2.39" + ] + }, + "schema": "buck-build-product/v1", + "semanticProvenance": { + "recipe": "cargo-workspace:otelite@0.0.0", + "target": "effect_utils//packages/@overeng/otelite:otelite-product", + "toolchain": "contract=effect-utils/buck2-rust-toolchain/v1;execution_platform=aarch64-linux;target_platform=//buck2/platforms:linux_aarch64;target_triple=aarch64-unknown-linux-gnu;rust-archiver=/nix/store/ywcfnjg8yrm1kvdpnvzswaiwagjyzfyi-ar:52a8164487ad78b2e50595f924432d95383a774cd029a707c09afa308a8414cc;rust-c-compiler=/nix/store/90wgh551c50129idqw8rcbhg30fbkmfd-cc:32e2e11cb267ca46c5130040d750ef5b88bb524dfd0d3da6828ad77a3f8d71d0;rust-dwp=/nix/store/x9h8lnq4jdm9vryamh33vxzba7c70w2q-dwp:ee23610df0e166d7016cac8aea2af5c0966ecfe662edb6980e904b44eda3c47b;rust-clippy-driver=/nix/store/q832j2j7wxb1a8w57w1frs1ivgp0v5qk-clippy-driver:d0cc6eb9f5810e8c8374da1f8343969638f9c7ebbd2ade6f8dd62c6d2aadb576;rust-compiler=/nix/store/vafz21y36qjarcgq6q2r7md3w5mzcyx2-rustc:f5ec8efd6a76ded37fb287df5fc666937e0ef629f1f588e9f425287eab93ff52;rust-cxx-compiler=/nix/store/7wwzzggdgl9m6khd3y3x1c8wqmxy4ifr-c++:fe5d5908fa4fb19bc7e2dac68579431c510921126c6865a3c381ef90eb417c34;rust-linker=/nix/store/7wwzzggdgl9m6khd3y3x1c8wqmxy4ifr-c++:fe5d5908fa4fb19bc7e2dac68579431c510921126c6865a3c381ef90eb417c34;rust-rustdoc=/nix/store/k7wjw07l4rl2jbdw9160ba9cl04scmxh-rustdoc:f3a2a2607aaa2dbfdcb5f2942a148df76bbea36ffabf0f22bd0c7346f221c64f;rust-nm=/nix/store/j2jm7yzby4x0yrry4vwhcp90z0161q1z-nm:54e6d6c83a50e344a34072ddaf4523a5560370c896cdc5efb34b7714b8be3b1a;rust-objcopy=/nix/store/maxzixxf6kwic6ppg0xmgar1can0gy6h-objcopy:160548eeecfb57bdf6fa98db34e7560b8ca4bc105d3ff7cc405caf8f80194c40;rust-objdump=/nix/store/9026lv5vp3z5vn1cp2kf2kpxndmfdblz-objdump:0564ecf687df5aeeff13a31ee79bb6f66a20632c0c7ec7b0be670f0d8a7a2145;rust-ranlib=/nix/store/05d43zybdh9qmsizc653c2y2npfy46d7-ranlib:e2bb73aa022dd0297ec97c4d3fb06e3c72c81d1b2d787ae9533f316e461367c2;rust-strip=/nix/store/9lrkvk74cz5l37xk3axksdlkm7gph6kg-strip:60477c9a7bb2fdb95afe0d79106189484140c286415f81aab480d21c9a45aa89;rust-shell=/nix/store/dgm1mdazv3xkhbmphwv4dwci0bqzs7rp-bash:69f62cbb488003a4023606cab697f52ab5ec14ae20f53aeab30990eea856f423" + } + }, + "descriptorSha256": "sha256:4bbcecf521771ae2fac3b01fdcfd92e53773869c6819ca23926373e6116f2aa3", + "release": { + "hash": "sha256-6x/YfI+mj117UsUXjbv9x06biFb7T4mv+/YC6xE8G2U=", + "name": "eb1fd87c8fa68f5d7b52c5178dbbfdc74e9b8856fb4f89affbf602eb113c1b65-otelite-linux-aarch64-glibc.tar", + "tag": "buck2-native-product-v1-otelite-linux-aarch64-glibc-eb1fd87c8fa68f5d7b52c5178dbbfdc74e9b8856fb4f89affbf602eb113c1b65", + "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-native-product-v1-otelite-linux-aarch64-glibc-eb1fd87c8fa68f5d7b52c5178dbbfdc74e9b8856fb4f89affbf602eb113c1b65/eb1fd87c8fa68f5d7b52c5178dbbfdc74e9b8856fb4f89affbf602eb113c1b65-otelite-linux-aarch64-glibc.tar" + } + }, + { + "descriptor": { + "entrypoints": [ + "bin/otelite" + ], + "name": "otelite", + "payload": { + "digest": { + "algorithm": "sha256", + "sri": "sha256-O6mmL+ptagiPi1fu5Idr65ugGK3F5vBx90EXlleanH8=" + }, + "file": "artifact.tar", + "format": "tar", + "sizeBytes": 17621504 + }, + "platform": { + "abi": "glibc", + "architecture": "x86_64", + "os": "linux" + }, + "runtime": { + "elfClass": "ELF64", + "inspectionContract": "elf-dynamic/v1", + "interpreter": "/lib64/ld-linux-x86-64.so.2", + "kind": "elf-dynamic", + "machine": "x86_64", + "neededLibraries": [ + "ld-linux-x86-64.so.2", + "libc.so.6", + "libgcc_s.so.1", + "libm.so.6" + ], + "rpathPolicy": "empty/v1", + "symbolVersionFloors": [ + "GCC_3.0", + "GCC_3.3", + "GCC_4.2.0", + "GLIBC_2.10", + "GLIBC_2.14", + "GLIBC_2.15", + "GLIBC_2.16", + "GLIBC_2.17", + "GLIBC_2.18", + "GLIBC_2.2.5", + "GLIBC_2.25", + "GLIBC_2.28", + "GLIBC_2.29", + "GLIBC_2.3", + "GLIBC_2.3.2", + "GLIBC_2.3.4", + "GLIBC_2.30", + "GLIBC_2.32", + "GLIBC_2.33", + "GLIBC_2.34", + "GLIBC_2.39", + "GLIBC_2.7", + "GLIBC_2.9" + ] + }, + "schema": "buck-build-product/v1", + "semanticProvenance": { + "recipe": "cargo-workspace:otelite@0.0.0", + "target": "effect_utils//packages/@overeng/otelite:otelite-product", + "toolchain": "contract=effect-utils/buck2-rust-toolchain/v1;execution_platform=x86_64-linux;target_platform=//buck2/platforms:linux_x86_64;target_triple=x86_64-unknown-linux-gnu;rust-archiver=/nix/store/bj1mfdd968knmbl0rcyr35pqjsh78gaq-ar:8ddb61934a99ba087deeea1765e9da0b84ad065121031f469f7bd8ae06621b0a;rust-c-compiler=/nix/store/ndad9i5wnxxrsisb208c1k79dvyvnw2f-cc:ea5cdeff444fa8758c3f54a1ebf9146ecc74745f89b7f1ba532e098ee74838d0;rust-dwp=/nix/store/8v6vlmbjglbv01zasqziwhmypq8iam33-dwp:35dacff2c48037a73807d190fe985c77e3ebc70ba20a4d56d784777b474b28ed;rust-clippy-driver=/nix/store/1x3h3g3lqz79bwb0xz0p7gq80dvjjlsq-clippy-driver:dd0052080a387712d03e59d9cc2369ec8441544a88fd5cb64bd1e6cb9bcf79de;rust-compiler=/nix/store/vk2bw22y8xrpfsqphcmb9v6vwh7085fi-rustc:5670b4ef087187b199a2d9e1c753c1d252e285e7c7225983c5694bd4405f11a7;rust-cxx-compiler=/nix/store/05ifm3sda8qgd534ff188k3zr7399csa-c++:729198fda42f53137ff7c8243c9807b4b8a90fa13e45ce9e5b54552b9e8b4b6a;rust-linker=/nix/store/05ifm3sda8qgd534ff188k3zr7399csa-c++:729198fda42f53137ff7c8243c9807b4b8a90fa13e45ce9e5b54552b9e8b4b6a;rust-rustdoc=/nix/store/0n51s93xixi22ff0g84qf3g1wr2khkcg-rustdoc:395989c0eda19224fff6a4c92a14047c0bacea85803701882ea166b600dc6eca;rust-nm=/nix/store/n0hhhcwc5b3nib41yfpfkappc29x6gx2-nm:4cf271ac874ec9aac9e6674cde28c0b62551a8d01935d808578e942ac2c8a858;rust-objcopy=/nix/store/azd96w4p3v2jzgz0npzdsnlwhscjcvp3-objcopy:3c5c30d6472ccdefcdedbb7883e4041c25fac3ba3f63997d8cc6ff2918c696bb;rust-objdump=/nix/store/blrn7bk4n3hq3b52128p2shcqkdynidx-objdump:d1dee52c9cfdd15ecf00c9647e6c138b155edb4a5117af9ca495f08268fcd9c0;rust-ranlib=/nix/store/fjvfmsym9h9kfh92q6fsiw255fpj1i3w-ranlib:8c2ada015ae830eacfc56cdf890e7f9d6ab982251f8da5bf75a037e6d731958c;rust-strip=/nix/store/vyn08yg3xavyw5jxkvk7y627nprfyz5d-strip:a24d4704f9a8731d0575f8a51bbe74d6cb73a2d3694d9be87d8aa7c613ff9ea0;rust-shell=/nix/store/75b5c1abflninf1dfd57qaxrxihi4030-bash:94c557aa408ebbc50a044a53cbe5fc3878637e257d58fc6e2db370dc2594e515" + } + }, + "descriptorSha256": "sha256:501e9579bde49f7f453ca8b3dc58ec82ab2e18893bfab623371850a6eb1de073", + "release": { + "hash": "sha256-O6mmL+ptagiPi1fu5Idr65ugGK3F5vBx90EXlleanH8=", + "name": "3ba9a62fea6d6a088f8b57eee4876beb9ba018adc5e6f071f7411796579a9c7f-otelite-linux-x86_64-glibc.tar", + "tag": "buck2-native-product-v1-otelite-linux-x86_64-glibc-3ba9a62fea6d6a088f8b57eee4876beb9ba018adc5e6f071f7411796579a9c7f", + "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-native-product-v1-otelite-linux-x86_64-glibc-3ba9a62fea6d6a088f8b57eee4876beb9ba018adc5e6f071f7411796579a9c7f/3ba9a62fea6d6a088f8b57eee4876beb9ba018adc5e6f071f7411796579a9c7f-otelite-linux-x86_64-glibc.tar" + } + }, + { + "descriptor": { + "entrypoints": [ + "bin/typescript-api-server" + ], + "name": "typescript-api-server", + "payload": { + "digest": { + "algorithm": "sha256", + "sri": "sha256-GCZlVqZSA6OUM3KC04i8UobyDaLyhZNi3PvtIkeP2vg=" + }, + "file": "artifact.tar", + "format": "tar", + "sizeBytes": 27526144 + }, + "platform": { + "abi": "darwin", + "architecture": "aarch64", + "os": "darwin" + }, + "runtime": { + "architecture": "arm64", + "dylibs": [ + "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation", + "/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices", + "/usr/lib/libSystem.B.dylib", + "/usr/lib/libresolv.9.dylib" + ], + "inspectionContract": "mach-o-dynamic/v1", + "installNamePolicy": "system-only/v1", + "kind": "mach-o-dynamic", + "minimumOs": "12.0", + "rpathPolicy": "empty/v1", + "signingPolicy": "embedded/v1" + }, + "schema": "buck-build-product/v1", + "semanticProvenance": { + "recipe": "pnpm-lock:@typescript/typescript-platform/lib", + "target": "effect_utils//packages/@overeng/genie:typescript-api-server-product", + "toolchain": "pnpm-lockfile:pnpm-lock.yaml" + } + }, + "descriptorSha256": "sha256:58992a4289d7bec05aa95520bd34156f8509b35643fd1ae9dd7ca8417df97cbf", + "release": { + "hash": "sha256-GCZlVqZSA6OUM3KC04i8UobyDaLyhZNi3PvtIkeP2vg=", + "name": "18266556a65203a394337282d388bc5286f20da2f2859362dcfbed22478fdaf8-typescript-api-server-darwin-aarch64-darwin.tar", + "tag": "buck2-native-product-v1-typescript-api-server-darwin-aarch64-darwin-18266556a65203a394337282d388bc5286f20da2f2859362dcfbed22478fdaf8", + "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-native-product-v1-typescript-api-server-darwin-aarch64-darwin-18266556a65203a394337282d388bc5286f20da2f2859362dcfbed22478fdaf8/18266556a65203a394337282d388bc5286f20da2f2859362dcfbed22478fdaf8-typescript-api-server-darwin-aarch64-darwin.tar" + } + }, + { + "descriptor": { + "entrypoints": [ + "bin/typescript-api-server" + ], + "name": "typescript-api-server", + "payload": { + "digest": { + "algorithm": "sha256", + "sri": "sha256-OiekZgj4DbUlZ+IjPfwlSasrFPAYmeB4Cct7o5Ehq+s=" + }, + "file": "artifact.tar", + "format": "tar", + "sizeBytes": 26745856 + }, + "platform": { + "abi": "glibc", + "architecture": "aarch64", + "os": "linux" + }, + "runtime": { + "elfClass": "ELF64", + "inspectionContract": "elf-static/v1", + "kind": "elf-static", + "machine": "aarch64" + }, + "schema": "buck-build-product/v1", + "semanticProvenance": { + "recipe": "pnpm-lock:@typescript/typescript-platform/lib", + "target": "effect_utils//packages/@overeng/genie:typescript-api-server-product", + "toolchain": "pnpm-lockfile:pnpm-lock.yaml" + } + }, + "descriptorSha256": "sha256:8aa2ab63b21fa9ec241d109547c333fe88d4e5afc784fd0ec5d260ae6c59fac0", + "release": { + "hash": "sha256-OiekZgj4DbUlZ+IjPfwlSasrFPAYmeB4Cct7o5Ehq+s=", + "name": "3a27a46608f80db52567e2233dfc2549ab2b14f01899e07809cb7ba39121abeb-typescript-api-server-linux-aarch64-glibc.tar", + "tag": "buck2-native-product-v1-typescript-api-server-linux-aarch64-glibc-3a27a46608f80db52567e2233dfc2549ab2b14f01899e07809cb7ba39121abeb", + "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-native-product-v1-typescript-api-server-linux-aarch64-glibc-3a27a46608f80db52567e2233dfc2549ab2b14f01899e07809cb7ba39121abeb/3a27a46608f80db52567e2233dfc2549ab2b14f01899e07809cb7ba39121abeb-typescript-api-server-linux-aarch64-glibc.tar" + } + }, + { + "descriptor": { + "entrypoints": [ + "bin/typescript-api-server" + ], + "name": "typescript-api-server", + "payload": { + "digest": { + "algorithm": "sha256", + "sri": "sha256-+VGhK2JCY0snt9XFV0HQ4FXc528Sgzc5XhV3D7s8rgA=" + }, + "file": "artifact.tar", + "format": "tar", + "sizeBytes": 27974656 + }, + "platform": { + "abi": "glibc", + "architecture": "x86_64", + "os": "linux" + }, + "runtime": { + "elfClass": "ELF64", + "inspectionContract": "elf-static/v1", + "kind": "elf-static", + "machine": "x86_64" + }, + "schema": "buck-build-product/v1", + "semanticProvenance": { + "recipe": "pnpm-lock:@typescript/typescript-platform/lib", + "target": "effect_utils//packages/@overeng/genie:typescript-api-server-product", + "toolchain": "pnpm-lockfile:pnpm-lock.yaml" + } + }, + "descriptorSha256": "sha256:bfdd155d0c6dbe69ea9a3a3525c61c9667ce3cc8559e4aeedb7417d6b737a0d1", + "release": { + "hash": "sha256-+VGhK2JCY0snt9XFV0HQ4FXc528Sgzc5XhV3D7s8rgA=", + "name": "f951a12b6242634b27b7d5c55741d0e055dce76f128337395e15770fbb3cae00-typescript-api-server-linux-x86_64-glibc.tar", + "tag": "buck2-native-product-v1-typescript-api-server-linux-x86_64-glibc-f951a12b6242634b27b7d5c55741d0e055dce76f128337395e15770fbb3cae00", + "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-native-product-v1-typescript-api-server-linux-x86_64-glibc-f951a12b6242634b27b7d5c55741d0e055dce76f128337395e15770fbb3cae00/f951a12b6242634b27b7d5c55741d0e055dce76f128337395e15770fbb3cae00-typescript-api-server-linux-x86_64-glibc.tar" + } + } + ], + "schema": "effect-utils/buck2-native-release-products/v1" +} diff --git a/nix/buck2-native-products/publish.sh b/nix/buck2-native-products/publish.sh new file mode 100755 index 0000000000..4a685bef21 --- /dev/null +++ b/nix/buck2-native-products/publish.sh @@ -0,0 +1,277 @@ +#!/usr/bin/env bash +# Publishes the complete Buck native-product matrix as immutable releases. +set -euo pipefail + +repo_root="${BUCK2_NATIVE_PRODUCTS_REPO:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P)}" +targets="$repo_root/nix/buck2-native-products/targets.json" +artifact_root="" +repository="overengineeringstudio/effect-utils" +proposal="" +dry_run=false + +fail() { + printf 'buck2-native-products-publish: %s\n' "$*" >&2 + exit 1 +} + +usage() { + cat <<'EOF' +Usage: nix/buck2-native-products/publish.sh --artifact-root PATH [--dry-run] [--proposal PATH] + +The artifact root must contain exactly: + --//{artifact.tar,descriptor.json} + +--dry-run Validate all descriptors and payloads; print the proposed manifest. +--proposal PATH Write the proposed manifest outside the Git worktree (live mode only). +EOF +} + +while (($#)); do + case "$1" in + --artifact-root) + (($# >= 2)) || fail "--artifact-root requires a path" + artifact_root="$2" + shift 2 + ;; + --dry-run) + dry_run=true + shift + ;; + --proposal) + (($# >= 2)) || fail "--proposal requires a path" + proposal="$2" + shift 2 + ;; + --help|-h) + usage + exit 0 + ;; + *) fail "unknown argument: $1" ;; + esac +done + +[[ -n "$artifact_root" ]] || fail "--artifact-root is required" +[[ -d "$artifact_root" && ! -L "$artifact_root" ]] || fail "artifact root must be a regular directory" +[[ -f "$targets" && ! -L "$targets" ]] || fail "target inventory must be a regular file: $targets" +for tool in cmp cp find gh git jq mktemp nix realpath sed sha256sum sort stat wc; do + command -v "$tool" >/dev/null || fail "$tool is required" +done + +if [[ -n "${GITHUB_EVENT_NAME:-}" && "${GITHUB_EVENT_NAME}" != "workflow_dispatch" ]]; then + fail "refusing untrusted GitHub event: ${GITHUB_EVENT_NAME}" +fi + +jq -e ' + (type == "object") and + ((keys | sort) == ["platforms", "products", "schema"]) and + (.schema == "effect-utils/buck2-native-release-targets/v1") and + (.platforms | type == "array" and length > 0 and all(.[ ]; + type == "object" and ((keys | sort) == ["abi", "architecture", "os", "system"]) and + (.abi | type == "string") and (.architecture | type == "string") and + (.os | type == "string") and (.system | type == "string") + )) and + (.products | type == "array" and length > 0 and all(.[ ]; + type == "object" and ((keys | sort) == ["name", "target"]) and + (.name | type == "string" and test("^[A-Za-z0-9][A-Za-z0-9._+-]*$")) and + (.target | type == "string" and test("^([A-Za-z0-9_]+)?//[^[:space:]\\[\\]]+:[^[:space:]\\[\\]]+$")) + )) and + ([.platforms[] | [.architecture, .os, .abi] | join("-")] | length == (unique | length)) and + ([.platforms[].system] | length == (unique | length)) and + ([.products[].name] | length == (unique | length)) and + ([.products[].target] | length == (unique | length)) +' "$targets" >/dev/null || fail "target inventory violates effect-utils/buck2-native-release-targets/v1" + +stage="$(mktemp -d)" +cleanup_draft_release_id="" +cleanup() { + status=$? + if [[ -n "$cleanup_draft_release_id" ]]; then + if release_state="$(gh api "repos/$repository/releases/$cleanup_draft_release_id" 2>/dev/null)" && + jq -e '.draft == true' <<<"$release_state" >/dev/null 2>&1; then + gh api --method DELETE "repos/$repository/releases/$cleanup_draft_release_id" --silent >/dev/null 2>&1 || true + fi + fi + rm -rf "$stage" + exit "$status" +} +trap cleanup EXIT + +expected_paths="$stage/expected-paths" +actual_paths="$stage/actual-paths" +: >"$expected_paths" +mapfile -t platform_rows < <(jq -r '.platforms[] | [.architecture, .os, .abi] | @tsv' "$targets") +mapfile -t product_rows < <(jq -r '.products[] | [.name, .target] | @tsv' "$targets") +for platform_row in "${platform_rows[@]}"; do + IFS=$'\t' read -r architecture os abi <<<"$platform_row" + platform_key="$architecture-$os-$abi" + for product_row in "${product_rows[@]}"; do + IFS=$'\t' read -r product_name _ <<<"$product_row" + printf '%s\n' "$platform_key/$product_name/artifact.tar" "$platform_key/$product_name/descriptor.json" >>"$expected_paths" + done +done +( + cd "$artifact_root" + find . -type f -print | sed 's#^./##' | sort +) >"$actual_paths" +sort -o "$expected_paths" "$expected_paths" +cmp "$expected_paths" "$actual_paths" >/dev/null || fail "artifact root does not exactly match the declared product matrix" +[[ -z "$(find "$artifact_root" -type l -print -quit)" ]] || fail "artifact root must not contain symlinks" + +entries="$stage/entries.jsonl" +: >"$entries" +declare -a release_assets=() release_tags=() asset_names=() +for platform_row in "${platform_rows[@]}"; do + IFS=$'\t' read -r architecture os abi <<<"$platform_row" + platform_key="$architecture-$os-$abi" + for product_row in "${product_rows[@]}"; do + IFS=$'\t' read -r product_name target <<<"$product_row" + product_root="$artifact_root/$platform_key/$product_name" + artifact="$product_root/artifact.tar" + descriptor_file="$product_root/descriptor.json" + descriptor="$(jq -cS . "$descriptor_file")" || fail "$platform_key/$product_name descriptor is not JSON" + descriptor_sha256="$(printf '%s' "$descriptor" | sha256sum)" + descriptor_sha256="sha256:${descriptor_sha256%% *}" + + jq -e --arg name "$product_name" --arg target "$target" \ + --arg architecture "$architecture" --arg os "$os" --arg abi "$abi" ' + .schema == "buck-build-product/v1" and + .name == $name and .semanticProvenance.target == $target and + .platform == {architecture:$architecture, os:$os, abi:$abi} and + .payload.file == "artifact.tar" and .payload.format == "tar" and + .entrypoints == ["bin/" + $name] + ' <<<"$descriptor" >/dev/null || fail "$platform_key/$product_name descriptor does not match its declaration" + + contract="$repo_root/nix/workspace-tools/lib/buck2-build-product-contract.nix" + DESCRIPTOR_FILE="$descriptor_file" DESCRIPTOR_DIGEST="$descriptor_sha256" CONTRACT_FILE="$contract" \ + nix eval --json --impure --expr ' + let + contract = import (builtins.getEnv "CONTRACT_FILE"); + descriptor = builtins.fromJSON (builtins.readFile (builtins.getEnv "DESCRIPTOR_FILE")); + in contract.verifyDescriptor { + inherit descriptor; + expectedDescriptorDigest = builtins.getEnv "DESCRIPTOR_DIGEST"; + } + ' >/dev/null || fail "$platform_key/$product_name descriptor violates buck-build-product/v1" + + expected_size="$(jq -r '.payload.sizeBytes' <<<"$descriptor")" + actual_size="$(stat -c '%s' "$artifact")" + [[ "$actual_size" == "$expected_size" ]] || fail "$platform_key/$product_name payload size mismatch" + payload_sha256="$(sha256sum "$artifact")" + payload_sha256="${payload_sha256%% *}" + expected_integrity="$(jq -r '.payload.digest.sri' <<<"$descriptor")" + actual_integrity="$(nix hash convert --hash-algo sha256 --to sri "$payload_sha256")" + [[ "$actual_integrity" == "$expected_integrity" ]] || fail "$platform_key/$product_name payload digest mismatch" + + tag="buck2-native-product-v1-$product_name-$os-$architecture-$abi-$payload_sha256" + asset_name="$payload_sha256-$product_name-$os-$architecture-$abi.tar" + asset_dir="$stage/release-assets/$platform_key/$product_name" + mkdir -p "$asset_dir" + release_asset="$asset_dir/$asset_name" + cp -- "$artifact" "$release_asset" + cmp -- "$artifact" "$release_asset" >/dev/null || fail "$platform_key/$product_name staged bytes changed" + release_url="https://github.com/$repository/releases/download/$tag/$asset_name" + jq -cnS --argjson descriptor "$descriptor" --arg descriptorSha256 "$descriptor_sha256" \ + --arg tag "$tag" --arg name "$asset_name" --arg url "$release_url" --arg hash "$expected_integrity" \ + '{descriptor:$descriptor,descriptorSha256:$descriptorSha256,release:{tag:$tag,name:$name,url:$url,hash:$hash}}' >>"$entries" + release_assets+=("$release_asset") + release_tags+=("$tag") + asset_names+=("$asset_name") + done +done + +proposal_stage="$stage/manifest.json" +jq -sS '{schema:"effect-utils/buck2-native-release-products/v1",products:(sort_by(.descriptor.name,.descriptor.platform.os,.descriptor.platform.architecture,.descriptor.platform.abi))}' "$entries" >"$proposal_stage" + +if $dry_run; then + [[ -z "$proposal" ]] || fail "--proposal is unavailable in dry-run mode" + cat "$proposal_stage" + exit 0 +fi + +if [[ -n "$proposal" ]]; then + proposal="$(realpath -m "$proposal")" + canonical_repo="$(realpath "$repo_root")" + case "$proposal" in + "$canonical_repo"|"$canonical_repo"/*) fail "proposal output must be outside the Git worktree" ;; + esac + [[ ! -e "$proposal" ]] || fail "refusing to overwrite proposal output: $proposal" +fi +head_commit="$(git -C "$repo_root" rev-parse --verify 'HEAD^{commit}')" +publication_commit="${GITHUB_SHA:-$head_commit}" +[[ "$publication_commit" =~ ^[0-9a-f]{40}$ ]] || fail "publication commit is not a full Git SHA" +[[ "$publication_commit" == "$head_commit" ]] || fail "GITHUB_SHA does not identify the checked-out commit" +[[ -z "$(git -C "$repo_root" status --porcelain --untracked-files=normal)" ]] || fail "refusing to publish from a dirty Git worktree" + +release_listing="$(gh api --paginate "repos/$repository/releases" --jq '.[] | [.tag_name, (.id | tostring), (.draft | tostring)] | @tsv')" || + fail "could not list existing releases; refusing to publish" +declare -A listed_release_ids=() listed_release_draft=() +while IFS=$'\t' read -r listed_tag listed_id listed_draft; do + [[ -n "$listed_tag" ]] || continue + [[ "$listed_id" =~ ^[0-9]+$ ]] || fail "GitHub listed $listed_tag without a numeric id" + if [[ -n "${listed_release_ids[$listed_tag]+present}" ]]; then + listed_release_ids["$listed_tag"]+=" $listed_id" + [[ "$listed_draft" == false ]] || listed_release_draft["$listed_tag"]=true + else + listed_release_ids["$listed_tag"]="$listed_id" + listed_release_draft["$listed_tag"]="$listed_draft" + fi +done <<<"$release_listing" + +release_holds_asset() { + local release_json="$1" expected_name="$2" asset_file="$3" expected_digest + expected_digest="$(sha256sum "$asset_file")" + expected_digest="sha256:${expected_digest%% *}" + jq -e --arg name "$expected_name" --arg digest "$expected_digest" ' + .draft == false and .immutable == true and + (.assets | length == 1) and .assets[0].name == $name and .assets[0].digest == $digest + ' <<<"$release_json" >/dev/null +} + +declare -a verified_reuse=() +for index in "${!release_tags[@]}"; do + tag="${release_tags[$index]}" + if [[ -z "${listed_release_ids[$tag]+present}" ]]; then + verified_reuse+=(false) + continue + fi + listed_ids="${listed_release_ids[$tag]}" + [[ "$listed_ids" == "${listed_ids% *}" ]] || fail "$tag is held by multiple releases: $listed_ids" + [[ "${listed_release_draft[$tag]}" == false ]] || fail "$tag exists as draft release id $listed_ids" + published="$(gh api "repos/$repository/releases/tags/$tag")" || fail "could not read existing $tag" + release_holds_asset "$published" "${asset_names[$index]}" "${release_assets[$index]}" || + fail "$tag does not hold exactly the staged asset" + gh release verify-asset "$tag" "${release_assets[$index]}" --repo "$repository" >/dev/null + verified_reuse+=(true) +done + +for index in "${!release_tags[@]}"; do + tag="${release_tags[$index]}" + asset_name="${asset_names[$index]}" + release_asset="${release_assets[$index]}" + if [[ "${verified_reuse[$index]}" == true ]]; then + printf 'buck2-native-products-publish: reusing verified release: %s\n' "$tag" >&2 + continue + fi + created="$(gh api --method POST "repos/$repository/releases" \ + -f tag_name="$tag" -f name="$tag" -f target_commitish="$publication_commit" \ + -F draft=true -F prerelease=false -F generate_release_notes=false)" + release_id="$(jq -er '.id | select(type == "number")' <<<"$created")" || fail "GitHub did not return a draft release id" + cleanup_draft_release_id="$release_id" + jq -e --arg tag "$tag" '.draft == true and .tag_name == $tag and (.assets | length == 0)' <<<"$created" >/dev/null || + fail "new release is not the requested empty draft" + gh release upload "$tag" "$release_asset" --repo "$repository" + gh api --method PATCH "repos/$repository/releases/$release_id" -F draft=false --silent + cleanup_draft_release_id="" + published="$(gh api "repos/$repository/releases/tags/$tag")" + release_holds_asset "$published" "$asset_name" "$release_asset" || fail "$tag failed immutable asset verification" + gh release verify-asset "$tag" "$release_asset" --repo "$repository" >/dev/null +done + +[[ "$(git -C "$repo_root" rev-parse --verify 'HEAD^{commit}')" == "$publication_commit" ]] || fail "checked-out commit changed during publication" +[[ -z "$(git -C "$repo_root" status --porcelain --untracked-files=normal)" ]] || fail "Git worktree changed during publication" +if [[ -n "$proposal" ]]; then + cp -- "$proposal_stage" "$proposal" + printf 'buck2-native-products-publish: proposed manifest: %s\n' "$proposal" >&2 +else + cat "$proposal_stage" +fi diff --git a/nix/buck2-native-products/targets.json b/nix/buck2-native-products/targets.json new file mode 100644 index 0000000000..13f8d4e968 --- /dev/null +++ b/nix/buck2-native-products/targets.json @@ -0,0 +1,37 @@ +{ + "platforms": [ + { + "abi": "glibc", + "architecture": "x86_64", + "os": "linux", + "system": "x86_64-linux" + }, + { + "abi": "glibc", + "architecture": "aarch64", + "os": "linux", + "system": "aarch64-linux" + }, + { + "abi": "darwin", + "architecture": "aarch64", + "os": "darwin", + "system": "aarch64-darwin" + } + ], + "products": [ + { + "name": "otel-scrape", + "target": "effect_utils//packages/@overeng/otel-scrape:otel-scrape-product" + }, + { + "name": "otelite", + "target": "effect_utils//packages/@overeng/otelite:otelite-product" + }, + { + "name": "typescript-api-server", + "target": "effect_utils//packages/@overeng/genie:typescript-api-server-product" + } + ], + "schema": "effect-utils/buck2-native-release-targets/v1" +} diff --git a/nix/buck2-products/default.nix b/nix/buck2-products/default.nix index c9f30abc98..dc8bc320a5 100644 --- a/nix/buck2-products/default.nix +++ b/nix/buck2-products/default.nix @@ -1,14 +1,25 @@ # Pure loader for immutable Buck-produced JavaScript release assets. # -# The tracked manifest is the only product-data authority. It embeds each -# canonical descriptor value and binds its payload digest to one deterministic -# immutable GitHub Release and asset. Evaluation validates the whole binding; -# realization fetches only the declared content-addressed module bytes. +# The generated target inventory is desired product authority; the publisher is +# the sole producer of the tracked manifest. Evaluation requires both sets to +# match exactly, validates every canonical descriptor/release binding, and +# realizes only the declared content-addressed module bytes. { pkgs }: let lib = pkgs.lib; manifest = builtins.fromJSON (builtins.readFile ./manifest.json); + targets = builtins.fromJSON (builtins.readFile ./targets.json); + targetGenerator = "effect-utils/genie/buck2-javascript-release-targets"; + targetFingerprint = "sha256:${ + builtins.hashString "sha256" ( + builtins.toJSON { + generator = targetGenerator; + schemaVersion = targets.schemaVersion; + semanticData = targets.products; + } + ) + }"; repositoryReleaseBase = "https://github.com/overengineeringstudio/effect-utils/releases/download"; expectedDescriptorKeys = [ "externalCapabilities" @@ -152,11 +163,72 @@ let }; }; checkedProducts = map checkedProduct manifest.products; - productNames = map (entry: entry.name) checkedProducts; + publishedProductNames = map (entry: entry.name) checkedProducts; releaseTags = map (entry: entry.value.release.tag) checkedProducts; - uniqueProductNames = lib.unique productNames; + uniquePublishedProductNames = lib.unique publishedProductNames; uniqueReleaseTags = lib.unique releaseTags; + declaredProductNames = map (product: product.name) targets.products; + declaredProductTargets = map (product: product.target) targets.products; + sortProducts = builtins.sort (left: right: left.name < right.name); + declaredProducts = sortProducts targets.products; + publishedProducts = sortProducts ( + map (entry: { + name = entry.name; + target = (builtins.fromJSON entry.value.descriptorContent).target; + }) checkedProducts + ); in +assert lib.assertMsg ( + builtins.attrNames targets == [ + "products" + "provenance" + "schemaVersion" + ] +) "buck2-products: target inventory fields are not exact"; +assert lib.assertMsg ( + targets.schemaVersion == 1 +) "buck2-products: unsupported target inventory schema"; +assert lib.assertMsg ( + builtins.attrNames targets.provenance == [ + "fingerprint" + "generator" + "regenerationCommand" + "semanticInputs" + "source" + ] + && targets.provenance.generator == targetGenerator + && targets.provenance.regenerationCommand == "devenv tasks run genie:run" + && + targets.provenance.semanticInputs == [ + "genie/buck2/javascript-product-registry.ts" + "nix/buck2-products/targets.json.genie.ts" + ] + && targets.provenance.source == "nix/buck2-products/targets.json.genie.ts" +) "buck2-products: target inventory provenance is invalid"; +assert lib.assertMsg ( + targets.provenance.fingerprint == targetFingerprint +) "buck2-products: target inventory fingerprint mismatch"; +assert lib.assertMsg ( + builtins.isList targets.products + && targets.products != [ ] + && builtins.all ( + product: + builtins.attrNames product == [ + "name" + "target" + ] + && builtins.isString product.name + && builtins.match "[A-Za-z0-9][A-Za-z0-9._+-]*" product.name != null + && builtins.isString product.target + && builtins.match "([A-Za-z0-9_]+)?//[^][[:space:]]+:[^][[:space:]]+" product.target != null + ) targets.products +) "buck2-products: target inventory products are malformed"; +assert lib.assertMsg ( + builtins.length (lib.unique declaredProductNames) == builtins.length declaredProductNames +) "buck2-products: target inventory product names must be unique"; +assert lib.assertMsg ( + builtins.length (lib.unique declaredProductTargets) == builtins.length declaredProductTargets +) "buck2-products: target inventory product targets must be unique"; assert lib.assertMsg ( builtins.attrNames manifest == [ "products" @@ -170,15 +242,18 @@ assert lib.assertMsg ( builtins.isList manifest.products && manifest.products != [ ] ) "buck2-products: manifest products must be a non-empty list"; assert lib.assertMsg ( - builtins.length uniqueProductNames == builtins.length productNames + builtins.length uniquePublishedProductNames == builtins.length publishedProductNames ) "buck2-products: product names must be unique"; +assert lib.assertMsg ( + declaredProducts == publishedProducts +) "buck2-products: declared target inventory does not match the published manifest"; assert lib.assertMsg ( builtins.length uniqueReleaseTags == builtins.length releaseTags ) "buck2-products: each product payload must have one unique release"; { - inherit manifest; - declaredProductNames = builtins.sort builtins.lessThan productNames; - publishedProductNames = builtins.sort builtins.lessThan productNames; + inherit manifest targets; + declaredProductNames = builtins.sort builtins.lessThan declaredProductNames; + publishedProductNames = builtins.sort builtins.lessThan publishedProductNames; products = builtins.listToAttrs checkedProducts; fullyPublished = true; } diff --git a/nix/buck2-products/manifest.json b/nix/buck2-products/manifest.json index 2dab9fe6b0..abd55ee18d 100644 --- a/nix/buck2-products/manifest.json +++ b/nix/buck2-products/manifest.json @@ -4,7 +4,7 @@ "descriptor": { "externalCapabilities": [], "externalModules": [], - "integrity": "sha256-a5Sdakgc0DhBZcGVywxuob4oNg4Fmh3wSqDAixJpnG4=", + "integrity": "sha256-1PWYRs7oHF2Iy7delxRTOxx0FpZFJaBGJLEwH89BQA0=", "modulePath": "ci-tools.js", "platform": { "abi": "any", @@ -22,15 +22,15 @@ "runtimeContractVersion": "v1", "runtimeKind": "node", "schema": "effect-utils/javascript-product/v2", - "sizeBytes": 1452506, + "sizeBytes": 1447547, "target": "effect_utils//packages/@overeng/ci-tools:ci-tools-candidate" }, - "descriptorSha256": "642df40e818076f54d9c5c41f6b252a6cab11ea0b88e2111d2e378a223f7d35f", + "descriptorSha256": "3343579b866220792f9bb3ad3500215c66ab6f278c5a7d6d8911404766b0b7a2", "release": { - "hash": "sha256-a5Sdakgc0DhBZcGVywxuob4oNg4Fmh3wSqDAixJpnG4=", - "name": "6b949d6a481cd0384165c195cb0c6ea1be28360e059a1df04aa0c08b12699c6e-ci-tools.js", - "tag": "buck2-product-v3-ci-tools-6b949d6a481cd0384165c195cb0c6ea1be28360e059a1df04aa0c08b12699c6e", - "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-product-v3-ci-tools-6b949d6a481cd0384165c195cb0c6ea1be28360e059a1df04aa0c08b12699c6e/6b949d6a481cd0384165c195cb0c6ea1be28360e059a1df04aa0c08b12699c6e-ci-tools.js" + "hash": "sha256-1PWYRs7oHF2Iy7delxRTOxx0FpZFJaBGJLEwH89BQA0=", + "name": "d4f59846cee81c5d88cbb75e9714533b1c7416964525a04624b1301fcf41400d-ci-tools.js", + "tag": "buck2-product-v3-ci-tools-d4f59846cee81c5d88cbb75e9714533b1c7416964525a04624b1301fcf41400d", + "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-product-v3-ci-tools-d4f59846cee81c5d88cbb75e9714533b1c7416964525a04624b1301fcf41400d/d4f59846cee81c5d88cbb75e9714533b1c7416964525a04624b1301fcf41400d-ci-tools.js" } }, { @@ -38,21 +38,11 @@ "externalCapabilities": [ "actionlint", "effect-tsgo", - "opentui-core-native", "oxfmt", "typescript-api-server" ], - "externalModules": [ - "@opentui/core-darwin-arm64", - "@opentui/core-darwin-x64", - "@opentui/core-linux-arm64", - "@opentui/core-linux-arm64-musl", - "@opentui/core-linux-x64", - "@opentui/core-linux-x64-musl", - "@opentui/core-win32-arm64", - "@opentui/core-win32-x64" - ], - "integrity": "sha256-AXQYm39u4VCkFjeks7BdMet+hVdwZYGwK0pPHbqMFAU=", + "externalModules": [], + "integrity": "sha256-s6EWEOMp0rUoQMecUeObTil2QjF5ancdplQivAkRN/o=", "modulePath": "genie.js", "platform": { "abi": "any", @@ -70,22 +60,24 @@ "runtimeContractVersion": "v1", "runtimeKind": "bun", "schema": "effect-utils/javascript-product/v2", - "sizeBytes": 6340482, + "sizeBytes": 3236268, "target": "effect_utils//packages/@overeng/genie:genie-candidate" }, - "descriptorSha256": "c28d4337009cab97e9be2abe6805f226fd982db59d709455e9972e5d65b8392e", + "descriptorSha256": "df9000283b8366256f0dc8788ffd8ff4115864ebbc2781adbbed463454236755", "release": { - "hash": "sha256-AXQYm39u4VCkFjeks7BdMet+hVdwZYGwK0pPHbqMFAU=", - "name": "0174189b7f6ee150a41637a4b3b05d31eb7e8557706581b02b4a4f1dba8c1405-genie.js", - "tag": "buck2-product-v3-genie-0174189b7f6ee150a41637a4b3b05d31eb7e8557706581b02b4a4f1dba8c1405", - "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-product-v3-genie-0174189b7f6ee150a41637a4b3b05d31eb7e8557706581b02b4a4f1dba8c1405/0174189b7f6ee150a41637a4b3b05d31eb7e8557706581b02b4a4f1dba8c1405-genie.js" + "hash": "sha256-s6EWEOMp0rUoQMecUeObTil2QjF5ancdplQivAkRN/o=", + "name": "b3a11610e329d2b52840c79c51e39b4e29764231796a771da65422bc091137fa-genie.js", + "tag": "buck2-product-v3-genie-b3a11610e329d2b52840c79c51e39b4e29764231796a771da65422bc091137fa", + "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-product-v3-genie-b3a11610e329d2b52840c79c51e39b4e29764231796a771da65422bc091137fa/b3a11610e329d2b52840c79c51e39b4e29764231796a771da65422bc091137fa-genie.js" } }, { "descriptor": { - "externalCapabilities": [], + "externalCapabilities": [ + "typescript-api-server" + ], "externalModules": [], - "integrity": "sha256-WiqkVQyTCrhBrjkvimKt30w5tTM51CFFKXgSz4ARdDM=", + "integrity": "sha256-SN4MPityKu/Q2F37mDPYufDOxp4RqCzj6++uZJK0nUM=", "modulePath": "genie-bootstrap-closure-check.js", "platform": { "abi": "any", @@ -103,15 +95,15 @@ "runtimeContractVersion": "v1", "runtimeKind": "bun", "schema": "effect-utils/javascript-product/v2", - "sizeBytes": 8848384, + "sizeBytes": 561262, "target": "effect_utils//packages/@overeng/genie:genie-bootstrap-closure-check-candidate" }, - "descriptorSha256": "40db4fdc19ab04316c857439394f6c6f6c6aa5feeca554c8dc788811a793126e", + "descriptorSha256": "00f89f944ed69f6556f0fffe34b3f850660ac46e4b18bc297f3dc6673af6db6b", "release": { - "hash": "sha256-WiqkVQyTCrhBrjkvimKt30w5tTM51CFFKXgSz4ARdDM=", - "name": "5a2aa4550c930ab841ae392f8a62addf4c39b53339d42145297812cf80117433-genie-bootstrap-closure-check.js", - "tag": "buck2-product-v3-genie-bootstrap-closure-check-5a2aa4550c930ab841ae392f8a62addf4c39b53339d42145297812cf80117433", - "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-product-v3-genie-bootstrap-closure-check-5a2aa4550c930ab841ae392f8a62addf4c39b53339d42145297812cf80117433/5a2aa4550c930ab841ae392f8a62addf4c39b53339d42145297812cf80117433-genie-bootstrap-closure-check.js" + "hash": "sha256-SN4MPityKu/Q2F37mDPYufDOxp4RqCzj6++uZJK0nUM=", + "name": "48de0c3e2b722aefd0d85dfb9833d8b9f0cec69e11a82ce3ebefae6492b49d43-genie-bootstrap-closure-check.js", + "tag": "buck2-product-v3-genie-bootstrap-closure-check-48de0c3e2b722aefd0d85dfb9833d8b9f0cec69e11a82ce3ebefae6492b49d43", + "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-product-v3-genie-bootstrap-closure-check-48de0c3e2b722aefd0d85dfb9833d8b9f0cec69e11a82ce3ebefae6492b49d43/48de0c3e2b722aefd0d85dfb9833d8b9f0cec69e11a82ce3ebefae6492b49d43-genie-bootstrap-closure-check.js" } }, { @@ -124,7 +116,7 @@ "watchman" ], "externalModules": [], - "integrity": "sha256-KO5Hj0CAXc0Nbr/3h1yeFWABNdHgd37Qfl31dVxvI00=", + "integrity": "sha256-REfn9DmHLygR4aac7I+ok/YCH9ijmXzy/Xtqr9P/ky8=", "modulePath": "mr.js", "platform": { "abi": "any", @@ -142,22 +134,22 @@ "runtimeContractVersion": "v1", "runtimeKind": "node", "schema": "effect-utils/javascript-product/v2", - "sizeBytes": 3762476, + "sizeBytes": 3792401, "target": "effect_utils//packages/@overeng/megarepo:megarepo-candidate" }, - "descriptorSha256": "763cdf589ba78da29969da7245e3248bd99a96949064397518aa828533c6b4b9", + "descriptorSha256": "0633e4568de9e701a6cc89c9ad0994841528702ac513f8e3822f9688e5177447", "release": { - "hash": "sha256-KO5Hj0CAXc0Nbr/3h1yeFWABNdHgd37Qfl31dVxvI00=", - "name": "28ee478f40805dcd0d6ebff7875c9e15600135d1e0777ed07e5df5755c6f234d-mr.js", - "tag": "buck2-product-v3-megarepo-28ee478f40805dcd0d6ebff7875c9e15600135d1e0777ed07e5df5755c6f234d", - "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-product-v3-megarepo-28ee478f40805dcd0d6ebff7875c9e15600135d1e0777ed07e5df5755c6f234d/28ee478f40805dcd0d6ebff7875c9e15600135d1e0777ed07e5df5755c6f234d-mr.js" + "hash": "sha256-REfn9DmHLygR4aac7I+ok/YCH9ijmXzy/Xtqr9P/ky8=", + "name": "4447e7f439872f2811e1a69cec8fa893f6021fd8a3997cf2fd7b6aafd3ff932f-mr.js", + "tag": "buck2-product-v3-megarepo-4447e7f439872f2811e1a69cec8fa893f6021fd8a3997cf2fd7b6aafd3ff932f", + "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-product-v3-megarepo-4447e7f439872f2811e1a69cec8fa893f6021fd8a3997cf2fd7b6aafd3ff932f/4447e7f439872f2811e1a69cec8fa893f6021fd8a3997cf2fd7b6aafd3ff932f-mr.js" } }, { "descriptor": { "externalCapabilities": [], "externalModules": [], - "integrity": "sha256-/u/lAU+4uMPbiohhbG295JUE8tXJ4+mdkq4f/7NhdDY=", + "integrity": "sha256-Y6rrX7KSE9M82ZwcLgr4TXEzZqhBU1/e6ARymhY6hHY=", "modulePath": "notion.js", "platform": { "abi": "any", @@ -175,15 +167,15 @@ "runtimeContractVersion": "v1", "runtimeKind": "node", "schema": "effect-utils/javascript-product/v2", - "sizeBytes": 3733008, + "sizeBytes": 3755253, "target": "effect_utils//packages/@overeng/notion-cli:notion-cli-candidate" }, - "descriptorSha256": "52ac286c2dbda0f017f1c61cc1a000e4b22cdaa5af2604a6e3f2051697cf4ddb", + "descriptorSha256": "461a6db72d6d8a88bbf03b58f2ea3b7345275917c3f5b1a5828bae19f37ad462", "release": { - "hash": "sha256-/u/lAU+4uMPbiohhbG295JUE8tXJ4+mdkq4f/7NhdDY=", - "name": "feefe5014fb8b8c3db8a88616c6dbde49504f2d5c9e3e99d92ae1fffb3617436-notion.js", - "tag": "buck2-product-v3-notion-cli-feefe5014fb8b8c3db8a88616c6dbde49504f2d5c9e3e99d92ae1fffb3617436", - "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-product-v3-notion-cli-feefe5014fb8b8c3db8a88616c6dbde49504f2d5c9e3e99d92ae1fffb3617436/feefe5014fb8b8c3db8a88616c6dbde49504f2d5c9e3e99d92ae1fffb3617436-notion.js" + "hash": "sha256-Y6rrX7KSE9M82ZwcLgr4TXEzZqhBU1/e6ARymhY6hHY=", + "name": "63aaeb5fb29213d33cd99c1c2e0af84d713366a841535fdee804729a163a8476-notion.js", + "tag": "buck2-product-v3-notion-cli-63aaeb5fb29213d33cd99c1c2e0af84d713366a841535fdee804729a163a8476", + "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-product-v3-notion-cli-63aaeb5fb29213d33cd99c1c2e0af84d713366a841535fdee804729a163a8476/63aaeb5fb29213d33cd99c1c2e0af84d713366a841535fdee804729a163a8476-notion.js" } }, { @@ -201,7 +193,7 @@ "@opentui/core-win32-arm64", "@opentui/core-win32-x64" ], - "integrity": "sha256-kqNSfwge7StUjIbm2cj8q3KWkLLkDFTdmWPgPnmqbF4=", + "integrity": "sha256-3wgnUdxiucnd0EUcdlz/aA0OQFof+npBlCT2cVQUt1Q=", "modulePath": "notion-db.js", "platform": { "abi": "any", @@ -219,22 +211,22 @@ "runtimeContractVersion": "v1", "runtimeKind": "node", "schema": "effect-utils/javascript-product/v2", - "sizeBytes": 6247564, + "sizeBytes": 6560459, "target": "effect_utils//packages/@overeng/notion-cli:notion-db-candidate" }, - "descriptorSha256": "42454e7f901bb6fe9eca86aebabbe7a3317b509fc94e449acc2976c043d3b1b8", + "descriptorSha256": "bcafb7d0274ea251c243ad83eab378373faee995217e8ad6d62f1f58130bacde", "release": { - "hash": "sha256-kqNSfwge7StUjIbm2cj8q3KWkLLkDFTdmWPgPnmqbF4=", - "name": "92a3527f081eed2b548c86e6d9c8fcab729690b2e40c54dd9963e03e79aa6c5e-notion-db.js", - "tag": "buck2-product-v3-notion-db-runtime-92a3527f081eed2b548c86e6d9c8fcab729690b2e40c54dd9963e03e79aa6c5e", - "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-product-v3-notion-db-runtime-92a3527f081eed2b548c86e6d9c8fcab729690b2e40c54dd9963e03e79aa6c5e/92a3527f081eed2b548c86e6d9c8fcab729690b2e40c54dd9963e03e79aa6c5e-notion-db.js" + "hash": "sha256-3wgnUdxiucnd0EUcdlz/aA0OQFof+npBlCT2cVQUt1Q=", + "name": "df082751dc62b9c9ddd0451c765cff680d0e405a1ffa7a419424f6715414b754-notion-db.js", + "tag": "buck2-product-v3-notion-db-runtime-df082751dc62b9c9ddd0451c765cff680d0e405a1ffa7a419424f6715414b754", + "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-product-v3-notion-db-runtime-df082751dc62b9c9ddd0451c765cff680d0e405a1ffa7a419424f6715414b754/df082751dc62b9c9ddd0451c765cff680d0e405a1ffa7a419424f6715414b754-notion-db.js" } }, { "descriptor": { "externalCapabilities": [], "externalModules": [], - "integrity": "sha256-/0OdQkDxh8mbgsBkeYc4DRFZkM9TzKpZ+bGn53MazuY=", + "integrity": "sha256-OZ3VajOTOnlVrcgik8bASR16nBoTvVcsBWAeaW6jiZA=", "modulePath": "notion-md.js", "platform": { "abi": "any", @@ -252,15 +244,15 @@ "runtimeContractVersion": "v1", "runtimeKind": "node", "schema": "effect-utils/javascript-product/v2", - "sizeBytes": 2291830, + "sizeBytes": 2313359, "target": "effect_utils//packages/@overeng/notion-md:notion-md-candidate" }, - "descriptorSha256": "5f4daf140a3ac45ae81b20dcf43637d37e0bbe2b946ebf34bdc3db42cdd9fc10", + "descriptorSha256": "2bfe7cfdc9bf7d288a3b98c869a25425012e97520b61eeb8a4228a757ac55d7e", "release": { - "hash": "sha256-/0OdQkDxh8mbgsBkeYc4DRFZkM9TzKpZ+bGn53MazuY=", - "name": "ff439d4240f187c99b82c0647987380d115990cf53ccaa59f9b1a7e7731acee6-notion-md.js", - "tag": "buck2-product-v3-notion-md-ff439d4240f187c99b82c0647987380d115990cf53ccaa59f9b1a7e7731acee6", - "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-product-v3-notion-md-ff439d4240f187c99b82c0647987380d115990cf53ccaa59f9b1a7e7731acee6/ff439d4240f187c99b82c0647987380d115990cf53ccaa59f9b1a7e7731acee6-notion-md.js" + "hash": "sha256-OZ3VajOTOnlVrcgik8bASR16nBoTvVcsBWAeaW6jiZA=", + "name": "399dd56a33933a7955adc82293c6c0491d7a9c1a13bd572c05601e696ea38990-notion-md.js", + "tag": "buck2-product-v3-notion-md-399dd56a33933a7955adc82293c6c0491d7a9c1a13bd572c05601e696ea38990", + "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-product-v3-notion-md-399dd56a33933a7955adc82293c6c0491d7a9c1a13bd572c05601e696ea38990/399dd56a33933a7955adc82293c6c0491d7a9c1a13bd572c05601e696ea38990-notion-md.js" } }, { @@ -269,7 +261,7 @@ "npm" ], "externalModules": [], - "integrity": "sha256-E21uTtrbrnRqkRv6gNm9ayVrFv+CeKy92s7w70YUWqk=", + "integrity": "sha256-syowIz8W23x67+DZY2oimeIeylN6fJ9TUpPBg6T1dek=", "modulePath": "npm-release.js", "platform": { "abi": "any", @@ -287,15 +279,15 @@ "runtimeContractVersion": "v1", "runtimeKind": "node", "schema": "effect-utils/javascript-product/v2", - "sizeBytes": 1149580, + "sizeBytes": 1170788, "target": "effect_utils//packages/@overeng/npm-release:npm-release-candidate" }, - "descriptorSha256": "b77939c2f535e0f764991c42fd31707e01393d85b68423c5d284bc8d61b2261e", + "descriptorSha256": "efa92c4287d0762b6c82cc3f7ee1766526c14aec420d4678c6c87de4e440d25e", "release": { - "hash": "sha256-E21uTtrbrnRqkRv6gNm9ayVrFv+CeKy92s7w70YUWqk=", - "name": "136d6e4edadbae746a911bfa80d9bd6b256b16ff8278acbddacef0ef46145aa9-npm-release.js", - "tag": "buck2-product-v3-npm-release-136d6e4edadbae746a911bfa80d9bd6b256b16ff8278acbddacef0ef46145aa9", - "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-product-v3-npm-release-136d6e4edadbae746a911bfa80d9bd6b256b16ff8278acbddacef0ef46145aa9/136d6e4edadbae746a911bfa80d9bd6b256b16ff8278acbddacef0ef46145aa9-npm-release.js" + "hash": "sha256-syowIz8W23x67+DZY2oimeIeylN6fJ9TUpPBg6T1dek=", + "name": "b32a30233f16db7c7aefe0d9636a2299e21eca537a7c9f535293c183a4f575e9-npm-release.js", + "tag": "buck2-product-v3-npm-release-b32a30233f16db7c7aefe0d9636a2299e21eca537a7c9f535293c183a4f575e9", + "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-product-v3-npm-release-b32a30233f16db7c7aefe0d9636a2299e21eca537a7c9f535293c183a4f575e9/b32a30233f16db7c7aefe0d9636a2299e21eca537a7c9f535293c183a4f575e9-npm-release.js" } }, { @@ -335,7 +327,40 @@ "descriptor": { "externalCapabilities": [], "externalModules": [], - "integrity": "sha256-Jtimr06V0hTF2aj8I5fvMRmLlVRWnBmCxIDtKHYg9eY=", + "integrity": "sha256-bsFZ3bdp9YvqfQV+BcI+2vdoMLY5yOaqikV8SWXTi9g=", + "modulePath": "oxc-config-stylex-upstream-plugin.js", + "platform": { + "abi": "any", + "architecture": "any", + "os": "any" + }, + "productKind": "module", + "productName": "oxc-config-stylex-upstream-plugin", + "provenance": { + "configuredTarget": "effect_utils//packages/@overeng/oxc-config:oxc-config-stylex-upstream-plugin-candidate (effect_utils//buck2/platforms:javascript_portable#069f7ef75d9e5edc)", + "dependencyClosureIdentity": "runtime=node;package_tree=effect_utils//packages/@overeng/oxc-config:package_tree (effect_utils//buck2/platforms:javascript_portable#069f7ef75d9e5edc)", + "module": "effect_utils//packages/@overeng/oxc-config:oxc-config-stylex-upstream-plugin-candidate-module" + }, + "runtimeContract": "javascript-esm", + "runtimeContractVersion": "v1", + "runtimeKind": "node", + "schema": "effect-utils/javascript-product/v2", + "sizeBytes": 435977, + "target": "effect_utils//packages/@overeng/oxc-config:oxc-config-stylex-upstream-plugin-candidate" + }, + "descriptorSha256": "87184cd0d76da86f0b152bb9285a98690d31b6cc2db6fae61bbfdec2a7bf26e7", + "release": { + "hash": "sha256-bsFZ3bdp9YvqfQV+BcI+2vdoMLY5yOaqikV8SWXTi9g=", + "name": "6ec159ddb769f58bea7d057e05c23edaf76830b639c8e6aa8a457c4965d38bd8-oxc-config-stylex-upstream-plugin.js", + "tag": "buck2-product-v3-oxc-config-stylex-upstream-plugin-6ec159ddb769f58bea7d057e05c23edaf76830b639c8e6aa8a457c4965d38bd8", + "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-product-v3-oxc-config-stylex-upstream-plugin-6ec159ddb769f58bea7d057e05c23edaf76830b639c8e6aa8a457c4965d38bd8/6ec159ddb769f58bea7d057e05c23edaf76830b639c8e6aa8a457c4965d38bd8-oxc-config-stylex-upstream-plugin.js" + } + }, + { + "descriptor": { + "externalCapabilities": [], + "externalModules": [], + "integrity": "sha256-b5B0rutC2MkDc44v/b3JP/QJcXFtUmcb1q41yzR9uCY=", "modulePath": "tui-stories.js", "platform": { "abi": "any", @@ -353,15 +378,15 @@ "runtimeContractVersion": "v1", "runtimeKind": "node", "schema": "effect-utils/javascript-product/v2", - "sizeBytes": 2236029, + "sizeBytes": 2258031, "target": "effect_utils//packages/@overeng/tui-stories:tui-stories-candidate" }, - "descriptorSha256": "3477b301a2286907b77db5996a51a311933feb4d1945a18f5847229d0d51036e", + "descriptorSha256": "d277011d1e86853d662e3cc79618bf0635553e1d25956e053b7a3dd05119a83a", "release": { - "hash": "sha256-Jtimr06V0hTF2aj8I5fvMRmLlVRWnBmCxIDtKHYg9eY=", - "name": "26d8a6af4e95d214c5d9a8fc2397ef31198b9554569c1982c480ed287620f5e6-tui-stories.js", - "tag": "buck2-product-v3-tui-stories-26d8a6af4e95d214c5d9a8fc2397ef31198b9554569c1982c480ed287620f5e6", - "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-product-v3-tui-stories-26d8a6af4e95d214c5d9a8fc2397ef31198b9554569c1982c480ed287620f5e6/26d8a6af4e95d214c5d9a8fc2397ef31198b9554569c1982c480ed287620f5e6-tui-stories.js" + "hash": "sha256-b5B0rutC2MkDc44v/b3JP/QJcXFtUmcb1q41yzR9uCY=", + "name": "6f9074aeeb42d8c903738e2ffdbdc93ff40971716d52671bd6ae35cb347db826-tui-stories.js", + "tag": "buck2-product-v3-tui-stories-6f9074aeeb42d8c903738e2ffdbdc93ff40971716d52671bd6ae35cb347db826", + "url": "https://github.com/overengineeringstudio/effect-utils/releases/download/buck2-product-v3-tui-stories-6f9074aeeb42d8c903738e2ffdbdc93ff40971716d52671bd6ae35cb347db826/6f9074aeeb42d8c903738e2ffdbdc93ff40971716d52671bd6ae35cb347db826-tui-stories.js" } } ], diff --git a/nix/buck2-products/publish.sh b/nix/buck2-products/publish.sh index 668a7ba21e..1060cecc61 100755 --- a/nix/buck2-products/publish.sh +++ b/nix/buck2-products/publish.sh @@ -3,7 +3,7 @@ set -euo pipefail repo_root="${BUCK2_RELEASE_PRODUCTS_REPO:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P)}" -inventory="$repo_root/nix/buck2-products/manifest.json" +targets="$repo_root/nix/buck2-products/targets.json" repository="overengineeringstudio/effect-utils" dry_run=false proposal="" @@ -15,11 +15,11 @@ fail() { usage() { cat <<'EOF' -Usage: nix/buck2-products/publish.sh [--dry-run] [--inventory PATH] [--proposal PATH] +Usage: nix/buck2-products/publish.sh [--dry-run] [--targets PATH] [--proposal PATH] ---dry-run Validate the inventory and print the complete build/publication plan. ---inventory PATH Read the single release inventory contract from PATH. ---proposal PATH Write the proposed manifest outside the Git worktree (live mode only). +--dry-run Validate the target inventory and print the complete build/publication plan. +--targets PATH Read the generated desired target inventory from PATH. +--proposal PATH Write the proposed manifest outside the Git worktree (live mode only). Without this option the proposed manifest is emitted on stdout. EOF } @@ -30,9 +30,9 @@ while (($#)); do dry_run=true shift ;; - --inventory) - (($# >= 2)) || fail "--inventory requires a path" - inventory="$2" + --targets) + (($# >= 2)) || fail "--targets requires a path" + targets="$2" shift 2 ;; --proposal) @@ -48,8 +48,10 @@ while (($#)); do esac done -[[ -f "$inventory" && ! -L "$inventory" ]] || fail "inventory must be a regular, non-symlink file: $inventory" -command -v jq >/dev/null || fail "jq is required" +[[ -f "$targets" && ! -L "$targets" ]] || fail "target inventory must be a regular, non-symlink file: $targets" +for tool in jq sha256sum tr; do + command -v "$tool" >/dev/null || fail "$tool is required" +done # This mutation surface is deliberately unavailable to pull-request jobs, even # in planning mode. A PR may run the separate contract test, never this tool. @@ -57,34 +59,52 @@ if [[ -n "${GITHUB_EVENT_NAME:-}" && "${GITHUB_EVENT_NAME}" != "workflow_dispatc fail "refusing untrusted GitHub event: ${GITHUB_EVENT_NAME}" fi -inventory_check=' +target_check=' (type == "object") and - ((keys | sort) == ["products", "schema"]) and - (.schema == "effect-utils/buck2-release-products/v1") and + ((keys | sort) == ["products", "provenance", "schemaVersion"]) and + (.schemaVersion == 1) and (.products | type == "array" and length > 0) and (all(.products[]; type == "object" and - ((keys | sort) == ["descriptor", "descriptorSha256", "release"]) and - (.descriptor | type == "object") and - (.descriptor.productName | type == "string" and test("^[A-Za-z0-9][A-Za-z0-9._+-]*$")) and - (.descriptor.target | type == "string" and test("^([A-Za-z0-9_]+)?//[^[:space:]\\[\\]]+:[^[:space:]\\[\\]]+$")) + ((keys | sort) == ["name", "target"]) and + (.name | type == "string" and test("^[A-Za-z0-9][A-Za-z0-9._+-]*$")) and + (.target | type == "string" and test("^([A-Za-z0-9_]+)?//[^[:space:]\\[\\]]+:[^[:space:]\\[\\]]+$")) )) and - ([.products[].descriptor.productName] | length == (unique | length)) and - ([.products[].descriptor.target] | length == (unique | length))' -if ! jq -e "$inventory_check" "$inventory" >/dev/null; then - fail "inventory violates effect-utils/buck2-release-products/v1" + ([.products[].name] | length == (unique | length)) and + ([.products[].target] | length == (unique | length)) and + (.provenance | type == "object") and + ((.provenance | keys | sort) == ["fingerprint", "generator", "regenerationCommand", "semanticInputs", "source"]) and + (.provenance.fingerprint | type == "string" and test("^sha256:[0-9a-f]{64}$")) and + (.provenance.generator == "effect-utils/genie/buck2-javascript-release-targets") and + (.provenance.regenerationCommand == "devenv tasks run genie:run") and + (.provenance.semanticInputs == [ + "genie/buck2/javascript-product-registry.ts", + "nix/buck2-products/targets.json.genie.ts" + ]) and + (.provenance.source == "nix/buck2-products/targets.json.genie.ts")' +if ! jq -e "$target_check" "$targets" >/dev/null; then + fail "target inventory violates effect-utils/buck2-release-targets/v1" fi +declared_fingerprint="$(jq -r '.provenance.fingerprint' "$targets")" +computed_fingerprint="$(jq -cS '{ + generator: .provenance.generator, + schemaVersion: .schemaVersion, + semanticData: .products +}' "$targets" | tr -d '\n' | sha256sum)" +computed_fingerprint="sha256:${computed_fingerprint%% *}" +[[ "$declared_fingerprint" == "$computed_fingerprint" ]] || + fail "target inventory fingerprint does not match its declared products" plan="$({ jq -cS '{ schema: "effect-utils/buck2-product-publication-plan/v1", repository: "overengineeringstudio/effect-utils", products: [.products[] | { - productName: .descriptor.productName, - candidateTarget: .descriptor.target, - descriptorTarget: (.descriptor.target + "[descriptor]") + productName: .name, + candidateTarget: .target, + descriptorTarget: (.target + "[descriptor]") }] | sort_by(.productName) - }' "$inventory" + }' "$targets" })" if $dry_run; then @@ -158,13 +178,13 @@ cleanup() { } trap cleanup EXIT -mapfile -t product_rows < <(jq -r '.products | sort_by(.descriptor.productName)[] | [.descriptor.productName, .descriptor.target] | @tsv' "$inventory") -((${#product_rows[@]} > 0)) || fail "inventory contains no products" +mapfile -t product_rows < <(jq -r '.products | sort_by(.name)[] | [.name, .target] | @tsv' "$targets") +((${#product_rows[@]} > 0)) || fail "target inventory contains no products" declare -a build_targets=() for row in "${product_rows[@]}"; do IFS=$'\t' read -r product_name target <<<"$row" - [[ -n "$product_name" && -n "$target" ]] || fail "inventory contains an incomplete product declaration" + [[ -n "$product_name" && -n "$target" ]] || fail "target inventory contains an incomplete product declaration" build_targets+=("$target" "$target[descriptor]") done @@ -176,7 +196,7 @@ while IFS=' ' read -r label path extra; do [[ -z "${outputs[$label]+present}" ]] || fail "Buck returned duplicate output for $label" outputs["$label"]="$path" done <"$build_outputs" -((${#outputs[@]} == ${#build_targets[@]})) || fail "Buck output set does not exactly match the inventory build plan" +((${#outputs[@]} == ${#build_targets[@]})) || fail "Buck output set does not exactly match the target inventory build plan" for target in "${build_targets[@]}"; do [[ -n "${outputs[$target]+present}" ]] || fail "Buck returned no output for $target" done @@ -348,6 +368,7 @@ done import_root="$stage/import" mkdir -p "$import_root" cp -- "$repo_root/nix/buck2-products/default.nix" "$import_root/default.nix" +cp -- "$targets" "$import_root/targets.json" cp -- "$proposal_stage" "$import_root/manifest.json" mapfile -t realized_paths < <(nix build --no-link --print-out-paths --impure --expr "let pkgs = import { }; diff --git a/nix/buck2-products/targets.json b/nix/buck2-products/targets.json new file mode 100644 index 0000000000..aa1edd1d7f --- /dev/null +++ b/nix/buck2-products/targets.json @@ -0,0 +1,59 @@ +{ + "products": [ + { + "name": "ci-tools", + "target": "effect_utils//packages/@overeng/ci-tools:ci-tools-candidate" + }, + { + "name": "genie", + "target": "effect_utils//packages/@overeng/genie:genie-candidate" + }, + { + "name": "genie-bootstrap-closure-check", + "target": "effect_utils//packages/@overeng/genie:genie-bootstrap-closure-check-candidate" + }, + { + "name": "megarepo", + "target": "effect_utils//packages/@overeng/megarepo:megarepo-candidate" + }, + { + "name": "notion-cli", + "target": "effect_utils//packages/@overeng/notion-cli:notion-cli-candidate" + }, + { + "name": "notion-db-runtime", + "target": "effect_utils//packages/@overeng/notion-cli:notion-db-candidate" + }, + { + "name": "notion-md", + "target": "effect_utils//packages/@overeng/notion-md:notion-md-candidate" + }, + { + "name": "npm-release", + "target": "effect_utils//packages/@overeng/npm-release:npm-release-candidate" + }, + { + "name": "oxc-config", + "target": "effect_utils//packages/@overeng/oxc-config:oxc-config-candidate" + }, + { + "name": "oxc-config-stylex-upstream-plugin", + "target": "effect_utils//packages/@overeng/oxc-config:oxc-config-stylex-upstream-plugin-candidate" + }, + { + "name": "tui-stories", + "target": "effect_utils//packages/@overeng/tui-stories:tui-stories-candidate" + } + ], + "provenance": { + "fingerprint": "sha256:d26312c03856cc45ee69bc8587b4792087beb9c76f411b44f66865b374283089", + "generator": "effect-utils/genie/buck2-javascript-release-targets", + "regenerationCommand": "devenv tasks run genie:run", + "semanticInputs": [ + "genie/buck2/javascript-product-registry.ts", + "nix/buck2-products/targets.json.genie.ts" + ], + "source": "nix/buck2-products/targets.json.genie.ts" + }, + "schemaVersion": 1 +} diff --git a/nix/buck2-products/targets.json.genie.ts b/nix/buck2-products/targets.json.genie.ts new file mode 100644 index 0000000000..e6cb3a9717 --- /dev/null +++ b/nix/buck2-products/targets.json.genie.ts @@ -0,0 +1,53 @@ +import { javaScriptProductPublications } from '../../genie/buck2/javascript-product-registry.ts' +import { buck2SemanticFingerprint } from '../../genie/buck2/mod.ts' +import { + projectionArtifact, + projectionValidators, +} from '../../packages/@overeng/genie/src/runtime/mod.ts' + +const generator = 'effect-utils/genie/buck2-javascript-release-targets' +const schemaVersion = 1 +const source = 'nix/buck2-products/targets.json.genie.ts' +const semanticInputs = ['genie/buck2/javascript-product-registry.ts', source] as const +const regenerationCommand = 'devenv tasks run genie:run' + +const products = javaScriptProductPublications.map(({ label, productName }) => ({ + name: productName, + target: `effect_utils${label}`, +})) +const fingerprint = buck2SemanticFingerprint({ + generator, + schemaVersion, + semanticData: products, +}) + +/** + * Desired JavaScript product inventory. The publisher consumes this generated + * projection and remains the sole producer of manifest.json. + */ +export default projectionArtifact.json({ + schemaVersion, + data: products, + project: (declaredProducts) => ({ + products: declaredProducts, + provenance: { + fingerprint, + generator, + regenerationCommand, + semanticInputs, + source, + }, + }), + validators: [ + projectionValidators.uniqueValues({ + rule: 'buck2-javascript-release-target-unique-name', + label: 'nix/buck2-products/targets.json', + values: ({ data }) => data.map(({ name }) => name), + }), + projectionValidators.uniqueValues({ + rule: 'buck2-javascript-release-target-unique-label', + label: 'nix/buck2-products/targets.json', + values: ({ data }) => data.map(({ target }) => target), + }), + ], +}) diff --git a/nix/devenv-modules/observability.nix b/nix/devenv-modules/observability.nix index 28b563f492..c3cc232888 100644 --- a/nix/devenv-modules/observability.nix +++ b/nix/devenv-modules/observability.nix @@ -41,7 +41,7 @@ let # Temporary compatibility producer for task-phase detail. Keep otelite and # the profile/verify surface after this producer can be retired. otelSpan = import ./otel/otel-span.nix { inherit pkgs; }; - otelite = import (../../packages + "/@overeng/otelite/nix/build.nix") { inherit pkgs; }; + otelite = (import ../buck2-native-products { inherit pkgs; }).products.otelite; capture = if profile == null then diff --git a/nix/devenv-modules/otel.nix b/nix/devenv-modules/otel.nix index 86a05657a0..b010eef02e 100644 --- a/nix/devenv-modules/otel.nix +++ b/nix/devenv-modules/otel.nix @@ -83,7 +83,6 @@ let "devenv-tasks" "devenv-task-duration-trends" "shell-entry" - "pnpm-install" "ts-app-traces" ]; }; diff --git a/nix/devenv-modules/otel/dashboards/devenv-task-duration-trends.jsonnet b/nix/devenv-modules/otel/dashboards/devenv-task-duration-trends.jsonnet index 39ad882851..349eb11c75 100644 --- a/nix/devenv-modules/otel/dashboards/devenv-task-duration-trends.jsonnet +++ b/nix/devenv-modules/otel/dashboards/devenv-task-duration-trends.jsonnet @@ -8,14 +8,13 @@ // // Main tasks tracked: // - check:quick (the most common developer workflow) -// - ts:check, ts:build, ts:emit (TypeScript compilation) -// - pnpm:install (dependency installation) +// - buck2:check (bounded TypeScript, test, and product authority) +// - buck2:editor:* (dependency projection) // - genie:run (config generation) // - lint:check (linting) // - test:run (test execution) // - mr:fetch-apply (repo synchronization) // - nix:build, nix:check (Nix operations) -// - tsc per-project breakdown (from extendedDiagnostics spans) local g = import 'g.libsonnet'; local lib = import 'lib.libsonnet'; local at = lib.at; @@ -75,22 +74,6 @@ local taskExecDurationPanel(title, taskFilter) = ], ); -// Helper: tsc project breakdown panel (from extendedDiagnostics child spans) -local tscProjectPanel(title) = - lib.durationTimeSeries( - title, - [ - lib.tempoMetricsQuery( - '{resource.service.name="effect-utils-devenv" && name="typescript.project.check"} | quantile_over_time(duration, 0.5) by (span.ts.project.name)', - 'p50', - ), - lib.tempoMetricsQuery( - '{resource.service.name="effect-utils-devenv" && name="typescript.project.check"} | quantile_over_time(duration, 0.95) by (span.ts.project.name)', - 'p95', - ), - ], - ); - // Y positions for layout (each row header is 1 unit, content is 8 units) local y = { // Row 1: Top-level overview @@ -99,33 +82,27 @@ local y = { // Row 2: check:quick (most common workflow) checkQuickRow: 9, checkQuickContent: 10, - // Row 3: TypeScript - tsRow: 18, - tsContent: 19, - // Row 4: Install + Genie - installRow: 27, - installContent: 28, - // Row 5: Lint Components - lintRow: 36, - lintContent: 37, - // Row 6: Test Execution - testRow: 45, - testContent: 46, - // Row 7: Nix Operations - nixRow: 54, - nixContent: 55, - // Row 8: Megarepo + Other - megarepoRow: 63, - megarepoContent: 64, - // Row 9: Shell Entry Performance - shellRow: 72, - shellContent: 73, - // Row 10: Per-Package Install Times - pkgInstallRow: 81, - pkgInstallContent: 82, - // Row 11: TypeScript Per-Project Breakdown - tscProjectRow: 90, - tscProjectContent: 91, + // Row 3: Dependency views + Genie + editorRow: 18, + editorContent: 19, + // Row 4: Lint Components + lintRow: 27, + lintContent: 28, + // Row 5: Test Execution + testRow: 36, + testContent: 37, + // Row 6: Nix Operations + nixRow: 45, + nixContent: 46, + // Row 7: Megarepo + Other + megarepoRow: 54, + megarepoContent: 55, + // Row 8: Shell Entry Performance + shellRow: 63, + shellContent: 64, + // Row 9: Per-package editor view times + packageEditorRow: 72, + packageEditorContent: 73, }; g.dashboard.new('devenv task Duration Trends') @@ -185,48 +162,28 @@ g.dashboard.new('devenv task Duration Trends') at( taskDurationPanel( 'check:quick sub-tasks (p50 / p95 / p99)', - 'ts:check|lint:check:oxlint|lint:check:format|lint:check:genie|genie:run|nix:check:quick:.*|workspace:check', + 'buck2:check|lint:check:oxlint|lint:check:format|lint:check:genie|genie:run|nix:check:quick:.*|workspace:check', ), 12, y.checkQuickContent, 12, 8, ), // ========================================================================= - // Row 3: TypeScript — ts:check, ts:build, and ts:emit + // Row 3: Dependency Views + Genie // ========================================================================= - at(g.panel.row.new('TypeScript Compilation'), 0, y.tsRow, 24, 1), - - at( - taskDurationPanel('ts:check duration (p50 / p95 / p99)', 'ts:check'), - 0, y.tsContent, 8, 8, - ), + at(g.panel.row.new('Dependency Views + Config Generation'), 0, y.editorRow, 24, 1), at( - taskDurationPanel('ts:build duration (p50 / p95 / p99)', 'ts:build'), - 8, y.tsContent, 8, 8, - ), - - at( - taskDurationPanel('ts:emit duration (p50 / p95 / p99)', 'ts:emit'), - 16, y.tsContent, 8, 8, - ), - - // ========================================================================= - // Row 4: Install + Genie - // ========================================================================= - at(g.panel.row.new('Install + Config Generation'), 0, y.installRow, 24, 1), - - at( - taskDurationPanel('pnpm:install (aggregate) (p50 / p95 / p99)', 'pnpm:install.*'), - 0, y.installContent, 12, 8, + taskDurationPanel('Editor dependency views (p50 / p95 / p99)', 'buck2:editor:bootstrap|buck2:editor:publish|buck2:editor:check'), + 0, y.editorContent, 12, 8, ), at( taskDurationPanel('genie:run duration (p50 / p95 / p99)', 'genie:run'), - 12, y.installContent, 12, 8, + 12, y.editorContent, 12, 8, ), // ========================================================================= - // Row 5: Lint Components + // Row 4: Lint Components // ========================================================================= at(g.panel.row.new('Lint Components'), 0, y.lintRow, 24, 1), @@ -246,7 +203,7 @@ g.dashboard.new('devenv task Duration Trends') ), // ========================================================================= - // Row 6: Test Execution + // Row 5: Test Execution // ========================================================================= at(g.panel.row.new('Test Execution'), 0, y.testRow, 24, 1), @@ -265,7 +222,7 @@ g.dashboard.new('devenv task Duration Trends') ), // ========================================================================= - // Row 7: Nix Operations + // Row 6: Nix Operations // ========================================================================= at(g.panel.row.new('Nix Operations'), 0, y.nixRow, 24, 1), @@ -280,7 +237,7 @@ g.dashboard.new('devenv task Duration Trends') ), // ========================================================================= - // Row 8: Megarepo + Other + // Row 7: Megarepo + Other // ========================================================================= at(g.panel.row.new('Megarepo + Other'), 0, y.megarepoRow, 24, 1), @@ -300,7 +257,7 @@ g.dashboard.new('devenv task Duration Trends') ), // ========================================================================= - // Row 9: Shell Entry Performance + // Row 8: Shell Entry Performance // ========================================================================= at(g.panel.row.new('Shell Entry Performance'), 0, y.shellRow, 24, 1), @@ -330,31 +287,22 @@ g.dashboard.new('devenv task Duration Trends') at( taskDurationPanel( 'Shell entry sub-tasks (p50 / p95)', - 'setup:gate|pnpm:install|genie:run|mr:fetch-apply|ts:emit|setup:completions|devenv:.*', + 'setup:gate|buck2:editor:bootstrap|genie:run|mr:apply|buck2:editor:publish|setup:completions|devenv:.*', ), 12, y.shellContent, 12, 8, ), // ========================================================================= - // Row 10: Per-Package Install Times + // Row 9: Per-Package Editor Views // ========================================================================= - at(g.panel.row.new('Per-Package Install Times'), 0, y.pkgInstallRow, 24, 1), + at(g.panel.row.new('Per-Package Editor View Times'), 0, y.packageEditorRow, 24, 1), at( taskDurationPanel( - 'pnpm:install per-package (p50 / p95)', - 'pnpm:install:tui-react|pnpm:install:megarepo|pnpm:install:genie|pnpm:install:notion-cli|pnpm:install:utils|pnpm:install:effect-path|pnpm:install:effect-react|pnpm:install:effect-rpc-tanstack|pnpm:install:effect-schema-form|pnpm:install:effect-schema-form-aria|pnpm:install:effect-ai-claude-cli|pnpm:install:react-inspector|pnpm:install:tui-core|pnpm:install:notion-effect-client|pnpm:install:notion-effect-schema|pnpm:install:oxc-config|pnpm:install:utils-dev', + 'Editor dependency view publication (p50 / p95)', + 'buck2:editor:publish|buck2:editor:check', ), - 0, y.pkgInstallContent, 24, 8, + 0, y.packageEditorContent, 24, 8, ), - // ========================================================================= - // Row 11: TypeScript Per-Project Breakdown (from tsc --extendedDiagnostics) - // ========================================================================= - at(g.panel.row.new('TypeScript Per-Project Breakdown (tsc diagnostics)'), 0, y.tscProjectRow, 24, 1), - - at( - tscProjectPanel('tsc per-project compilation time (p50 / p95)'), - 0, y.tscProjectContent, 24, 8, - ), ]) diff --git a/nix/devenv-modules/otel/dashboards/pnpm-install.jsonnet b/nix/devenv-modules/otel/dashboards/pnpm-install.jsonnet deleted file mode 100644 index 882a825376..0000000000 --- a/nix/devenv-modules/otel/dashboards/pnpm-install.jsonnet +++ /dev/null @@ -1,97 +0,0 @@ -// pnpm Install Deep-Dive dashboard -// Per-package install analysis. Directly addresses network overhead from #110/#114. -local g = import 'g.libsonnet'; -local lib = import 'lib.libsonnet'; -local at = lib.at; - -local y = { - statsRow: 0, - stats: 1, - installRow: 5, - install: 6, - perPkgRow: 16, - perPkg: 17, - noteRow: 27, - note: 28, -}; - -g.dashboard.new('pnpm Install Deep-Dive') -+ g.dashboard.withUid('otel-pnpm-install') -+ g.dashboard.withDescription('Per-package pnpm install timing and cache analysis') -+ g.dashboard.graphTooltip.withSharedCrosshair() -+ g.dashboard.withTimezone('browser') -+ g.dashboard.withPanels([ - - // Row: Aggregate stats - at(g.panel.row.new('Aggregate Install'), 0, y.statsRow, 24, 1), - - at( - g.panel.stat.new('Total installs') - + g.panel.stat.queryOptions.withTargets([ - lib.tempoQuery('{resource.service.name="effect-utils-devenv" && name="devenv.task.exec" && span.task.name="pnpm:install"}', 'A', 100), - ]), - 0, y.stats, 8, 4, - ), - - at( - g.panel.stat.new('Per-package installs') - + g.panel.stat.queryOptions.withTargets([ - lib.tempoQuery('{resource.service.name="effect-utils-devenv" && name="devenv.task.exec" && span.task.name=~"pnpm:install:.*"}', 'A', 100), - ]), - 8, y.stats, 8, 4, - ), - - at( - g.panel.stat.new('Failed installs') - + g.panel.stat.queryOptions.withTargets([ - lib.tempoQuery('{resource.service.name="effect-utils-devenv" && name="devenv.task.exec" && span.task.name=~"pnpm:install.*" && status.code=error}', 'A', 100), - ]), - 16, y.stats, 8, 4, - ), - - // Row: All install traces - at(g.panel.row.new('Install Traces'), 0, y.installRow, 24, 1), - - at( - lib.tempoTable( - 'pnpm:install aggregate traces (shows total duration)', - '{resource.service.name="effect-utils-devenv" && name="devenv.task.exec" && span.task.name="pnpm:install"}', - 'A', - 50, - ), - 0, y.install, 24, 10, - ), - - // Row: Per-package breakdown - at(g.panel.row.new('Per-Package Traces'), 0, y.perPkgRow, 24, 1), - - at( - lib.tempoTable( - 'Per-package install traces (pnpm:install:*)', - '{resource.service.name="effect-utils-devenv" && name="devenv.task.exec" && span.task.name=~"pnpm:install:.*"}', - 'A', - 100, - ), - 0, y.perPkg, 24, 10, - ), - - // Row: Sequential chain analysis - at(g.panel.row.new('Sequential Chain'), 0, y.noteRow, 24, 1), - - at( - g.panel.text.new('Sequential Chain Note') - + g.panel.text.options.withContent(||| - ## Sequential Chain Analysis - - pnpm installs run **sequentially** to avoid race conditions from overlapping - workspace members. To see the full sequential chain, click on a `pnpm:install` - trace above to see its child spans (one per package). - - Look for: - - **Long individual packages**: which package takes the most time? - - **Network vs cached**: uncached installs (cold) are much slower - - **Total wall time**: sum of all sequential packages - |||), - 0, y.note, 24, 6, - ), -]) diff --git a/nix/devenv-modules/otel/dashboards/shell-entry.jsonnet b/nix/devenv-modules/otel/dashboards/shell-entry.jsonnet index 64af449122..5fb575497e 100644 --- a/nix/devenv-modules/otel/dashboards/shell-entry.jsonnet +++ b/nix/devenv-modules/otel/dashboards/shell-entry.jsonnet @@ -1,8 +1,8 @@ // Shell Entry (enterShell) dashboard // How long do shell entry tasks take, with breakdown by task. // -// Shell entry runs optional tasks: pnpm:install, genie:run, mr:apply -// These tasks are only executed when their dependencies change (git hash caching). +// Shell entry runs dependency bootstrap, generation, composition, and authoritative publication. +// These tasks are only executed when their dependencies change. // Use FORCE_SETUP=1 to force re-run even when cached. local g = import 'g.libsonnet'; local lib = import 'lib.libsonnet'; @@ -30,7 +30,7 @@ local traceTable(title, query, limit=50) = g.dashboard.new('Shell Entry Performance') + g.dashboard.withUid('otel-shell-entry') -+ g.dashboard.withDescription('Performance breakdown of devenv shell entry tasks (pnpm:install, genie:run, mr:apply)') ++ g.dashboard.withDescription('Performance breakdown of dependency bootstrap, generation, composition, and authoritative editor publication') + g.dashboard.graphTooltip.withSharedCrosshair() + g.dashboard.withTimezone('browser') + g.dashboard.withPanels( @@ -39,8 +39,8 @@ g.dashboard.new('Shell Entry Performance') g.panel.row.new('Shell Entry Tasks'), traceTable( - 'All shell entry tasks (pnpm:install, genie:run, mr:apply)', - '{resource.service.name="effect-utils-devenv" && name="devenv.task.exec" && span.task.name=~"pnpm:install|genie:run|mr:apply"}', + 'All shell entry tasks', + '{resource.service.name="effect-utils-devenv" && name="devenv.task.exec" && span.task.name=~"buck2:editor:bootstrap|genie:run|mr:apply|buck2:editor:publish"}', 50, ), @@ -48,8 +48,8 @@ g.dashboard.new('Shell Entry Performance') g.panel.row.new('Task Breakdown'), traceTable( - 'pnpm:install', - '{resource.service.name="effect-utils-devenv" && name="devenv.task.exec" && span.task.name="pnpm:install"}', + 'buck2:editor:bootstrap', + '{resource.service.name="effect-utils-devenv" && name="devenv.task.exec" && span.task.name="buck2:editor:bootstrap"}', 30, ), @@ -64,5 +64,11 @@ g.dashboard.new('Shell Entry Performance') '{resource.service.name="effect-utils-devenv" && name="devenv.task.exec" && span.task.name="mr:apply"}', 30, ), + + traceTable( + 'buck2:editor:publish', + '{resource.service.name="effect-utils-devenv" && name="devenv.task.exec" && span.task.name="buck2:editor:publish"}', + 30, + ), ], panelWidth=24, panelHeight=10) ) diff --git a/nix/devenv-modules/tasks/README.md b/nix/devenv-modules/tasks/README.md index b1a82a09d8..2857325b1d 100644 --- a/nix/devenv-modules/tasks/README.md +++ b/nix/devenv-modules/tasks/README.md @@ -134,9 +134,7 @@ They assume the effect-utils repo structure and are not exported in flake.nix. ### Available Modules: -- `asset-import-type-reference.nix` - effect-utils package export policy check for asset side-effect imports - `devenv-module-tests.nix` - CI task that runs shell tests for reusable task modules -- `workspace-check.nix` - Validates `allPackages` in devenv.nix matches filesystem ## `lib/` - Shared Utilities diff --git a/nix/devenv-modules/tasks/local/asset-import-type-reference.nix b/nix/devenv-modules/tasks/local/asset-import-type-reference.nix deleted file mode 100644 index dc0ce04a07..0000000000 --- a/nix/devenv-modules/tasks/local/asset-import-type-reference.nix +++ /dev/null @@ -1,57 +0,0 @@ -{ lib, pkgs, ... }: -let - trace = import ../lib/trace.nix { inherit lib; }; - git = "${pkgs.git}/bin/git"; -in -{ - tasks."lint:check:asset-import-needs-type-reference" = { - description = "Require a /// for asset side-effect imports in compiled source"; - exec = trace.exec "lint:check:asset-import-needs-type-reference" '' - set -euo pipefail - - # A bare `import '...css'` (or scss/sass/less) in compiled, exported source needs an ambient - # `*.css` declaration to type it. If that ambient lives only in a floating `.d.ts` pulled in - # by this package's own tsconfig `include`, it does NOT travel into a downstream consumer - # that compiles this source via `exports`-resolution — the side-effect import then fails with - # TS2882 (see #837). A `/// ` directive in the SAME file is part of - # that file's load graph, so the declaration travels into every program that compiles it. - # - # This guard requires that any compiled-source file with an asset side-effect import also - # carries a `/// `. It runs out-of-band (an inline `oxlint-disable` of - # `no-unassigned-import` cannot suppress it). Exempts the globs where side-effect imports are - # allowed and not type-checked into downstream graphs: `.storybook/**`, `*.gen.*`, `*.d.ts`, - # `*.test.*`, `*.stories.*`. - offenders=$( - { - ${git} ls-files -- 'packages/*/src/**/*.ts' 'packages/*/src/**/*.tsx' \ - 'context/**/*.ts' 'context/**/*.tsx' - ${git} ls-files --others --exclude-standard -- \ - 'packages/*/src/**/*.ts' 'packages/*/src/**/*.tsx' \ - 'context/**/*.ts' 'context/**/*.tsx' - } | sort -u | while IFS= read -r f; do - [ -z "$f" ] && continue - case "$f" in - */.storybook/*|*.gen.*|*.d.ts|*.test.*|*.stories.*) continue ;; - esac - ${pkgs.gawk}/bin/awk ' - /^[[:space:]]*import[[:space:]]+['"'"'"][^'"'"'"]*\.(css|scss|sass|less)['"'"'"]/ { asset = 1 } - /^[[:space:]]*\/\/\/[[:space:]]*' to a shipped '*.css' ambient in the importing" - echo "file so the declaration travels into downstream TS checks (see #837), or move the" - echo "import under a '.storybook/*' entry that is not type-checked downstream." - exit 1 - fi - echo "All asset side-effect imports in compiled source carry a type reference" - ''; - }; - - tasks."lint:check".after = lib.mkAfter [ "lint:check:asset-import-needs-type-reference" ]; -} diff --git a/nix/devenv-modules/tasks/local/workspace-check.nix b/nix/devenv-modules/tasks/local/workspace-check.nix deleted file mode 100644 index 95b3b589ca..0000000000 --- a/nix/devenv-modules/tasks/local/workspace-check.nix +++ /dev/null @@ -1,54 +0,0 @@ -# Local workspace validation for effect-utils repo -# -# This module is LOCAL to the effect-utils repo and NOT meant for reuse. -# It validates repo-specific configuration like allPackages in devenv.nix. -# -# Provides: workspace:check -{ pkgs, lib, ... }: -let - trace = import ../lib/trace.nix { inherit lib; }; -in -{ - tasks."workspace:check" = { - description = "Validate workspace configuration (allPackages)"; - exec = trace.exec "workspace:check" '' - set -euo pipefail - - echo "Checking allPackages matches filesystem packages..." - - # Find all packages/@overeng/* directories that have package.json (real packages) - actual=$(find packages/@overeng -maxdepth 1 -type d -exec test -f {}/package.json \; -print | sort) - - # Extract packages from allPackages list in devenv.nix - declared=$(grep -o '"packages/@[^"]*"' devenv.nix | tr -d '"' | sort) - - # Find packages on filesystem but not in allPackages - missing=$(comm -23 <(echo "$actual") <(echo "$declared")) - - if [ -n "$missing" ]; then - echo "" - echo "❌ Error: These packages exist but are NOT in allPackages:" - echo "$missing" | sed 's/^/ /' - echo "" - echo "Add them to allPackages in devenv.nix:" - echo "$missing" | while read -r pkg; do - echo " \"$pkg\"" - done - echo "" - exit 1 - fi - - # Find packages in allPackages that don't exist on filesystem - orphaned=$(comm -13 <(echo "$actual") <(echo "$declared")) - - if [ -n "$orphaned" ]; then - echo "" - echo "⚠️ Warning: These packages are in allPackages but don't exist on filesystem:" - echo "$orphaned" | sed 's/^/ /' - echo "" - fi - - echo "✓ allPackages is complete and matches filesystem" - ''; - }; -} diff --git a/nix/devenv-modules/tasks/shared/nix-cli.nix b/nix/devenv-modules/tasks/shared/nix-cli.nix index 71538805e5..6067e8f965 100644 --- a/nix/devenv-modules/tasks/shared/nix-cli.nix +++ b/nix/devenv-modules/tasks/shared/nix-cli.nix @@ -5,9 +5,9 @@ # (inputs.effect-utils.devenvModules.tasks.nix-cli { # cliPackages = [ # { -# name = "oxlint-npm"; -# flakeRef = ".#oxlint-npm"; -# hashSource = "nix/oxc-config-plugin.nix"; +# name = "source-built-cli"; +# flakeRef = ".#source-built-cli"; +# hashSource = "nix/source-built-cli.nix"; # lockfile = "pnpm-lock.yaml"; # } # ]; @@ -44,6 +44,7 @@ # - nix:flake:check - Runs `nix flake check` (validates entire flake, all packages) { cliPackages ? [ ], + dependencyTask ? "pnpm:install", }: { pkgs, lib, ... }: let @@ -311,9 +312,9 @@ let "nix:check:${pkg.name}" = { description = "Check if ${pkg.name} hash is stale (full build)"; exec = trace.exec "nix:check:${pkg.name}" "${checkHashScript} '${pkg.flakeRef}' '${pkg.name}' '${pkg.hashSource}' '${pkg.lockfile or ""}' '${pkg.packageJson or ""}'"; - # Depends on the full workspace pnpm:install so the staged build inputs - # stay synchronized with the authoritative repo-root lockfile. - after = lib.optional (pkg ? lockfile) "pnpm:install"; + # Consumers may order lockfile-backed inputs after their dependency + # publisher. A null task keeps the Nix check independent. + after = lib.optional (pkg ? lockfile && dependencyTask != null) dependencyTask; }; }; @@ -349,15 +350,30 @@ let hasPackages = cliPackages != [ ]; in -lib.mkIf hasPackages { +{ tasks = lib.mkMerge ( - # Per-package tasks - (map mkBuildTask cliPackages) - ++ (map mkCheckTask cliPackages) - ++ (map mkQuickCheckTask packagesWithLockfile) - ++ - # Aggregate tasks - [ + [ + { + # These are repository-wide Nix validation surfaces, not pnpm FOD + # surfaces. Keep them present even when no source-built CLI packages + # remain so check:quick and check:all retain valid dependency edges. + "nix:check:quick" = { + description = "Quick lockfile fingerprint check for all CLI packages"; + after = map (p: "nix:check:quick:${p.name}") packagesWithLockfile; + }; + + "nix:flake:check" = { + description = "Full nix flake validation (builds all flake packages)"; + exec = trace.exec "nix:flake:check" "${pkgs.nix}/bin/nix flake check"; + }; + } + ] + ++ lib.optionals hasPackages ( + # Source-build and FOD checks exist only when consumers declare packages. + (map mkBuildTask cliPackages) + ++ (map mkCheckTask cliPackages) + ++ (map mkQuickCheckTask packagesWithLockfile) + ++ [ { "nix:build" = { description = "Build all CLI Nix packages"; @@ -367,19 +383,10 @@ lib.mkIf hasPackages { "nix:check" = { description = "Check if any CLI hashes are stale (for CI, full build)"; exec = trace.exec "nix:check" "${sequentialNixCheckScript}"; - after = lib.optional (packagesWithLockfile != [ ]) "pnpm:install"; - }; - - "nix:check:quick" = { - description = "Quick lockfile fingerprint check for all CLI packages"; - after = map (p: "nix:check:quick:${p.name}") packagesWithLockfile; - }; - - "nix:flake:check" = { - description = "Full nix flake validation (builds all flake packages)"; - exec = trace.exec "nix:flake:check" "${pkgs.nix}/bin/nix flake check"; + after = lib.optional (packagesWithLockfile != [ ] && dependencyTask != null) dependencyTask; }; } ] + ) ); } diff --git a/nix/devenv-modules/tasks/shared/pnpm.nix b/nix/devenv-modules/tasks/shared/pnpm.nix index 3d2ef5dcfb..dea5b88ec5 100644 --- a/nix/devenv-modules/tasks/shared/pnpm.nix +++ b/nix/devenv-modules/tasks/shared/pnpm.nix @@ -4,12 +4,15 @@ # The repo-root pnpm-lock.yaml is the only authoritative lockfile for this # live-worktree model. # -# Provides: +# Provides in materialization mode: # - pnpm:install # - pnpm:update # - pnpm:dedupe # - pnpm:clean # - pnpm:reset-lock-files +# +# With `materialize = false`, only the lockfile authoring tasks remain and every +# pnpm mutation is forced to `--lockfile-only`. { packages, workspaceRoot ? ".", @@ -17,6 +20,7 @@ taskSuffix ? null, globalCache ? true, frozenInCi ? true, + materialize ? true, installFlags ? [ ], # Canonical package-source directories consumed from outside this # Materialization Root. Each path is staged once under root-owned `.devenv` @@ -135,6 +139,7 @@ let ] ++ pnpmInstallPolicy.liveInstallPolicyFlags; pureInstallFlagsString = lib.escapeShellArgs pureInstallFlags; + lockfileOnlyFlag = lib.optionalString (!materialize) " --lockfile-only"; packageNameToPath = builtins.listToAttrs ( builtins.filter (x: x != null) ( @@ -508,7 +513,7 @@ let fi set +e - ${lib.escapeShellArg "${effectivePnpmLockMutatorPkg}/bin/pnpm"} install --fix-lockfile \ + ${lib.escapeShellArg "${effectivePnpmLockMutatorPkg}/bin/pnpm"} install --fix-lockfile${lockfileOnlyFlag} \ ${liveRealizationPolicyFlagsString} \ --config.package-import-method="$PNPM_PACKAGE_IMPORT_METHOD" \ --config.store-dir="$npm_config_store_dir" @@ -751,7 +756,7 @@ let cd ${lib.escapeShellArg workspaceRootAbs} ${managedPnpmMutationPrologue} ${stageSourceInputs} - pnpm dedupe ${liveRealizationPolicyFlagsString} \ + pnpm dedupe${lockfileOnlyFlag} ${liveRealizationPolicyFlagsString} \ --config.package-import-method="$PNPM_PACKAGE_IMPORT_METHOD" \ --config.store-dir="$npm_config_store_dir" ${gcSourceInputs} @@ -839,6 +844,17 @@ let ''; }; }; + selectedTasks = + if materialize then + allTasks + else + removeAttrs allTasks [ + installTaskName + cleanTaskName + doctorTaskName + repairTaskName + migrateLegacyStoreTaskName + ]; in assert lib.assertMsg pnpmLockMutatorOverrideIsSupported '' @@ -849,7 +865,7 @@ assert lib.assertMsg pnpmLockMutatorOverrideIsSupported '' assert lib.assertMsg (!sourceInputPathsOverlap) "sourceInputPaths entries must not overlap"; { packages = cliGuard.fromTasks { - tasks = allTasks; + tasks = selectedTasks; reals = lib.optionalAttrs (pnpmPkg != null) { pnpm = pnpmPkg; }; }; @@ -861,5 +877,5 @@ assert lib.assertMsg (!sourceInputPathsOverlap) "sourceInputPaths entries must n export npm_config_pm_on_fail=ignore ''; - tasks = cliGuard.stripGuards allTasks; + tasks = cliGuard.stripGuards selectedTasks; } diff --git a/nix/devenv-modules/tasks/shared/tests/megarepo-status.test.sh b/nix/devenv-modules/tasks/shared/tests/megarepo-status.test.sh index 7bc7f12142..1c160eaf46 100755 --- a/nix/devenv-modules/tasks/shared/tests/megarepo-status.test.sh +++ b/nix/devenv-modules/tasks/shared/tests/megarepo-status.test.sh @@ -224,6 +224,7 @@ for runtime_name in \ MR_COMPOSITION_GIT_BIN \ MR_COMPOSITION_WATCHMAN_BIN \ MR_CAPABILITY_NIX_BIN \ + MR_CAPABILITY_PROJECTION \ MR_CAPABILITY_MV_BIN do if ! grep -F "env.$runtime_name =" "$devenv_file" >/dev/null; then diff --git a/nix/devenv-modules/tasks/shared/tests/nix-cli-no-hash-refresh.test.sh b/nix/devenv-modules/tasks/shared/tests/nix-cli-no-hash-refresh.test.sh index fe8ef2c11b..8d85c1d016 100755 --- a/nix/devenv-modules/tasks/shared/tests/nix-cli-no-hash-refresh.test.sh +++ b/nix/devenv-modules/tasks/shared/tests/nix-cli-no-hash-refresh.test.sh @@ -14,8 +14,16 @@ if grep -qi 'ever''green' "$module"; then exit 1 fi +if grep -q '^lib\.mkIf hasPackages {' "$module"; then + echo "empty cliPackages still disables repository-wide Nix validation" + exit 1 +fi + +grep -q 'lib.optionals hasPackages' "$module" +grep -q '"nix:check:quick"' "$module" +grep -q '"nix:flake:check"' "$module" grep -q 'nix:build' "$module" grep -q 'nix:check' "$module" grep -q 'refresh Nix FOD hashes' "$module" -echo "nix-cli hash-refresh task surfaces are absent" +echo "nix-cli keeps universal validation while hash-refresh surfaces stay absent" diff --git a/nix/devenv-modules/tasks/shared/tests/oxlint-plugin-injection.test.sh b/nix/devenv-modules/tasks/shared/tests/oxlint-plugin-injection.test.sh index a9b0b1b591..9f105e325f 100755 --- a/nix/devenv-modules/tasks/shared/tests/oxlint-plugin-injection.test.sh +++ b/nix/devenv-modules/tasks/shared/tests/oxlint-plugin-injection.test.sh @@ -1,17 +1,16 @@ #!/usr/bin/env bash # Regression tests for nix/oxlint-with-plugins.nix. # -# The wrapper rewrites a project's oxlint config so the `@overeng/oxc-config` JS -# plugin resolves. Three defects it used to have, each reproduced here against the -# REAL built wrapper and the real oxlint binary rather than a stub, because all -# three were failures of plugin RESOLUTION — the one thing a stub cannot model: +# The wrapper rewrites a project's oxlint config so both JavaScript plugin entry +# points owned by @overeng/oxc-config resolve from immutable Buck products. The +# tests use the real built wrapper and oxlint binary because plugin resolution is +# the observable boundary: # -# 1. it replaced `jsPlugins` wholesale, so no third-party JS plugin could load -# beside ours ("Plugin 'x' not found"); -# 2. `oxlint --config X ...` with the config flag FIRST exited 1 with no output -# at all, which in a pipeline is indistinguishable from a lint failure; -# 3. the injected plugin is a build-time snapshot, so a newly added rule -# reported "not found in plugin 'overeng'" and could not be exercised. +# 1. unrelated plugin entries remain untouched; +# 2. the overeng and @stylexjs entries are substituted independently; +# 3. explicit live-source overrides remain separate authoring escape hatches; +# 4. a configured namespace with a missing or malformed entry fails closed; +# 5. argument-order and persistent-cache behavior remain stable. set -euo pipefail TESTS_DIR="$(cd "$(dirname "$0")" && pwd)" @@ -48,6 +47,14 @@ assert_equals() { echo " ok: $label" } +assert_nonzero() { + local actual="$1" label="$2" + if [ "$actual" -eq 0 ]; then + fail "$label" "expected a non-zero exit status" + fi + echo " ok: $label" +} + echo "Running oxlint plugin injection tests..." echo "" @@ -80,8 +87,8 @@ workspace="$tmpdir/workspace" mkdir -p "$workspace/oxc-config/src" "$workspace/live/oxc-config/src" cd "$workspace" -# A third-party JS plugin, standing in for @stylexjs/eslint-plugin. Namespace -# comes from `meta.name`, so the assertions can name it. +# An unrelated third-party JS plugin. Namespace comes from `meta.name`, so the +# assertions can name it. cat > probe-plugin.js <<'EOF' module.exports = { meta: { name: 'probe', version: '0.0.1' }, @@ -143,6 +150,27 @@ export default { } EOF +# A separate live plugin under the `@stylexjs` namespace. It deliberately has a +# rule absent from the immutable product, proving that its override changes only +# the StyleX entry while the overeng entry keeps resolving from its own product. +cat > live/oxc-config/src/stylex-upstream-plugin.ts <<'EOF' +export default { + meta: { name: '@stylexjs', version: '0.0.1' }, + rules: { + 'live-source-only': { + meta: { messages: { hit: 'live StyleX plugin source fired' } }, + create(context: { report: (d: unknown) => void }) { + return { + DebuggerStatement(node: unknown) { + context.report({ node, messageId: 'hit' }) + }, + } + }, + }, + }, +} +EOF + cat > fixture.ts <<'EOF' debugger export const now = Date.now() @@ -184,8 +212,29 @@ out="$("$wrapper" fixture.ts --config .oxlintrc.json 2>&1 || true)" assert_contains "sibling(always-report)" "$out" "sibling plugin entry survives the rewrite" assert_contains "overeng(no-raw-nondeterminism)" "$out" "our entry point is the one substituted" + +echo "" +echo "Test 3: the two owned plugin entries are substituted independently" +write_config <<'EOF' +{ + "jsPlugins": [ + "./oxc-config/src/mod.ts", + "./oxc-config/src/stylex-upstream-plugin.ts" + ], + "rules": { + "overeng/no-raw-nondeterminism": "error", + "@stylexjs/live-source-only": "error" + } +} +EOF +status_stylex_live=0 +out="$(OVERENG_STYLEX_UPSTREAM_PLUGIN="$workspace/live/oxc-config/src/stylex-upstream-plugin.ts" \ + "$wrapper" fixture.ts --config .oxlintrc.json 2>&1)" || status_stylex_live=$? +assert_contains "@stylexjs(live-source-only)" "$out" "StyleX live-source entry is substituted" +assert_contains "overeng(no-raw-nondeterminism)" "$out" "overeng entry keeps its own product" +assert_equals "1" "$status_stylex_live" "violations from both plugin products fail the run" echo "" -echo "Test 3: the config flag may come first (bug 2)" +echo "Test 4: the config flag may come first (bug 2)" write_config <<'EOF' { "jsPlugins": ["./oxc-config/src/mod.ts"], @@ -208,7 +257,7 @@ echo "" # a hash crawler mid-read. So the contract is not "nothing is left behind" — # it is "what is left behind has the one deterministic name the gitignore # covers", and the randomly-suffixed STAGED file never lands in the tree. -echo "Test 4: the published cache is deterministic and gitignore-covered" +echo "Test 5: the published cache is deterministic and gitignore-covered" published="$(find . -maxdepth 1 -name '.oxlint-with-plugins.*' -print | sort)" assert_equals "./.oxlint-with-plugins.json" "$published" \ "exactly the one deterministic cache name is published" @@ -216,7 +265,7 @@ staged_leak="$(find . -maxdepth 1 -name 'oxlint-with-plugins.*' -print)" assert_equals "" "$staged_leak" "no randomly-suffixed staged config leaks into the tree" echo "" -echo "Test 5: OVERENG_OXC_CONFIG_PLUGIN lints live plugin source (bug 3)" +echo "Test 6: OVERENG_OXC_CONFIG_PLUGIN lints live plugin source (bug 3)" write_config <<'EOF' { "jsPlugins": ["./oxc-config/src/mod.ts"], @@ -234,5 +283,45 @@ out_live="$(OVERENG_OXC_CONFIG_PLUGIN="$workspace/live/oxc-config/src/mod.ts" \ assert_contains "overeng(live-source-only)" "$out_live" "live plugin source is linted without a Nix rebuild" assert_equals "1" "$status_live" "a violation from live source still fails the run" +echo "" +echo "Test 7: a namespace with no matching configured entry fails closed" +write_config <<'EOF' +{ + "jsPlugins": ["./probe-plugin.js"], + "rules": { "overeng/no-raw-nondeterminism": "error" } +} +EOF +status_missing=0 +out="$("$wrapper" fixture.ts --config .oxlintrc.json 2>&1)" || status_missing=$? +assert_nonzero "$status_missing" "missing overeng entry is rejected" +assert_contains "expected exactly one configured overeng plugin entry" "$out" \ + "missing overeng entry has a focused diagnostic" + +write_config <<'EOF' +{ + "jsPlugins": ["./oxc-config/src/mod.ts"], + "rules": { "@stylexjs/valid-styles": "error" } +} +EOF +status_missing=0 +out="$("$wrapper" fixture.ts --config .oxlintrc.json 2>&1)" || status_missing=$? +assert_nonzero "$status_missing" "missing StyleX entry is rejected" +assert_contains "expected exactly one configured StyleX upstream plugin entry" "$out" \ + "missing StyleX entry has a focused diagnostic" + +echo "" +echo "Test 8: malformed jsPlugins entries fail closed before oxlint runs" +write_config <<'EOF' +{ + "jsPlugins": [["overeng"]], + "rules": { "overeng/no-raw-nondeterminism": "error" } +} +EOF +status_malformed=0 +out="$("$wrapper" fixture.ts --config .oxlintrc.json 2>&1)" || status_malformed=$? +assert_nonzero "$status_malformed" "malformed plugin entry is rejected" +assert_contains "jsPlugins entries must be path strings or [alias, path] string pairs" "$out" \ + "malformed plugin entry has a focused diagnostic" + echo "" echo "All oxlint plugin injection tests passed" diff --git a/nix/devenv-modules/tasks/shared/tests/pnpm-task-smoke.test.sh b/nix/devenv-modules/tasks/shared/tests/pnpm-task-smoke.test.sh index 04518e3939..9387a5a164 100644 --- a/nix/devenv-modules/tasks/shared/tests/pnpm-task-smoke.test.sh +++ b/nix/devenv-modules/tasks/shared/tests/pnpm-task-smoke.test.sh @@ -136,6 +136,25 @@ eval_unversioned_lock_mutator() { " } +eval_lockfile_only_tasks() { + local output_path="$1" + + nix-instantiate --eval --strict --json --expr " + let + flake = builtins.getFlake \"$NIX_FLAKE_REF\"; + pkgs = import flake.inputs.nixpkgs { system = builtins.currentSystem; }; + module = (import $ROOT/nix/devenv-modules/tasks/shared/pnpm.nix { + packages = [ ]; + materialize = false; + }) { + inherit pkgs; + lib = pkgs.lib; + config = { devenv.root = \"$workspace\"; }; + }; + in builtins.attrNames module.tasks + " > "$output_path" +} + extract_shared_task_script() { local module_path="$1" local task_name="$2" @@ -399,6 +418,9 @@ extract_task_script "$workspace" "exec" "$tmpdir/pnpm-repair.exec.sh" 'packages extract_task_script "$workspace" "exec" "$tmpdir/pnpm-clean.exec.sh" 'packages = [ "packages/demo" ];' "pnpm:clean" extract_task_script "$workspace" "exec" "$tmpdir/pnpm-update.exec.sh" 'packages = [ ];' "pnpm:update" extract_task_script "$workspace" "exec" "$tmpdir/pnpm-dedupe.exec.sh" 'packages = [ ];' "pnpm:dedupe" +extract_task_script "$workspace" "exec" "$tmpdir/pnpm-lockfile-only-update.exec.sh" 'packages = [ ]; materialize = false;' "pnpm:update" +extract_task_script "$workspace" "exec" "$tmpdir/pnpm-lockfile-only-dedupe.exec.sh" 'packages = [ ]; materialize = false;' "pnpm:dedupe" +eval_lockfile_only_tasks "$tmpdir/pnpm-lockfile-only-tasks.json" extract_task_script "$workspace" "exec" "$tmpdir/pnpm-source-install.exec.sh" 'packages = [ ]; sourceInputPaths = [ "repos/source/packages/pkg" ];' extract_task_script "$workspace" "status" "$tmpdir/pnpm-source-install.status.sh" 'packages = [ ]; sourceInputPaths = [ "repos/source/packages/pkg" ];' extract_task_script "$workspace" "exec" "$tmpdir/pnpm-source-update.exec.sh" 'packages = [ ]; sourceInputPaths = [ "repos/source/packages/pkg" ];' "pnpm:update" @@ -436,6 +458,8 @@ rewrite_unrealized_tool_paths "$tmpdir/pnpm-repair.exec.sh" rewrite_unrealized_tool_paths "$tmpdir/pnpm-clean.exec.sh" rewrite_unrealized_tool_paths "$tmpdir/pnpm-update.exec.sh" rewrite_unrealized_tool_paths "$tmpdir/pnpm-dedupe.exec.sh" +rewrite_unrealized_tool_paths "$tmpdir/pnpm-lockfile-only-update.exec.sh" +rewrite_unrealized_tool_paths "$tmpdir/pnpm-lockfile-only-dedupe.exec.sh" rewrite_unrealized_tool_paths "$tmpdir/pnpm-source-install.exec.sh" rewrite_unrealized_tool_paths "$tmpdir/pnpm-source-install.status.sh" rewrite_unrealized_tool_paths "$tmpdir/pnpm-source-update.exec.sh" @@ -467,6 +491,15 @@ unset PNPM_STORE_DIR unset PNPM_CONFIG_STORE_DIR unset npm_config_store_dir +echo "Test -1: lockfile-only mode removes every dependency materialization task" +assert_json_field \ + "pnpm:dedupe,pnpm:reset-lock-files,pnpm:update" \ + "$tmpdir/pnpm-lockfile-only-tasks.json" \ + 'value => value.join(",")' \ + "lockfile-only task surface" +grep -qF -- '--lockfile-only' "$tmpdir/pnpm-lockfile-only-update.exec.sh" +grep -qF -- '--lockfile-only' "$tmpdir/pnpm-lockfile-only-dedupe.exec.sh" + echo "Test 0: install ignores disposable historical root-local cache content" ( cd "$workspace" diff --git a/nix/devenv-modules/tasks/shared/tests/typescript-materialize-dist.test.sh b/nix/devenv-modules/tasks/shared/tests/typescript-materialize-dist.test.sh index 7148160bd8..40822424f7 100755 --- a/nix/devenv-modules/tasks/shared/tests/typescript-materialize-dist.test.sh +++ b/nix/devenv-modules/tasks/shared/tests/typescript-materialize-dist.test.sh @@ -7,8 +7,6 @@ MATERIALIZER="$ROOT/scripts/typescript-materialize-dist.sh" PACKAGE_PATH="packages/@overeng/tui-core" TARGET="effect_utils//packages/@overeng/tui-core:dist" DECLARATION_ENTRYPOINT="src/mod.d.ts" -PROJECT="tsconfig.json" -DIFF_BIN="$(command -v diff)" REAL_MV="$(command -v mv)" TEST_ROOT="$(cd "$(mktemp -d)" && pwd -P)" trap 'rm -rf "$TEST_ROOT"' EXIT @@ -88,9 +86,9 @@ assert_no_staging() { test_missing_directory() { repo="$TEST_ROOT/missing-directory" make_repo "$repo" - if FAKE_BUCK_SCENARIO=missing-directory TYPESCRIPT_DIST_MODE=publish \ - WORKSPACE_ROOT="$repo" BUCK2_BIN="$repo/bin/buck2" \ - bash "$MATERIALIZER" "$repo" "$PACKAGE_PATH" "$TARGET" "$DECLARATION_ENTRYPOINT" "$PROJECT"; then + if FAKE_BUCK_SCENARIO=missing-directory WORKSPACE_ROOT="$repo" \ + BUCK2_BIN="$repo/bin/buck2" \ + bash "$MATERIALIZER" "$repo" "$PACKAGE_PATH" "$TARGET" "$DECLARATION_ENTRYPOINT"; then echo "FAIL: missing Buck output directory was accepted" >&2 return 1 fi @@ -101,9 +99,9 @@ test_missing_directory() { test_missing_mod() { repo="$TEST_ROOT/missing-mod" make_repo "$repo" - if FAKE_BUCK_SCENARIO=missing-mod TYPESCRIPT_DIST_MODE=publish \ - WORKSPACE_ROOT="$repo" BUCK2_BIN="$repo/bin/buck2" \ - bash "$MATERIALIZER" "$repo" "$PACKAGE_PATH" "$TARGET" "$DECLARATION_ENTRYPOINT" "$PROJECT"; then + if FAKE_BUCK_SCENARIO=missing-mod WORKSPACE_ROOT="$repo" \ + BUCK2_BIN="$repo/bin/buck2" \ + bash "$MATERIALIZER" "$repo" "$PACKAGE_PATH" "$TARGET" "$DECLARATION_ENTRYPOINT"; then echo "FAIL: Buck output without src/mod.d.ts was accepted" >&2 return 1 fi @@ -115,9 +113,9 @@ test_replaces_stale_dist() { repo="$TEST_ROOT/replaces-stale" make_repo "$repo" FAKE_BUCK_SCENARIO=success NEW_DECLARATIONS='fresh declarations' \ - FAKE_BUCK_LOG="$repo/buck-args" TYPESCRIPT_DIST_MODE=publish \ - WORKSPACE_ROOT="$repo" BUCK2_BIN="$repo/bin/buck2" \ - bash "$MATERIALIZER" "$repo" "$PACKAGE_PATH" "$TARGET" "$DECLARATION_ENTRYPOINT" "$PROJECT" + FAKE_BUCK_LOG="$repo/buck-args" WORKSPACE_ROOT="$repo" \ + BUCK2_BIN="$repo/bin/buck2" \ + bash "$MATERIALIZER" "$repo" "$PACKAGE_PATH" "$TARGET" "$DECLARATION_ENTRYPOINT" mapfile -t buck_args < "$repo/buck-args" # The materializer anchors its staging directory on the physical repository # root (`pwd -P`), so the expectation has to be stated in the same resolved @@ -160,9 +158,9 @@ fi MV chmod +x "$repo/bin/mv" if PATH="$repo/bin:$PATH" REAL_MV="$REAL_MV" MV_COUNT_FILE="$repo/mv-count" \ - FAKE_BUCK_SCENARIO=success TYPESCRIPT_DIST_MODE=publish \ - WORKSPACE_ROOT="$repo" BUCK2_BIN="$repo/bin/buck2" \ - bash "$MATERIALIZER" "$repo" "$PACKAGE_PATH" "$TARGET" "$DECLARATION_ENTRYPOINT" "$PROJECT"; then + FAKE_BUCK_SCENARIO=success WORKSPACE_ROOT="$repo" \ + BUCK2_BIN="$repo/bin/buck2" \ + bash "$MATERIALIZER" "$repo" "$PACKAGE_PATH" "$TARGET" "$DECLARATION_ENTRYPOINT"; then echo "FAIL: post-publish validation failure returned success" >&2 return 1 fi @@ -170,207 +168,6 @@ MV assert_no_staging "$repo" } -make_freshness_tools() { - repo="$1" - cat > "$repo/bin/tsgo" <<'TSGO' -#!/usr/bin/env bash -set -euo pipefail -if [ -n "${TSGO_INVOCATION_LOG:-}" ]; then - printf 'ran\n' > "$TSGO_INVOCATION_LOG" -fi -out="" -while [ "$#" -gt 0 ]; do - if [ "$1" = "--outDir" ]; then - out="$2" - shift 2 - else - shift - fi -done -mkdir -p "$out/src" -printf '%s\n' "${FAKE_EMIT_DECLARATIONS:?}" > "$out/src/mod.d.ts" -# A declaration map records its sources relative to the directory the map is -# emitted into, so its bytes depend on how deep the emit directory sits below -# the package root. Reproduce that dependency: it is the only way a fixture can -# tell a depth-faithful staging directory from a deeper one. -if [ -n "${FAKE_EMIT_DECLARATION_MAP:-}" ]; then - printf '{"sources":["%s"]}\n' "$(realpath --relative-to="$out/src" "$PWD/src/mod.ts")" \ - > "$out/src/mod.d.ts.map" -fi -TSGO - chmod +x "$repo/bin/tsgo" -} - -test_standalone_freshness_passes() { - repo="$TEST_ROOT/standalone-fresh" - make_repo "$repo" - make_freshness_tools "$repo" - FAKE_EMIT_DECLARATIONS='old declarations' TYPESCRIPT_DIST_MODE=check \ - TSGO_BIN="$repo/bin/tsgo" DIFF_BIN="$DIFF_BIN" \ - bash "$MATERIALIZER" "$repo" "$PACKAGE_PATH" "$TARGET" "$DECLARATION_ENTRYPOINT" "$PROJECT" - assert_old_dist "$repo" - assert_no_staging "$repo" -} - -test_standalone_staleness_fails() { - repo="$TEST_ROOT/standalone-stale" - make_repo "$repo" - make_freshness_tools "$repo" - if FAKE_EMIT_DECLARATIONS='fresh declarations' TYPESCRIPT_DIST_MODE=check \ - TSGO_BIN="$repo/bin/tsgo" DIFF_BIN="$DIFF_BIN" \ - bash "$MATERIALIZER" "$repo" "$PACKAGE_PATH" "$TARGET" "$DECLARATION_ENTRYPOINT" "$PROJECT"; then - echo "FAIL: stale standalone declarations were accepted" >&2 - return 1 - fi - assert_old_dist "$repo" - assert_no_staging "$repo" -} - -test_standalone_missing_publication_is_actionable() { - repo="$TEST_ROOT/standalone-missing-publication" - make_repo "$repo" - make_freshness_tools "$repo" - rm -rf -- "$repo/$PACKAGE_PATH/dist" - set +e - output="$(FAKE_EMIT_DECLARATIONS='old declarations' TYPESCRIPT_DIST_MODE=check \ - TSGO_BIN="$repo/bin/tsgo" DIFF_BIN="$DIFF_BIN" \ - TSGO_INVOCATION_LOG="$repo/tsgo-invoked" \ - bash "$MATERIALIZER" "$repo" "$PACKAGE_PATH" "$TARGET" "$DECLARATION_ENTRYPOINT" "$PROJECT" 2>&1)" - status=$? - set -e - [ "$status" -ne 0 ] || { - echo "FAIL: an unpublished dist was accepted in check mode" >&2 - return 1 - } - case "$output" in - *"found no published declarations at $PACKAGE_PATH/dist/$DECLARATION_ENTRYPOINT"*) ;; - *) - echo "FAIL: missing publication did not name the absent declaration: $output" >&2 - return 1 - ;; - esac - case "$output" in - *"composed workspace root"*) ;; - *) - echo "FAIL: missing publication did not name the publishing path: $output" >&2 - return 1 - ;; - esac - [ ! -e "$repo/tsgo-invoked" ] || { - echo "FAIL: the compiler ran before the publication prerequisite was proven" >&2 - return 1 - } - assert_no_staging "$repo" -} - -test_standalone_handwritten_declarations_compare() { - repo="$TEST_ROOT/standalone-handwritten" - make_repo "$repo" - make_freshness_tools "$repo" - mkdir -p "$repo/$PACKAGE_PATH/src" - printf 'declare const handwritten: true\n' > "$repo/$PACKAGE_PATH/src/vendor.d.ts" - cp "$repo/$PACKAGE_PATH/src/vendor.d.ts" "$repo/$PACKAGE_PATH/dist/src/vendor.d.ts" - # The compiler never emits a handwritten declaration, so a published copy is - # only fresh because the materializer stages the same registry-declared set. - FAKE_EMIT_DECLARATIONS='old declarations' TYPESCRIPT_DIST_MODE=check \ - TSGO_BIN="$repo/bin/tsgo" DIFF_BIN="$DIFF_BIN" \ - bash "$MATERIALIZER" "$repo" "$PACKAGE_PATH" "$TARGET" "$DECLARATION_ENTRYPOINT" "$PROJECT" \ - src/vendor.d.ts - printf 'declare const handwritten: false\n' > "$repo/$PACKAGE_PATH/dist/src/vendor.d.ts" - if FAKE_EMIT_DECLARATIONS='old declarations' TYPESCRIPT_DIST_MODE=check \ - TSGO_BIN="$repo/bin/tsgo" DIFF_BIN="$DIFF_BIN" \ - bash "$MATERIALIZER" "$repo" "$PACKAGE_PATH" "$TARGET" "$DECLARATION_ENTRYPOINT" "$PROJECT" \ - src/vendor.d.ts; then - echo "FAIL: a drifted handwritten declaration copy was accepted" >&2 - return 1 - fi - # Registry drift stays visible: an undeclared published file is staleness, not - # something the comparison excludes. - cp "$repo/$PACKAGE_PATH/src/vendor.d.ts" "$repo/$PACKAGE_PATH/dist/src/vendor.d.ts" - if FAKE_EMIT_DECLARATIONS='old declarations' TYPESCRIPT_DIST_MODE=check \ - TSGO_BIN="$repo/bin/tsgo" DIFF_BIN="$DIFF_BIN" \ - bash "$MATERIALIZER" "$repo" "$PACKAGE_PATH" "$TARGET" "$DECLARATION_ENTRYPOINT" "$PROJECT"; then - echo "FAIL: an undeclared published declaration was accepted" >&2 - return 1 - fi - # A declared source that no longer exists is registry drift, not staleness. - rm -f -- "$repo/$PACKAGE_PATH/src/vendor.d.ts" - if FAKE_EMIT_DECLARATIONS='old declarations' TYPESCRIPT_DIST_MODE=check \ - TSGO_BIN="$repo/bin/tsgo" DIFF_BIN="$DIFF_BIN" \ - bash "$MATERIALIZER" "$repo" "$PACKAGE_PATH" "$TARGET" "$DECLARATION_ENTRYPOINT" "$PROJECT" \ - src/vendor.d.ts; then - echo "FAIL: a missing declared declaration source was accepted" >&2 - return 1 - fi - assert_no_staging "$repo" -} - -test_standalone_declaration_maps_compare() { - repo="$TEST_ROOT/standalone-declaration-maps" - make_repo "$repo" - make_freshness_tools "$repo" - mkdir -p "$repo/$PACKAGE_PATH/src" - printf 'export const mod = 1\n' > "$repo/$PACKAGE_PATH/src/mod.ts" - # What a compiler emitting into `/dist` writes: two levels up to the - # package root, then into `src`. A staging directory at any other depth - # produces different bytes here. - printf '{"sources":["../../src/mod.ts"]}\n' \ - > "$repo/$PACKAGE_PATH/dist/src/mod.d.ts.map" - FAKE_EMIT_DECLARATIONS='old declarations' FAKE_EMIT_DECLARATION_MAP=1 \ - TYPESCRIPT_DIST_MODE=check TSGO_BIN="$repo/bin/tsgo" DIFF_BIN="$DIFF_BIN" \ - bash "$MATERIALIZER" "$repo" "$PACKAGE_PATH" "$TARGET" "$DECLARATION_ENTRYPOINT" "$PROJECT" - # Maps are compared, not excluded: a drifted map is staleness even when every - # declaration matches. - printf '{"sources":["../../src/other.ts"]}\n' \ - > "$repo/$PACKAGE_PATH/dist/src/mod.d.ts.map" - if FAKE_EMIT_DECLARATIONS='old declarations' FAKE_EMIT_DECLARATION_MAP=1 \ - TYPESCRIPT_DIST_MODE=check TSGO_BIN="$repo/bin/tsgo" DIFF_BIN="$DIFF_BIN" \ - bash "$MATERIALIZER" "$repo" "$PACKAGE_PATH" "$TARGET" "$DECLARATION_ENTRYPOINT" "$PROJECT"; then - echo "FAIL: a drifted declaration map was accepted" >&2 - return 1 - fi - assert_no_staging "$repo" -} - -test_standalone_buildinfo_alone_is_not_staleness() { - repo="$TEST_ROOT/standalone-buildinfo" - make_repo "$repo" - make_freshness_tools "$repo" - # Source-owned build metadata, not a published declaration: it embeds absolute - # machine paths and the comparison never emits one. - printf 'machine-local build state\n' \ - > "$repo/$PACKAGE_PATH/dist/tsconfig.tsbuildinfo" - FAKE_EMIT_DECLARATIONS='old declarations' TYPESCRIPT_DIST_MODE=check \ - TSGO_BIN="$repo/bin/tsgo" DIFF_BIN="$DIFF_BIN" \ - bash "$MATERIALIZER" "$repo" "$PACKAGE_PATH" "$TARGET" "$DECLARATION_ENTRYPOINT" "$PROJECT" - assert_old_dist "$repo" - assert_no_staging "$repo" -} - -test_standalone_published_contamination_fails() { - repo="$TEST_ROOT/standalone-contamination" - make_repo "$repo" - make_freshness_tools "$repo" - # The published dist carries declarations only. JavaScript in it means some - # source-side build wrote through the Buck-owned directory. - printf 'export const mod = 1\n' > "$repo/$PACKAGE_PATH/dist/src/mod.js" - if FAKE_EMIT_DECLARATIONS='old declarations' TYPESCRIPT_DIST_MODE=check \ - TSGO_BIN="$repo/bin/tsgo" DIFF_BIN="$DIFF_BIN" \ - bash "$MATERIALIZER" "$repo" "$PACKAGE_PATH" "$TARGET" "$DECLARATION_ENTRYPOINT" "$PROJECT"; then - echo "FAIL: published JavaScript in the declaration dist was accepted" >&2 - return 1 - fi - rm -f -- "$repo/$PACKAGE_PATH/dist/src/mod.js" - printf 'declare const extra: true\n' > "$repo/$PACKAGE_PATH/dist/src/extra.d.ts" - if FAKE_EMIT_DECLARATIONS='old declarations' TYPESCRIPT_DIST_MODE=check \ - TSGO_BIN="$repo/bin/tsgo" DIFF_BIN="$DIFF_BIN" \ - bash "$MATERIALIZER" "$repo" "$PACKAGE_PATH" "$TARGET" "$DECLARATION_ENTRYPOINT" "$PROJECT"; then - echo "FAIL: an extra published declaration nobody emitted was accepted" >&2 - return 1 - fi - assert_no_staging "$repo" -} - extract_devenv_scripts() { local nix_expr nix_expr='let @@ -379,8 +176,8 @@ extract_devenv_scripts() { module = import '"$ROOT"'/devenv.nix { inherit pkgs; lib = pkgs.lib; + inputs = { }; config = { }; - inputs.tsgo.packages.${pkgs.stdenv.hostPlatform.system}.effect-tsgo = "/tsgo"; }; in { materializeTask = pkgs.writeShellScript "test-materialize-task" @@ -406,7 +203,6 @@ make_runtime_probe() { mkdir -p "$checkout/genie/buck2" cat > "$checkout/genie/buck2/typescript-authority-runtime.ts" <<'PROBE' console.log([ - process.env.TYPESCRIPT_DIST_MODE, process.env.WORKSPACE_ROOT ?? '', process.env.BUCK2_BIN ?? '', ].join('|')) @@ -414,15 +210,22 @@ PROBE } test_composed_worktree_selection() { - local standalone seed repo_root workspace_root member_root mode admin_dir + local standalone seed repo_root workspace_root member_root mode admin_dir status output standalone="$TEST_ROOT/lookalike/repos/effect-utils" mkdir -p "$(dirname "$standalone")" make_git_commit "$standalone" make_runtime_probe "$standalone" - mode="$(DEVENV_ROOT="$standalone" bash "$TEST_ROOT/materialize-task.sh")" - case "$mode" in - check\|*) ;; - *) echo "FAIL: repos/ lookalike selected publish mode: $mode" >&2; return 1 ;; + set +e + output="$(DEVENV_ROOT="$standalone" bash "$TEST_ROOT/materialize-task.sh" 2>&1)" + status=$? + set -e + [ "$status" -ne 0 ] || { + echo "FAIL: standalone lookalike was allowed to publish declarations" >&2 + return 1 + } + case "$output" in + *"requires a composed megarepo workspace"*) ;; + *) echo "FAIL: standalone refusal was not actionable: $output" >&2; return 1 ;; esac seed="$TEST_ROOT/composed-seed" @@ -436,7 +239,7 @@ test_composed_worktree_selection() { make_runtime_probe "$member_root" mkdir -p "$workspace_root/.megarepo/bin" mode="$(DEVENV_ROOT="$member_root" bash "$TEST_ROOT/materialize-task.sh")" - expected_mode="publish|$workspace_root|$workspace_root/.megarepo/bin/buck2" + expected_mode="$workspace_root|$workspace_root/.megarepo/bin/buck2" if [ "$mode" != "$expected_mode" ]; then echo "FAIL: composed materializer mode: expected '$expected_mode', got '$mode'" >&2 return 1 @@ -483,19 +286,11 @@ test_cleanup_refuses_nonreciprocal_worktree() { refs/heads/ci-77-1-cleanup-test } -extract_devenv_scripts - run_test 'missing Buck directory fails and preserves old dist' test_missing_directory run_test 'missing src/mod.d.ts fails and preserves old dist' test_missing_mod run_test 'stale dist is atomically replaced by fresh bytes' test_replaces_stale_dist run_test 'post-publish validation failure is nonzero and restores old dist' test_post_publish_validation_failure -run_test 'standalone fresh declarations pass without publication' test_standalone_freshness_passes -run_test 'standalone stale declarations fail without mutation' test_standalone_staleness_fails -run_test 'standalone check without a published dist is actionable and skips the compiler' test_standalone_missing_publication_is_actionable -run_test 'handwritten declaration copies compare instead of reading as staleness' test_standalone_handwritten_declarations_compare -run_test 'declaration maps compare at the published depth' test_standalone_declaration_maps_compare -run_test 'a published tsbuildinfo alone is not staleness' test_standalone_buildinfo_alone_is_not_staleness -run_test 'published JavaScript and extra declarations read as staleness' test_standalone_published_contamination_fails +extract_devenv_scripts run_test 'only reciprocal composed worktrees select parent publication' test_composed_worktree_selection run_test 'cleanup refuses non-reciprocal worktree metadata without deletion' test_cleanup_refuses_nonreciprocal_worktree diff --git a/nix/oxc-config-plugin.nix b/nix/oxc-config-plugin.nix deleted file mode 100644 index 45d72af101..0000000000 --- a/nix/oxc-config-plugin.nix +++ /dev/null @@ -1,333 +0,0 @@ -# Build pre-bundled @overeng/oxc-config JS plugin for oxlint. -# -# Bundles the custom overeng rules (including the native overeng/storybook/* -# rules) into a single self-contained JS file usable as an oxlint jsPlugin -# without node_modules. -# Imported by oxlint-npm.nix when src is provided. -# -# ============================================================================= -# Updating the pnpmDepsHash (after changing oxc-config's dependencies) -# ============================================================================= -# -# 1. Run: nix build .#oxlint-npm 2>&1 -# (the FOD will fail with expected vs actual hash) -# -# 2. Update pnpmDepsHash below with the actual hash from the error -# -# ============================================================================= -{ - pkgs, - bun, - src, - depsBuilds, - hashSourcePath, -}: - -let - lib = pkgs.lib; - pinnedPnpm = import ./pnpm.nix { inherit pkgs; }; - pnpmDepsHelper = import ./workspace-tools/lib/mk-pnpm-deps.nix { - inherit pkgs; - pnpm = pinnedPnpm; - }; - packageDir = "packages/@overeng/oxc-config"; - depsBuild = depsBuilds."."; - pnpmDepsHash = depsBuild.hash; - - srcPath = - if builtins.isAttrs src && builtins.hasAttr "outPath" src then - src.outPath - else if builtins.isPath src then - src - else - builtins.toPath src; - - # Patches referenced in pnpm-workspace.yaml (shared across all workspaces) - patchesDirs = [ - "patches" - ]; - - rootPnpmWorkspaceYamlPath = srcPath + "/pnpm-workspace.yaml"; - rootPnpmWorkspaceYaml = builtins.readFile rootPnpmWorkspaceYamlPath; - - hasPathPrefix = - relPath: prefix: - relPath == prefix - || lib.hasPrefix "${prefix}/" relPath - || ( - relPath != "" - && builtins.elem relPath ( - lib.genList (index: lib.concatStringsSep "/" (lib.take (index + 1) (lib.splitString "/" prefix))) ( - lib.length (lib.splitString "/" prefix) - 1 - ) - ) - ); - - workspaceSuffixLines = - workspaceYaml: - let - dropUntilPackagesHeader = - lines: - if lines == [ ] then - throw "oxc-config-plugin: pnpm-workspace.yaml is missing packages:" - else if lib.hasPrefix "packages:" (lib.trim (builtins.head lines)) then - lib.tail lines - else - dropUntilPackagesHeader (lib.tail lines); - - dropPackageBlock = - lines: - if lines == [ ] then - [ ] - else - let - line = builtins.head lines; - trimmed = lib.trim line; - in - if trimmed == "" || lib.hasPrefix "-" trimmed || lib.hasPrefix " " line then - dropPackageBlock (lib.tail lines) - else - lines; - - stripPrepLocalPnpmSettings = - lines: - # The FOD must not inherit caller-local GVS/store paths; its private - # install root is part of the reproducible derivation boundary. - builtins.filter ( - l: - !(lib.hasPrefix "enableGlobalVirtualStore" (lib.trim l)) && !(lib.hasPrefix "storeDir" (lib.trim l)) - ) lines; - in - stripPrepLocalPnpmSettings ( - dropPackageBlock (dropUntilPackagesHeader (lib.splitString "\n" workspaceYaml)) - ); - - formatWorkspaceYaml = - packageDirs: suffixLines: - let - packagesBlock = builtins.concatStringsSep "\n" ( - [ "packages:" ] ++ map (dir: " - ${dir}") packageDirs - ); - suffix = builtins.concatStringsSep "\n" suffixLines; - in - if suffix == "" then "${packagesBlock}\n" else "${packagesBlock}\n\n${suffix}\n"; - - filteredRootPnpmWorkspaceYamlFile = pkgs.writeText "oxc-config-pnpm-workspace.yaml" ( - formatWorkspaceYaml [ packageDir ] (workspaceSuffixLines rootPnpmWorkspaceYaml) - ); - - sourceExclusions = [ - ".git" - ".devenv" - ".cache" - ".turbo" - ".next" - ".bun" - ".pnpm-store" - "node_modules" - "dist" - "result" - "coverage" - "tmp" - "out" - ]; - - depsSrc = lib.cleanSourceWith { - src = srcPath; - filter = - path: type: - let - relPath = lib.removePrefix (toString srcPath + "/") (toString path); - baseName = baseNameOf path; - in - !(lib.elem baseName sourceExclusions) - && ( - builtins.elem relPath [ - "package.json" - "pnpm-lock.yaml" - "pnpm-workspace.yaml" - ".npmrc" - "tsconfig.base.json" - ] - || hasPathPrefix relPath "${packageDir}/package.json" - || builtins.any (dir: hasPathPrefix relPath dir) patchesDirs - ); - }; - - # Full source for building (includes .ts files, excludes node_modules etc.) - buildSrc = lib.cleanSourceWith { - src = srcPath; - filter = - path: type: - let - relPath = lib.removePrefix (toString srcPath + "/") (toString path); - baseName = baseNameOf path; - in - !(lib.elem baseName sourceExclusions) - && ( - builtins.elem relPath [ - "package.json" - "pnpm-lock.yaml" - "pnpm-workspace.yaml" - ".npmrc" - "tsconfig.base.json" - ] - || hasPathPrefix relPath packageDir - || builtins.any (dir: hasPathPrefix relPath dir) patchesDirs - ); - }; - - pnpmDeps = pnpmDepsHelper.mkDeps { - name = "oxc-config"; - src = depsSrc; - sourceRoot = "."; - inherit pnpmDepsHash; - pnpmFilters = [ "@overeng/oxc-config..." ]; - preInstall = '' - chmod +w pnpm-workspace.yaml - cp ${filteredRootPnpmWorkspaceYamlFile} pnpm-workspace.yaml - ''; - }; - -in -pkgs.stdenv.mkDerivation { - pname = "oxc-config-plugin"; - version = "0.1.0"; - passthru = { - # Export the prepared dependency boundary and its source-owned hash identity - # in the same shape as mkPnpmCli consumers. - inherit pnpmDeps; - depsBuildsByInstallRoot.root = pnpmDeps; - depsBuildEntries = [ - { - attrName = "root"; - dir = "."; - hash = pnpmDepsHash; - lockfilePath = "pnpm-lock.yaml"; - memberDirs = [ packageDir ]; - profileKey = "oxc-config-root"; - } - ]; - fodHashRepairTargets = [ - { - schemaVersion = 1; - kind = "dependency-fod-hash-repair-target"; - producer = "effect-utils.oxc-config-plugin"; - subject = { - packageName = "@overeng/oxc-config"; - inherit packageDir; - }; - attrName = "root"; - installDir = "."; - lockfilePath = "pnpm-lock.yaml"; - memberDirs = [ packageDir ]; - profileKey = "oxc-config-root"; - declaredHash = pnpmDepsHash; - depsDrvPath = pnpmDeps.drvPath; - hashPath = [ - "depsBuilds" - "." - "hash" - ]; - } - ]; - evergreen.fodGraph.v1 = - let - packageAttr = ".#packages.${pkgs.stdenv.hostPlatform.system}.\"oxc-config-plugin\""; - boundaryAttr = "${packageAttr}.passthru.depsBuildsByInstallRoot.root"; - in - { - schema = "evergreen.fodGraph.v1"; - version = 1; - consumer = { - attr = packageAttr; - consumerAttr = packageAttr; - system = pkgs.stdenv.hostPlatform.system; - package = "oxc-config"; - surfacedName = "oxc-config"; - }; - capabilityGaps = [ ]; - boundaries = [ - { - attr = boundaryAttr; - variant = "depsBuilds"; - consumerAttr = packageAttr; - system = pkgs.stdenv.hostPlatform.system; - package = "oxc-config"; - surfacedName = "oxc-config"; - inherit boundaryAttr packageDir hashSourcePath; - builderFile = hashSourcePath; - hashSet = "depsBuilds"; - installRoot = "."; - installRootAttr = "root"; - lockfilePath = "pnpm-lock.yaml"; - memberDirs = [ packageDir ]; - profileKey = "oxc-config-root"; - hashKey = "."; - equivalenceKey = "oxc-config-root"; - hash = pnpmDepsHash; - hashPath = [ - "depsBuilds" - "." - "hash" - ]; - depsBuildDrvPath = pnpmDeps.drvPath; - depsBuildDrvPaths = [ pnpmDeps.drvPath ]; - supportedSystems = [ pkgs.stdenv.hostPlatform.system ]; - } - ]; - }; - }; - - nativeBuildInputs = [ - bun - pkgs.nodejs - pkgs.perl - ]; - - dontUnpack = true; - dontFixup = true; - - buildPhase = '' - set -euo pipefail - runHook preBuild - - cp -r ${buildSrc} workspace - chmod -R +w workspace - ${pnpmDepsHelper.mkRestoreScript { - deps = pnpmDeps; - target = "workspace"; - }} - cd workspace - - cd ${packageDir} - chmod +w . - - # Bundle into single JS file. - # --external jiti: eslint's config loader uses jiti for dynamic imports, but - # oxlint's JS plugin runtime never invokes the config loader, so jiti is safe - # to exclude. This avoids bundling issues with jiti's native module resolution. - bun build src/mod.ts --bundle --target=bun --external jiti --outfile=plugin.js - - runHook postBuild - ''; - - checkPhase = '' - # Verify the bundle is self-contained (no missing modules like jiti). - # buildPhase leaves CWD in workspace/${packageDir} where plugin.js was produced. - test -f plugin.js || { echo "error: plugin.js not found in $(pwd)"; exit 1; } - bun -e "const p = require('./plugin.js'); if (!p || typeof p !== 'object') throw new Error('plugin did not export an object')" - ''; - - installPhase = '' - runHook preInstall - mkdir -p $out - cp plugin.js $out/ - runHook postInstall - ''; - - meta = with pkgs.lib; { - description = "Pre-bundled @overeng/oxc-config oxlint JS plugin"; - license = licenses.mit; - }; -} diff --git a/nix/oxlint-npm.nix b/nix/oxlint-npm.nix index 4c7ee08ce1..1517a19a36 100644 --- a/nix/oxlint-npm.nix +++ b/nix/oxlint-npm.nix @@ -4,15 +4,18 @@ # execute JS plugins. The npm version uses NAPI bindings to run Rust code from # a JS runtime (Bun), enabling jsPlugins support. # -# When `src` is provided (the effect-utils source), the @overeng/oxc-config -# plugin is bundled alongside (via nix/oxc-config-plugin.nix) and exposed as -# passthru.pluginPath for consumer repos to inject into oxlint configs. +# The two @overeng/oxc-config plugin entry points are imported from the tracked +# immutable Buck product manifest and exposed as stable passthru paths. Nix +# remains only the oxlint runtime packager; it does not rebuild plugin sources. # # Usage: -# oxlintNpm = import ./oxlint-npm.nix { inherit pkgs bun; src = self; }; -# # => oxlintNpm provides the `oxlint` command on PATH -# # => oxlintNpm.pluginPath is the absolute path to the bundled plugin JS file (or null) -# +# tracked = import ./buck2-products { inherit pkgs; }; +# oxlintNpm = import ./oxlint-npm.nix { +# inherit pkgs bun; +# products = tracked.products; +# }; +# # => oxlintNpm.pluginPath is the overeng plugin module +# # => oxlintNpm.stylexUpstreamPluginPath is the @stylexjs plugin module # ============================================================================= # Updating to a new version # ============================================================================= @@ -49,7 +52,7 @@ { pkgs, bun, - src ? null, + products, }: let lib = pkgs.lib; @@ -99,16 +102,31 @@ let hash = platformPkg.hash; }; - # Optional: build the @overeng/oxc-config plugin bundle when src is provided - hasPlugin = src != null; - pluginBundle = - if hasPlugin then - import (../. + "/packages/@overeng/oxc-config/nix/build.nix") { inherit pkgs bun src; } - else - null; + importProduct = import ./workspace-tools/lib/javascript-product-import.nix { inherit pkgs; }; + importPlugin = + productName: + let + product = products.${productName}; + in + importProduct { + inherit (product) + artifact + descriptor + descriptorContent + expectedDescriptorSha256 + expectedModuleSha256 + ; + expectedProductKind = "module"; + expectedProductName = productName; + generateCompletions = false; + }; + overengPlugin = importPlugin "oxc-config"; + stylexUpstreamPlugin = importPlugin "oxc-config-stylex-upstream-plugin"; + overengPluginModule = "${overengPlugin}/libexec/${overengPlugin.checkedDescriptor.modulePath}"; + stylexUpstreamPluginModule = "${stylexUpstreamPlugin}/libexec/${stylexUpstreamPlugin.checkedDescriptor.modulePath}"; in -pkgs.stdenv.mkDerivation { +pkgs.stdenv.mkDerivation (finalAttrs: { pname = "oxlint-npm"; inherit version; @@ -130,10 +148,10 @@ pkgs.stdenv.mkDerivation { # Extract platform-specific binary package tar -xzf ${binaryPackage} -C $out/lib/node_modules/${platformPkg.name} --strip-components=1 - ${lib.optionalString hasPlugin '' - # Symlink pre-bundled oxc-config plugin for discoverability - ln -s ${pluginBundle}/plugin.js $out/lib/oxc-config-plugin.js - ''} + # Keep both independently attested modules in the oxlint closure and expose + # stable package-local paths to wrapper consumers. + ln -s ${overengPluginModule} "$out/lib/oxc-config-plugin.js" + ln -s ${stylexUpstreamPluginModule} "$out/lib/stylex-upstream-plugin.js" runHook postBuild ''; @@ -149,10 +167,10 @@ pkgs.stdenv.mkDerivation { runHook postInstall ''; - # Expose plugin path for consumers (e.g., lint-oxc.nix jsPlugins parameter). passthru = { - pluginBundle = if hasPlugin then pluginBundle else null; - pluginPath = if hasPlugin then "${pluginBundle}/plugin.js" else null; + pluginPath = "${finalAttrs.finalPackage}/lib/oxc-config-plugin.js"; + stylexUpstreamPluginPath = "${finalAttrs.finalPackage}/lib/stylex-upstream-plugin.js"; + inherit overengPlugin stylexUpstreamPlugin; }; meta = with pkgs.lib; { @@ -162,4 +180,4 @@ pkgs.stdenv.mkDerivation { mainProgram = "oxlint"; platforms = builtins.attrNames platformPackages; }; -} +}) diff --git a/nix/oxlint-with-plugins.nix b/nix/oxlint-with-plugins.nix index 2a6452f801..5c6a2d0c8f 100644 --- a/nix/oxlint-with-plugins.nix +++ b/nix/oxlint-with-plugins.nix @@ -1,43 +1,40 @@ -# Wrapper around oxlint-npm that points the @overeng/oxc-config JS plugin entry at -# a resolvable implementation. +# Wrapper around oxlint-npm that points the two @overeng/oxc-config JavaScript +# plugin entries at independently tracked immutable Buck products. # -# When the project's .oxlintrc.json (or an explicit -c config) contains overeng/* -# rules, this wrapper rewrites that config's `jsPlugins` entry for our plugin to a -# concrete path, via an injected config copy. Projects without overeng rules get -# plain pass-through. -# -# The rewrite SUBSTITUTES our entry and leaves every other `jsPlugins` entry -# alone, so third-party JS plugins (e.g. `@stylexjs/eslint-plugin`) declared next -# to ours still resolve. +# When the project's .oxlintrc.json (or an explicit -c config) contains +# overeng/* or @stylexjs/* rules, this wrapper substitutes the corresponding +# configured `jsPlugins` entries in an injected config copy. It leaves unrelated +# entries alone and refuses to invent a missing entry: the config remains the +# authority for which namespaces are enabled. # # Plugin source selection: -# default the Nix-built plugin snapshot (hermetic) -# OVERENG_OXC_CONFIG_PLUGIN=

use

instead — point it at -# packages/@overeng/oxc-config/src/mod.ts to lint -# against live plugin source (rule development; -# no Nix rebuild between edits) +# default tracked Buck product modules +# OVERENG_OXC_CONFIG_PLUGIN=

live src/mod.ts override +# OVERENG_STYLEX_UPSTREAM_PLUGIN=

live src/stylex-upstream-plugin.ts +# +# The overrides are explicit rule-authoring escape hatches. Normal development, +# CI and downstream wrappers all use the immutable products. # # Usage: -# oxlintWithPlugins = import ./oxlint-with-plugins.nix { inherit pkgs; oxlintNpm = ...; }; -# # => provides `oxlint` on PATH with automatic plugin injection +# oxlintWithPlugins = import ./oxlint-with-plugins.nix { inherit pkgs oxlintNpm; }; +# # => provides `oxlint` on PATH with automatic plugin substitution { pkgs, oxlintNpm, }: -assert oxlintNpm.pluginPath != null; +assert oxlintNpm.pluginPath != null && oxlintNpm.stylexUpstreamPluginPath != null; pkgs.writeShellApplication { name = "oxlint"; runtimeInputs = [ pkgs.jq pkgs.flock + pkgs.tsgolint ]; text = '' - # Rule development escape hatch: the default plugin is a Nix build-time - # snapshot, so edits to packages/@overeng/oxc-config/src/*.ts are invisible and - # a newly added rule reports "not found in plugin 'overeng'". Overriding this - # with the plugin's TypeScript entry point makes the wrapper lint against live - # source (the host runtime is Bun, which imports .ts directly). - pluginPath="''${OVERENG_OXC_CONFIG_PLUGIN:-${oxlintNpm.pluginPath}}" + # Rule-authoring escape hatches. Keep the two entries separate so changing + # one live source cannot silently replace the other namespace. + overengPluginPath="''${OVERENG_OXC_CONFIG_PLUGIN:-${oxlintNpm.pluginPath}}" + stylexUpstreamPluginPath="''${OVERENG_STYLEX_UPSTREAM_PLUGIN:-${oxlintNpm.stylexUpstreamPluginPath}}" # Find the config file: explicit -c/--config arg, or default .oxlintrc.json config_file="" @@ -45,7 +42,11 @@ pkgs.writeShellApplication { for ((i=0; i<''${#args[@]}; i++)); do case "''${args[$i]}" in -c|--config) - config_file="''${args[$((i+1))]}" + if [ "$((i + 1))" -ge "''${#args[@]}" ]; then + echo "oxlint-with-plugins: ''${args[$i]} requires a config path" >&2 + exit 2 + fi + config_file="''${args[$((i + 1))]}" break ;; esac @@ -54,55 +55,81 @@ pkgs.writeShellApplication { config_file=".oxlintrc.json" fi - # If config has overeng rules, inject the Nix-built plugin path (replaces any existing jsPlugins) - if [ -n "$config_file" ] && grep -q '"overeng/' "$config_file" 2>/dev/null; then + if [ -n "$config_file" ] && grep -Eq '"(overeng/|@stylexjs/)' "$config_file" 2>/dev/null; then # The injected copy is written into the SAME directory as the source config # (repo root for the default .oxlintrc.json). Under oxlint 1.39 this was # load-bearing for correctness: plugin rules only applied to files located # UNDER the injected config's directory, so a /tmp copy silently dropped - # every overeng/* rule for the deep file paths CI passes. oxlint 1.82 applies - # plugin rules to targets outside the config directory (verified against - # 1.82.0 with a config in one directory and the target in another), so the + # every configured plugin rule for the deep file paths CI passes. Oxlint + # 1.82 applies plugin rules to targets outside the config directory, so the # location is now only a cache decision: a repo-root copy stays stable across # runs and keeps the hash-crawler-safe atomic publish below. The published # copy DELIBERATELY outlives the process; see below. config_dir=$(dirname "$config_file") # Publish a persistent, git-ignored root cache atomically, and serialize - # concurrent wrappers by locking the source config itself (without - # creating another repository-local lock file). Keeping the complete file - # avoids a hash-crawler stat/open race with an EXIT-time deletion. + # concurrent wrappers by locking the source config itself. Keeping the + # complete file avoids a hash-crawler stat/open race with EXIT-time + # deletion. exec 9<"$config_file" flock --exclusive 9 tmpconfig="$config_dir/.oxlint-with-plugins.json" staged_config=$(mktemp "''${TMPDIR:-/tmp}/oxlint-with-plugins.XXXXXX.json") trap 'rm -f "$staged_config"' EXIT - # Substitute OUR entry in place rather than replacing the whole list. - # Replacing it wholesale made every third-party plugin declared beside ours - # unresolvable ("Plugin 'x' not found"), which is why consumers grew local - # workarounds. Entries are either a path string or an ["alias", path] tuple; - # a tuple keeps its alias. When no entry of ours is present (consumer configs - # that rely purely on injection) ours is appended. - # - # The match is the plugin's ENTRY POINT, not merely the package directory: - # `@overeng/oxc-config` also ships sibling plugin entries (the `@stylexjs` - # namespace shim), and substituting one of those would silently replace a - # third-party plugin with ours -- the very failure this fix removes. - jq --arg p "$pluginPath" ' - def is_ours: - if type == "string" then test("oxc-config/src/mod\\.ts$") or test("oxc-config-plugin[^/]*/plugin\\.js$") - elif type == "array" then (.[1] | type == "string" and (test("oxc-config/src/mod\\.ts$") or test("oxc-config-plugin[^/]*/plugin\\.js$"))) - else false - end; - def substituted: - if type == "array" then [.[0], $p] else $p end; - .jsPlugins = ( - (.jsPlugins // []) as $existing - | if any($existing[]; is_ours) - then $existing | map(if is_ours then substituted else . end) - else $existing + [$p] - end - ) + + # Every entry must be a path string or an [alias, path] pair. Each enabled + # owned namespace must have exactly one corresponding source entry; a + # missing or duplicate entry is configuration drift, not permission to + # append an implicit plugin. Tuple aliases are preserved. + jq --arg overeng "$overengPluginPath" --arg stylex "$stylexUpstreamPluginPath" ' + def is_plugin_entry: + type == "string" + or (type == "array" and length == 2 and all(.[]; type == "string")); + def entry_path: + if type == "string" then . else .[1] end; + def is_overeng: + entry_path as $path + | $path == $overeng or ($path | test("oxc-config/src/mod\\.ts$")); + def is_stylex: + entry_path as $path + | $path == $stylex or ($path | test("oxc-config/src/stylex-upstream-plugin\\.ts$")); + def substituted($path): + if type == "array" then [.[0], $path] else $path end; + def rule_names: + ((.rules // {}) | keys[]), + ((.overrides // [])[]? | (.rules // {}) | keys[]); + def uses_rule_prefix($prefix): + any(rule_names; startswith($prefix)); + + . as $config + | ($config.jsPlugins // []) as $existing + | if ($config.jsPlugins != null and ($config.jsPlugins | type) != "array") + then error("jsPlugins must be an array") + elif any($existing[]; is_plugin_entry | not) + then error("jsPlugins entries must be path strings or [alias, path] string pairs") + else . + end + | ([$existing[] | select(is_overeng)] | length) as $overeng_count + | ([$existing[] | select(is_stylex)] | length) as $stylex_count + | if uses_rule_prefix("overeng/") and $overeng_count != 1 + then error("expected exactly one configured overeng plugin entry") + elif uses_rule_prefix("@stylexjs/") and $stylex_count != 1 + then error("expected exactly one configured StyleX upstream plugin entry") + elif $overeng_count > 1 + then error("expected at most one configured overeng plugin entry") + elif $stylex_count > 1 + then error("expected at most one configured StyleX upstream plugin entry") + else + .jsPlugins = ( + $existing + | map( + if is_overeng then substituted($overeng) + elif is_stylex then substituted($stylex) + else . + end + ) + ) + end ' "$config_file" > "$staged_config" mv "$staged_config" "$tmpconfig" diff --git a/nix/workspace-tools/lib/buck2-artifact-import.nix b/nix/workspace-tools/lib/buck2-artifact-import.nix index 52d31a7ac0..12a255c712 100644 --- a/nix/workspace-tools/lib/buck2-artifact-import.nix +++ b/nix/workspace-tools/lib/buck2-artifact-import.nix @@ -5,6 +5,7 @@ { pkgs, inspectElfDynamic ? import ./buck2-runtime-inspect-elf-dynamic.nix { inherit pkgs; }, + inspectElfStatic ? import ./buck2-runtime-inspect-elf-static.nix { inherit pkgs; }, inspectMachODynamic ? if pkgs.stdenv.hostPlatform.isDarwin then import ./buck2-runtime-inspect-mach-o-dynamic.nix { @@ -61,6 +62,7 @@ assert lib.assertMsg ( if !(builtins.elem runtimeKind [ "elf-dynamic" + "elf-static" "mach-o-dynamic" ]) then @@ -98,7 +100,12 @@ else --no-same-owner --no-same-permissions ${scan} tree "$out" ${ - if runtimeKind == "elf-dynamic" then inspectElfDynamic else inspectMachODynamic + if runtimeKind == "elf-dynamic" then + inspectElfDynamic + else if runtimeKind == "elf-static" then + inspectElfStatic + else + inspectMachODynamic } ${descriptorFile} "$out" ${pkgs.findutils}/bin/find "$out" -type d -exec chmod 0555 {} + diff --git a/nix/workspace-tools/lib/buck2-build-product-contract.nix b/nix/workspace-tools/lib/buck2-build-product-contract.nix index 57792ada64..babb16bc9d 100644 --- a/nix/workspace-tools/lib/buck2-build-product-contract.nix +++ b/nix/workspace-tools/lib/buck2-build-product-contract.nix @@ -119,6 +119,25 @@ let ) "descriptor.runtime.symbolVersionFloors must be sorted") (ensure (value.rpathPolicy == "empty/v1") "descriptor.runtime.rpathPolicy must be empty/v1") ] value + else if kind == "elf-static" then + let + value = exactAttrs "descriptor.runtime" [ + "elfClass" + "inspectionContract" + "kind" + "machine" + ] runtime; + in + force [ + (ensure ( + value.inspectionContract == "elf-static/v1" + ) "descriptor.runtime.inspectionContract must be elf-static/v1") + (ensure (builtins.elem value.elfClass [ + "ELF32" + "ELF64" + ]) "descriptor.runtime.elfClass must be ELF32 or ELF64") + (ensure (nonEmptyString value.machine) "descriptor.runtime.machine must be a non-empty string") + ] value else if kind == "mach-o-dynamic" then let value = exactAttrs "descriptor.runtime" [ @@ -219,6 +238,23 @@ let expectedGlibcInterpreter != null && runtime.interpreter == expectedGlibcInterpreter ) "descriptor.runtime.interpreter does not prove the declared glibc architecture") ] + else if runtime.kind == "elf-static" then + [ + (ensure ( + platform.os == "linux" + ) "descriptor.runtime elf-static requires descriptor.platform.os = linux") + (ensure ( + platform.abi == "glibc" + ) "descriptor.runtime elf-static/v1 currently requires descriptor.platform.abi = glibc") + (ensure ( + runtime.machine == platform.architecture + ) "descriptor.runtime.machine must match descriptor.platform.architecture") + (ensure (builtins.elem platform.architecture [ + "x86_64" + "aarch64" + ]) "descriptor.runtime elf-static architecture is unsupported") + (ensure (runtime.elfClass == "ELF64") "descriptor.runtime elf-static architecture requires ELF64") + ] else if runtime.kind == "mach-o-dynamic" then [ (ensure ( @@ -244,7 +280,10 @@ let runtime.installNamePolicy == "system-only/v1" ) "descriptor.runtime.installNamePolicy must be system-only/v1") (ensure (runtime.rpathPolicy == "empty/v1") "descriptor.runtime.rpathPolicy must be empty/v1") - (ensure (runtime.signingPolicy == "adhoc/v1") "descriptor.runtime.signingPolicy must be adhoc/v1") + (ensure (builtins.elem runtime.signingPolicy [ + "adhoc/v1" + "embedded/v1" + ]) "descriptor.runtime.signingPolicy is unsupported") (ensure ( runtime.dylibs == builtins.sort builtins.lessThan runtime.dylibs ) "descriptor.runtime.dylibs must be sorted") diff --git a/nix/workspace-tools/lib/buck2-darwin-rust-capability.nix b/nix/workspace-tools/lib/buck2-darwin-rust-capability.nix index d0c5f30173..d39ca4b38d 100644 --- a/nix/workspace-tools/lib/buck2-darwin-rust-capability.nix +++ b/nix/workspace-tools/lib/buck2-darwin-rust-capability.nix @@ -30,6 +30,9 @@ let export MACOSX_DEPLOYMENT_TARGET=${lib.escapeShellArg deploymentTarget} export PATH=${ lib.makeBinPath [ + # Buck's Rust prelude emits linker wrappers with `#!/usr/bin/env bash`. + # Keep bash visible after this wrapper replaces the action's PATH. + pkgs.bash pkgs.coreutils sigtool cctools @@ -38,18 +41,43 @@ let output= previous= + capture_output() { + if [ "$previous" = -o ]; then output="$1"; fi + case "$1" in --emit=link=*) output="''${1#--emit=link=}" ;; esac + previous="$1" + } for argument in "$@"; do - if [ "$previous" = -o ]; then output="$argument"; fi - previous="$argument" + case "$argument" in + @*) + response_file="''${argument#@}" + if [ -f "$response_file" ]; then + while IFS= read -r response_argument; do capture_output "$response_argument"; done <"$response_file" + fi + ;; + *) capture_output "$argument" ;; + esac done ${pkgs.rustc}/bin/rustc \ -C linker=${pkgs.clang}/bin/clang \ -C link-arg=-isysroot \ -C link-arg=${lib.escapeShellArg sdk.sdkroot} \ + -C link-arg=${lib.escapeShellArg "-L${pkgs.libiconv}/lib"} \ "$@" if [ -n "$output" ]; then + # nixpkgs' Darwin stdenv links iconv from the store. Product binaries must + # instead use macOS' ABI-compatible dyld-cache install name. source ${signingUtils} - signIfRequired "$output" + if ${cctools}/bin/otool -L "$output" 2>/dev/null \ + | ${pkgs.gnugrep}/bin/grep -Fq ${lib.escapeShellArg "${pkgs.libiconv}/lib/libiconv.2.dylib"}; then + ${cctools}/bin/install_name_tool \ + -change ${lib.escapeShellArg "${pkgs.libiconv}/lib/libiconv.2.dylib"} \ + /usr/lib/libiconv.2.dylib \ + "$output" + # install_name_tool invalidates the compiler-produced signature. + sign "$output" + else + signIfRequired "$output" + fi fi ''; preflight = pkgs.writeShellScript "buck2-rust-darwin-preflight" '' diff --git a/nix/workspace-tools/lib/buck2-product-candidates.nix b/nix/workspace-tools/lib/buck2-product-candidates.nix index dda2bcd465..1f3647f611 100644 --- a/nix/workspace-tools/lib/buck2-product-candidates.nix +++ b/nix/workspace-tools/lib/buck2-product-candidates.nix @@ -8,7 +8,9 @@ { pkgs, products, + nativeProducts ? (import ../../buck2-native-products { inherit pkgs; }).products, typeProofCompilerBin, + capabilityProjection ? null, oxfmtPkg ? pkgs.oxfmt, gitRev ? "unknown", commitTs ? 0, @@ -63,7 +65,7 @@ let CLI_BUILD_STAMP = buildStamp; GENIE_ACTIONLINT_BIN = "${pkgs.actionlint}/bin/actionlint"; GENIE_EXPORT_TYPE_PROOF_COMPILER = typeProofCompilerBin; - GENIE_TYPESCRIPT_API_SERVER = "${pkgs.typescript}/bin/tsc"; + GENIE_TYPESCRIPT_API_SERVER = "${nativeProducts.typescript-api-server}/bin/typescript-api-server"; }; expectedExternalCapabilities = [ "actionlint" @@ -79,8 +81,10 @@ let smokeTestArgs = [ "--dry-run" ]; }; genie-bootstrap-closure-check = mk "genie-bootstrap-closure-check" { + environment.GENIE_TYPESCRIPT_API_SERVER = "${nativeProducts.typescript-api-server}/bin/typescript-api-server"; binaryName = "genie-bootstrap-closure-check"; expectedProductKind = "cli"; + expectedExternalCapabilities = [ "typescript-api-server" ]; smokeTestArgs = [ "--help" ]; }; ci-tools = mk "ci-tools" { @@ -101,6 +105,10 @@ let MR_COMPOSITION_GIT_BIN = "${pkgs.git}/bin/git"; MR_COMPOSITION_PLATFORM = if pkgs.stdenv.hostPlatform.isDarwin then "darwin" else "linux"; MR_COMPOSITION_SYSTEM = pkgs.stdenv.hostPlatform.system; + MR_COMPOSITION_WATCHMAN_BIN = "${pkgs.watchman}/bin/watchman"; + } + // pkgs.lib.optionalAttrs (capabilityProjection != null) { + MR_CAPABILITY_PROJECTION = "${capabilityProjection}"; }; expectedExternalCapabilities = [ "buck2" @@ -180,17 +188,32 @@ let pathPackages = [ pkgs.nodejs ]; smokeTestArgs = [ "--help" ]; }; - # A module product, not a CLI: consumers import the file, so the candidate - # publishes a stable `lib/oxc-config.js` and proves it is importable. + # These are module products, not CLIs: consumers import the files. The + # composed package publishes stable paths for both oxlint plugin entries and + # keeps their independently attested product boundaries visible in passthru. oxcConfigModule = mk "oxc-config" { expectedProductKind = "module"; generateCompletions = false; }; - oxc-config = pkgs.runCommand "oxc-config-buck2-candidate" { } '' - mkdir -p "$out/lib" - ln -s ${oxcConfigModule}/libexec/${oxcConfigModule.checkedDescriptor.modulePath} "$out/lib/oxc-config.js" - ${pkgs.nodejs_24 or pkgs.nodejs}/bin/node -e 'import(process.argv[1])' "$out/lib/oxc-config.js" - ''; + oxcConfigStylexUpstreamModule = mk "oxc-config-stylex-upstream-plugin" { + expectedProductKind = "module"; + generateCompletions = false; + }; + oxc-config = + pkgs.runCommand "oxc-config-buck2-candidate" + { + passthru = { + pluginPath = "${oxcConfigModule}/libexec/${oxcConfigModule.checkedDescriptor.modulePath}"; + stylexUpstreamPluginPath = "${oxcConfigStylexUpstreamModule}/libexec/${oxcConfigStylexUpstreamModule.checkedDescriptor.modulePath}"; + }; + } + '' + mkdir -p "$out/lib" + ln -s ${oxcConfigModule}/libexec/${oxcConfigModule.checkedDescriptor.modulePath} "$out/lib/oxc-config.js" + ln -s ${oxcConfigStylexUpstreamModule}/libexec/${oxcConfigStylexUpstreamModule.checkedDescriptor.modulePath} "$out/lib/stylex-upstream-plugin.js" + ${pkgs.nodejs_24 or pkgs.nodejs}/bin/node -e 'Promise.all(process.argv.slice(1).map((path) => import(path)))' \ + "$out/lib/oxc-config.js" "$out/lib/stylex-upstream-plugin.js" + ''; # A candidate exists only when every product it composes is published, so an # unpublished product surfaces as a missing attribute instead of a candidate # wired to absent bytes. @@ -205,7 +228,10 @@ let ]; notion-md = [ "notion-md" ]; npm-release = [ "npm-release" ]; - oxc-config = [ "oxc-config" ]; + oxc-config = [ + "oxc-config" + "oxc-config-stylex-upstream-plugin" + ]; tui-stories = [ "tui-stories" ]; }; candidates = { diff --git a/nix/workspace-tools/lib/buck2-runtime-inspect-elf-static.nix b/nix/workspace-tools/lib/buck2-runtime-inspect-elf-static.nix new file mode 100644 index 0000000000..4f2db3946b --- /dev/null +++ b/nix/workspace-tools/lib/buck2-runtime-inspect-elf-static.nix @@ -0,0 +1,65 @@ +# Inspect an extracted buck-build-product/v1 elf-static payload without +# rewriting it. The descriptor is a claim; readelf output is the observation. +{ + pkgs, + readelf ? "${pkgs.binutils}/bin/readelf", +}: + +pkgs.writeShellScript "buck2-runtime-inspect-elf-static" '' + set -euo pipefail + export LC_ALL=C + + fail() { + echo "buck2-runtime-inspect-elf-static: FATAL - $*" >&2 + exit 1 + } + + [ "$#" -eq 2 ] || fail "usage: $0 DESCRIPTOR_JSON EXTRACTED_ROOT" + descriptor="$1" + root="$2" + [ -f "$descriptor" ] || fail "descriptor does not exist" + [ -d "$root" ] || fail "extracted root does not exist" + + [ "$(${pkgs.jq}/bin/jq -r '.runtime.kind' "$descriptor")" = elf-static ] \ + || fail "descriptor runtime kind must be elf-static" + [ "$(${pkgs.jq}/bin/jq -r '.runtime.inspectionContract' "$descriptor")" = elf-static/v1 ] \ + || fail "unsupported inspection contract" + + inspect_entrypoint() { + local relative="$1" + local executable="$root/$relative" + [ -f "$executable" ] && [ ! -L "$executable" ] \ + || fail "entrypoint must be a regular non-symlink file: $relative" + [ -x "$executable" ] || fail "entrypoint is not executable: $relative" + + local actual_class expected_class raw_machine actual_machine expected_machine headers + actual_class="$(${readelf} --file-header "$executable" \ + | ${pkgs.gawk}/bin/awk -F: '$1 ~ /^[[:space:]]*Class$/ { sub(/^[[:space:]]+/, "", $2); print $2 }')" + expected_class="$(${pkgs.jq}/bin/jq -r '.runtime.elfClass' "$descriptor")" + [ "$actual_class" = "$expected_class" ] \ + || fail "ELF class mismatch for $relative: expected $expected_class, got $actual_class" + + raw_machine="$(${readelf} --file-header "$executable" \ + | ${pkgs.gawk}/bin/awk -F: '$1 ~ /^[[:space:]]*Machine$/ { sub(/^[[:space:]]+/, "", $2); print $2 }')" + case "$raw_machine" in + "Advanced Micro Devices X86-64") actual_machine=x86_64 ;; + "AArch64") actual_machine=aarch64 ;; + *) fail "unsupported ELF machine for $relative: $raw_machine" ;; + esac + expected_machine="$(${pkgs.jq}/bin/jq -r '.runtime.machine' "$descriptor")" + [ "$actual_machine" = "$expected_machine" ] \ + || fail "ELF machine mismatch for $relative: expected $expected_machine, got $actual_machine" + + headers="$(${readelf} --program-headers "$executable")" \ + || fail "readelf --program-headers failed for $relative" + printf '%s\n' "$headers" | ${pkgs.gnugrep}/bin/grep -Eq '^[[:space:]]*LOAD[[:space:]]' \ + || fail "entrypoint has no loadable ELF segment: $relative" + if printf '%s\n' "$headers" | ${pkgs.gnugrep}/bin/grep -Eq '^[[:space:]]*(INTERP|DYNAMIC)[[:space:]]'; then + fail "entrypoint is not static: $relative" + fi + } + + while IFS= read -r entrypoint; do + inspect_entrypoint "$entrypoint" + done < <(${pkgs.jq}/bin/jq -r '.entrypoints[]' "$descriptor") +'' diff --git a/nix/workspace-tools/lib/buck2-runtime-inspect-mach-o-dynamic.nix b/nix/workspace-tools/lib/buck2-runtime-inspect-mach-o-dynamic.nix index 831f6ab985..d05d4e179c 100644 --- a/nix/workspace-tools/lib/buck2-runtime-inspect-mach-o-dynamic.nix +++ b/nix/workspace-tools/lib/buck2-runtime-inspect-mach-o-dynamic.nix @@ -76,7 +76,10 @@ let headers="$(${pkgs.lib.escapeShellArg inspectionTools.otool.executable} -hv "$executable")" \ || fail "otool header inspection failed for $relative" header_architecture="$(printf '%s\n' "$headers" | ${pkgs.gawk}/bin/awk ' - NR == 2 { print $2; seen = 1 } + $1 == "MH_MAGIC_64" && ($2 == "ARM64" || $2 == "X86_64") { + print tolower($2) + seen++ + } END { if (seen != 1) exit 2 } ')" || fail "malformed Mach-O architecture observation: $relative" [ "$header_architecture" = "$actual_architecture" ] \ @@ -93,7 +96,8 @@ let print platform, minos } ') || fail "malformed Mach-O build-version observation: $relative" - [ "$actual_platform" = "MACOS" ] || fail "Mach-O build platform mismatch for $relative" + [ "$actual_platform" = "MACOS" ] || [ "$actual_platform" = "1" ] \ + || fail "Mach-O build platform mismatch for $relative" [ "$actual_minimum_os" = "$(${pkgs.jq}/bin/jq -r '.runtime.minimumOs' "$descriptor")" ] \ || fail "Mach-O minimum OS mismatch for $relative" @@ -111,7 +115,12 @@ let if printf '%s\n' "$load_commands" | ${pkgs.gnugrep}/bin/grep -Eq '^ cmd LC_RPATH$'; then fail "Mach-O LC_RPATH must be absent: $relative" fi - local signature_offset signature_size file_size magic declared_size count index slot blob_offset blob_magic flags + local signing_policy signature_offset signature_size file_size magic declared_size count index slot blob_offset blob_magic blob_size flags cms_size cms_count + signing_policy="$(${pkgs.jq}/bin/jq -r '.runtime.signingPolicy' "$descriptor")" + case "$signing_policy" in + adhoc/v1|embedded/v1) ;; + *) fail "unsupported Mach-O signing policy: $signing_policy" ;; + esac read -r signature_offset signature_size < <(printf '%s\n' "$load_commands" | ${pkgs.gawk}/bin/awk ' /^ cmd LC_CODE_SIGNATURE$/ { in_signature = 1; matches++; next } in_signature && /^ dataoff / { offset = $2; next } @@ -129,27 +138,50 @@ let [ "$magic" -eq 4208856256 ] || fail "Mach-O code signature is not a superblob: $relative" declared_size="$(read_be32 "$executable" "$((signature_offset + 4))")" count="$(read_be32 "$executable" "$((signature_offset + 8))")" - [ "$declared_size" -eq "$signature_size" ] \ - && [ "$count" -le "$(( (signature_size - 12) / 8 ))" ] \ + [ "$declared_size" -ge 12 ] \ + && [ "$declared_size" -le "$signature_size" ] \ + && [ "$count" -le "$(( (declared_size - 12) / 8 ))" ] \ || fail "malformed Mach-O code signature superblob: $relative" flags= + cms_size= + cms_count=0 index=0 while [ "$index" -lt "$count" ]; do slot="$(read_be32 "$executable" "$((signature_offset + 12 + index * 8))")" blob_offset="$(read_be32 "$executable" "$((signature_offset + 16 + index * 8))")" - [ "$blob_offset" -le "$((signature_size - 16))" ] \ + [ "$blob_offset" -le "$((declared_size - 8))" ] \ || fail "Mach-O code-signature blob is outside the superblob: $relative" - [ "$slot" -ne 65536 ] || fail "Mach-O CMS signature must be absent: $relative" + if [ "$slot" -eq 65536 ]; then + blob_magic="$(read_be32 "$executable" "$((signature_offset + blob_offset))")" + blob_size="$(read_be32 "$executable" "$((signature_offset + blob_offset + 4))")" + [ "$blob_magic" -eq 4208855809 ] \ + && [ "$blob_size" -ge 8 ] \ + && [ "$((blob_offset + blob_size))" -le "$declared_size" ] \ + || fail "Mach-O CMS signature blob is invalid: $relative" + cms_size="$blob_size" + cms_count="$((cms_count + 1))" + fi if [ "$slot" -eq 0 ]; then blob_magic="$(read_be32 "$executable" "$((signature_offset + blob_offset))")" - [ "$blob_magic" -eq 4208856066 ] \ - || fail "Mach-O CodeDirectory has invalid magic: $relative" + blob_size="$(read_be32 "$executable" "$((signature_offset + blob_offset + 4))")" + [ "$blob_magic" -ge 4208856066 ] \ + && [ "$blob_magic" -le 4208856068 ] \ + && [ "$blob_size" -ge 16 ] \ + && [ "$((blob_offset + blob_size))" -le "$declared_size" ] \ + || fail "Mach-O CodeDirectory is invalid: $relative" flags="$(read_be32 "$executable" "$((signature_offset + blob_offset + 12))")" fi index="$((index + 1))" done [ -n "$flags" ] || fail "Mach-O CodeDirectory must be present: $relative" - [ "$((flags & 2))" -eq 2 ] || fail "Mach-O CodeDirectory must carry the ad-hoc flag: $relative" + [ "$cms_count" -eq 1 ] || fail "Mach-O CMS signature wrapper must be present exactly once: $relative" + if [ "$signing_policy" = adhoc/v1 ]; then + [ "$((flags & 2))" -eq 2 ] || fail "Mach-O CodeDirectory must carry the ad-hoc flag: $relative" + [ "$cms_size" -eq 8 ] || fail "Mach-O CMS signature blob must be empty: $relative" + else + [ "$((flags & 2))" -eq 0 ] || fail "Mach-O CodeDirectory must not carry the ad-hoc flag: $relative" + [ "$cms_size" -gt 8 ] || fail "Mach-O CMS signature blob must be embedded: $relative" + fi } while IFS= read -r entrypoint; do diff --git a/nix/workspace-tools/lib/mk-pnpm-deps.nix b/nix/workspace-tools/lib/mk-pnpm-deps.nix index c63f64b6c6..eb8c426bef 100644 --- a/nix/workspace-tools/lib/mk-pnpm-deps.nix +++ b/nix/workspace-tools/lib/mk-pnpm-deps.nix @@ -18,7 +18,7 @@ # Downstream repos should therefore follow `effect-utils/nixpkgs` when they # consume these prepared trees so the full builder graph stays canonical. # -# Provides two functions used by both mk-pnpm-cli.nix and oxc-config-plugin.nix: +# Provides two functions used by mk-pnpm-cli.nix: # # 1. mkDeps: Creates a fixed-output derivation (FOD) that installs a staged # manifest-only workspace and stores the resulting prepared install tree as diff --git a/nix/workspace-tools/lib/mk-rust-workspace-source.nix b/nix/workspace-tools/lib/mk-rust-workspace-source.nix deleted file mode 100644 index 728a821cec..0000000000 --- a/nix/workspace-tools/lib/mk-rust-workspace-source.nix +++ /dev/null @@ -1,48 +0,0 @@ -{ lib, pkgs }: - -{ - repositoryRoot, - workspaceRoot, - packageRoot, - includeReadme ? false, - includeTests ? true, -}: -let - workspaceManifest = workspaceRoot + "/Cargo.toml"; - workspace = builtins.fromTOML (builtins.readFile workspaceManifest); - memberManifests = map (member: workspaceRoot + "/${member}/Cargo.toml") workspace.workspace.members; - rustSource = lib.fileset.toSource { - root = workspaceRoot; - fileset = lib.fileset.unions [ - workspaceManifest - (workspaceRoot + "/Cargo.lock") - ]; - }; - packageSource = lib.fileset.toSource { - root = packageRoot; - fileset = lib.fileset.unions ( - [ - (packageRoot + "/Cargo.toml") - (lib.fileset.fileFilter (file: file.hasExt "rs") (packageRoot + "/src")) - ] - ++ lib.optional includeReadme (packageRoot + "/README.md") - ++ lib.optional includeTests (lib.fileset.maybeMissing (packageRoot + "/tests")) - ); - }; - packageRelative = lib.removePrefix "${toString repositoryRoot}/" (toString packageRoot); - copyMemberManifests = lib.concatMapStringsSep "\n" ( - manifest: - let - relative = lib.removePrefix "${toString repositoryRoot}/" (toString manifest); - in - ''install -Dm0644 ${manifest} "$out/${relative}"'' - ) memberManifests; -in -pkgs.runCommand "rust-workspace-source" { } '' - mkdir -p "$out/$(dirname ${lib.escapeShellArg packageRelative})" - cp -R ${rustSource} "$out/rust" - cp -R ${packageSource} "$out/${packageRelative}" - chmod -R u+w "$out" - cp ${repositoryRoot + "/rust-toolchain.toml"} "$out/rust-toolchain.toml" - ${copyMemberManifests} -'' diff --git a/nix/workspace-tools/lib/tests/buck2-bridge.nix b/nix/workspace-tools/lib/tests/buck2-bridge.nix index a857329f1e..3da417aa60 100644 --- a/nix/workspace-tools/lib/tests/buck2-bridge.nix +++ b/nix/workspace-tools/lib/tests/buck2-bridge.nix @@ -3,6 +3,8 @@ let importArtifact = import ../buck2-artifact-import.nix { inherit pkgs; }; hostArchitecture = if pkgs.stdenv.hostPlatform.isAarch64 then "aarch64" else "x86_64"; + # Keep the forbidden store reference stable when nixpkgs changes between cached evaluations. + storeReferenceFixture = builtins.toFile "buck2-store-reference-fixture" "fixture"; hostElfMachine = hostArchitecture; hostInterpreter = if pkgs.stdenv.hostPlatform.isAarch64 then @@ -137,19 +139,21 @@ let case "''${1-}" in -hv) printf '%s\n' \ + "$2:" \ 'Mach header' \ - 'MH_MAGIC_64 arm64 ALL 0x00 EXECUTE 0 0 NOUNDEFS' + ' magic cputype cpusubtype caps filetype ncmds sizeofcmds flags' \ + 'MH_MAGIC_64 ARM64 ALL 0x00 EXECUTE 19 1984 NOUNDEFS' ;; -l) printf '%s\n' \ 'Load command 0' \ ' cmd LC_BUILD_VERSION' \ - ' platform MACOS' \ + ' platform 1' \ ' minos 14.0' \ 'Load command 1' \ ' cmd LC_CODE_SIGNATURE' \ ' dataoff 64' \ - ' datasize 44' + ' datasize 60' ;; -L) printf '%s\n' \ @@ -241,7 +245,7 @@ let mkdir -p payload/bin "$out" printf '%s\n' 'int main(void) { return 0; }' > fixture.c $CC -static fixture.c -o payload/bin/fixture-tool - printf '%s\n' ${pkgs.hello} >> payload/bin/fixture-tool + printf '%s\n' ${storeReferenceFixture} >> payload/bin/fixture-tool tar --create --format=gnu --sort=name --mtime=@1 --owner=0 --group=0 --numeric-owner \ --file "$out/artifact.tar" --directory payload . digest="sha256-$(openssl dgst -sha256 -binary "$out/artifact.tar" | openssl base64 -A)" diff --git a/nix/workspace-tools/lib/tests/buck2-bridge.sh b/nix/workspace-tools/lib/tests/buck2-bridge.sh index 34a8742afc..4dff009bb9 100755 --- a/nix/workspace-tools/lib/tests/buck2-bridge.sh +++ b/nix/workspace-tools/lib/tests/buck2-bridge.sh @@ -108,6 +108,31 @@ expect_build_failure \ "runtime inspector is not available for self-contained" \ "$unsupported_runtime_expr" +static_runtime_expr="let + $common_let + exported = builtins.storePath (builtins.getEnv \"BUCK2_BRIDGE_STATIC_PRODUCT\"); + original = builtins.fromJSON (builtins.readFile (exported + \"/descriptor.json\")); + descriptor = original // { + platform = original.platform // { abi = \"glibc\"; }; + runtime = { + elfClass = \"ELF64\"; + inspectionContract = \"elf-static/v1\"; + kind = \"elf-static\"; + machine = original.platform.architecture; + }; + }; +in test.mkImport { + inherit descriptor; + expectedDescriptorDigest = contract.descriptorDigest descriptor; + expectedPlatform = descriptor.platform; + artifact = exported + \"/artifact.tar\"; +}" +static_import="$(build_expr "$static_runtime_expr")" +[ -x "$static_import/bin/fixture-tool" ] || { + echo "buck2-bridge-test: admitted static entrypoint is missing" >&2 + exit 1 +} + dynamic_export="$(build_expr "($base_expr).dynamicExport")" export BUCK2_BRIDGE_DYNAMIC_EXPORT="$dynamic_export" jq -e ' @@ -241,7 +266,7 @@ rm -f "$empty_descriptor" mach_o_root="$(mktemp -d)" mkdir -p "$mach_o_root/bin" dd if=/dev/zero of="$mach_o_root/bin/fixture-tool" bs=1 count=64 status=none -printf '\372\336\014\300\000\000\000\054\000\000\000\001\000\000\000\000\000\000\000\024\372\336\014\002\000\000\000\030\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000' >>"$mach_o_root/bin/fixture-tool" +printf '\372\336\014\300\000\000\000\074\000\000\000\002\000\000\000\000\000\000\000\034\000\001\000\000\000\000\000\064\372\336\014\002\000\000\000\030\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\372\336\013\001\000\000\000\010' >>"$mach_o_root/bin/fixture-tool" chmod +x "$mach_o_root/bin/fixture-tool" mach_o_descriptor="$(mktemp)" jq -cn '{ @@ -264,15 +289,23 @@ in import (repo + \"/nix/workspace-tools/lib/buck2-runtime-inspect-mach-o-dynami mach_o_inspector_out="$(build_expr "$mach_o_inspector_expr")" "$mach_o_inspector_out" "$mach_o_descriptor" "$mach_o_root" cp "$mach_o_root/bin/fixture-tool" "$mach_o_root/bin/no-adhoc-tool" -printf '\000\000\000\000' | dd of="$mach_o_root/bin/no-adhoc-tool" bs=1 seek=96 conv=notrunc status=none +printf '\000\000\000\000' | dd of="$mach_o_root/bin/no-adhoc-tool" bs=1 seek=104 conv=notrunc status=none jq '.entrypoints = ["bin/no-adhoc-tool"]' "$mach_o_descriptor" >"$mach_o_descriptor.no-adhoc" expect_command_failure "Mach-O CodeDirectory without ad-hoc flag" "must carry the ad-hoc flag" \ "$mach_o_inspector_out" "$mach_o_descriptor.no-adhoc" "$mach_o_root" cp "$mach_o_root/bin/fixture-tool" "$mach_o_root/bin/cms-tool" -printf '\000\001\000\000' | dd of="$mach_o_root/bin/cms-tool" bs=1 seek=76 conv=notrunc status=none +printf '\024' | dd of="$mach_o_root/bin/cms-tool" bs=1 seek=99 conv=notrunc status=none +printf '\060' | dd of="$mach_o_root/bin/cms-tool" bs=1 seek=91 conv=notrunc status=none +printf '\372\336\013\001\000\000\000\014\001\002\003\004' \ + | dd of="$mach_o_root/bin/cms-tool" bs=1 seek=112 conv=notrunc status=none jq '.entrypoints = ["bin/cms-tool"]' "$mach_o_descriptor" >"$mach_o_descriptor.cms" -expect_command_failure "Mach-O CMS signature slot" "CMS signature must be absent" \ +expect_command_failure "ad-hoc Mach-O with non-empty CMS signature" "CMS signature blob must be empty" \ "$mach_o_inspector_out" "$mach_o_descriptor.cms" "$mach_o_root" +cp "$mach_o_root/bin/cms-tool" "$mach_o_root/bin/embedded-tool" +printf '\000\000\000\000' | dd of="$mach_o_root/bin/embedded-tool" bs=1 seek=104 conv=notrunc status=none +jq '.entrypoints = ["bin/embedded-tool"] | .runtime.signingPolicy = "embedded/v1"' \ + "$mach_o_descriptor" >"$mach_o_descriptor.embedded" +"$mach_o_inspector_out" "$mach_o_descriptor.embedded" "$mach_o_root" hostile_mach_o_inspector_expr="let $common_let in import (repo + \"/nix/workspace-tools/lib/buck2-runtime-inspect-mach-o-dynamic.nix\") { @@ -298,7 +331,8 @@ fat_mach_o_inspector_out="$(build_expr "$fat_mach_o_inspector_expr")" expect_command_failure "Mach-O universal binary" "must contain exactly one architecture" \ "$fat_mach_o_inspector_out" "$mach_o_descriptor" "$mach_o_root" rm -rf "$mach_o_root" -rm -f "$mach_o_descriptor" "$mach_o_descriptor.no-adhoc" "$mach_o_descriptor.cms" +rm -f "$mach_o_descriptor" "$mach_o_descriptor.no-adhoc" "$mach_o_descriptor.cms" \ + "$mach_o_descriptor.embedded" tampered_archive="$(mktemp)" cp "$dynamic_export/artifact.tar" "$tampered_archive" diff --git a/nix/workspace-tools/lib/tests/buck2-build-product-contract.sh b/nix/workspace-tools/lib/tests/buck2-build-product-contract.sh index 70b7e21320..c4a39308e8 100755 --- a/nix/workspace-tools/lib/tests/buck2-build-product-contract.sh +++ b/nix/workspace-tools/lib/tests/buck2-build-product-contract.sh @@ -241,7 +241,7 @@ expect_eval_failure \ entrypoints = [ "bin/fixture-tool" "bin/fixture-tool" ]; })' -for variant in interpreter elf-dynamic mach-o-dynamic self-contained; do +for variant in interpreter elf-dynamic elf-static mach-o-dynamic self-contained; do platform_override='' case "$variant" in interpreter) @@ -251,6 +251,10 @@ for variant in interpreter elf-dynamic mach-o-dynamic self-contained; do runtime='{ kind = "elf-dynamic"; inspectionContract = "elf-dynamic/v1"; elfClass = "ELF64"; machine = "x86_64"; interpreter = "/lib64/ld-linux-x86-64.so.2"; neededLibraries = [ "libc.so.6" ]; symbolVersionFloors = [ "GLIBC_2.39" ]; rpathPolicy = "empty/v1"; }' platform_override='platform = valid.platform // { abi = "glibc"; };' ;; + elf-static) + runtime='{ kind = "elf-static"; inspectionContract = "elf-static/v1"; elfClass = "ELF64"; machine = "x86_64"; }' + platform_override='platform = valid.platform // { abi = "glibc"; };' + ;; mach-o-dynamic) runtime='{ kind = "mach-o-dynamic"; inspectionContract = "mach-o-dynamic/v1"; architecture = "arm64"; minimumOs = "14.0"; dylibs = [ "/usr/lib/libSystem.B.dylib" ]; installNamePolicy = "system-only/v1"; rpathPolicy = "empty/v1"; signingPolicy = "adhoc/v1"; }' platform_override='platform = { os = "darwin"; architecture = "aarch64"; abi = "darwin"; };' @@ -369,9 +373,14 @@ expect_eval_failure \ runtime = validMachO.runtime // { rpathPolicy = "declared/v1"; }; })' +embedded_mach_o_digest="$(eval_raw 'contract.descriptorDigest (validMachO // { + runtime = validMachO.runtime // { signingPolicy = "embedded/v1"; }; +})')" +[[ "$embedded_mach_o_digest" =~ ^sha256:[0-9a-f]{64}$ ]] + expect_eval_failure \ "Mach-O signing policy mismatch" \ - "descriptor.runtime.signingPolicy must be adhoc/v1" \ + "descriptor.runtime.signingPolicy is unsupported" \ 'contract.descriptorDigest (validMachO // { runtime = validMachO.runtime // { signingPolicy = "unsigned/v1"; }; })' @@ -425,6 +434,32 @@ expect_eval_failure \ }; })' +expect_eval_failure \ + "static ELF machine and platform architecture mismatch" \ + "descriptor.runtime.machine must match descriptor.platform.architecture" \ + 'contract.descriptorDigest (valid // { + platform = valid.platform // { abi = "glibc"; }; + runtime = { + kind = "elf-static"; + inspectionContract = "elf-static/v1"; + elfClass = "ELF64"; + machine = "aarch64"; + }; + })' + +expect_eval_failure \ + "static ELF on a non-Linux platform" \ + "elf-static requires descriptor.platform.os = linux" \ + 'contract.descriptorDigest (valid // { + platform = { os = "darwin"; architecture = "x86_64"; abi = "glibc"; }; + runtime = { + kind = "elf-static"; + inspectionContract = "elf-static/v1"; + elfClass = "ELF64"; + machine = "x86_64"; + }; + })' + expect_eval_failure \ "dynamic ELF on a non-Linux platform" \ "elf-dynamic requires descriptor.platform.os = linux" \ diff --git a/nix/workspace-tools/lib/tests/buck2-release-products.sh b/nix/workspace-tools/lib/tests/buck2-release-products.sh index 1e128245d4..f4ae9b8640 100755 --- a/nix/workspace-tools/lib/tests/buck2-release-products.sh +++ b/nix/workspace-tools/lib/tests/buck2-release-products.sh @@ -53,7 +53,7 @@ expect_failure() { } summary="$(eval_loader "$repo_root/nix/buck2-products")" -expected_names='["ci-tools","genie","genie-bootstrap-closure-check","megarepo","notion-cli","notion-db-runtime","notion-md","npm-release","oxc-config","tui-stories"]' +expected_names='["ci-tools","genie","genie-bootstrap-closure-check","megarepo","notion-cli","notion-db-runtime","notion-md","npm-release","oxc-config","oxc-config-stylex-upstream-plugin","tui-stories"]' jq -e --argjson expected "$expected_names" ' .fullyPublished == true and @@ -73,11 +73,27 @@ jq -e --argjson expected "$expected_names" ' mkdir -p "$tmp/products" cp "$repo_root/nix/buck2-products/default.nix" "$tmp/products/default.nix" +cp "$repo_root/nix/buck2-products/targets.json" "$tmp/products/targets.json" +chmod u+w "$tmp/products/targets.json" write_mutation() { jq "$1" "$repo_root/nix/buck2-products/manifest.json" >"$tmp/products/manifest.json" } +write_target_mutation() { + local fingerprint + jq "$1" "$repo_root/nix/buck2-products/targets.json" >"$tmp/products/targets.next.json" + fingerprint="$(jq -cS '{ + generator: .provenance.generator, + schemaVersion: .schemaVersion, + semanticData: .products + }' "$tmp/products/targets.next.json" | tr -d '\n' | sha256sum)" + fingerprint="sha256:${fingerprint%% *}" + jq --arg fingerprint "$fingerprint" '.provenance.fingerprint = $fingerprint' \ + "$tmp/products/targets.next.json" >"$tmp/products/targets.json" + cp "$repo_root/nix/buck2-products/manifest.json" "$tmp/products/manifest.json" +} + write_mutation '.schema = "effect-utils/buck2-release-products/v0"' expect_failure "unsupported manifest schema" "unsupported manifest schema" @@ -102,11 +118,21 @@ expect_failure "release URL drift" "release URL does not match its tag and asset write_mutation '.products[0].release.hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="' expect_failure "release hash drift" "release hash does not match descriptor integrity" +write_target_mutation '.products |= .[1:]' +expect_failure "unpublished declaration" "declared target inventory does not match the published manifest" + +write_target_mutation '.products[0].target = .products[1].target' +expect_failure "duplicate declared target" "target inventory product targets must be unique" + +write_target_mutation '.products[0].target += "[descriptor]"' +expect_failure "configured declared target" "target inventory products are malformed" + jq -r '.releases | to_entries[] | "buck2-release-products-test: \(.key) \(.value.tag)"' <<<"$summary" publisher="$repo_root/nix/buck2-products/publish.sh" test -f "$publisher" cp "$repo_root/nix/buck2-products/manifest.json" "$tmp/manifest.before.json" +cp "$repo_root/nix/buck2-products/targets.json" "$tmp/targets.before.json" # Planning is a pure use of the same inventory contract. Put sentinels for all # network/mutation tools first on PATH so an accidental call is observable. @@ -130,15 +156,16 @@ if [[ -e "$tmp/unexpected-tools" ]]; then sed -n '1,160p' "$tmp/unexpected-tools" >&2 exit 1 fi -if ! cmp "$repo_root/nix/buck2-products/manifest.json" "$tmp/manifest.before.json"; then - echo "buck2-release-products-test: publisher dry-run mutated the inventory" >&2 +if ! cmp "$repo_root/nix/buck2-products/targets.json" "$tmp/targets.before.json"; then + echo "buck2-release-products-test: publisher dry-run mutated the target inventory" >&2 exit 1 fi +cmp "$repo_root/nix/buck2-products/manifest.json" "$tmp/manifest.before.json" if ! jq -e --argjson expected "$expected_names" ' .schema == "effect-utils/buck2-product-publication-plan/v1" and .repository == "overengineeringstudio/effect-utils" and [.products[].productName] == $expected and - (.products | length == 10) and + (.products | length == 11) and all( .products[]; (.candidateTarget | test("^([A-Za-z0-9_]+)?//")) and @@ -196,13 +223,22 @@ for forbidden in "$legacy_tool" "$legacy_token" "$legacy_cache_path"; do fi done -jq '.products[1].descriptor.target = .products[0].descriptor.target' \ - "$repo_root/nix/buck2-products/manifest.json" >"$tmp/duplicate-target.json" -if PATH="$tmp/bin:$PATH" bash "$publisher" --dry-run --inventory "$tmp/duplicate-target.json" >"$publish_failure" 2>&1; then +jq '.products[1].target = .products[0].target' \ + "$repo_root/nix/buck2-products/targets.json" >"$tmp/duplicate-target.json" +if PATH="$tmp/bin:$PATH" bash "$publisher" --dry-run --targets "$tmp/duplicate-target.json" >"$publish_failure" 2>&1; then echo "buck2-release-products-test: publisher accepted a duplicate candidate target" >&2 exit 1 fi -grep -F "inventory violates effect-utils/buck2-release-products/v1" "$publish_failure" >/dev/null +grep -F "target inventory violates effect-utils/buck2-release-targets/v1" "$publish_failure" >/dev/null +test ! -e "$tmp/unexpected-tools" + +jq '.provenance.fingerprint = "sha256:" + ("0" * 64)' \ + "$repo_root/nix/buck2-products/targets.json" >"$tmp/stale-fingerprint.json" +if PATH="$tmp/bin:$PATH" bash "$publisher" --dry-run --targets "$tmp/stale-fingerprint.json" >"$publish_failure" 2>&1; then + echo "buck2-release-products-test: publisher accepted a stale target fingerprint" >&2 + exit 1 +fi +grep -F "target inventory fingerprint does not match its declared products" "$publish_failure" >/dev/null test ! -e "$tmp/unexpected-tools" if grep -F -- '--clobber' "$publisher" >/dev/null; then @@ -237,19 +273,20 @@ echo "buck2-release-products-test: publisher dry-run/refusal OK" live="$tmp/live" mkdir -p "$live/bin" "$live/build" real_nix="$(command -v nix)" +real_nix_path="$PATH" printf '{}\n' >"$live/outputs.json" # Each product is materialized once: real bytes, a real digest, a real v2 -# descriptor, a real inventory entry and a Buck output mapping. Scenarios then -# compose inventories from these products, so partially published multi-product -# runs are testable. +# descriptor, a target inventory entry and a Buck output mapping. Scenarios then +# compose generated-inventory-shaped target sets, so partially published +# multi-product runs are testable. declare -A live_tag=() live_asset=() live_module=() live_add_product() { local name="$1" module_path="$2" body="$3" local target="root//live:$name" local module="$live/build/$module_path" printf '%s\n' "$body" >"$module" - local size sha sri descriptor descriptor_sha tag asset + local size sha sri descriptor tag asset size="$(stat -c '%s' "$module")" sha="$(sha256sum "$module")" sha="${sha%% *}" @@ -281,26 +318,10 @@ live_add_product() { sizeBytes: $sizeBytes, target: $target }' >"$descriptor" - descriptor_sha="$(jq -cS . "$descriptor" | tr -d '\n' | sha256sum)" - descriptor_sha="${descriptor_sha%% *}" tag="buck2-product-v3-$name-$sha" asset="$sha-$module_path" - jq -nS \ - --slurpfile descriptor "$descriptor" \ - --arg descriptorSha256 "$descriptor_sha" \ - --arg tag "$tag" \ - --arg name "$asset" \ - --arg hash "$sri" \ - '{ - descriptor: $descriptor[0], - descriptorSha256: $descriptorSha256, - release: { - tag: $tag, - name: $name, - url: ("https://github.com/overengineeringstudio/effect-utils/releases/download/" + $tag + "/" + $name), - hash: $hash - } - }' >"$live/entry-$name.json" + jq -nS --arg name "$name" --arg target "$target" \ + '{name:$name,target:$target}' >"$live/target-$name.json" jq --arg target "$target" --arg module "$module" --arg descriptor "$descriptor" \ '.[$target] = $module | .[$target + "[descriptor]"] = $descriptor' \ "$live/outputs.json" >"$live/outputs.next.json" @@ -313,12 +334,34 @@ live_add_product() { live_inventory() { local path="$1" shift - local name + local name fingerprint local -a entries=() for name in "$@"; do - entries+=("$live/entry-$name.json") + entries+=("$live/target-$name.json") done - jq -sS '{schema:"effect-utils/buck2-release-products/v1",products:.}' "${entries[@]}" >"$path" + jq -sS '{ + products: ., + provenance: { + fingerprint: "", + generator: "effect-utils/genie/buck2-javascript-release-targets", + regenerationCommand: "devenv tasks run genie:run", + semanticInputs: [ + "genie/buck2/javascript-product-registry.ts", + "nix/buck2-products/targets.json.genie.ts" + ], + source: "nix/buck2-products/targets.json.genie.ts" + }, + schemaVersion: 1 + }' "${entries[@]}" >"$path" + fingerprint="$(jq -cS '{ + generator: .provenance.generator, + schemaVersion: .schemaVersion, + semanticData: .products + }' "$path" | tr -d '\n' | sha256sum)" + fingerprint="sha256:${fingerprint%% *}" + jq --arg fingerprint "$fingerprint" '.provenance.fingerprint = $fingerprint' \ + "$path" >"$path.next" + mv "$path.next" "$path" } live_add_product live-product live-product.mjs 'export const liveProduct = "live";' @@ -360,7 +403,7 @@ cat >"$live/bin/nix" <"$log" 2>&1 || status=$? + bash "$publisher" --targets "$targets" >"$log" 2>&1 || status=$? if [[ "$expect" == ok && "$status" -ne 0 ]]; then echo "buck2-release-products-test: expected live $label to succeed" >&2 sed -n '1,160p' "$log" >&2 @@ -856,5 +899,6 @@ live_reject preflight-mismatch 'VERIFY-ASSET' grep -F "does not hold exactly the staged module" "$live/preflight-mismatch.log" >/dev/null echo "buck2-release-products-test: live preflight mismatch blocked every product" +cmp "$repo_root/nix/buck2-products/targets.json" "$tmp/targets.before.json" cmp "$repo_root/nix/buck2-products/manifest.json" "$tmp/manifest.before.json" echo "buck2-release-products-test: OK" diff --git a/packages/@overeng/agent-session-ingest/BUCK b/packages/@overeng/agent-session-ingest/BUCK index 5df3cd4b3d..b9b5491dfe 100644 --- a/packages/@overeng/agent-session-ingest/BUCK +++ b/packages/@overeng/agent-session-ingest/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/agent-session-ingest/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:0f8e15e151e9f4df4e282180f6ae3fd9175e277e22c8095cfb0ca150255c190f -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/agent-session-ingest/BUCK.genie.ts, packages/@overeng/agent-session-ingest/BUCK.genie.ts, packages/@overeng/agent-session-ingest/package.json.genie.ts, packages/@overeng/agent-session-ingest/src/**/*.cts, packages/@overeng/agent-session-ingest/src/**/*.js, packages/@overeng/agent-session-ingest/src/**/*.mts, packages/@overeng/agent-session-ingest/src/**/*.spec.cjs, packages/@overeng/agent-session-ingest/src/**/*.spec.jsx, packages/@overeng/agent-session-ingest/src/**/*.spec.mjs, packages/@overeng/agent-session-ingest/src/**/*.test.cjs, packages/@overeng/agent-session-ingest/src/**/*.test.jsx, packages/@overeng/agent-session-ingest/src/**/*.test.mjs, packages/@overeng/agent-session-ingest/src/**/*.ts, packages/@overeng/agent-session-ingest/src/**/*.tsx, packages/@overeng/agent-session-ingest/src/**/__snapshots__/*.snap, packages/@overeng/agent-session-ingest/tsconfig.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts +# Semantic fingerprint: sha256:25cabbf9d1b83b7e754341f83cd1217e7cb2792eaa2c60fa0657f10ef7a9c466 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/agent-session-ingest/BUCK.genie.ts, packages/@overeng/agent-session-ingest/BUCK.genie.ts, packages/@overeng/agent-session-ingest/package.json.genie.ts, packages/@overeng/agent-session-ingest/src/**/*.cts, packages/@overeng/agent-session-ingest/src/**/*.js, packages/@overeng/agent-session-ingest/src/**/*.mts, packages/@overeng/agent-session-ingest/src/**/*.spec.cjs, packages/@overeng/agent-session-ingest/src/**/*.spec.jsx, packages/@overeng/agent-session-ingest/src/**/*.spec.mjs, packages/@overeng/agent-session-ingest/src/**/*.test.cjs, packages/@overeng/agent-session-ingest/src/**/*.test.jsx, packages/@overeng/agent-session-ingest/src/**/*.test.mjs, packages/@overeng/agent-session-ingest/src/**/*.ts, packages/@overeng/agent-session-ingest/src/**/*.tsx, packages/@overeng/agent-session-ingest/src/**/__snapshots__/*.snap, packages/@overeng/agent-session-ingest/tsconfig.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -48,6 +49,14 @@ export_materialization_inputs([ "src/watch.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/agent-session-ingest", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_agent_session_ingest_6dae38a37f1d", @@ -103,7 +112,7 @@ package_view( "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -153,7 +162,7 @@ package_view( "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/agent-session-ingest/BUCK.genie.ts b/packages/@overeng/agent-session-ingest/BUCK.genie.ts index 30df5726f8..d72e39f42f 100644 --- a/packages/@overeng/agent-session-ingest/BUCK.genie.ts +++ b/packages/@overeng/agent-session-ingest/BUCK.genie.ts @@ -20,11 +20,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils-dev:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/buck2-tools/BUCK b/packages/@overeng/buck2-tools/BUCK new file mode 100644 index 0000000000..93a9d1c309 --- /dev/null +++ b/packages/@overeng/buck2-tools/BUCK @@ -0,0 +1,167 @@ +# Generated file - DO NOT EDIT +# Source: BUCK.genie.ts + +# Projection source: packages/@overeng/buck2-tools/BUCK.genie.ts +# Projection schema version: 11 +# Projection generator: effect-utils/genie/buck2-typescript-package-projection +# Semantic fingerprint: sha256:d01cd05dc66ce370c04ce653238598cd494037c8acdf26a9bd006118d624a0c2 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/BUCK.genie.ts, packages/@overeng/buck2-tools/BUCK.genie.ts, packages/@overeng/buck2-tools/package.json.genie.ts, packages/@overeng/buck2-tools/src/**/*.cts, packages/@overeng/buck2-tools/src/**/*.js, packages/@overeng/buck2-tools/src/**/*.mts, packages/@overeng/buck2-tools/src/**/*.spec.cjs, packages/@overeng/buck2-tools/src/**/*.spec.jsx, packages/@overeng/buck2-tools/src/**/*.spec.mjs, packages/@overeng/buck2-tools/src/**/*.test.cjs, packages/@overeng/buck2-tools/src/**/*.test.jsx, packages/@overeng/buck2-tools/src/**/*.test.mjs, packages/@overeng/buck2-tools/src/**/*.ts, packages/@overeng/buck2-tools/src/**/*.tsx, packages/@overeng/buck2-tools/src/**/__snapshots__/*.snap, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/buck2-tools/tsconfig.json.genie.ts +# Regenerate: devenv tasks run genie:run + +load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") +load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") +load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") + +export_file( + name = "package.json", + src = "package.json", + visibility = ["PUBLIC"], +) + +export_materialization_inputs([ + "src/buck-watch.ts", + "src/buck-watch.unit.test.ts", + "src/canonical.ts", + "src/editor-view-authority.integration.test.ts", + "src/editor-view-authority.ts", + "src/editor-view.integration.test.ts", + "src/editor-view.ts", + "src/editor-view.unit.test.ts", + "src/javascript-runner.integration.test.ts", + "src/javascript-runner.ts", + "src/javascript-runner.unit.test.ts", + "src/mod.ts", + "src/owned-files.integration.test.ts", + "src/owned-files.ts", + "src/owned-files.unit.test.ts", + "src/package-command-runner.integration.test.ts", + "src/package-command-runner.ts", + "src/package-command-runner.unit.test.ts", + "src/package-tree.ts", + "src/package-tree.unit.test.ts", + "src/real-path.ts", + "src/repository-policy-runner.ts", + "src/repository-policy-runner.unit.test.ts", + "src/static-check-runner.ts", + "src/typescript-runner.ts", + "src/typescript-runner.unit.test.ts", +]) + +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/buck2-tools", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + +alias( + name = "node_modules", + actual = "//buck2/dependencies:view_packages_overeng_buck2_tools_e521acf736cf", + visibility = ["PUBLIC"], +) + +alias( + name = "editor_inputs", + actual = ":node_modules", + visibility = ["PUBLIC"], +) + +package_view( + name = "package_tree", + dependency_view = "//buck2/dependencies:view_packages_overeng_buck2_tools_e521acf736cf", + files = { + "package.json": "package.json", + "src/buck-watch.ts": "src/buck-watch.ts", + "src/buck-watch.unit.test.ts": "src/buck-watch.unit.test.ts", + "src/canonical.ts": "src/canonical.ts", + "src/editor-view-authority.integration.test.ts": "src/editor-view-authority.integration.test.ts", + "src/editor-view-authority.ts": "src/editor-view-authority.ts", + "src/editor-view.integration.test.ts": "src/editor-view.integration.test.ts", + "src/editor-view.ts": "src/editor-view.ts", + "src/editor-view.unit.test.ts": "src/editor-view.unit.test.ts", + "src/javascript-runner.integration.test.ts": "src/javascript-runner.integration.test.ts", + "src/javascript-runner.ts": "src/javascript-runner.ts", + "src/javascript-runner.unit.test.ts": "src/javascript-runner.unit.test.ts", + "src/mod.ts": "src/mod.ts", + "src/owned-files.integration.test.ts": "src/owned-files.integration.test.ts", + "src/owned-files.ts": "src/owned-files.ts", + "src/owned-files.unit.test.ts": "src/owned-files.unit.test.ts", + "src/package-command-runner.integration.test.ts": "src/package-command-runner.integration.test.ts", + "src/package-command-runner.ts": "src/package-command-runner.ts", + "src/package-command-runner.unit.test.ts": "src/package-command-runner.unit.test.ts", + "src/package-tree.ts": "src/package-tree.ts", + "src/package-tree.unit.test.ts": "src/package-tree.unit.test.ts", + "src/real-path.ts": "src/real-path.ts", + "src/repository-policy-runner.ts": "src/repository-policy-runner.ts", + "src/repository-policy-runner.unit.test.ts": "src/repository-policy-runner.unit.test.ts", + "src/static-check-runner.ts": "src/static-check-runner.ts", + "src/typescript-runner.ts": "src/typescript-runner.ts", + "src/typescript-runner.unit.test.ts": "src/typescript-runner.unit.test.ts", + "tsconfig.json": "tsconfig.json", + }, + workspace_dist = { + }, + workspace_dependency_views = { + }, + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", + runtime_entry = "package-tree.ts", + visibility = ["PUBLIC"], +) + +editor_view_inputs( + name = "editor_view_inputs", + editor_inputs = ":editor_inputs", + package_tree = ":package_tree", + visibility = ["PUBLIC"], +) + +tsgo_typecheck( + name = "typecheck", + package_tree = ":package_tree", + visibility = ["PUBLIC"], +) + +tsgo_emit( + name = "dist", + package_tree = ":package_tree", + declaration_sources = { + }, + declaration_entrypoint = "src/mod.d.ts", + visibility = ["PUBLIC"], +) + +filegroup( + name = "package_tree_runtime", + srcs = { + "package-tree.ts": "src/package-tree.ts", + "real-path.ts": "src/real-path.ts", + }, + visibility = ["PUBLIC"], +) + +filegroup( + name = "package_command_runtime", + srcs = { + "package-command-runner.ts": "src/package-command-runner.ts", + "real-path.ts": "src/real-path.ts", + "typescript-runner.ts": "src/typescript-runner.ts", + }, + visibility = ["PUBLIC"], +) + +filegroup( + name = "javascript_action_runtime", + srcs = { + "javascript-runner.ts": "src/javascript-runner.ts", + "typescript-runner.ts": "src/typescript-runner.ts", + }, + visibility = ["PUBLIC"], +) + +export_file( + name = "typescript-runner.ts", + src = "src/typescript-runner.ts", + visibility = ["PUBLIC"], +) diff --git a/packages/@overeng/buck2-tools/BUCK.genie.ts b/packages/@overeng/buck2-tools/BUCK.genie.ts new file mode 100644 index 0000000000..85d22491ec --- /dev/null +++ b/packages/@overeng/buck2-tools/BUCK.genie.ts @@ -0,0 +1,14 @@ +import { withBuck2ToolsRuntimes } from '../../../genie/buck2/runtime-modules.ts' +import type { Buck2TypeScriptAdmission } from '../../../genie/buck2/typescript-admissions.ts' +import { buck2TypeScriptPackageProjection } from '../../../genie/buck2/typescript-package-projection.ts' + +export const buck2TypeScriptAdmission = { + dependencyImporter: '//buck2/dependencies:importer_packages_overeng_buck2_tools_e521acf736cf', + packageName: '@overeng/buck2-tools', + packagePath: 'packages/@overeng/buck2-tools', + projectionSource: 'packages/@overeng/buck2-tools/BUCK.genie.ts', + sourceRoots: ['src'], + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], +} as const satisfies Buck2TypeScriptAdmission + +export default withBuck2ToolsRuntimes(buck2TypeScriptPackageProjection(buck2TypeScriptAdmission)) diff --git a/packages/@overeng/buck2-tools/README.md b/packages/@overeng/buck2-tools/README.md index bcdcd72560..c36033b2e9 100644 --- a/packages/@overeng/buck2-tools/README.md +++ b/packages/@overeng/buck2-tools/README.md @@ -1,14 +1,23 @@ # `@overeng/buck2-tools` Repository-owned TypeScript helpers for Buck dependency materialization, -TypeScript execution, and the scoped editor view. +TypeScript execution, and workspace editor views. -## Scoped editor publisher +## Editor publisher -`src/editor-view.ts` publishes and checks the tui-core editor dependency view. -It consumes the built Buck `:editor_inputs` and `:node_modules` artifacts, -uses immutable Nix `cp -al` and GNU `mv --exchange --no-copy`, and retains all -published snapshots and any exchanged root-install directory. Repository tasks -`buck2:tui-core:publish-editor`, `buck2:tui-core:check-editor`, and the -exact-token `buck2:tui-core:recover-editor-lock` are scoped and are not wired -into global checks. +`src/editor-view.ts` atomically publishes and checks one dependency view. +`scripts/editor-view-authority.ts` derives the root source-generator consumer and +every package consumer from the canonical workspace registry, proves that Buck +owns each tracked manifest, builds every `:editor_view_inputs` manifest, and +invokes the publisher in deterministic order. Published snapshots byte-own the +finite provider-declared closure; no link points back into disposable +`buck-out`. + +`buck2:editor:bootstrap` publishes only the dependency views named by the +committed generated root manifest so `genie:check` can run before trusting the +generated graph. After generation and composition, repository tasks +`buck2:editor:authority`, `buck2:editor:publish`, and `buck2:editor:check` +operate on the complete current registry. The exact-token +`buck2:editor:recover-lock` task recovers only the named consumer's shared +publication lock. These tasks require a real composed megarepo workspace and +are not global check dependencies. diff --git a/packages/@overeng/buck2-tools/package.json b/packages/@overeng/buck2-tools/package.json index a68528172d..fbf45c3966 100644 --- a/packages/@overeng/buck2-tools/package.json +++ b/packages/@overeng/buck2-tools/package.json @@ -12,7 +12,10 @@ "type": "module", "private": true, "exports": { - ".": "./src/mod.ts" + ".": { + "types": "./dist/src/mod.d.ts", + "default": "./src/mod.ts" + } }, "devDependencies": { "@overeng/utils-dev": "workspace:^", diff --git a/packages/@overeng/buck2-tools/package.json.genie.ts b/packages/@overeng/buck2-tools/package.json.genie.ts index 624c6f5cc0..43b731f873 100644 --- a/packages/@overeng/buck2-tools/package.json.genie.ts +++ b/packages/@overeng/buck2-tools/package.json.genie.ts @@ -22,7 +22,10 @@ export default packageJson( name: '@overeng/buck2-tools', ...privatePackageDefaults, exports: { - '.': exportEntry('./src/mod.ts', { environment: 'node' }), + '.': exportEntry( + { types: './dist/src/mod.d.ts', default: './src/mod.ts' }, + { environment: 'node' }, + ), }, publishConfig: { access: 'public', diff --git a/packages/@overeng/buck2-tools/src/buck-watch.ts b/packages/@overeng/buck2-tools/src/buck-watch.ts index 43bb8efde3..c0704b890e 100755 --- a/packages/@overeng/buck2-tools/src/buck-watch.ts +++ b/packages/@overeng/buck2-tools/src/buck-watch.ts @@ -490,7 +490,7 @@ export type BuckReconcilerOptions = { readonly repoRoot: string readonly workspaceRoot: string readonly buck2: string - readonly editorViewProgram: string + readonly editorViewCommand: readonly [executable: string, ...prefix: string[]] readonly workspaceAuthority: string readonly cp: string readonly mv: string @@ -534,8 +534,9 @@ export const reconcileBuckViews = async ({ workspaceRoot: options.workspaceRoot, }) await execute({ - command: options.editorViewProgram, + command: options.editorViewCommand[0], args: [ + ...options.editorViewCommand.slice(1), options.mode, '--repo-root', options.repoRoot, diff --git a/packages/@overeng/buck2-tools/src/buck-watch.unit.test.ts b/packages/@overeng/buck2-tools/src/buck-watch.unit.test.ts index c617ddcc72..a69c60b383 100644 --- a/packages/@overeng/buck2-tools/src/buck-watch.unit.test.ts +++ b/packages/@overeng/buck2-tools/src/buck-watch.unit.test.ts @@ -271,7 +271,7 @@ describe('Buck watch reconciliation', () => { repoRoot: root, workspaceRoot: root, buck2: '/tools/buck2', - editorViewProgram: '/tools/editor-view', + editorViewCommand: ['/tools/bun', '/tools/editor-view'], workspaceAuthority: '/repo/authority.json', cp: '/tools/cp', mv: '/tools/mv', @@ -293,7 +293,8 @@ describe('Buck watch reconciliation', () => { expect(invocations[0]?.detached).toBeUndefined() expect(invocations[1]?.detached).toBe(true) expect(invocations[1]?.signal).toBeUndefined() - expect(invocations[1]?.command).toBe('/tools/editor-view') + expect(invocations[1]?.command).toBe('/tools/bun') + expect(invocations[1]?.args[0]).toBe('/tools/editor-view') expect(invocations[1]?.args).toContain('--backing-root') expect(invocations[1]?.args).toEqual( expect.arrayContaining([ @@ -317,7 +318,7 @@ describe('Buck watch reconciliation', () => { repoRoot: root, workspaceRoot: root, buck2: '/tools/buck2', - editorViewProgram: '/tools/editor-view', + editorViewCommand: ['/tools/bun', '/tools/editor-view'], workspaceAuthority: '/repo/authority.json', cp: '/tools/cp', mv: '/tools/mv', diff --git a/packages/@overeng/buck2-tools/src/editor-view-authority.integration.test.ts b/packages/@overeng/buck2-tools/src/editor-view-authority.integration.test.ts index 7720655d26..9785fbbd2d 100644 --- a/packages/@overeng/buck2-tools/src/editor-view-authority.integration.test.ts +++ b/packages/@overeng/buck2-tools/src/editor-view-authority.integration.test.ts @@ -1,4 +1,4 @@ -import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs' +import { mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' @@ -35,7 +35,7 @@ const makeRunner = ({ if (invocation.command.endsWith('/git') === true) return { status: 0, - stdout: Buffer.from('packages/z/package.json\0packages/a/package.json\0'), + stdout: Buffer.from('package.json\0packages/z/package.json\0packages/a/package.json\0'), stderr: Buffer.from(''), } const argument = invocation.args[4] @@ -49,13 +49,18 @@ const makeRunner = ({ JSON.stringify( Object.fromEntries( candidates.map((candidate) => { - const packagePath = candidate.slice(0, -'/package.json'.length) + const repositoryCandidate = candidate.replace(/^repos\/effect-utils\//, '') + const root = repositoryCandidate === 'package.json' + const packagePath = + root === true ? '.' : repositoryCandidate.slice(0, -'/package.json'.length) const owned = - packagePath === 'packages/a' ? missing === false : nonAdmittedOwned === true - return [ - candidate, - owned === true ? [`effect_utils//${packagePath}:package.json`] : [], - ] + root === true || + (packagePath === 'packages/a' ? missing === false : nonAdmittedOwned === true) + const owner = + root === true + ? 'effect_utils//:package.json' + : `effect_utils//${packagePath}:package.json` + return [candidate, owned === true ? [owner] : []] }), ), ), @@ -96,6 +101,59 @@ describe('editor view authority production flow', () => { } }) + it('proves the repository-root source-generator consumer explicitly', async () => { + const fixture = makeFixture() + try { + writeFileSync(join(fixture.root, 'package.json'), '{}\n') + const { ownershipCandidates, runCommand } = makeRunner() + const authority = await writeEditorViewAuthority({ + repoRoot: fixture.root, + workspaceRoot: fixture.root, + requiredPackages: ['.'], + cell: 'effect_utils', + buck2: '/nix/store/test-buck2/bin/buck2', + git: '/nix/store/test-git/bin/git', + output: fixture.output, + runCommand, + }) + + expect(ownershipCandidates).toEqual(['package.json']) + expect(authority.requiredPackages).toEqual(['.']) + expect(authority.ownedPackages).toEqual(['.']) + } finally { + rmSync(fixture.root, { recursive: true, force: true }) + } + }) + + it('queries Buck through the logical composed-workspace symlink', async () => { + const fixture = makeFixture() + const workspaceRoot = mkdtempSync(join(tmpdir(), 'editor-view-workspace-')) + const logicalRepoRoot = join(workspaceRoot, 'repos', 'effect-utils') + try { + mkdirSync(join(workspaceRoot, 'repos')) + symlinkSync(fixture.root, logicalRepoRoot) + writeFileSync(join(fixture.root, 'package.json'), '{}\n') + const { calls, ownershipCandidates, runCommand } = makeRunner() + await writeEditorViewAuthority({ + repoRoot: logicalRepoRoot, + workspaceRoot, + requiredPackages: ['.'], + cell: 'effect_utils', + buck2: '/nix/store/test-buck2/bin/buck2', + git: '/nix/store/test-git/bin/git', + output: fixture.output, + runCommand, + }) + + expect(calls[0]?.cwd).toBe(fixture.root) + expect(calls[1]?.cwd).toBe(workspaceRoot) + expect(ownershipCandidates).toEqual(['repos/effect-utils/package.json']) + } finally { + rmSync(fixture.root, { recursive: true, force: true }) + rmSync(workspaceRoot, { recursive: true, force: true }) + } + }) + it('fails before replacing the prior authority when Buck ownership is incomplete', async () => { const fixture = makeFixture() try { diff --git a/packages/@overeng/buck2-tools/src/editor-view-authority.ts b/packages/@overeng/buck2-tools/src/editor-view-authority.ts index 295e61704b..37b6f830a3 100755 --- a/packages/@overeng/buck2-tools/src/editor-view-authority.ts +++ b/packages/@overeng/buck2-tools/src/editor-view-authority.ts @@ -55,11 +55,12 @@ const requirePackagePaths = (value: unknown): readonly string[] => { isUnknownArray(value) === true ? value : fail('editor consumer admission registry must be an array') - const paths = entries.map((entry) => - typeof entry === 'string' + const paths = entries.map((entry) => { + if (entry === '.') return entry + return typeof entry === 'string' ? requireRepositoryRelativePath(entry) - : fail('editor consumer admission registry contains a non-string package path'), - ) + : fail('editor consumer admission registry contains a non-string package path') + }) if (paths.length === 0) fail('editor consumer admission registry must not be empty') const sorted = paths.toSorted((left, right) => compareBytes({ left, right })) if (new Set(sorted).size !== sorted.length) @@ -130,8 +131,9 @@ export const writeEditorViewAuthority = async ({ fail(`cell must be a portable Buck cell name: ${cell}`) if (isAbsolute(buck2) === false) fail(`Buck2 must be an absolute path: ${buck2}`) if (isAbsolute(git) === false) fail(`Git must be an absolute path: ${git}`) - const canonicalRepoRoot = realpathSync(repoRoot) - const canonicalWorkspaceRoot = realpathSync(workspaceRoot) + const logicalRepoRoot = resolve(repoRoot) + const logicalWorkspaceRoot = resolve(workspaceRoot) + const canonicalRepoRoot = realpathSync(logicalRepoRoot) // `output` may arrive as an absolute path in a different namespace than the // canonical repository root (macOS `/tmp` vs `/private/tmp`), in which case // `resolve` returns it unchanged and the containment check below compares two @@ -145,7 +147,7 @@ export const writeEditorViewAuthority = async ({ outputFromRepo.startsWith('../') === true ) fail(`authority output escapes repository: ${outputPath}`) - const pathFromWorkspace = relative(canonicalWorkspaceRoot, canonicalRepoRoot) + const pathFromWorkspace = relative(logicalWorkspaceRoot, logicalRepoRoot) if ( isAbsolute(pathFromWorkspace) === true || pathFromWorkspace === '..' || @@ -163,8 +165,8 @@ export const writeEditorViewAuthority = async ({ }) requireCommandSuccess({ command: git, result: gitResult }) const trackedPaths = new Set(parseGitCandidatePaths(gitResult.stdout)) - const repositoryPackageManifests = requiredPackages.map( - (packagePath) => `${packagePath}/package.json`, + const repositoryPackageManifests = requiredPackages.map((packagePath) => + packagePath === '.' ? 'package.json' : `${packagePath}/package.json`, ) for (const manifest of repositoryPackageManifests) if (trackedPaths.has(manifest) === false) @@ -177,7 +179,7 @@ export const writeEditorViewAuthority = async ({ const ownershipResult = runCommand({ command: buck2, args: ['uquery', '--output-format', 'json', 'owner(%s)', `@${argumentFile}`], - cwd: canonicalWorkspaceRoot, + cwd: logicalWorkspaceRoot, }) requireCommandSuccess({ command: buck2, result: ownershipResult }) const ownersByCandidate = parseBuckOwnershipQuery({ @@ -188,7 +190,9 @@ export const writeEditorViewAuthority = async ({ const candidate = candidates[index] ?? fail(`missing ownership candidate for ${packagePath}`) const owners = ownersByCandidate.get(candidate) ?? fail(`missing Buck ownership for ${candidate}`) - return owners.includes(`${cell}//${packagePath}:package.json`) + const expectedOwner = + packagePath === '.' ? `${cell}//:package.json` : `${cell}//${packagePath}:package.json` + return owners.includes(expectedOwner) }) const missing = requiredPackages.filter( (packagePath) => ownedPackages.includes(packagePath) === false, diff --git a/packages/@overeng/buck2-tools/src/editor-view.integration.test.ts b/packages/@overeng/buck2-tools/src/editor-view.integration.test.ts index cbff06ff5a..affff7d953 100644 --- a/packages/@overeng/buck2-tools/src/editor-view.integration.test.ts +++ b/packages/@overeng/buck2-tools/src/editor-view.integration.test.ts @@ -249,6 +249,41 @@ describe('editor view publisher', () => { } }) + it('publishes the source-generator dependency closure at the repository root', async () => { + const fixture = makeFixture() + try { + writeFileSync(join(fixture.root, 'package.json'), '{"private":true}\n') + mkdirSync(join(fixture.root, 'node_modules')) + writeFileSync(join(fixture.root, 'node_modules', 'legacy-root-install'), 'retained') + writeFileSync( + fixture.workspaceAuthority, + `${JSON.stringify({ + schema: 'effect-utils/workspace-dependency-authority/v1', + requiredPackages: ['.'], + ownedPackages: ['.'], + })}\n`, + ) + const options: EditorViewOptions = { + ...fixture.options, + package: '.', + viewName: 'root', + cell: 'effect_utils', + target: '//:editor_inputs', + consumerCache: join(fixture.root, '.devenv', 'vite-cache', 'root'), + } + + const record = await publishEditorView(options) + + expect(readlinkSync(join(fixture.root, 'node_modules'))).toBe( + '.editor-view/root/node_modules', + ) + expect(readlinkSync(join(fixture.root, '.editor-view', 'root'))).toBe(record.snapshot) + await expect(checkEditorView(options)).resolves.toEqual(record) + } finally { + cleanup(fixture) + } + }) + it('survives deletion of every backing artifact', async () => { const fixture = makeFixture() try { diff --git a/packages/@overeng/buck2-tools/src/editor-view.ts b/packages/@overeng/buck2-tools/src/editor-view.ts index 39c57c84b1..6f5f3c4d22 100644 --- a/packages/@overeng/buck2-tools/src/editor-view.ts +++ b/packages/@overeng/buck2-tools/src/editor-view.ts @@ -467,12 +467,13 @@ const readRecord = (path: string): EditorViewRecord => { const requirePortablePackage = (value: string): string => { if ( - value.length === 0 || - isAbsolute(value) === true || - value.includes('\\') === true || - value - .split('/') - .some((component) => component === '' || component === '.' || component === '..') === true + value !== '.' && + (value.length === 0 || + isAbsolute(value) === true || + value.includes('\\') === true || + value + .split('/') + .some((component) => component === '' || component === '.' || component === '..') === true) ) fail(`package must be a normalized repository-relative path: ${value}`) return value @@ -617,8 +618,10 @@ const requireViewName = (viewName: string): string => { /** Repository-relative package path reduced to its stable view-name default. */ export const defaultEditorViewName = (packagePath: string): string => { - const segments = requirePortablePackage(packagePath).split('/') - return requireViewName(segments[segments.length - 1] ?? packagePath) + const normalized = requirePortablePackage(packagePath) + if (normalized === '.') return 'root' + const segments = normalized.split('/') + return requireViewName(segments[segments.length - 1] ?? normalized) } const makePaths = (options: EditorViewOptions): ViewPaths => { @@ -632,13 +635,16 @@ const makePaths = (options: EditorViewOptions): ViewPaths => { const repoRoot = realpathSync(options.repoRoot) requireDirectory({ path: repoRoot, field: 'repository root' }) const packagePath = requirePortablePackage(options.package) - const packageDir = resolve(repoRoot, packagePath) + const packageDir = packagePath === '.' ? repoRoot : resolve(repoRoot, packagePath) if (isWithin({ root: repoRoot, candidate: packageDir }) === false) fail(`package escapes repository root: ${packagePath}`) requireDirectory({ path: packageDir, field: 'package directory' }) if (realpathSync(packageDir) !== packageDir) fail(`package path must not contain symbolic links: ${packageDir}`) - const editorRoot = resolve(packageDir, '..', '..', '.editor-view') + const editorRoot = + packagePath === '.' + ? resolve(repoRoot, '.editor-view') + : resolve(packageDir, '..', '..', '.editor-view') if (isWithin({ root: repoRoot, candidate: editorRoot }) === false) fail(`editor root escapes repository: ${editorRoot}`) // The consumer cache is the one path a caller supplies absolutely, so it can @@ -648,7 +654,7 @@ const makePaths = (options: EditorViewOptions): ViewPaths => { if ( isWithin({ root: repoRoot, candidate: consumerCache }) === false || isWithin({ root: editorRoot, candidate: consumerCache }) === true || - isWithin({ root: packageDir, candidate: consumerCache }) === true + (packagePath !== '.' && isWithin({ root: packageDir, candidate: consumerCache }) === true) ) fail( `consumer cache must be inside the repository and outside package and snapshot views: ${consumerCache}`, @@ -674,7 +680,7 @@ const requireRecordIdentity = (options: EditorViewOptions): void => { if (cellPattern.test(options.cell) === false) fail(`cell must be a portable identifier: ${options.cell}`) const packagePath = requirePortablePackage(options.package) - const prefix = `//${packagePath}:` + const prefix = packagePath === '.' ? '//:' : `//${packagePath}:` const name = options.target.startsWith(prefix) === true ? options.target.slice(prefix.length) : '' if (targetNamePattern.test(name) === false) fail(`target must be the stable label ${prefix}: ${options.target}`) diff --git a/packages/@overeng/buck2-tools/src/editor-view.unit.test.ts b/packages/@overeng/buck2-tools/src/editor-view.unit.test.ts index e2b1211de9..ea1f2b4a46 100644 --- a/packages/@overeng/buck2-tools/src/editor-view.unit.test.ts +++ b/packages/@overeng/buck2-tools/src/editor-view.unit.test.ts @@ -22,6 +22,7 @@ describe('editor view identity', () => { it('defaults the view name to the package directory name', () => { expect(defaultEditorViewName('packages/@overeng/tui-core')).toBe('tui-core') expect(defaultEditorViewName('packages/@overeng/tui-react')).toBe('tui-react') + expect(defaultEditorViewName('.')).toBe('root') }) it('rejects package paths and view names that are not portable identifiers', () => { diff --git a/packages/@overeng/buck2-tools/src/package-command-runner.integration.test.ts b/packages/@overeng/buck2-tools/src/package-command-runner.integration.test.ts index e293a3c7a3..037456bc21 100644 --- a/packages/@overeng/buck2-tools/src/package-command-runner.integration.test.ts +++ b/packages/@overeng/buck2-tools/src/package-command-runner.integration.test.ts @@ -1,5 +1,5 @@ import { existsSync, realpathSync } from 'node:fs' -import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises' +import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' import { join } from 'node:path' import { fileURLToPath } from 'node:url' @@ -18,6 +18,7 @@ describe('package command input immutability', () => { const packageTree = join(root, 'package-tree') const dependency = join(root, 'dependency') const verdict = join(root, 'verdict') + const stderrPath = join(root, 'stderr') try { await Promise.all([mkdir(packageTree), mkdir(dependency)]) await writeFile( @@ -42,12 +43,10 @@ writeFileSync(process.argv[2]!, 'mutated') const child = Bun.spawn(command, { stdin: 'ignore', stdout: 'ignore', - stderr: 'pipe', + stderr: Bun.file(stderrPath), }) - const [exitCode, stderr] = await Promise.all([ - child.exited, - new Response(child.stderr).text(), - ]) + const exitCode = await child.exited + const stderr = await readFile(stderrPath, 'utf8') expect(exitCode).toBe(1) expect(stderr).toContain('declared inputs changed while mutate.ts was running') diff --git a/packages/@overeng/buck2-tools/src/package-command-runner.ts b/packages/@overeng/buck2-tools/src/package-command-runner.ts index c3396495b6..664c64a03b 100644 --- a/packages/@overeng/buck2-tools/src/package-command-runner.ts +++ b/packages/@overeng/buck2-tools/src/package-command-runner.ts @@ -581,42 +581,52 @@ const bundleImportSpecifiers = (bundle: string): readonly string[] => { */ const verifyExternalSurface = ({ allowed, + bundle = '', declaredCapabilities, gatedManifest, specifiers, target, }: { readonly allowed: readonly string[] + readonly bundle?: string readonly declaredCapabilities: readonly string[] readonly gatedManifest: PlatformGatedManifest readonly specifiers: readonly string[] readonly target: 'bun' | 'node' }): { readonly capabilities: readonly string[]; readonly modules: readonly string[] } => { const allowedSet = new Set(allowed) - const modules = [ - ...new Set( - specifiers.flatMap((specifier) => { - const name = bareSpecifierPackage({ specifier, target }) - return name === undefined ? [] : [name] - }), - ), - ].toSorted((left, right) => (left < right ? -1 : left > right ? 1 : 0)) - const undeclared = modules.filter((name) => allowedSet.has(name) === false) + const moduleSet = new Set( + specifiers.flatMap((specifier) => { + const name = bareSpecifierPackage({ specifier, target }) + return name === undefined ? [] : [name] + }), + ) + const staticModules = [...moduleSet].toSorted((left, right) => + left < right ? -1 : left > right ? 1 : 0, + ) + const undeclared = staticModules.filter((name) => allowedSet.has(name) === false) if (undeclared.length > 0) { fail( `bundle leaves undeclared bare imports external: ${undeclared.join(', ')}; declare them or keep them resolvable`, ) } // The capability set for the gated families is EXACT, in both directions. - // A missing declaration breaks the product on the user's machine; a surplus - // one silently grants a native closure the product never reaches, and the - // next reader cannot tell which of the two a declaration is. + // Static imports name one package. Some dispatch packages instead construct + // a platform package name at runtime; the emitted family prefix is then the + // fail-closed evidence that the bundle can reach the native family. const derived = new Set() const required = new Set() for (const family of gatedManifest.families) { if (family.capability === null) continue derived.add(family.capability) - if (modules.some((name) => family.packages.includes(name)) === false) continue + const packagePrefix = `${family.family}-` + const hasDynamicFamilyReference = + family.packages.every((name) => name.startsWith(packagePrefix)) && + bundle.includes(packagePrefix) + const hasStaticFamilyReference = staticModules.some((name) => family.packages.includes(name)) + if (hasStaticFamilyReference === false && hasDynamicFamilyReference === false) continue + if (hasDynamicFamilyReference) + for (const packageName of family.packages) moduleSet.add(packageName) required.add(family.capability) } const declared = new Set(declaredCapabilities) @@ -633,7 +643,7 @@ const verifyExternalSurface = ({ for (const capability of [...declared].toSorted()) { if (derived.has(capability) === true && required.has(capability) === false) { fail( - `product declares the native external capability ${capability}, but no bare import in the bundle requires it; remove the declaration`, + `product declares the native external capability ${capability}, but no static or dynamic import evidence in the bundle requires it; remove the declaration`, ) } } @@ -641,7 +651,7 @@ const verifyExternalSurface = ({ capabilities: [...declaredCapabilities].toSorted((left, right) => left < right ? -1 : left > right ? 1 : 0, ), - modules, + modules: [...moduleSet].toSorted((left, right) => (left < right ? -1 : left > right ? 1 : 0)), } } @@ -1033,6 +1043,7 @@ const runBundle = async (command: PackageCommand): Promise => { if (command.kind === 'cli') assertNoUnboundRequireMain(text) const surface = verifyExternalSurface({ allowed: external, + bundle: text, declaredCapabilities: command.externalCapabilities, gatedManifest, specifiers: bundleImportSpecifiers(text), diff --git a/packages/@overeng/buck2-tools/src/package-command-runner.unit.test.ts b/packages/@overeng/buck2-tools/src/package-command-runner.unit.test.ts index 0cdad28f73..9c77766a6e 100644 --- a/packages/@overeng/buck2-tools/src/package-command-runner.unit.test.ts +++ b/packages/@overeng/buck2-tools/src/package-command-runner.unit.test.ts @@ -543,7 +543,24 @@ describe('the verified external surface', () => { ).toThrow('does not declare that external capability') }) - it('rejects a declared native capability no bare import in the bundle requires', () => { + it('requires a capability when a bundle constructs a gated package name dynamically', () => { + expect( + verifyExternalSurface({ + allowed: ['@opentui/core-linux-x64'], + bundle: + 'const packageName = `@opentui/core-${target.platform}-${target.arch}`; await import(packageName)', + declaredCapabilities: ['opentui-core-native'], + gatedManifest, + specifiers: [], + target: 'node', + }), + ).toStrictEqual({ + capabilities: ['opentui-core-native'], + modules: ['@opentui/core-linux-x64'], + }) + }) + + it('rejects a declared native capability without static or dynamic import evidence', () => { expect(() => verifyExternalSurface({ allowed: ['@opentui/core-linux-x64', 'fsevents'], diff --git a/packages/@overeng/buck2-tools/src/repository-policy-runner.ts b/packages/@overeng/buck2-tools/src/repository-policy-runner.ts new file mode 100644 index 0000000000..dd1937a281 --- /dev/null +++ b/packages/@overeng/buck2-tools/src/repository-policy-runner.ts @@ -0,0 +1,104 @@ +import { readFileSync } from 'node:fs' +import path from 'node:path' +import { parseArgs } from 'node:util' + +type PolicyManifest = { + readonly declaredPackages: readonly string[] + readonly sourcePaths: readonly string[] +} + +const assetImport = /^\s*import\s+['"][^'"]*\.(?:css|less|sass|scss)['"]/mu +const travellingReference = /^\s*\/\/\/\s* => { + const sourcePaths = [...manifest.sourcePaths].toSorted() + const assetSources = sourcePaths.filter( + (sourcePath) => + compiledSource.test(sourcePath) && excludedAssetSource.test(sourcePath) === false, + ) + const assetOffenders: string[] = [] + for (const sourcePath of assetSources) { + const source = readFileSync(path.join(sourceRoot, sourcePath), 'utf8') + if (assetImport.test(source) === true && travellingReference.test(source) === false) { + assetOffenders.push(sourcePath) + } + } + const sourcePathSet = new Set(sourcePaths) + + const generatedCoverageMissing = sourcePaths + .filter( + (sourcePath) => + sourcePath.startsWith('packages/') && + (path.posix.basename(sourcePath) === 'package.json' || + path.posix.basename(sourcePath) === 'tsconfig.json'), + ) + .filter((sourcePath) => sourcePathSet.has(`${sourcePath}.genie.ts`) === false) + + const declaredPackages = [...manifest.declaredPackages].toSorted() + const actualDirectPackages = sourcePaths + .filter((sourcePath) => directPackageManifest.test(sourcePath)) + .map((sourcePath) => path.posix.dirname(sourcePath)) + .toSorted() + const declaredDirectPackages = declaredPackages + .filter((packagePath) => /^packages\/@overeng\/[^/]+$/u.test(packagePath)) + .toSorted() + const declaredDirectPackageSet = new Set(declaredDirectPackages) + const missingPackages = actualDirectPackages.filter( + (packagePath) => declaredDirectPackageSet.has(packagePath) === false, + ) + const nonexistentPackages = declaredPackages.filter( + (packagePath) => sourcePathSet.has(`${packagePath}/package.json`) === false, + ) + + const failures = [ + ...(assetOffenders.length === 0 + ? [] + : [ + `Asset side-effect imports lack travelling type references:\n${assetOffenders.join('\n')}`, + ]), + ...(generatedCoverageMissing.length === 0 + ? [] + : [`Generated configuration sources are missing:\n${generatedCoverageMissing.join('\n')}`]), + ...(missingPackages.length === 0 + ? [] + : [ + `Workspace packages are absent from the authority registry:\n${missingPackages.join('\n')}`, + ]), + ...(nonexistentPackages.length === 0 + ? [] + : [`Authority registry packages have no package.json:\n${nonexistentPackages.join('\n')}`]), + ] + if (failures.length > 0) throw new Error(failures.join('\n\n')) + return { checkedAssetSources: assetSources.length, declaredPackages: declaredPackages.length } +} + +if (import.meta.main) { + const { values } = parseArgs({ + args: Bun.argv.slice(2), + options: { + manifest: { type: 'string' }, + output: { type: 'string' }, + source: { type: 'string' }, + }, + strict: true, + }) + if (values.manifest === undefined) throw new Error('missing --manifest') + if (values.output === undefined) throw new Error('missing --output') + if (values.source === undefined) throw new Error('missing --source') + const manifest = (await Bun.file(values.manifest).json()) as PolicyManifest + const summary = await checkRepositoryPolicy({ manifest, sourceRoot: values.source }) + await Bun.write( + values.output, + `${JSON.stringify({ schema: 'effect-utils/repository-policy/v1', status: 'passed', ...summary }, null, 2)}\n`, + ) +} diff --git a/packages/@overeng/buck2-tools/src/repository-policy-runner.unit.test.ts b/packages/@overeng/buck2-tools/src/repository-policy-runner.unit.test.ts new file mode 100644 index 0000000000..2eb1d88c6f --- /dev/null +++ b/packages/@overeng/buck2-tools/src/repository-policy-runner.unit.test.ts @@ -0,0 +1,78 @@ +import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs' +import { tmpdir } from 'node:os' +import path from 'node:path' + +import { afterEach, describe, expect, it } from 'vitest' + +import { checkRepositoryPolicy } from './repository-policy-runner.ts' + +const roots: string[] = [] + +const fixture = (files: Readonly>): string => { + const root = mkdtempSync(path.join(tmpdir(), 'repository-policy-')) + roots.push(root) + for (const [relativePath, content] of Object.entries(files)) { + const absolutePath = path.join(root, relativePath) + mkdirSync(path.dirname(absolutePath), { recursive: true }) + writeFileSync(absolutePath, content) + } + return root +} + +afterEach(() => { + for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }) +}) + +describe('repository policy', () => { + it('accepts a declared generated package and travelling asset reference', async () => { + const files = { + 'packages/@overeng/example/package.json': '{}\n', + 'packages/@overeng/example/package.json.genie.ts': 'export default {}\n', + 'packages/@overeng/example/src/mod.ts': + '/// \nimport "./style.css"\n', + 'packages/@overeng/example/tsconfig.json': '{}\n', + 'packages/@overeng/example/tsconfig.json.genie.ts': 'export default {}\n', + } + await expect( + checkRepositoryPolicy({ + manifest: { + declaredPackages: ['packages/@overeng/example'], + sourcePaths: Object.keys(files), + }, + sourceRoot: fixture(files), + }), + ).resolves.toEqual({ checkedAssetSources: 1, declaredPackages: 1 }) + }) + + it('rejects an asset side-effect import without a travelling reference', async () => { + const files = { + 'packages/@overeng/example/package.json': '{}\n', + 'packages/@overeng/example/package.json.genie.ts': 'export default {}\n', + 'packages/@overeng/example/src/mod.ts': 'import "./style.css"\n', + } + await expect( + checkRepositoryPolicy({ + manifest: { + declaredPackages: ['packages/@overeng/example'], + sourcePaths: Object.keys(files), + }, + sourceRoot: fixture(files), + }), + ).rejects.toThrow('Asset side-effect imports lack travelling type references') + }) + + it('rejects unmanaged configuration and package inventory drift together', async () => { + const files = { + 'packages/@overeng/unmanaged/package.json': '{}\n', + 'packages/@overeng/unmanaged/tsconfig.json': '{}\n', + } + await expect( + checkRepositoryPolicy({ + manifest: { declaredPackages: [], sourcePaths: Object.keys(files) }, + sourceRoot: fixture(files), + }), + ).rejects.toThrow( + /Generated configuration sources are missing[\s\S]*Workspace packages are absent/u, + ) + }) +}) diff --git a/packages/@overeng/buck2-tools/src/static-check-runner.ts b/packages/@overeng/buck2-tools/src/static-check-runner.ts new file mode 100644 index 0000000000..76574f4c97 --- /dev/null +++ b/packages/@overeng/buck2-tools/src/static-check-runner.ts @@ -0,0 +1,42 @@ +import path from 'node:path' +import { parseArgs } from 'node:util' + +const { values } = parseArgs({ + args: Bun.argv.slice(2), + options: { + kind: { type: 'string' }, + output: { type: 'string' }, + path: { type: 'string', multiple: true }, + source: { type: 'string' }, + tool: { type: 'string' }, + }, + strict: true, +}) + +const { kind, output, path: paths, source, tool } = values +if (kind !== 'format' && kind !== 'lint') throw new Error(`unsupported static check kind: ${kind}`) +if (output === undefined) throw new Error('missing --output') +if (paths === undefined || paths.length === 0) throw new Error('missing --path') +if (source === undefined) throw new Error('missing --source') +if (tool === undefined) throw new Error('missing --tool') +const args = + kind === 'format' + ? ['--check', '--config=.oxfmtrc.json', '--disable-nested-config', ...paths] + : [ + '--import-plugin', + '--type-aware', + '--tsconfig=tsconfig.lint.json', + '--deny-warnings', + ...paths, + ] +const check = Bun.spawnSync({ + cmd: [path.resolve(tool), ...args], + cwd: source, + env: { ...process.env, CI: 'true', DEVENV_TASK_PASSTHROUGH: '1' }, + stdin: 'ignore', + stdout: 'inherit', + stderr: 'inherit', +}) +if (check.exitCode !== 0) process.exit(check.exitCode) + +await Bun.write(output, `${JSON.stringify({ kind, status: 'passed' }, null, 2)}\n`) diff --git a/packages/@overeng/buck2-tools/src/typescript-runner.ts b/packages/@overeng/buck2-tools/src/typescript-runner.ts index 0c30fa8538..bd68e60649 100644 --- a/packages/@overeng/buck2-tools/src/typescript-runner.ts +++ b/packages/@overeng/buck2-tools/src/typescript-runner.ts @@ -54,8 +54,14 @@ const fail = (message: string): never => { throw new Error(`typescript runner: ${message}`) } -const formatError = (error: unknown): string => - error instanceof Error ? (error.stack ?? error.message) : String(error) +/** Formats runtime errors without losing messages from message-less Bun stack strings. */ +export const formatError = (error: unknown): string => { + if (error instanceof Error === false) return String(error) + if (error.stack === undefined) return error.message + return error.stack.includes(error.message) === true + ? error.stack + : `${error.message}\n${error.stack}` +} const isErrnoException = (error: unknown): error is NodeJS.ErrnoException => error instanceof Error && 'code' in error diff --git a/packages/@overeng/buck2-tools/src/typescript-runner.unit.test.ts b/packages/@overeng/buck2-tools/src/typescript-runner.unit.test.ts index 9c712dc01f..8fdcde0587 100644 --- a/packages/@overeng/buck2-tools/src/typescript-runner.unit.test.ts +++ b/packages/@overeng/buck2-tools/src/typescript-runner.unit.test.ts @@ -18,6 +18,7 @@ import { afterEach, describe, expect, it } from 'vitest' import { copyDeclarationSources, + formatError, hashDeclaredInputRoots, linkStagedWorkspaceProjects, parseEmitOptions, @@ -41,6 +42,15 @@ afterEach(() => { for (const directory of scratchDirectories.splice(0)) rmSync(directory, { recursive: true }) }) +it('preserves an error message when the runtime stack omits it', () => { + const error = new Error('expected declaration entrypoint was not emitted: mod.d.ts') + error.stack = 'Error\n at validateOutput (typescript-runner.ts:471:7)' + + expect(formatError(error)).toContain( + 'expected declaration entrypoint was not emitted: mod.d.ts\nError', + ) +}) + describe('TypeScript emit declaration command', () => { it('parses explicit normalized declaration paths', () => { const options = parseEmitOptions([ diff --git a/packages/@overeng/buck2-tools/tsconfig.json b/packages/@overeng/buck2-tools/tsconfig.json index a7cfaa92a1..166f20fd31 100644 --- a/packages/@overeng/buck2-tools/tsconfig.json +++ b/packages/@overeng/buck2-tools/tsconfig.json @@ -49,7 +49,8 @@ "types": [ "node", "bun" - ] + ], + "noEmit": true }, "include": [ "src/**/*" diff --git a/packages/@overeng/buck2-tools/tsconfig.json.genie.ts b/packages/@overeng/buck2-tools/tsconfig.json.genie.ts index 4a8459934b..c2ad25c149 100644 --- a/packages/@overeng/buck2-tools/tsconfig.json.genie.ts +++ b/packages/@overeng/buck2-tools/tsconfig.json.genie.ts @@ -11,6 +11,7 @@ export default tsconfigJson({ ...packageTsconfigCompilerOptions, ...nodeTypes, types: ['node', 'bun'], + noEmit: true, }, include: ['src/**/*'], references: [], diff --git a/packages/@overeng/ci-tools/BUCK b/packages/@overeng/ci-tools/BUCK index b6eb45ddd8..e14a7da06e 100644 --- a/packages/@overeng/ci-tools/BUCK +++ b/packages/@overeng/ci-tools/BUCK @@ -5,14 +5,15 @@ load("//buck2:package_tools.bzl", "package_bin_artifact") load("//buck2/products:defs.bzl", "javascript_product") # Projection source: packages/@overeng/ci-tools/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:4bc34b79bd090ba97ceee9e0b7a0624f5a234226361a51d6a22c3d0d3b157e57 -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/ci-tools/BUCK.genie.ts, packages/@overeng/ci-tools/BUCK.genie.ts, packages/@overeng/ci-tools/bin/**/*.cts, packages/@overeng/ci-tools/bin/**/*.js, packages/@overeng/ci-tools/bin/**/*.mts, packages/@overeng/ci-tools/bin/**/*.spec.cjs, packages/@overeng/ci-tools/bin/**/*.spec.jsx, packages/@overeng/ci-tools/bin/**/*.spec.mjs, packages/@overeng/ci-tools/bin/**/*.test.cjs, packages/@overeng/ci-tools/bin/**/*.test.jsx, packages/@overeng/ci-tools/bin/**/*.test.mjs, packages/@overeng/ci-tools/bin/**/*.ts, packages/@overeng/ci-tools/bin/**/*.tsx, packages/@overeng/ci-tools/bin/**/__snapshots__/*.snap, packages/@overeng/ci-tools/package.json.genie.ts, packages/@overeng/ci-tools/src/**/*.cts, packages/@overeng/ci-tools/src/**/*.js, packages/@overeng/ci-tools/src/**/*.mts, packages/@overeng/ci-tools/src/**/*.spec.cjs, packages/@overeng/ci-tools/src/**/*.spec.jsx, packages/@overeng/ci-tools/src/**/*.spec.mjs, packages/@overeng/ci-tools/src/**/*.test.cjs, packages/@overeng/ci-tools/src/**/*.test.jsx, packages/@overeng/ci-tools/src/**/*.test.mjs, packages/@overeng/ci-tools/src/**/*.ts, packages/@overeng/ci-tools/src/**/*.tsx, packages/@overeng/ci-tools/src/**/__snapshots__/*.snap, packages/@overeng/ci-tools/tsconfig.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts +# Semantic fingerprint: sha256:a2be1f5fc37fcc244259f00d7fc5f8c48d940c6a3fc371b510053e22ac77864a +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/ci-tools/BUCK.genie.ts, packages/@overeng/ci-tools/BUCK.genie.ts, packages/@overeng/ci-tools/bin/**/*.cts, packages/@overeng/ci-tools/bin/**/*.js, packages/@overeng/ci-tools/bin/**/*.mts, packages/@overeng/ci-tools/bin/**/*.spec.cjs, packages/@overeng/ci-tools/bin/**/*.spec.jsx, packages/@overeng/ci-tools/bin/**/*.spec.mjs, packages/@overeng/ci-tools/bin/**/*.test.cjs, packages/@overeng/ci-tools/bin/**/*.test.jsx, packages/@overeng/ci-tools/bin/**/*.test.mjs, packages/@overeng/ci-tools/bin/**/*.ts, packages/@overeng/ci-tools/bin/**/*.tsx, packages/@overeng/ci-tools/bin/**/__snapshots__/*.snap, packages/@overeng/ci-tools/package.json.genie.ts, packages/@overeng/ci-tools/src/**/*.cts, packages/@overeng/ci-tools/src/**/*.js, packages/@overeng/ci-tools/src/**/*.mts, packages/@overeng/ci-tools/src/**/*.spec.cjs, packages/@overeng/ci-tools/src/**/*.spec.jsx, packages/@overeng/ci-tools/src/**/*.spec.mjs, packages/@overeng/ci-tools/src/**/*.test.cjs, packages/@overeng/ci-tools/src/**/*.test.jsx, packages/@overeng/ci-tools/src/**/*.test.mjs, packages/@overeng/ci-tools/src/**/*.ts, packages/@overeng/ci-tools/src/**/*.tsx, packages/@overeng/ci-tools/src/**/__snapshots__/*.snap, packages/@overeng/ci-tools/tsconfig.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -44,6 +45,14 @@ export_materialization_inputs([ "src/workflow-report.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/ci-tools", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_ci_tools_ed163de971d5", @@ -95,7 +104,7 @@ package_view( "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -142,7 +151,7 @@ package_view( "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/ci-tools/BUCK.genie.ts b/packages/@overeng/ci-tools/BUCK.genie.ts index 23be974684..49cf99f686 100644 --- a/packages/@overeng/ci-tools/BUCK.genie.ts +++ b/packages/@overeng/ci-tools/BUCK.genie.ts @@ -26,11 +26,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils-dev:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/content-address/BUCK b/packages/@overeng/content-address/BUCK index 5fd007ce45..65900872b0 100644 --- a/packages/@overeng/content-address/BUCK +++ b/packages/@overeng/content-address/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/content-address/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:740a23496a9d065af1246800f0879e6657cef3d65782c3fb8fafed0139d205a2 -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/content-address/BUCK.genie.ts, packages/@overeng/content-address/BUCK.genie.ts, packages/@overeng/content-address/package.json.genie.ts, packages/@overeng/content-address/src/**/*.cts, packages/@overeng/content-address/src/**/*.js, packages/@overeng/content-address/src/**/*.mts, packages/@overeng/content-address/src/**/*.spec.cjs, packages/@overeng/content-address/src/**/*.spec.jsx, packages/@overeng/content-address/src/**/*.spec.mjs, packages/@overeng/content-address/src/**/*.test.cjs, packages/@overeng/content-address/src/**/*.test.jsx, packages/@overeng/content-address/src/**/*.test.mjs, packages/@overeng/content-address/src/**/*.ts, packages/@overeng/content-address/src/**/*.tsx, packages/@overeng/content-address/src/**/__snapshots__/*.snap, packages/@overeng/content-address/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts +# Semantic fingerprint: sha256:174c3c645262b561aa6c50c772eb230171e57f4dc37f83b5f21495c101256e76 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/content-address/BUCK.genie.ts, packages/@overeng/content-address/BUCK.genie.ts, packages/@overeng/content-address/package.json.genie.ts, packages/@overeng/content-address/src/**/*.cts, packages/@overeng/content-address/src/**/*.js, packages/@overeng/content-address/src/**/*.mts, packages/@overeng/content-address/src/**/*.spec.cjs, packages/@overeng/content-address/src/**/*.spec.jsx, packages/@overeng/content-address/src/**/*.spec.mjs, packages/@overeng/content-address/src/**/*.test.cjs, packages/@overeng/content-address/src/**/*.test.jsx, packages/@overeng/content-address/src/**/*.test.mjs, packages/@overeng/content-address/src/**/*.ts, packages/@overeng/content-address/src/**/*.tsx, packages/@overeng/content-address/src/**/__snapshots__/*.snap, packages/@overeng/content-address/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -25,6 +26,14 @@ export_materialization_inputs([ "src/schema.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/content-address", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_content_address_a119c50f74bb", @@ -54,7 +63,7 @@ package_view( workspace_dependency_views = { "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -78,7 +87,7 @@ package_view( "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/content-address/BUCK.genie.ts b/packages/@overeng/content-address/BUCK.genie.ts index ef3b7e24bb..670be1364a 100644 --- a/packages/@overeng/content-address/BUCK.genie.ts +++ b/packages/@overeng/content-address/BUCK.genie.ts @@ -14,11 +14,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils-dev:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/effect-ai-claude-cli/BUCK b/packages/@overeng/effect-ai-claude-cli/BUCK index b512accb19..84146f5d5e 100644 --- a/packages/@overeng/effect-ai-claude-cli/BUCK +++ b/packages/@overeng/effect-ai-claude-cli/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/effect-ai-claude-cli/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:d01f467b1011dfb4c3901a670c8e83514479871fe9feb0fb873c2278b03d2cdb -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/effect-ai-claude-cli/BUCK.genie.ts, packages/@overeng/effect-ai-claude-cli/BUCK.genie.ts, packages/@overeng/effect-ai-claude-cli/package.json.genie.ts, packages/@overeng/effect-ai-claude-cli/src/**/*.cts, packages/@overeng/effect-ai-claude-cli/src/**/*.js, packages/@overeng/effect-ai-claude-cli/src/**/*.mts, packages/@overeng/effect-ai-claude-cli/src/**/*.spec.cjs, packages/@overeng/effect-ai-claude-cli/src/**/*.spec.jsx, packages/@overeng/effect-ai-claude-cli/src/**/*.spec.mjs, packages/@overeng/effect-ai-claude-cli/src/**/*.test.cjs, packages/@overeng/effect-ai-claude-cli/src/**/*.test.jsx, packages/@overeng/effect-ai-claude-cli/src/**/*.test.mjs, packages/@overeng/effect-ai-claude-cli/src/**/*.ts, packages/@overeng/effect-ai-claude-cli/src/**/*.tsx, packages/@overeng/effect-ai-claude-cli/src/**/__snapshots__/*.snap, packages/@overeng/effect-ai-claude-cli/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts +# Semantic fingerprint: sha256:f8a2b303738bc7466749adcaee1fa5ca5106b0258cd7db1a956e05b9c7372170 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/effect-ai-claude-cli/BUCK.genie.ts, packages/@overeng/effect-ai-claude-cli/BUCK.genie.ts, packages/@overeng/effect-ai-claude-cli/package.json.genie.ts, packages/@overeng/effect-ai-claude-cli/src/**/*.cts, packages/@overeng/effect-ai-claude-cli/src/**/*.js, packages/@overeng/effect-ai-claude-cli/src/**/*.mts, packages/@overeng/effect-ai-claude-cli/src/**/*.spec.cjs, packages/@overeng/effect-ai-claude-cli/src/**/*.spec.jsx, packages/@overeng/effect-ai-claude-cli/src/**/*.spec.mjs, packages/@overeng/effect-ai-claude-cli/src/**/*.test.cjs, packages/@overeng/effect-ai-claude-cli/src/**/*.test.jsx, packages/@overeng/effect-ai-claude-cli/src/**/*.test.mjs, packages/@overeng/effect-ai-claude-cli/src/**/*.ts, packages/@overeng/effect-ai-claude-cli/src/**/*.tsx, packages/@overeng/effect-ai-claude-cli/src/**/__snapshots__/*.snap, packages/@overeng/effect-ai-claude-cli/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -26,6 +27,14 @@ export_materialization_inputs([ "src/mod.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/effect-ai-claude-cli", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_effect_ai_claude_cli_12fdf58adc3f", @@ -56,7 +65,7 @@ package_view( workspace_dependency_views = { "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -81,7 +90,7 @@ package_view( "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/effect-ai-claude-cli/BUCK.genie.ts b/packages/@overeng/effect-ai-claude-cli/BUCK.genie.ts index e5610e0eb4..1ef76bf1d2 100644 --- a/packages/@overeng/effect-ai-claude-cli/BUCK.genie.ts +++ b/packages/@overeng/effect-ai-claude-cli/BUCK.genie.ts @@ -15,11 +15,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils-dev:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/effect-distributed-lock/BUCK b/packages/@overeng/effect-distributed-lock/BUCK index e31d00571c..ba64578c56 100644 --- a/packages/@overeng/effect-distributed-lock/BUCK +++ b/packages/@overeng/effect-distributed-lock/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/effect-distributed-lock/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:847a6068fd08229e54990acf6036be0b4e984441ce5208b0b0d719cf32677794 -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/effect-distributed-lock/BUCK.genie.ts, packages/@overeng/effect-distributed-lock/BUCK.genie.ts, packages/@overeng/effect-distributed-lock/package.json.genie.ts, packages/@overeng/effect-distributed-lock/src/**/*.cts, packages/@overeng/effect-distributed-lock/src/**/*.js, packages/@overeng/effect-distributed-lock/src/**/*.mts, packages/@overeng/effect-distributed-lock/src/**/*.spec.cjs, packages/@overeng/effect-distributed-lock/src/**/*.spec.jsx, packages/@overeng/effect-distributed-lock/src/**/*.spec.mjs, packages/@overeng/effect-distributed-lock/src/**/*.test.cjs, packages/@overeng/effect-distributed-lock/src/**/*.test.jsx, packages/@overeng/effect-distributed-lock/src/**/*.test.mjs, packages/@overeng/effect-distributed-lock/src/**/*.ts, packages/@overeng/effect-distributed-lock/src/**/*.tsx, packages/@overeng/effect-distributed-lock/src/**/__snapshots__/*.snap, packages/@overeng/effect-distributed-lock/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts +# Semantic fingerprint: sha256:9bf749cea75e199bae03c097fe0d67da3b4afbe84ceb3ac16b4378bc008033a0 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/effect-distributed-lock/BUCK.genie.ts, packages/@overeng/effect-distributed-lock/BUCK.genie.ts, packages/@overeng/effect-distributed-lock/package.json.genie.ts, packages/@overeng/effect-distributed-lock/src/**/*.cts, packages/@overeng/effect-distributed-lock/src/**/*.js, packages/@overeng/effect-distributed-lock/src/**/*.mts, packages/@overeng/effect-distributed-lock/src/**/*.spec.cjs, packages/@overeng/effect-distributed-lock/src/**/*.spec.jsx, packages/@overeng/effect-distributed-lock/src/**/*.spec.mjs, packages/@overeng/effect-distributed-lock/src/**/*.test.cjs, packages/@overeng/effect-distributed-lock/src/**/*.test.jsx, packages/@overeng/effect-distributed-lock/src/**/*.test.mjs, packages/@overeng/effect-distributed-lock/src/**/*.ts, packages/@overeng/effect-distributed-lock/src/**/*.tsx, packages/@overeng/effect-distributed-lock/src/**/__snapshots__/*.snap, packages/@overeng/effect-distributed-lock/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -27,6 +28,14 @@ export_materialization_inputs([ "src/mod.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/effect-distributed-lock", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_effect_distributed_lock_f36a75b36a62", @@ -58,7 +67,7 @@ package_view( workspace_dependency_views = { "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -84,7 +93,7 @@ package_view( "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/effect-distributed-lock/BUCK.genie.ts b/packages/@overeng/effect-distributed-lock/BUCK.genie.ts index 45377b8e02..16b34cc1e0 100644 --- a/packages/@overeng/effect-distributed-lock/BUCK.genie.ts +++ b/packages/@overeng/effect-distributed-lock/BUCK.genie.ts @@ -15,11 +15,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils-dev:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/effect-path/BUCK b/packages/@overeng/effect-path/BUCK index 80ecfea8c7..1c396787b8 100644 --- a/packages/@overeng/effect-path/BUCK +++ b/packages/@overeng/effect-path/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/effect-path/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:49afd4abbbf4667660578d01c56d6bf278dc87067c5bdc8d38aebf1439dd7350 -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/effect-path/BUCK.genie.ts, packages/@overeng/effect-path/BUCK.genie.ts, packages/@overeng/effect-path/package.json.genie.ts, packages/@overeng/effect-path/src/**/*.cts, packages/@overeng/effect-path/src/**/*.js, packages/@overeng/effect-path/src/**/*.mts, packages/@overeng/effect-path/src/**/*.spec.cjs, packages/@overeng/effect-path/src/**/*.spec.jsx, packages/@overeng/effect-path/src/**/*.spec.mjs, packages/@overeng/effect-path/src/**/*.test.cjs, packages/@overeng/effect-path/src/**/*.test.jsx, packages/@overeng/effect-path/src/**/*.test.mjs, packages/@overeng/effect-path/src/**/*.ts, packages/@overeng/effect-path/src/**/*.tsx, packages/@overeng/effect-path/src/**/__snapshots__/*.snap, packages/@overeng/effect-path/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts +# Semantic fingerprint: sha256:a73c298899506fd2db404cb219fc6382f0c7b4bd3aba6b606396ab890b35de6c +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/effect-path/BUCK.genie.ts, packages/@overeng/effect-path/BUCK.genie.ts, packages/@overeng/effect-path/package.json.genie.ts, packages/@overeng/effect-path/src/**/*.cts, packages/@overeng/effect-path/src/**/*.js, packages/@overeng/effect-path/src/**/*.mts, packages/@overeng/effect-path/src/**/*.spec.cjs, packages/@overeng/effect-path/src/**/*.spec.jsx, packages/@overeng/effect-path/src/**/*.spec.mjs, packages/@overeng/effect-path/src/**/*.test.cjs, packages/@overeng/effect-path/src/**/*.test.jsx, packages/@overeng/effect-path/src/**/*.test.mjs, packages/@overeng/effect-path/src/**/*.ts, packages/@overeng/effect-path/src/**/*.tsx, packages/@overeng/effect-path/src/**/__snapshots__/*.snap, packages/@overeng/effect-path/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -37,6 +38,14 @@ export_materialization_inputs([ "src/verified.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/effect-path", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_effect_path_f923dc1b49cc", @@ -78,7 +87,7 @@ package_view( workspace_dependency_views = { "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -114,7 +123,7 @@ package_view( "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/effect-path/BUCK.genie.ts b/packages/@overeng/effect-path/BUCK.genie.ts index 40d9787a5c..3c70da53f4 100644 --- a/packages/@overeng/effect-path/BUCK.genie.ts +++ b/packages/@overeng/effect-path/BUCK.genie.ts @@ -14,11 +14,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils-dev:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/effect-react/BUCK b/packages/@overeng/effect-react/BUCK index 39143b77ef..1d62f848ea 100644 --- a/packages/@overeng/effect-react/BUCK +++ b/packages/@overeng/effect-react/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/effect-react/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:245f23436333ad52226d431335280d89779912721150b9e31a09a9de7a1f4678 -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/effect-react/BUCK.genie.ts, packages/@overeng/effect-react/BUCK.genie.ts, packages/@overeng/effect-react/package.json.genie.ts, packages/@overeng/effect-react/src/**/*.cts, packages/@overeng/effect-react/src/**/*.js, packages/@overeng/effect-react/src/**/*.mts, packages/@overeng/effect-react/src/**/*.spec.cjs, packages/@overeng/effect-react/src/**/*.spec.jsx, packages/@overeng/effect-react/src/**/*.spec.mjs, packages/@overeng/effect-react/src/**/*.test.cjs, packages/@overeng/effect-react/src/**/*.test.jsx, packages/@overeng/effect-react/src/**/*.test.mjs, packages/@overeng/effect-react/src/**/*.ts, packages/@overeng/effect-react/src/**/*.tsx, packages/@overeng/effect-react/src/**/__snapshots__/*.snap, packages/@overeng/effect-react/test/**/*.cts, packages/@overeng/effect-react/test/**/*.js, packages/@overeng/effect-react/test/**/*.mts, packages/@overeng/effect-react/test/**/*.spec.cjs, packages/@overeng/effect-react/test/**/*.spec.jsx, packages/@overeng/effect-react/test/**/*.spec.mjs, packages/@overeng/effect-react/test/**/*.test.cjs, packages/@overeng/effect-react/test/**/*.test.jsx, packages/@overeng/effect-react/test/**/*.test.mjs, packages/@overeng/effect-react/test/**/*.ts, packages/@overeng/effect-react/test/**/*.tsx, packages/@overeng/effect-react/test/**/__snapshots__/*.snap, packages/@overeng/effect-react/tsconfig.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts +# Semantic fingerprint: sha256:788ba7fab008eb3d980d96d8b20d36849821c822b8c0e83e8b421c8e75211715 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/effect-react/BUCK.genie.ts, packages/@overeng/effect-react/BUCK.genie.ts, packages/@overeng/effect-react/package.json.genie.ts, packages/@overeng/effect-react/src/**/*.cts, packages/@overeng/effect-react/src/**/*.js, packages/@overeng/effect-react/src/**/*.mts, packages/@overeng/effect-react/src/**/*.spec.cjs, packages/@overeng/effect-react/src/**/*.spec.jsx, packages/@overeng/effect-react/src/**/*.spec.mjs, packages/@overeng/effect-react/src/**/*.test.cjs, packages/@overeng/effect-react/src/**/*.test.jsx, packages/@overeng/effect-react/src/**/*.test.mjs, packages/@overeng/effect-react/src/**/*.ts, packages/@overeng/effect-react/src/**/*.tsx, packages/@overeng/effect-react/src/**/__snapshots__/*.snap, packages/@overeng/effect-react/test/**/*.cts, packages/@overeng/effect-react/test/**/*.js, packages/@overeng/effect-react/test/**/*.mts, packages/@overeng/effect-react/test/**/*.spec.cjs, packages/@overeng/effect-react/test/**/*.spec.jsx, packages/@overeng/effect-react/test/**/*.spec.mjs, packages/@overeng/effect-react/test/**/*.test.cjs, packages/@overeng/effect-react/test/**/*.test.jsx, packages/@overeng/effect-react/test/**/*.test.mjs, packages/@overeng/effect-react/test/**/*.ts, packages/@overeng/effect-react/test/**/*.tsx, packages/@overeng/effect-react/test/**/__snapshots__/*.snap, packages/@overeng/effect-react/tsconfig.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -32,6 +33,14 @@ export_materialization_inputs([ "test/runtime-baseline.test.tsx", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/effect-react", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_effect_react_111d6e63d407", @@ -71,7 +80,7 @@ package_view( "node_modules/@overeng/otel-contract/node_modules": "//packages/@overeng/otel-contract:package_tree", "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -105,7 +114,7 @@ package_view( "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/effect-react/BUCK.genie.ts b/packages/@overeng/effect-react/BUCK.genie.ts index 073d42e6a7..e14a3c4b88 100644 --- a/packages/@overeng/effect-react/BUCK.genie.ts +++ b/packages/@overeng/effect-react/BUCK.genie.ts @@ -19,11 +19,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/effect-rpc-tanstack/BUCK b/packages/@overeng/effect-rpc-tanstack/BUCK index 7a4d321439..901e29ab4e 100644 --- a/packages/@overeng/effect-rpc-tanstack/BUCK +++ b/packages/@overeng/effect-rpc-tanstack/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/effect-rpc-tanstack/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:7b9a564ad2aed7e21a6f901f2c0b2ca6d03b4f0a0b8465f3a64ec242284428f3 -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/effect-rpc-tanstack/BUCK.genie.ts, packages/@overeng/effect-rpc-tanstack/BUCK.genie.ts, packages/@overeng/effect-rpc-tanstack/package.json.genie.ts, packages/@overeng/effect-rpc-tanstack/src/**/*.cts, packages/@overeng/effect-rpc-tanstack/src/**/*.js, packages/@overeng/effect-rpc-tanstack/src/**/*.mts, packages/@overeng/effect-rpc-tanstack/src/**/*.spec.cjs, packages/@overeng/effect-rpc-tanstack/src/**/*.spec.jsx, packages/@overeng/effect-rpc-tanstack/src/**/*.spec.mjs, packages/@overeng/effect-rpc-tanstack/src/**/*.test.cjs, packages/@overeng/effect-rpc-tanstack/src/**/*.test.jsx, packages/@overeng/effect-rpc-tanstack/src/**/*.test.mjs, packages/@overeng/effect-rpc-tanstack/src/**/*.ts, packages/@overeng/effect-rpc-tanstack/src/**/*.tsx, packages/@overeng/effect-rpc-tanstack/src/**/__snapshots__/*.snap, packages/@overeng/effect-rpc-tanstack/tsconfig.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts +# Semantic fingerprint: sha256:fffce117991b06ab462ce20bba64ed19fe2481411cf6eebf1b41bc010c11df84 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/effect-rpc-tanstack/BUCK.genie.ts, packages/@overeng/effect-rpc-tanstack/BUCK.genie.ts, packages/@overeng/effect-rpc-tanstack/package.json.genie.ts, packages/@overeng/effect-rpc-tanstack/src/**/*.cts, packages/@overeng/effect-rpc-tanstack/src/**/*.js, packages/@overeng/effect-rpc-tanstack/src/**/*.mts, packages/@overeng/effect-rpc-tanstack/src/**/*.spec.cjs, packages/@overeng/effect-rpc-tanstack/src/**/*.spec.jsx, packages/@overeng/effect-rpc-tanstack/src/**/*.spec.mjs, packages/@overeng/effect-rpc-tanstack/src/**/*.test.cjs, packages/@overeng/effect-rpc-tanstack/src/**/*.test.jsx, packages/@overeng/effect-rpc-tanstack/src/**/*.test.mjs, packages/@overeng/effect-rpc-tanstack/src/**/*.ts, packages/@overeng/effect-rpc-tanstack/src/**/*.tsx, packages/@overeng/effect-rpc-tanstack/src/**/__snapshots__/*.snap, packages/@overeng/effect-rpc-tanstack/tsconfig.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -29,6 +30,14 @@ export_materialization_inputs([ "src/streaming.unit.test.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/effect-rpc-tanstack", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES + ["examples/basic/**"]), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_effect_rpc_tanstack_269934211838", @@ -62,7 +71,7 @@ package_view( workspace_dependency_views = { "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -91,7 +100,7 @@ package_view( "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/effect-rpc-tanstack/BUCK.genie.ts b/packages/@overeng/effect-rpc-tanstack/BUCK.genie.ts index 966e3a328f..009e97640b 100644 --- a/packages/@overeng/effect-rpc-tanstack/BUCK.genie.ts +++ b/packages/@overeng/effect-rpc-tanstack/BUCK.genie.ts @@ -15,11 +15,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/effect-rpc-tanstack/examples/basic/BUCK b/packages/@overeng/effect-rpc-tanstack/examples/basic/BUCK new file mode 100644 index 0000000000..0280f2e58c --- /dev/null +++ b/packages/@overeng/effect-rpc-tanstack/examples/basic/BUCK @@ -0,0 +1,102 @@ +# Generated file - DO NOT EDIT +# Source: BUCK.genie.ts + +# Projection source: packages/@overeng/effect-rpc-tanstack/examples/basic/BUCK.genie.ts +# Projection schema version: 11 +# Projection generator: effect-utils/genie/buck2-typescript-package-projection +# Semantic fingerprint: sha256:4c166f25fead4091913673bb152f2eba5dea478ab9c9543e3937401f0b96d5d9 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/effect-rpc-tanstack/BUCK.genie.ts, packages/@overeng/effect-rpc-tanstack/examples/basic/BUCK.genie.ts, packages/@overeng/effect-rpc-tanstack/examples/basic/BUCK.genie.ts, packages/@overeng/effect-rpc-tanstack/examples/basic/package.json.genie.ts, packages/@overeng/effect-rpc-tanstack/examples/basic/src/**/*.cts, packages/@overeng/effect-rpc-tanstack/examples/basic/src/**/*.js, packages/@overeng/effect-rpc-tanstack/examples/basic/src/**/*.mts, packages/@overeng/effect-rpc-tanstack/examples/basic/src/**/*.spec.cjs, packages/@overeng/effect-rpc-tanstack/examples/basic/src/**/*.spec.jsx, packages/@overeng/effect-rpc-tanstack/examples/basic/src/**/*.spec.mjs, packages/@overeng/effect-rpc-tanstack/examples/basic/src/**/*.test.cjs, packages/@overeng/effect-rpc-tanstack/examples/basic/src/**/*.test.jsx, packages/@overeng/effect-rpc-tanstack/examples/basic/src/**/*.test.mjs, packages/@overeng/effect-rpc-tanstack/examples/basic/src/**/*.ts, packages/@overeng/effect-rpc-tanstack/examples/basic/src/**/*.tsx, packages/@overeng/effect-rpc-tanstack/examples/basic/src/**/__snapshots__/*.snap, packages/@overeng/effect-rpc-tanstack/examples/basic/tsconfig.json.genie.ts, packages/@overeng/effect-rpc-tanstack/examples/basic/vite.config.ts, packages/@overeng/effect-rpc-tanstack/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts +# Regenerate: devenv tasks run genie:run + +load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") +load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") +load("//buck2:typescript.bzl", "tsgo_typecheck") + +export_file( + name = "package.json", + src = "package.json", + visibility = ["PUBLIC"], +) + +export_materialization_inputs([ + "src/client.tsx", + "src/routeTree.gen.ts", + "src/router.tsx", + "src/routes/__root.tsx", + "src/routes/api/rpc.ts", + "src/routes/index.tsx", + "src/routes/users.$id.tsx", + "src/rpc/api.ts", + "src/rpc/client.ts", + "src/rpc/server.ts", + "src/ssr.tsx", + "vite.config.ts", +]) + +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/effect-rpc-tanstack/examples/basic", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + +alias( + name = "node_modules", + actual = "//buck2/dependencies:view_packages_overeng_effect_rpc_tanstack_examples_basic_cdf25b205fd8", + visibility = ["PUBLIC"], +) + +alias( + name = "editor_inputs", + actual = ":node_modules", + visibility = ["PUBLIC"], +) + +package_view( + name = "package_tree", + dependency_view = "//buck2/dependencies:view_packages_overeng_effect_rpc_tanstack_examples_basic_cdf25b205fd8", + files = { + "package.json": "package.json", + "src/client.tsx": "src/client.tsx", + "src/routeTree.gen.ts": "src/routeTree.gen.ts", + "src/router.tsx": "src/router.tsx", + "src/routes/__root.tsx": "src/routes/__root.tsx", + "src/routes/api/rpc.ts": "src/routes/api/rpc.ts", + "src/routes/index.tsx": "src/routes/index.tsx", + "src/routes/users.$id.tsx": "src/routes/users.$id.tsx", + "src/rpc/api.ts": "src/rpc/api.ts", + "src/rpc/client.ts": "src/rpc/client.ts", + "src/rpc/server.ts": "src/rpc/server.ts", + "src/ssr.tsx": "src/ssr.tsx", + "tsconfig.json": "tsconfig.json", + "vite.config.ts": "vite.config.ts", + }, + workspace_dist = { + "node_modules/@overeng/effect-rpc-tanstack/dist": "//packages/@overeng/effect-rpc-tanstack:dist", + "node_modules/@overeng/effect-rpc-tanstack/package.json": "//packages/@overeng/effect-rpc-tanstack:package.json", + "node_modules/@overeng/utils/dist": "//packages/@overeng/utils:dist", + "node_modules/@overeng/utils/package.json": "//packages/@overeng/utils:package.json", + }, + workspace_dependency_views = { + "node_modules/@overeng/effect-rpc-tanstack/node_modules": "//packages/@overeng/effect-rpc-tanstack:package_tree", + "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", + }, + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", + runtime_entry = "package-tree.ts", + visibility = ["PUBLIC"], +) + +editor_view_inputs( + name = "editor_view_inputs", + editor_inputs = ":editor_inputs", + package_tree = ":package_tree", + visibility = ["PUBLIC"], +) + +tsgo_typecheck( + name = "typecheck", + package_tree = ":package_tree", + visibility = ["PUBLIC"], +) diff --git a/packages/@overeng/effect-rpc-tanstack/examples/basic/BUCK.genie.ts b/packages/@overeng/effect-rpc-tanstack/examples/basic/BUCK.genie.ts new file mode 100644 index 0000000000..5bc3a9e661 --- /dev/null +++ b/packages/@overeng/effect-rpc-tanstack/examples/basic/BUCK.genie.ts @@ -0,0 +1,26 @@ +import type { Buck2TypeScriptAdmission } from '../../../../../genie/buck2/typescript-admissions.ts' +import { buck2TypeScriptPackageProjection } from '../../../../../genie/buck2/typescript-package-projection.ts' + +export const buck2TypeScriptAdmission = { + dependencyImporter: + '//buck2/dependencies:importer_packages_overeng_effect_rpc_tanstack_examples_basic_cdf25b205fd8', + packageName: 'effect-rpc-tanstack-example-basic', + packagePath: 'packages/@overeng/effect-rpc-tanstack/examples/basic', + projectionSource: 'packages/@overeng/effect-rpc-tanstack/examples/basic/BUCK.genie.ts', + sourceRoots: ['src'], + workspaceSiblings: [ + { + packageName: '@overeng/effect-rpc-tanstack', + packagePath: 'packages/@overeng/effect-rpc-tanstack', + distTarget: '//packages/@overeng/effect-rpc-tanstack:dist', + }, + { + packageName: '@overeng/utils', + packagePath: 'packages/@overeng/utils', + distTarget: '//packages/@overeng/utils:dist', + }, + ], + authorities: [{ projectFile: 'tsconfig.json', projectInputs: ['vite.config.ts'] }], +} as const satisfies Buck2TypeScriptAdmission + +export default buck2TypeScriptPackageProjection(buck2TypeScriptAdmission) diff --git a/packages/@overeng/effect-rpc-tanstack/examples/basic/package.json b/packages/@overeng/effect-rpc-tanstack/examples/basic/package.json index 729cd3f956..2fea817fb6 100644 --- a/packages/@overeng/effect-rpc-tanstack/examples/basic/package.json +++ b/packages/@overeng/effect-rpc-tanstack/examples/basic/package.json @@ -5,6 +5,7 @@ "workspaceClosureDirs": [ "packages/@overeng/content-address", "packages/@overeng/effect-distributed-lock", + "packages/@overeng/effect-rpc-tanstack", "packages/@overeng/effect-rpc-tanstack/examples/basic", "packages/@overeng/otel-contract", "packages/@overeng/utils", @@ -22,6 +23,8 @@ "test:e2e": "playwright test" }, "dependencies": { + "@effect/platform-node": "4.0.0-rc.112", + "@overeng/effect-rpc-tanstack": "workspace:^", "@tanstack/react-router": "1.170.33", "@tanstack/react-start": "1.168.50", "effect": "4.0.0-rc.112", diff --git a/packages/@overeng/effect-rpc-tanstack/examples/basic/package.json.genie.ts b/packages/@overeng/effect-rpc-tanstack/examples/basic/package.json.genie.ts index 035c9ad32b..b7f5bba0ad 100644 --- a/packages/@overeng/effect-rpc-tanstack/examples/basic/package.json.genie.ts +++ b/packages/@overeng/effect-rpc-tanstack/examples/basic/package.json.genie.ts @@ -7,14 +7,17 @@ import { type PackageJsonInputData, } from '../../../../../genie/internal.ts' import utilsPkg from '../../../utils/package.json.genie.ts' +import effectRpcTanstackPkg from '../../package.json.genie.ts' const workspaceDeps = catalog.compose({ workspace: workspaceMember({ memberPath: 'packages/@overeng/effect-rpc-tanstack/examples/basic', }), dependencies: { + workspace: [effectRpcTanstackPkg], external: { ...catalog.pick( + '@effect/platform-node', '@tanstack/react-router', '@tanstack/react-start', 'effect', diff --git a/packages/@overeng/effect-rpc-tanstack/examples/basic/src/routes/api/rpc.ts b/packages/@overeng/effect-rpc-tanstack/examples/basic/src/routes/api/rpc.ts index 5f8563331c..6118225223 100644 --- a/packages/@overeng/effect-rpc-tanstack/examples/basic/src/routes/api/rpc.ts +++ b/packages/@overeng/effect-rpc-tanstack/examples/basic/src/routes/api/rpc.ts @@ -1,6 +1,7 @@ import { createFileRoute, type FileRoutesByPath } from '@tanstack/react-router' -import { makeHandler } from '../../../../../src/server.ts' +import { makeHandler } from '@overeng/effect-rpc-tanstack/server' + import { UserApi } from '../../rpc/api.ts' import { UserHandlers } from '../../rpc/server.ts' diff --git a/packages/@overeng/effect-rpc-tanstack/examples/basic/src/routes/index.tsx b/packages/@overeng/effect-rpc-tanstack/examples/basic/src/routes/index.tsx index 168622d230..88d4bcb5f3 100644 --- a/packages/@overeng/effect-rpc-tanstack/examples/basic/src/routes/index.tsx +++ b/packages/@overeng/effect-rpc-tanstack/examples/basic/src/routes/index.tsx @@ -6,7 +6,8 @@ import { createEffectRoute, type ExitEncoded, makeEffectLoaderResult, -} from '../../../../src/router.ts' +} from '@overeng/effect-rpc-tanstack/router' + import type { User } from '../rpc/api.ts' import { userClient } from '../rpc/client.ts' diff --git a/packages/@overeng/effect-rpc-tanstack/examples/basic/src/routes/users.$id.tsx b/packages/@overeng/effect-rpc-tanstack/examples/basic/src/routes/users.$id.tsx index 0c1dde78dd..5b9edc9a56 100644 --- a/packages/@overeng/effect-rpc-tanstack/examples/basic/src/routes/users.$id.tsx +++ b/packages/@overeng/effect-rpc-tanstack/examples/basic/src/routes/users.$id.tsx @@ -4,7 +4,8 @@ import { createEffectRoute, type ExitEncoded, makeEffectLoaderResult, -} from '../../../../src/router.ts' +} from '@overeng/effect-rpc-tanstack/router' + import { type User, UserNotFoundError } from '../rpc/api.ts' import { userClient } from '../rpc/client.ts' diff --git a/packages/@overeng/effect-rpc-tanstack/examples/basic/src/rpc/client.ts b/packages/@overeng/effect-rpc-tanstack/examples/basic/src/rpc/client.ts index 5715fb3a40..6d24feee81 100644 --- a/packages/@overeng/effect-rpc-tanstack/examples/basic/src/rpc/client.ts +++ b/packages/@overeng/effect-rpc-tanstack/examples/basic/src/rpc/client.ts @@ -5,7 +5,8 @@ import { Effect } from 'effect' import { RpcClient, type RpcClientError } from 'effect/unstable/rpc' -import { layerClient } from '../../../../src/client.ts' +import { layerClient } from '@overeng/effect-rpc-tanstack/client' + import { type User, UserApi, type UserNotFoundError } from './api.ts' /** diff --git a/packages/@overeng/effect-schema-form-aria/BUCK b/packages/@overeng/effect-schema-form-aria/BUCK new file mode 100644 index 0000000000..1ba4bfc381 --- /dev/null +++ b/packages/@overeng/effect-schema-form-aria/BUCK @@ -0,0 +1,161 @@ +# Generated file - DO NOT EDIT +# Source: BUCK.genie.ts + +# Projection source: packages/@overeng/effect-schema-form-aria/BUCK.genie.ts +# Projection schema version: 11 +# Projection generator: effect-utils/genie/buck2-typescript-package-projection +# Semantic fingerprint: sha256:bc755c50d1bb6fe4d9955df727611cae562c338b4796c7b056ce471674488ebb +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/effect-schema-form-aria/BUCK.genie.ts, packages/@overeng/effect-schema-form-aria/BUCK.genie.ts, packages/@overeng/effect-schema-form-aria/package.json.genie.ts, packages/@overeng/effect-schema-form-aria/src/**/*.cts, packages/@overeng/effect-schema-form-aria/src/**/*.js, packages/@overeng/effect-schema-form-aria/src/**/*.mts, packages/@overeng/effect-schema-form-aria/src/**/*.spec.cjs, packages/@overeng/effect-schema-form-aria/src/**/*.spec.jsx, packages/@overeng/effect-schema-form-aria/src/**/*.spec.mjs, packages/@overeng/effect-schema-form-aria/src/**/*.test.cjs, packages/@overeng/effect-schema-form-aria/src/**/*.test.jsx, packages/@overeng/effect-schema-form-aria/src/**/*.test.mjs, packages/@overeng/effect-schema-form-aria/src/**/*.ts, packages/@overeng/effect-schema-form-aria/src/**/*.tsx, packages/@overeng/effect-schema-form-aria/src/**/__snapshots__/*.snap, packages/@overeng/effect-schema-form-aria/tsconfig.json.genie.ts, packages/@overeng/effect-schema-form/BUCK.genie.ts, packages/@overeng/effect-schema-form/package.json.genie.ts, packages/@overeng/stylex-tokens/BUCK.genie.ts, packages/@overeng/stylex-tokens/package.json.genie.ts +# Regenerate: devenv tasks run genie:run + +load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") +load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") +load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") +load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") + +export_file( + name = "package.json", + src = "package.json", + visibility = ["PUBLIC"], +) + +export_materialization_inputs([ + "src/AriaSchemaForm.tsx", + "src/components/BooleanField.tsx", + "src/components/FieldGroup.tsx", + "src/components/FieldWrapper.tsx", + "src/components/LiteralField.tsx", + "src/components/NumberField.tsx", + "src/components/TextField.tsx", + "src/components/UnknownField.tsx", + "src/mod.ts", + "src/mod.unit.test.tsx", + "src/renderers.tsx", + "src/stories/AriaSchemaForm.stories.tsx", + "src/stories/BooleanField.stories.tsx", + "src/stories/FieldGroup.stories.tsx", + "src/stories/FocusRing.stories.tsx", + "src/stories/LiteralField.stories.tsx", + "src/stories/NumberField.stories.tsx", + "src/stories/TextField.stories.tsx", + "src/tokens.stylex.ts", +]) + +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/effect-schema-form-aria", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + +alias( + name = "node_modules", + actual = "//buck2/dependencies:view_packages_overeng_effect_schema_form_aria_baba449ec9b4", + visibility = ["PUBLIC"], +) + +alias( + name = "editor_inputs", + actual = ":node_modules", + visibility = ["PUBLIC"], +) + +package_view( + name = "package_tree", + dependency_view = "//buck2/dependencies:view_packages_overeng_effect_schema_form_aria_baba449ec9b4", + files = { + "package.json": "package.json", + "src/AriaSchemaForm.tsx": "src/AriaSchemaForm.tsx", + "src/components/BooleanField.tsx": "src/components/BooleanField.tsx", + "src/components/FieldGroup.tsx": "src/components/FieldGroup.tsx", + "src/components/FieldWrapper.tsx": "src/components/FieldWrapper.tsx", + "src/components/LiteralField.tsx": "src/components/LiteralField.tsx", + "src/components/NumberField.tsx": "src/components/NumberField.tsx", + "src/components/TextField.tsx": "src/components/TextField.tsx", + "src/components/UnknownField.tsx": "src/components/UnknownField.tsx", + "src/mod.ts": "src/mod.ts", + "src/mod.unit.test.tsx": "src/mod.unit.test.tsx", + "src/renderers.tsx": "src/renderers.tsx", + "src/stories/AriaSchemaForm.stories.tsx": "src/stories/AriaSchemaForm.stories.tsx", + "src/stories/BooleanField.stories.tsx": "src/stories/BooleanField.stories.tsx", + "src/stories/FieldGroup.stories.tsx": "src/stories/FieldGroup.stories.tsx", + "src/stories/FocusRing.stories.tsx": "src/stories/FocusRing.stories.tsx", + "src/stories/LiteralField.stories.tsx": "src/stories/LiteralField.stories.tsx", + "src/stories/NumberField.stories.tsx": "src/stories/NumberField.stories.tsx", + "src/stories/TextField.stories.tsx": "src/stories/TextField.stories.tsx", + "src/tokens.stylex.ts": "src/tokens.stylex.ts", + "tsconfig.json": "tsconfig.json", + }, + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", + runtime_entry = "package-tree.ts", + visibility = ["PUBLIC"], +) + +package_view( + name = "test_package_tree", + dependency_view = "//buck2/dependencies:view_packages_overeng_effect_schema_form_aria_baba449ec9b4", + files = { + "package.json": "package.json", + "src/AriaSchemaForm.tsx": "src/AriaSchemaForm.tsx", + "src/components/BooleanField.tsx": "src/components/BooleanField.tsx", + "src/components/FieldGroup.tsx": "src/components/FieldGroup.tsx", + "src/components/FieldWrapper.tsx": "src/components/FieldWrapper.tsx", + "src/components/LiteralField.tsx": "src/components/LiteralField.tsx", + "src/components/NumberField.tsx": "src/components/NumberField.tsx", + "src/components/TextField.tsx": "src/components/TextField.tsx", + "src/components/UnknownField.tsx": "src/components/UnknownField.tsx", + "src/mod.ts": "src/mod.ts", + "src/mod.unit.test.tsx": "src/mod.unit.test.tsx", + "src/renderers.tsx": "src/renderers.tsx", + "src/stories/AriaSchemaForm.stories.tsx": "src/stories/AriaSchemaForm.stories.tsx", + "src/stories/BooleanField.stories.tsx": "src/stories/BooleanField.stories.tsx", + "src/stories/FieldGroup.stories.tsx": "src/stories/FieldGroup.stories.tsx", + "src/stories/FocusRing.stories.tsx": "src/stories/FocusRing.stories.tsx", + "src/stories/LiteralField.stories.tsx": "src/stories/LiteralField.stories.tsx", + "src/stories/NumberField.stories.tsx": "src/stories/NumberField.stories.tsx", + "src/stories/TextField.stories.tsx": "src/stories/TextField.stories.tsx", + "src/tokens.stylex.ts": "src/tokens.stylex.ts", + "tsconfig.json": "tsconfig.json", + "vitest.config.ts": "vitest.config.ts", + }, + strip_project_references = True, + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", + runtime_entry = "package-tree.ts", + visibility = ["PUBLIC"], +) + +editor_view_inputs( + name = "editor_view_inputs", + editor_inputs = ":editor_inputs", + package_tree = ":package_tree", + visibility = ["PUBLIC"], +) + +tsgo_typecheck( + name = "typecheck", + package_tree = ":package_tree", + visibility = ["PUBLIC"], +) + +tsgo_emit( + name = "dist", + package_tree = ":package_tree", + declaration_sources = { + }, + declaration_entrypoint = "mod.d.ts", + visibility = ["PUBLIC"], +) + +vitest_test( + name = "test", + package_tree = ":test_package_tree", + visibility = ["PUBLIC"], +) + +vitest_collect( + name = "test_collect", + package_tree = ":test_package_tree", + visibility = ["PUBLIC"], +) diff --git a/packages/@overeng/effect-schema-form-aria/BUCK.genie.ts b/packages/@overeng/effect-schema-form-aria/BUCK.genie.ts new file mode 100644 index 0000000000..46b3a0bba2 --- /dev/null +++ b/packages/@overeng/effect-schema-form-aria/BUCK.genie.ts @@ -0,0 +1,32 @@ +import type { Buck2TypeScriptAdmission } from '../../../genie/buck2/typescript-admissions.ts' +import { buck2TypeScriptPackageProjection } from '../../../genie/buck2/typescript-package-projection.ts' + +export const buck2TypeScriptAdmission = { + dependencyImporter: + '//buck2/dependencies:importer_packages_overeng_effect_schema_form_aria_baba449ec9b4', + packageName: '@overeng/effect-schema-form-aria', + packagePath: 'packages/@overeng/effect-schema-form-aria', + projectionSource: 'packages/@overeng/effect-schema-form-aria/BUCK.genie.ts', + sourceRoots: ['src'], + workspaceSiblings: [ + { + packageName: '@overeng/effect-schema-form', + packagePath: 'packages/@overeng/effect-schema-form', + distTarget: '//packages/@overeng/effect-schema-form:dist', + }, + { + packageName: '@overeng/stylex-tokens', + packagePath: 'packages/@overeng/stylex-tokens', + distTarget: '//packages/@overeng/stylex-tokens:dist', + }, + ], + authorities: [{ declarationEntrypoint: 'mod.d.ts', projectFile: 'tsconfig.json' }], + tests: [ + { + name: 'test', + runner: 'vitest', + }, + ], +} as const satisfies Buck2TypeScriptAdmission + +export default buck2TypeScriptPackageProjection(buck2TypeScriptAdmission) diff --git a/packages/@overeng/effect-schema-form-aria/package.json b/packages/@overeng/effect-schema-form-aria/package.json index 5c75e8254f..ec5b1e9c26 100644 --- a/packages/@overeng/effect-schema-form-aria/package.json +++ b/packages/@overeng/effect-schema-form-aria/package.json @@ -18,7 +18,10 @@ "type": "module", "private": true, "exports": { - ".": "./src/mod.ts", + ".": { + "types": "./dist/mod.d.ts", + "default": "./src/mod.ts" + }, "./styles.css": "./src/styles.css" }, "scripts": { diff --git a/packages/@overeng/effect-schema-form-aria/package.json.genie.ts b/packages/@overeng/effect-schema-form-aria/package.json.genie.ts index abf242240c..ee4d405327 100644 --- a/packages/@overeng/effect-schema-form-aria/package.json.genie.ts +++ b/packages/@overeng/effect-schema-form-aria/package.json.genie.ts @@ -48,7 +48,10 @@ export default packageJson( name: '@overeng/effect-schema-form-aria', ...privatePackageDefaults, exports: { - '.': exportEntry('./src/mod.ts', { environment: 'browser' }), + '.': exportEntry( + { types: './dist/mod.d.ts', default: './src/mod.ts' }, + { environment: 'browser' }, + ), './styles.css': exportEntry('./src/styles.css', { environment: 'browser' }), }, publishConfig: { diff --git a/packages/@overeng/effect-schema-form-aria/tsconfig.json b/packages/@overeng/effect-schema-form-aria/tsconfig.json index 75cee66286..38589a2207 100644 --- a/packages/@overeng/effect-schema-form-aria/tsconfig.json +++ b/packages/@overeng/effect-schema-form-aria/tsconfig.json @@ -48,7 +48,8 @@ "composite": true, "rootDir": "./src", "tsBuildInfoFile": "./dist/tsconfig.tsbuildinfo", - "jsx": "react-jsx" + "jsx": "react-jsx", + "noEmit": true }, "include": [ "src/**/*" diff --git a/packages/@overeng/effect-schema-form-aria/tsconfig.json.genie.ts b/packages/@overeng/effect-schema-form-aria/tsconfig.json.genie.ts index 1152e612f4..61f0b57a79 100644 --- a/packages/@overeng/effect-schema-form-aria/tsconfig.json.genie.ts +++ b/packages/@overeng/effect-schema-form-aria/tsconfig.json.genie.ts @@ -13,6 +13,7 @@ export default tsconfigJson({ ...reactJsx, rootDir: './src', lib: [...domLib], + noEmit: true, }, include: ['src/**/*'], } satisfies TSConfigArgs) diff --git a/packages/@overeng/effect-schema-form/BUCK b/packages/@overeng/effect-schema-form/BUCK index 75bfb26820..5e4ec200c5 100644 --- a/packages/@overeng/effect-schema-form/BUCK +++ b/packages/@overeng/effect-schema-form/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/effect-schema-form/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:be2d010918a395fd13d61510c3070bb68ded52ec0155ca9067ce3ba9c6f43b92 -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/effect-schema-form/BUCK.genie.ts, packages/@overeng/effect-schema-form/BUCK.genie.ts, packages/@overeng/effect-schema-form/package.json.genie.ts, packages/@overeng/effect-schema-form/src/**/*.cts, packages/@overeng/effect-schema-form/src/**/*.js, packages/@overeng/effect-schema-form/src/**/*.mts, packages/@overeng/effect-schema-form/src/**/*.spec.cjs, packages/@overeng/effect-schema-form/src/**/*.spec.jsx, packages/@overeng/effect-schema-form/src/**/*.spec.mjs, packages/@overeng/effect-schema-form/src/**/*.test.cjs, packages/@overeng/effect-schema-form/src/**/*.test.jsx, packages/@overeng/effect-schema-form/src/**/*.test.mjs, packages/@overeng/effect-schema-form/src/**/*.ts, packages/@overeng/effect-schema-form/src/**/*.tsx, packages/@overeng/effect-schema-form/src/**/__snapshots__/*.snap, packages/@overeng/effect-schema-form/tsconfig.json.genie.ts +# Semantic fingerprint: sha256:0e294c4107a1f841fb8088b3531a2f38d8322a2e1655c08e80c1d1c2335cc623 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/effect-schema-form/BUCK.genie.ts, packages/@overeng/effect-schema-form/BUCK.genie.ts, packages/@overeng/effect-schema-form/package.json.genie.ts, packages/@overeng/effect-schema-form/src/**/*.cts, packages/@overeng/effect-schema-form/src/**/*.js, packages/@overeng/effect-schema-form/src/**/*.mts, packages/@overeng/effect-schema-form/src/**/*.spec.cjs, packages/@overeng/effect-schema-form/src/**/*.spec.jsx, packages/@overeng/effect-schema-form/src/**/*.spec.mjs, packages/@overeng/effect-schema-form/src/**/*.test.cjs, packages/@overeng/effect-schema-form/src/**/*.test.jsx, packages/@overeng/effect-schema-form/src/**/*.test.mjs, packages/@overeng/effect-schema-form/src/**/*.ts, packages/@overeng/effect-schema-form/src/**/*.tsx, packages/@overeng/effect-schema-form/src/**/__snapshots__/*.snap, packages/@overeng/effect-schema-form/tsconfig.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -30,6 +31,14 @@ export_materialization_inputs([ "src/utils.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/effect-schema-form", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_effect_schema_form_9234ab1a7f4a", @@ -61,7 +70,7 @@ package_view( }, workspace_dependency_views = { }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -87,7 +96,7 @@ package_view( workspace_dependency_views = { }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/effect-schema-form/BUCK.genie.ts b/packages/@overeng/effect-schema-form/BUCK.genie.ts index 316506de8f..8e4cc890b7 100644 --- a/packages/@overeng/effect-schema-form/BUCK.genie.ts +++ b/packages/@overeng/effect-schema-form/BUCK.genie.ts @@ -8,11 +8,7 @@ export const buck2TypeScriptAdmission = { packagePath: 'packages/@overeng/effect-schema-form', projectionSource: 'packages/@overeng/effect-schema-form/BUCK.genie.ts', sourceRoots: ['src'], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/genie/BUCK b/packages/@overeng/genie/BUCK index 56111827f4..a3daa5fcc0 100644 --- a/packages/@overeng/genie/BUCK +++ b/packages/@overeng/genie/BUCK @@ -1,18 +1,22 @@ # Generated file - DO NOT EDIT # Source: BUCK.genie.ts +load("//buck2/platforms:defs.bzl", "host_standalone_platform_label") +load("//buck2/products:defs.bzl", "build_product", "package_tree_product_executable") + load("//buck2:package_tools.bzl", "package_bin_artifact") load("//buck2/products:defs.bzl", "javascript_product") # Projection source: packages/@overeng/genie/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:3db04d9d71d9c2182597374158147b1edd8d2fe6218c2843201cec8769bdfb8e -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/genie/BUCK.genie.ts, packages/@overeng/genie/BUCK.genie.ts, packages/@overeng/genie/bin/**/*.cts, packages/@overeng/genie/bin/**/*.js, packages/@overeng/genie/bin/**/*.mts, packages/@overeng/genie/bin/**/*.spec.cjs, packages/@overeng/genie/bin/**/*.spec.jsx, packages/@overeng/genie/bin/**/*.spec.mjs, packages/@overeng/genie/bin/**/*.test.cjs, packages/@overeng/genie/bin/**/*.test.jsx, packages/@overeng/genie/bin/**/*.test.mjs, packages/@overeng/genie/bin/**/*.ts, packages/@overeng/genie/bin/**/*.tsx, packages/@overeng/genie/bin/**/__snapshots__/*.snap, packages/@overeng/genie/package.json.genie.ts, packages/@overeng/genie/src/**/*.cts, packages/@overeng/genie/src/**/*.js, packages/@overeng/genie/src/**/*.mts, packages/@overeng/genie/src/**/*.spec.cjs, packages/@overeng/genie/src/**/*.spec.jsx, packages/@overeng/genie/src/**/*.spec.mjs, packages/@overeng/genie/src/**/*.test.cjs, packages/@overeng/genie/src/**/*.test.jsx, packages/@overeng/genie/src/**/*.test.mjs, packages/@overeng/genie/src/**/*.ts, packages/@overeng/genie/src/**/*.tsx, packages/@overeng/genie/src/**/__snapshots__/*.snap, packages/@overeng/genie/tsconfig.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/tui-react/BUCK.genie.ts, packages/@overeng/tui-react/package.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts +# Semantic fingerprint: sha256:f61e168b287b5cfd9091fd7517b49ef80694dda6672b73e5805088bfd0e2b02d +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/genie/BUCK.genie.ts, packages/@overeng/genie/BUCK.genie.ts, packages/@overeng/genie/bin/**/*.cts, packages/@overeng/genie/bin/**/*.js, packages/@overeng/genie/bin/**/*.mts, packages/@overeng/genie/bin/**/*.spec.cjs, packages/@overeng/genie/bin/**/*.spec.jsx, packages/@overeng/genie/bin/**/*.spec.mjs, packages/@overeng/genie/bin/**/*.test.cjs, packages/@overeng/genie/bin/**/*.test.jsx, packages/@overeng/genie/bin/**/*.test.mjs, packages/@overeng/genie/bin/**/*.ts, packages/@overeng/genie/bin/**/*.tsx, packages/@overeng/genie/bin/**/__snapshots__/*.snap, packages/@overeng/genie/package.json.genie.ts, packages/@overeng/genie/src/**/*.cts, packages/@overeng/genie/src/**/*.js, packages/@overeng/genie/src/**/*.mts, packages/@overeng/genie/src/**/*.spec.cjs, packages/@overeng/genie/src/**/*.spec.jsx, packages/@overeng/genie/src/**/*.spec.mjs, packages/@overeng/genie/src/**/*.test.cjs, packages/@overeng/genie/src/**/*.test.jsx, packages/@overeng/genie/src/**/*.test.mjs, packages/@overeng/genie/src/**/*.ts, packages/@overeng/genie/src/**/*.tsx, packages/@overeng/genie/src/**/__snapshots__/*.snap, packages/@overeng/genie/tsconfig.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/tui-react/BUCK.genie.ts, packages/@overeng/tui-react/package.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -128,6 +132,14 @@ export_materialization_inputs([ "src/sdk/mod.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/genie", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_genie_b7534483be10", @@ -250,23 +262,7 @@ package_view( "src/sdk/mod.ts": "src/sdk/mod.ts", "tsconfig.json": "tsconfig.json", }, - workspace_dist = { - "node_modules/@overeng/otel-contract/dist": "//packages/@overeng/otel-contract:dist", - "node_modules/@overeng/otel-contract/package.json": "//packages/@overeng/otel-contract:package.json", - "node_modules/@overeng/tui-react/dist": "//packages/@overeng/tui-react:dist", - "node_modules/@overeng/tui-react/package.json": "//packages/@overeng/tui-react:package.json", - "node_modules/@overeng/utils-dev/dist": "//packages/@overeng/utils-dev:dist", - "node_modules/@overeng/utils-dev/package.json": "//packages/@overeng/utils-dev:package.json", - "node_modules/@overeng/utils/dist": "//packages/@overeng/utils:dist", - "node_modules/@overeng/utils/package.json": "//packages/@overeng/utils:package.json", - }, - workspace_dependency_views = { - "node_modules/@overeng/otel-contract/node_modules": "//packages/@overeng/otel-contract:package_tree", - "node_modules/@overeng/tui-react/node_modules": "//packages/@overeng/tui-react:package_tree", - "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", - "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", - }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -383,24 +379,8 @@ package_view( "tsconfig.json": "tsconfig.json", "vitest.config.ts": "vitest.config.ts", }, - workspace_dist = { - "node_modules/@overeng/otel-contract/dist": "//packages/@overeng/otel-contract:dist", - "node_modules/@overeng/otel-contract/package.json": "//packages/@overeng/otel-contract:package.json", - "node_modules/@overeng/tui-react/dist": "//packages/@overeng/tui-react:dist", - "node_modules/@overeng/tui-react/package.json": "//packages/@overeng/tui-react:package.json", - "node_modules/@overeng/utils-dev/dist": "//packages/@overeng/utils-dev:dist", - "node_modules/@overeng/utils-dev/package.json": "//packages/@overeng/utils-dev:package.json", - "node_modules/@overeng/utils/dist": "//packages/@overeng/utils:dist", - "node_modules/@overeng/utils/package.json": "//packages/@overeng/utils:package.json", - }, - workspace_dependency_views = { - "node_modules/@overeng/otel-contract/node_modules": "//packages/@overeng/otel-contract:package_tree", - "node_modules/@overeng/tui-react/node_modules": "//packages/@overeng/tui-react:package_tree", - "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", - "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", - }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -423,6 +403,7 @@ tsgo_emit( package_tree = ":package_tree", declaration_sources = { }, + declaration_entrypoint = "src/runtime/mod.d.ts", visibility = ["PUBLIC"], ) @@ -489,7 +470,7 @@ package_bin_artifact( name = "genie-bootstrap-closure-check-candidate-module", entrypoint = "bin/bootstrap-closure-check.ts", external = [], - external_capabilities = [], + external_capabilities = ["typescript-api-server"], kind = "cli", output = "genie-bootstrap-closure-check.js", package_tree = ":package_tree", @@ -504,3 +485,33 @@ javascript_product( product_name = "genie-bootstrap-closure-check", visibility = ["PUBLIC"], ) + + +package_tree_product_executable( + name = "typescript-api-server-product-executable", + package_tree = ":package_tree", + package_anchor = "node_modules/typescript", + executable_paths = { + "aarch64-darwin-darwin": "@typescript/typescript-darwin-arm64/lib/tsc", + "aarch64-linux-glibc": "@typescript/typescript-linux-arm64/lib/tsc", + "x86_64-linux-glibc": "@typescript/typescript-linux-x64/lib/tsc", + }, + support_directory_paths = { + "aarch64-darwin-darwin": "@typescript/typescript-darwin-arm64/lib", + "aarch64-linux-glibc": "@typescript/typescript-linux-arm64/lib", + "x86_64-linux-glibc": "@typescript/typescript-linux-x64/lib", + }, + support_destination = "bin", + recipe = "pnpm-lock:@typescript/typescript-platform/lib", + target_platform = host_standalone_platform_label(), + toolchain = "pnpm-lockfile:pnpm-lock.yaml", +) + +build_product( + name = "typescript-api-server-product", + entrypoint = "bin/typescript-api-server", + executable = ":typescript-api-server-product-executable", + product_name = "typescript-api-server", + target_platform = host_standalone_platform_label(), + visibility = ["PUBLIC"], +) diff --git a/packages/@overeng/genie/BUCK.genie.ts b/packages/@overeng/genie/BUCK.genie.ts index bea86f6b2a..b58f1b91b0 100644 --- a/packages/@overeng/genie/BUCK.genie.ts +++ b/packages/@overeng/genie/BUCK.genie.ts @@ -2,6 +2,10 @@ import { withJavaScriptCandidates } from '../../../genie/buck2/javascript-candid import { javaScriptProductsFor } from '../../../genie/buck2/javascript-product-registry.ts' import type { Buck2TypeScriptAdmission } from '../../../genie/buck2/typescript-admissions.ts' import { buck2TypeScriptPackageProjection } from '../../../genie/buck2/typescript-package-projection.ts' +import { + createGenieOutput, + type GenieOutput, +} from '../../../packages/@overeng/genie/src/runtime/core.ts' export const buck2TypeScriptAdmission = { dependencyImporter: '//buck2/dependencies:importer_packages_overeng_genie_b7534483be10', @@ -31,7 +35,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils-dev:dist', }, ], - editorViewConsumer: false, + authorities: [{ declarationEntrypoint: 'src/runtime/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', @@ -56,7 +60,50 @@ export const buck2TypeScriptAdmission = { ], } as const satisfies Buck2TypeScriptAdmission -export default withJavaScriptCandidates({ - projection: buck2TypeScriptPackageProjection(buck2TypeScriptAdmission), - products: javaScriptProductsFor(buck2TypeScriptAdmission.packagePath), -}) +const withTypeScriptApiServerProduct = ( + projection: GenieOutput, +): GenieOutput => + createGenieOutput({ + ...projection, + stringify: (context) => `load("//buck2/platforms:defs.bzl", "host_standalone_platform_label") +load("//buck2/products:defs.bzl", "build_product", "package_tree_product_executable") + +${projection.stringify(context)} + +package_tree_product_executable( + name = "typescript-api-server-product-executable", + package_tree = ":package_tree", + package_anchor = "node_modules/typescript", + executable_paths = { + "aarch64-darwin-darwin": "@typescript/typescript-darwin-arm64/lib/tsc", + "aarch64-linux-glibc": "@typescript/typescript-linux-arm64/lib/tsc", + "x86_64-linux-glibc": "@typescript/typescript-linux-x64/lib/tsc", + }, + support_directory_paths = { + "aarch64-darwin-darwin": "@typescript/typescript-darwin-arm64/lib", + "aarch64-linux-glibc": "@typescript/typescript-linux-arm64/lib", + "x86_64-linux-glibc": "@typescript/typescript-linux-x64/lib", + }, + support_destination = "bin", + recipe = "pnpm-lock:@typescript/typescript-platform/lib", + target_platform = host_standalone_platform_label(), + toolchain = "pnpm-lockfile:pnpm-lock.yaml", +) + +build_product( + name = "typescript-api-server-product", + entrypoint = "bin/typescript-api-server", + executable = ":typescript-api-server-product-executable", + product_name = "typescript-api-server", + target_platform = host_standalone_platform_label(), + visibility = ["PUBLIC"], +) +`, + }) + +export default withTypeScriptApiServerProduct( + withJavaScriptCandidates({ + projection: buck2TypeScriptPackageProjection(buck2TypeScriptAdmission), + products: javaScriptProductsFor(buck2TypeScriptAdmission.packagePath), + }), +) diff --git a/packages/@overeng/genie/package.json b/packages/@overeng/genie/package.json index 569c5667a1..3f983c2336 100644 --- a/packages/@overeng/genie/package.json +++ b/packages/@overeng/genie/package.json @@ -18,11 +18,26 @@ "type": "module", "private": true, "exports": { - ".": "./src/runtime/mod.ts", - "./cli": "./src/build/mod.tsx", - "./composition": "./src/runtime/composition/mod.ts", - "./node": "./src/runtime/node/mod.ts", - "./sdk": "./src/sdk/mod.ts" + ".": { + "types": "./dist/src/runtime/mod.d.ts", + "default": "./src/runtime/mod.ts" + }, + "./cli": { + "types": "./dist/src/build/mod.d.ts", + "default": "./src/build/mod.tsx" + }, + "./composition": { + "types": "./dist/src/runtime/composition/mod.d.ts", + "default": "./src/runtime/composition/mod.ts" + }, + "./node": { + "types": "./dist/src/runtime/node/mod.d.ts", + "default": "./src/runtime/node/mod.ts" + }, + "./sdk": { + "types": "./dist/src/sdk/mod.d.ts", + "default": "./src/sdk/mod.ts" + } }, "scripts": { "storybook": "storybook dev -p 6008", diff --git a/packages/@overeng/genie/package.json.genie.ts b/packages/@overeng/genie/package.json.genie.ts index da0ff6f785..221bec7ebe 100644 --- a/packages/@overeng/genie/package.json.genie.ts +++ b/packages/@overeng/genie/package.json.genie.ts @@ -56,20 +56,36 @@ export default packageJson( // consumer (e.g. a `.bzl` genie generator) can import `GenieOutput`/`Strict` and the builders without // dragging genie's runtime ambient globals into its program. Filesystem/spawn capabilities used during // validation are injected via `GenieContext` (`io`, `actionlint`) by the engine. - '.': exportEntry('./src/runtime/mod.ts', { - environment: 'isomorphic-es2024', - typeProof: 'strict', - }), + '.': exportEntry( + { types: './dist/src/runtime/mod.d.ts', default: './src/runtime/mod.ts' }, + { + environment: 'isomorphic-es2024', + typeProof: 'strict', + }, + ), // Node-resident entry: re-exports `.` plus the node-only members (nodeGenieIO, actionlint runner, // github-ruleset reconcile ops, fs-discovery tsconfigJsonFromPackages, repo-context). - './node': exportEntry('./src/runtime/node/mod.ts', { environment: 'node' }), + './node': exportEntry( + { types: './dist/src/runtime/node/mod.d.ts', default: './src/runtime/node/mod.ts' }, + { environment: 'node' }, + ), // Explicit reusable composition layer. Keep `.` focused on thin artifact builders; put cross-artifact // helpers that consume structured Genie metadata here. - './composition': exportEntry('./src/runtime/composition/mod.ts', { - environment: 'isomorphic-es2024', - }), - './cli': exportEntry('./src/build/mod.tsx', { environment: 'node' }), - './sdk': exportEntry('./src/sdk/mod.ts', { environment: 'node' }), + './composition': exportEntry( + { + types: './dist/src/runtime/composition/mod.d.ts', + default: './src/runtime/composition/mod.ts', + }, + { environment: 'isomorphic-es2024' }, + ), + './cli': exportEntry( + { types: './dist/src/build/mod.d.ts', default: './src/build/mod.tsx' }, + { environment: 'node' }, + ), + './sdk': exportEntry( + { types: './dist/src/sdk/mod.d.ts', default: './src/sdk/mod.ts' }, + { environment: 'node' }, + ), }, publishConfig: { access: 'public', diff --git a/packages/@overeng/genie/src/runtime/github-workflow/ci-workflow-helpers.unit.test.ts b/packages/@overeng/genie/src/runtime/github-workflow/ci-workflow-helpers.unit.test.ts index a871d30b4d..f61010a2e5 100644 --- a/packages/@overeng/genie/src/runtime/github-workflow/ci-workflow-helpers.unit.test.ts +++ b/packages/@overeng/genie/src/runtime/github-workflow/ci-workflow-helpers.unit.test.ts @@ -25,6 +25,7 @@ const ciWorkflowSource = [ 'ci-workflow/setup.ts', 'ci-workflow/measurements.ts', 'ci-workflow/reporting.ts', + 'ci-workflow/default-ref-policy-script.ts', 'ci-workflow/megarepo.ts', 'ci-workflow/merge-queue.ts', 'ci-workflow/deploy.ts', @@ -148,13 +149,13 @@ const mainOnlyCheckContexts: Record = { 'test-live-deploy-ci-tools': true, 'deploy-storybooks': true, } -const matrixCheckJobs = new Set(['test', 'nix-check', 'nix-fod-check']) +const matrixCheckJobs: Record = { test: true } const matrixRunners = ['namespace-profile-linux-x86-64', 'namespace-profile-macos-arm64'] as const const generatedNonAdvisoryCheckContexts = generatedCiJobKeys .flatMap((jobKey) => { if (jobKey === 'ci-measurements-report') return ['ci/measurements-report'] - if (matrixCheckJobs.has(jobKey) === true) { + if (matrixCheckJobs[jobKey] === true) { return matrixRunners.map((runner) => `${jobKey} (${runner})`) } return [jobKey] @@ -208,12 +209,11 @@ const resolveDevenvScript = readFileSync(resolveDevenvScriptUrl, 'utf8') const applyMegarepoLockStepSource = extractSourceBlock( ciWorkflowSource, 'export const applyMegarepoLockStep = (opts?: { skip?: string[]; cacheableStore?: boolean }) => {', - 'export type DefaultRefPolicyCheckStepOptions = {', + "export const mergeQueueAdmissionLabel = 'mq:ci-admitted' as const", ) -const defaultRefPolicyCheckStepSource = extractSourceBlock( - ciWorkflowSource, - 'export type DefaultRefPolicyCheckStepOptions = {', - '/** Fail when first-party megarepo/flake/devenv inputs target non-default refs. */', +const defaultRefPolicySource = readFileSync( + new URL('../../../../../../genie/ci-workflow/default-ref-policy-script.ts', import.meta.url), + 'utf8', ) const mergeQueueSource = extractSourceBlock( ciWorkflowSource, @@ -718,37 +718,33 @@ printf '%s\\n' "$NIX_OUTPUT" expect(megarepoTaskModuleSource).not.toContain('.value.members[].name') }) - it('normalizes GitHub branch refs through an explicit default-ref policy option', () => { - expect(defaultRefPolicyCheckStepSource).toContain('normalizeGitBranchRefs?: boolean') - expect(defaultRefPolicyCheckStepSource).toContain('NORMALIZE_GIT_BRANCH_REFS') - expect(defaultRefPolicyCheckStepSource).toContain("ref.startsWith('refs/heads/')") + it('keeps the source-policy trust gate available before composition', () => { + expect(defaultRefPolicySource).toContain('NORMALIZE_GIT_BRANCH_REFS') + expect(defaultRefPolicySource).toContain("ref.startsWith('refs/heads/')") }) it('allows only explicitly opted-in immutable legacy member refs', () => { - expect(defaultRefPolicyCheckStepSource).toContain('allowLegacyMemberCommitRefs?: boolean') - expect(defaultRefPolicyCheckStepSource).toContain('ALLOW_LEGACY_MEMBER_COMMIT_REFS') - expect(defaultRefPolicyCheckStepSource).toContain("memberName.endsWith('-legacy')") - expect(defaultRefPolicyCheckStepSource).toContain( + expect(defaultRefPolicySource).toContain('ALLOW_LEGACY_MEMBER_COMMIT_REFS') + expect(defaultRefPolicySource).toContain("memberName.endsWith('-legacy')") + expect(defaultRefPolicySource).toContain( 'const immutableCommitRef = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/i', ) - expect(defaultRefPolicyCheckStepSource).toContain( + expect(defaultRefPolicySource).toContain( 'isAllowedLegacyMemberRef({ memberName, ref: normalizedRef })', ) }) it('retries temporary git repository cleanup after reachability checks', () => { - expect(defaultRefPolicyCheckStepSource).toContain( + expect(defaultRefPolicySource).toContain( 'fs.rmSync(tmp, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 })', ) }) - it('uses the same Nix-provided Node runtime for default-ref policy checks', () => { - expect(ciWorkflowSource).toContain('nix shell nixpkgs#nodejs_24 -c node') - }) - - it('provides a dedicated default-ref policy job so regular jobs keep their signal', () => { - expect(ciWorkflowSource).toContain('export const defaultRefPolicyCheckJob') - expect(ciWorkflowSource).toContain('name === undefined ? {} : { name }') + it('runs the dedicated default-ref policy job before composition', () => { + expect(generatedWorkflowSource).toContain("'default-ref-policy': {") + expect(generatedWorkflowSource).toContain('defaultRefPolicyCheckJob({') + expect(generatedWorkflowSource).not.toContain("runDevenvTasksBefore('policy:default-ref')") + expect(ciWorkflowSource).toContain('defaultRefPolicyCheckJob') expect(ciWorkflowSource).toContain('defaultRefPolicyCheckStep(stepOpts)') }) }) @@ -1331,7 +1327,6 @@ describe('ci workflow devenv perf helpers', () => { expect(ciWorkflowSource).toContain("opts?.matrix === true ? '-${{ strategy.job-index }}' : ''") expect(ciWorkflowSource).toContain('const isMatrixJob = (job: GitHubWorkflowArgs') expect(generatedCiWorkflowYamlSource).toContain('}}-test-${{ strategy.job-index }}') - expect(generatedCiWorkflowYamlSource).toContain('}}-nix-check-${{ strategy.job-index }}') expect(generatedCiWorkflowYamlSource).toContain("format('measurement-baseline-{0}'") expect(generatedCiWorkflowYamlSource).not.toContain("format('measurement-pr-{0}-run-{1}'") expect(generatedCiWorkflowYamlSource).not.toContain('inputs.measurement_pr_number') @@ -1700,28 +1695,31 @@ describe('effect-utils CI composition workspace', () => { ([, name, body]) => [name!, body!] as const, ), ) - const exemptions = new Set([ - 'default-ref-policy', - 'nix-fod-check', - 'source-shape', - 'ci-measurements-report', - 'notify-alignment', - ]) + const exemptions: Record = { + 'default-ref-policy': true, + 'source-shape': true, + 'ci-measurements-report': true, + 'notify-alignment': true, + } expect( [...blocks.keys()].filter( (name) => blocks.get(name)?.includes('Prepare effect-utils composition') !== true, ), - ).toEqual([...exemptions]) + ).toEqual(Object.keys(exemptions)) for (const [name, block] of blocks) { const taskIndex = block.indexOf('tasks run ') if (taskIndex < 0) continue - expect(exemptions.has(name), name).toBe(false) + expect(exemptions[name] === true, name).toBe(false) const compositionIndex = block.indexOf('Prepare effect-utils composition') expect(compositionIndex, name).toBeGreaterThanOrEqual(0) expect(compositionIndex, name).toBeLessThan(taskIndex) expect(block.indexOf('Cleanup effect-utils composition'), name).toBeGreaterThan(taskIndex) } expect(generatedCiWorkflowYamlSource).not.toMatch(/^\s+(?:buck2|\.\/[^ ]*buck2)\s/m) + expect(blocks.has('nix-fod-check')).toBe(false) + expect(blocks.has('nix-check')).toBe(false) + expect(generatedCiWorkflowYamlSource).not.toContain('Evict cached pnpm deps for oxlint-npm') + expect(generatedCiWorkflowYamlSource).not.toContain('.#oxc-config-plugin-pnpm-deps') }) it('keeps pull-request source execution credentialless and read-only', () => { diff --git a/packages/@overeng/genie/src/runtime/github-workflow/github-workflow.unit.test.ts b/packages/@overeng/genie/src/runtime/github-workflow/github-workflow.unit.test.ts index 410ca21dbf..8b0622e955 100644 --- a/packages/@overeng/genie/src/runtime/github-workflow/github-workflow.unit.test.ts +++ b/packages/@overeng/genie/src/runtime/github-workflow/github-workflow.unit.test.ts @@ -596,6 +596,24 @@ describe('GitHub expression validation', () => { expect(yaml).toContain("group: '${{ github.workflow }}-${{ github.ref }}'") }) + it('does not indent empty lines in block scalars', () => { + const workflow = githubWorkflow({ + name: 'CI', + on: { push: { branches: ['main'] } }, + jobs: { + build: { + 'runs-on': 'ubuntu-latest', + steps: [{ run: 'const first = true\n\nconst second = true' }], + }, + }, + }) + + const yaml = workflow.stringify(mockGenieContext) + + expect(yaml).toContain('const first = true\n\n') + expect(yaml.split('\n').filter((line) => /[ \t]+$/u.test(line))).toEqual([]) + }) + it('keeps expressions quoted in inline arrays', () => { const workflow = githubWorkflow({ name: 'CI', diff --git a/packages/@overeng/genie/src/runtime/package-json/package-json.unit.test.ts b/packages/@overeng/genie/src/runtime/package-json/package-json.unit.test.ts index 7e854e08c8..9a311e7992 100644 --- a/packages/@overeng/genie/src/runtime/package-json/package-json.unit.test.ts +++ b/packages/@overeng/genie/src/runtime/package-json/package-json.unit.test.ts @@ -870,9 +870,23 @@ describe('packageJson', () => { fs.writeFileSync(path.join(repo.repoRoot, 'package.json'), '{"name":"repo"}\n') fs.writeFileSync(path.join(packageDir, 'package.json'), '{"name":"@test/package"}\n') fs.writeFileSync(path.join(packageDir, 'src/mod.ts'), 'export const value = 1\n') + const compilerBin = path.join(repo.repoRoot, 'fake-tsgo') + fs.writeFileSync( + compilerBin, + [ + '#!/usr/bin/env bash', + 'if [ "$1" = "--version" ]; then', + ' echo "Fake TypeScript 1.0.0"', + 'fi', + ].join('\n'), + ) + fs.chmodSync(compilerBin, 0o755) + const runtime = createNodePackageJsonValidationRuntime({ + typeProofCompiler: { path: compilerBin, kind: 'tsgo' }, + }) const validate = async () => - await nodePackageJsonValidationRuntime.validateExportEnvironments({ + await runtime.validateExportEnvironments({ cwd: repo.repoRoot, location: 'packages/pkg', packageName: '@test/package', @@ -1142,28 +1156,6 @@ describe('packageJson', () => { }) }, 30_000) - it('accepts a strict isomorphic TypeScript proof for the pure genie runtime entry', async () => { - const repoRoot = path.resolve(import.meta.dirname, '../../../../../..') - const result = packageJson({ - name: '@overeng/genie', - version: '0.0.0', - exports: { - '.': exportEntry('./src/runtime/mod.ts', { - environment: 'isomorphic-es2024', - typeProof: 'strict', - }), - }, - }) - - const issues = await result.validate?.({ - cwd: repoRoot, - location: 'packages/@overeng/genie', - validation: { packageJson: nodePackageJsonValidationRuntime }, - }) - - expect(issues).toEqual([]) - }, 30_000) - it('preserves non-emitted metadata when provided as the second argument', async () => { const result = packageJson( { diff --git a/packages/@overeng/genie/src/runtime/utils/yaml.ts b/packages/@overeng/genie/src/runtime/utils/yaml.ts index d144ea5a00..41212cbf2d 100644 --- a/packages/@overeng/genie/src/runtime/utils/yaml.ts +++ b/packages/@overeng/genie/src/runtime/utils/yaml.ts @@ -61,7 +61,7 @@ const quoteString = ({ const linePrefix = INDENT.repeat(indent) return `|\n${str .split('\n') - .map((line) => linePrefix + line) + .map((line) => (line === '' ? '' : linePrefix + line)) .join('\n')}` } if (needsQuoting({ str, flow }) === true) { diff --git a/packages/@overeng/genie/tsconfig.json b/packages/@overeng/genie/tsconfig.json index 28d95f45cc..7f902f73a5 100644 --- a/packages/@overeng/genie/tsconfig.json +++ b/packages/@overeng/genie/tsconfig.json @@ -50,7 +50,8 @@ "node", "bun" ], - "jsx": "react-jsx" + "jsx": "react-jsx", + "noEmit": true }, "include": [ "src/**/*.ts", diff --git a/packages/@overeng/genie/tsconfig.json.genie.ts b/packages/@overeng/genie/tsconfig.json.genie.ts index 198d3f1f07..2b0e1a4e41 100644 --- a/packages/@overeng/genie/tsconfig.json.genie.ts +++ b/packages/@overeng/genie/tsconfig.json.genie.ts @@ -12,6 +12,7 @@ export default tsconfigJson({ ...nodeTypes, types: ['node', 'bun'], jsx: 'react-jsx', + noEmit: true, }, include: ['src/**/*.ts', 'src/**/*.tsx', 'bin/**/*.ts', 'bin/**/*.tsx'], } satisfies TSConfigArgs) diff --git a/packages/@overeng/gh-ci-utils/BUCK b/packages/@overeng/gh-ci-utils/BUCK new file mode 100644 index 0000000000..4a8bd011af --- /dev/null +++ b/packages/@overeng/gh-ci-utils/BUCK @@ -0,0 +1,473 @@ +# Generated file - DO NOT EDIT +# Source: BUCK.genie.ts + +# Projection source: packages/@overeng/gh-ci-utils/BUCK.genie.ts +# Projection schema version: 11 +# Projection generator: effect-utils/genie/buck2-typescript-package-projection +# Semantic fingerprint: sha256:49cfc7c72942f57686db7c3845f5fe1db66f591c5692ad30e2610f977e904148 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/gh-ci-utils/BUCK.genie.ts, packages/@overeng/gh-ci-utils/BUCK.genie.ts, packages/@overeng/gh-ci-utils/bin/**/*.cts, packages/@overeng/gh-ci-utils/bin/**/*.js, packages/@overeng/gh-ci-utils/bin/**/*.mts, packages/@overeng/gh-ci-utils/bin/**/*.spec.cjs, packages/@overeng/gh-ci-utils/bin/**/*.spec.jsx, packages/@overeng/gh-ci-utils/bin/**/*.spec.mjs, packages/@overeng/gh-ci-utils/bin/**/*.test.cjs, packages/@overeng/gh-ci-utils/bin/**/*.test.jsx, packages/@overeng/gh-ci-utils/bin/**/*.test.mjs, packages/@overeng/gh-ci-utils/bin/**/*.ts, packages/@overeng/gh-ci-utils/bin/**/*.tsx, packages/@overeng/gh-ci-utils/bin/**/__snapshots__/*.snap, packages/@overeng/gh-ci-utils/package.json.genie.ts, packages/@overeng/gh-ci-utils/src/**/*.cts, packages/@overeng/gh-ci-utils/src/**/*.js, packages/@overeng/gh-ci-utils/src/**/*.mts, packages/@overeng/gh-ci-utils/src/**/*.spec.cjs, packages/@overeng/gh-ci-utils/src/**/*.spec.jsx, packages/@overeng/gh-ci-utils/src/**/*.spec.mjs, packages/@overeng/gh-ci-utils/src/**/*.test.cjs, packages/@overeng/gh-ci-utils/src/**/*.test.jsx, packages/@overeng/gh-ci-utils/src/**/*.test.mjs, packages/@overeng/gh-ci-utils/src/**/*.ts, packages/@overeng/gh-ci-utils/src/**/*.tsx, packages/@overeng/gh-ci-utils/src/**/__snapshots__/*.snap, packages/@overeng/gh-ci-utils/test/**/*.cts, packages/@overeng/gh-ci-utils/test/**/*.js, packages/@overeng/gh-ci-utils/test/**/*.mts, packages/@overeng/gh-ci-utils/test/**/*.spec.cjs, packages/@overeng/gh-ci-utils/test/**/*.spec.jsx, packages/@overeng/gh-ci-utils/test/**/*.spec.mjs, packages/@overeng/gh-ci-utils/test/**/*.test.cjs, packages/@overeng/gh-ci-utils/test/**/*.test.jsx, packages/@overeng/gh-ci-utils/test/**/*.test.mjs, packages/@overeng/gh-ci-utils/test/**/*.ts, packages/@overeng/gh-ci-utils/test/**/*.tsx, packages/@overeng/gh-ci-utils/test/**/__snapshots__/*.snap, packages/@overeng/gh-ci-utils/tsconfig.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/tui-react/BUCK.genie.ts, packages/@overeng/tui-react/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts +# Regenerate: devenv tasks run genie:run + +load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") +load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") +load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") +load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") + +export_file( + name = "package.json", + src = "package.json", + visibility = ["PUBLIC"], +) + +export_materialization_inputs([ + "bin/gh-ci-utils.ts", + "src/cli.ts", + "src/isomorphic/Errors.ts", + "src/isomorphic/GitHubSchemas.ts", + "src/isomorphic/lib/apiMeta.ts", + "src/isomorphic/lib/constants.ts", + "src/isomorphic/lib/format.ts", + "src/isomorphic/lib/inspectAssessment.ts", + "src/isomorphic/lib/inspectFacts.ts", + "src/isomorphic/lib/logFilter.ts", + "src/isomorphic/lib/rateLimit.ts", + "src/isomorphic/lib/summary.ts", + "src/isomorphic/lib/viewModels.ts", + "src/isomorphic/lib/watchPlan.ts", + "src/isomorphic/renderers/CiOutput/app.ts", + "src/isomorphic/renderers/CiOutput/mod.ts", + "src/isomorphic/renderers/CiOutput/ndjson.ts", + "src/isomorphic/renderers/CiOutput/schema.ts", + "src/isomorphic/renderers/CiOutput/stories/AllPassing.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/AllQueued.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/AuthError.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/BranchBehind.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/CancelledRun.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/ConflictsWithFailure.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/InProgress.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/LintFailure.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/Loading.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/MergeConflicts.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/NixHashMismatch.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/NoRuns.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/RateLimitWarning.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/_fixtures.ts", + "src/isomorphic/renderers/CiOutput/view.tsx", + "src/isomorphic/renderers/InspectOutput/app.ts", + "src/isomorphic/renderers/InspectOutput/mod.ts", + "src/isomorphic/renderers/InspectOutput/schema.ts", + "src/isomorphic/renderers/InspectOutput/stories/Active.stories.tsx", + "src/isomorphic/renderers/InspectOutput/stories/Error.stories.tsx", + "src/isomorphic/renderers/InspectOutput/stories/Idle.stories.tsx", + "src/isomorphic/renderers/InspectOutput/stories/Loading.stories.tsx", + "src/isomorphic/renderers/InspectOutput/stories/NotNamespaceRunner.stories.tsx", + "src/isomorphic/renderers/InspectOutput/stories/NscMissing.stories.tsx", + "src/isomorphic/renderers/InspectOutput/stories/ResourcePressure.stories.tsx", + "src/isomorphic/renderers/InspectOutput/stories/_fixtures.ts", + "src/isomorphic/renderers/InspectOutput/view.tsx", + "src/isomorphic/renderers/LogsOutput/app.ts", + "src/isomorphic/renderers/LogsOutput/mod.ts", + "src/isomorphic/renderers/LogsOutput/schema.ts", + "src/isomorphic/renderers/LogsOutput/stories/ErrorFiltered.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/Failed.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/GrepFiltered.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/Loading.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/LongOutput.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/NoLogs.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/Success.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/Truncated.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/_fixtures.ts", + "src/isomorphic/renderers/LogsOutput/view.tsx", + "src/isomorphic/renderers/MutationOutput/app.ts", + "src/isomorphic/renderers/MutationOutput/mod.ts", + "src/isomorphic/renderers/MutationOutput/schema.ts", + "src/isomorphic/renderers/MutationOutput/view.tsx", + "src/isomorphic/renderers/RunnersOutput/app.ts", + "src/isomorphic/renderers/RunnersOutput/mod.ts", + "src/isomorphic/renderers/RunnersOutput/schema.ts", + "src/isomorphic/renderers/RunnersOutput/stories/AllActive.stories.tsx", + "src/isomorphic/renderers/RunnersOutput/stories/AllIdle.stories.tsx", + "src/isomorphic/renderers/RunnersOutput/stories/AllUnreachable.stories.tsx", + "src/isomorphic/renderers/RunnersOutput/stories/Loading.stories.tsx", + "src/isomorphic/renderers/RunnersOutput/stories/MixedStatus.stories.tsx", + "src/isomorphic/renderers/RunnersOutput/stories/_fixtures.ts", + "src/isomorphic/renderers/RunnersOutput/view.tsx", + "src/mod.ts", + "src/node/Config.ts", + "src/node/GitHubClient.ts", + "src/node/GitHubInternal.ts", + "src/node/GitHubSession.ts", + "src/node/NamespaceClient.ts", + "src/node/RunId.ts", + "src/node/RunnerClient.ts", + "src/node/commands/auth.ts", + "src/node/commands/inspect.ts", + "src/node/commands/logs.ts", + "src/node/commands/rerun.ts", + "src/node/commands/runners.ts", + "src/node/commands/status.ts", + "src/node/lib/apiMeta.ts", + "src/node/lib/toolFailure.ts", + "src/node/observability.ts", + "src/vite-env.d.ts", + "test/GitHubClient.test.ts", + "test/GitHubClientLogs.test.ts", + "test/GitHubInternal.test.ts", + "test/GitHubSchemas.test.ts", + "test/GitHubSession.test.ts", + "test/RunId.test.ts", + "test/RunnerClient.test.ts", + "test/azureBlobError.test.ts", + "test/cliTokenFallback.test.ts", + "test/exitCode.test.ts", + "test/format.test.ts", + "test/inspectAssessment.test.ts", + "test/inspectJsonContract.test.ts", + "test/jsonContract.test.ts", + "test/jsonOutput.test.ts", + "test/logFilter.test.ts", + "test/namespaceAdapter.test.ts", + "test/ndjsonHeartbeat.test.ts", + "test/rateLimit.test.ts", + "test/rerun.test.ts", + "test/runSelection.test.ts", + "test/runnerIdentity.test.ts", + "test/toolFailure.test.ts", + "test/watchPlan.test.ts", +]) + +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/gh-ci-utils", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + +alias( + name = "node_modules", + actual = "//buck2/dependencies:view_packages_overeng_gh_ci_utils_a08905b5a8f3", + visibility = ["PUBLIC"], +) + +alias( + name = "editor_inputs", + actual = ":node_modules", + visibility = ["PUBLIC"], +) + +package_view( + name = "package_tree", + dependency_view = "//buck2/dependencies:view_packages_overeng_gh_ci_utils_a08905b5a8f3", + files = { + "bin/gh-ci-utils.ts": "bin/gh-ci-utils.ts", + "package.json": "package.json", + "src/cli.ts": "src/cli.ts", + "src/isomorphic/Errors.ts": "src/isomorphic/Errors.ts", + "src/isomorphic/GitHubSchemas.ts": "src/isomorphic/GitHubSchemas.ts", + "src/isomorphic/lib/apiMeta.ts": "src/isomorphic/lib/apiMeta.ts", + "src/isomorphic/lib/constants.ts": "src/isomorphic/lib/constants.ts", + "src/isomorphic/lib/format.ts": "src/isomorphic/lib/format.ts", + "src/isomorphic/lib/inspectAssessment.ts": "src/isomorphic/lib/inspectAssessment.ts", + "src/isomorphic/lib/inspectFacts.ts": "src/isomorphic/lib/inspectFacts.ts", + "src/isomorphic/lib/logFilter.ts": "src/isomorphic/lib/logFilter.ts", + "src/isomorphic/lib/rateLimit.ts": "src/isomorphic/lib/rateLimit.ts", + "src/isomorphic/lib/summary.ts": "src/isomorphic/lib/summary.ts", + "src/isomorphic/lib/viewModels.ts": "src/isomorphic/lib/viewModels.ts", + "src/isomorphic/lib/watchPlan.ts": "src/isomorphic/lib/watchPlan.ts", + "src/isomorphic/renderers/CiOutput/app.ts": "src/isomorphic/renderers/CiOutput/app.ts", + "src/isomorphic/renderers/CiOutput/mod.ts": "src/isomorphic/renderers/CiOutput/mod.ts", + "src/isomorphic/renderers/CiOutput/ndjson.ts": "src/isomorphic/renderers/CiOutput/ndjson.ts", + "src/isomorphic/renderers/CiOutput/schema.ts": "src/isomorphic/renderers/CiOutput/schema.ts", + "src/isomorphic/renderers/CiOutput/stories/AllPassing.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/AllPassing.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/AllQueued.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/AllQueued.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/AuthError.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/AuthError.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/BranchBehind.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/BranchBehind.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/CancelledRun.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/CancelledRun.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/ConflictsWithFailure.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/ConflictsWithFailure.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/InProgress.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/InProgress.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/LintFailure.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/LintFailure.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/Loading.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/Loading.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/MergeConflicts.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/MergeConflicts.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/NixHashMismatch.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/NixHashMismatch.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/NoRuns.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/NoRuns.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/RateLimitWarning.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/RateLimitWarning.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/_fixtures.ts": "src/isomorphic/renderers/CiOutput/stories/_fixtures.ts", + "src/isomorphic/renderers/CiOutput/view.tsx": "src/isomorphic/renderers/CiOutput/view.tsx", + "src/isomorphic/renderers/InspectOutput/app.ts": "src/isomorphic/renderers/InspectOutput/app.ts", + "src/isomorphic/renderers/InspectOutput/mod.ts": "src/isomorphic/renderers/InspectOutput/mod.ts", + "src/isomorphic/renderers/InspectOutput/schema.ts": "src/isomorphic/renderers/InspectOutput/schema.ts", + "src/isomorphic/renderers/InspectOutput/stories/Active.stories.tsx": "src/isomorphic/renderers/InspectOutput/stories/Active.stories.tsx", + "src/isomorphic/renderers/InspectOutput/stories/Error.stories.tsx": "src/isomorphic/renderers/InspectOutput/stories/Error.stories.tsx", + "src/isomorphic/renderers/InspectOutput/stories/Idle.stories.tsx": "src/isomorphic/renderers/InspectOutput/stories/Idle.stories.tsx", + "src/isomorphic/renderers/InspectOutput/stories/Loading.stories.tsx": "src/isomorphic/renderers/InspectOutput/stories/Loading.stories.tsx", + "src/isomorphic/renderers/InspectOutput/stories/NotNamespaceRunner.stories.tsx": "src/isomorphic/renderers/InspectOutput/stories/NotNamespaceRunner.stories.tsx", + "src/isomorphic/renderers/InspectOutput/stories/NscMissing.stories.tsx": "src/isomorphic/renderers/InspectOutput/stories/NscMissing.stories.tsx", + "src/isomorphic/renderers/InspectOutput/stories/ResourcePressure.stories.tsx": "src/isomorphic/renderers/InspectOutput/stories/ResourcePressure.stories.tsx", + "src/isomorphic/renderers/InspectOutput/stories/_fixtures.ts": "src/isomorphic/renderers/InspectOutput/stories/_fixtures.ts", + "src/isomorphic/renderers/InspectOutput/view.tsx": "src/isomorphic/renderers/InspectOutput/view.tsx", + "src/isomorphic/renderers/LogsOutput/app.ts": "src/isomorphic/renderers/LogsOutput/app.ts", + "src/isomorphic/renderers/LogsOutput/mod.ts": "src/isomorphic/renderers/LogsOutput/mod.ts", + "src/isomorphic/renderers/LogsOutput/schema.ts": "src/isomorphic/renderers/LogsOutput/schema.ts", + "src/isomorphic/renderers/LogsOutput/stories/ErrorFiltered.stories.tsx": "src/isomorphic/renderers/LogsOutput/stories/ErrorFiltered.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/Failed.stories.tsx": "src/isomorphic/renderers/LogsOutput/stories/Failed.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/GrepFiltered.stories.tsx": "src/isomorphic/renderers/LogsOutput/stories/GrepFiltered.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/Loading.stories.tsx": "src/isomorphic/renderers/LogsOutput/stories/Loading.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/LongOutput.stories.tsx": "src/isomorphic/renderers/LogsOutput/stories/LongOutput.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/NoLogs.stories.tsx": "src/isomorphic/renderers/LogsOutput/stories/NoLogs.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/Success.stories.tsx": "src/isomorphic/renderers/LogsOutput/stories/Success.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/Truncated.stories.tsx": "src/isomorphic/renderers/LogsOutput/stories/Truncated.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/_fixtures.ts": "src/isomorphic/renderers/LogsOutput/stories/_fixtures.ts", + "src/isomorphic/renderers/LogsOutput/view.tsx": "src/isomorphic/renderers/LogsOutput/view.tsx", + "src/isomorphic/renderers/MutationOutput/app.ts": "src/isomorphic/renderers/MutationOutput/app.ts", + "src/isomorphic/renderers/MutationOutput/mod.ts": "src/isomorphic/renderers/MutationOutput/mod.ts", + "src/isomorphic/renderers/MutationOutput/schema.ts": "src/isomorphic/renderers/MutationOutput/schema.ts", + "src/isomorphic/renderers/MutationOutput/view.tsx": "src/isomorphic/renderers/MutationOutput/view.tsx", + "src/isomorphic/renderers/RunnersOutput/app.ts": "src/isomorphic/renderers/RunnersOutput/app.ts", + "src/isomorphic/renderers/RunnersOutput/mod.ts": "src/isomorphic/renderers/RunnersOutput/mod.ts", + "src/isomorphic/renderers/RunnersOutput/schema.ts": "src/isomorphic/renderers/RunnersOutput/schema.ts", + "src/isomorphic/renderers/RunnersOutput/stories/AllActive.stories.tsx": "src/isomorphic/renderers/RunnersOutput/stories/AllActive.stories.tsx", + "src/isomorphic/renderers/RunnersOutput/stories/AllIdle.stories.tsx": "src/isomorphic/renderers/RunnersOutput/stories/AllIdle.stories.tsx", + "src/isomorphic/renderers/RunnersOutput/stories/AllUnreachable.stories.tsx": "src/isomorphic/renderers/RunnersOutput/stories/AllUnreachable.stories.tsx", + "src/isomorphic/renderers/RunnersOutput/stories/Loading.stories.tsx": "src/isomorphic/renderers/RunnersOutput/stories/Loading.stories.tsx", + "src/isomorphic/renderers/RunnersOutput/stories/MixedStatus.stories.tsx": "src/isomorphic/renderers/RunnersOutput/stories/MixedStatus.stories.tsx", + "src/isomorphic/renderers/RunnersOutput/stories/_fixtures.ts": "src/isomorphic/renderers/RunnersOutput/stories/_fixtures.ts", + "src/isomorphic/renderers/RunnersOutput/view.tsx": "src/isomorphic/renderers/RunnersOutput/view.tsx", + "src/mod.ts": "src/mod.ts", + "src/node/Config.ts": "src/node/Config.ts", + "src/node/GitHubClient.ts": "src/node/GitHubClient.ts", + "src/node/GitHubInternal.ts": "src/node/GitHubInternal.ts", + "src/node/GitHubSession.ts": "src/node/GitHubSession.ts", + "src/node/NamespaceClient.ts": "src/node/NamespaceClient.ts", + "src/node/RunId.ts": "src/node/RunId.ts", + "src/node/RunnerClient.ts": "src/node/RunnerClient.ts", + "src/node/commands/auth.ts": "src/node/commands/auth.ts", + "src/node/commands/inspect.ts": "src/node/commands/inspect.ts", + "src/node/commands/logs.ts": "src/node/commands/logs.ts", + "src/node/commands/rerun.ts": "src/node/commands/rerun.ts", + "src/node/commands/runners.ts": "src/node/commands/runners.ts", + "src/node/commands/status.ts": "src/node/commands/status.ts", + "src/node/lib/apiMeta.ts": "src/node/lib/apiMeta.ts", + "src/node/lib/toolFailure.ts": "src/node/lib/toolFailure.ts", + "src/node/observability.ts": "src/node/observability.ts", + "src/vite-env.d.ts": "src/vite-env.d.ts", + "test/GitHubClient.test.ts": "test/GitHubClient.test.ts", + "test/GitHubClientLogs.test.ts": "test/GitHubClientLogs.test.ts", + "test/GitHubInternal.test.ts": "test/GitHubInternal.test.ts", + "test/GitHubSchemas.test.ts": "test/GitHubSchemas.test.ts", + "test/GitHubSession.test.ts": "test/GitHubSession.test.ts", + "test/RunId.test.ts": "test/RunId.test.ts", + "test/RunnerClient.test.ts": "test/RunnerClient.test.ts", + "test/azureBlobError.test.ts": "test/azureBlobError.test.ts", + "test/cliTokenFallback.test.ts": "test/cliTokenFallback.test.ts", + "test/exitCode.test.ts": "test/exitCode.test.ts", + "test/format.test.ts": "test/format.test.ts", + "test/inspectAssessment.test.ts": "test/inspectAssessment.test.ts", + "test/inspectJsonContract.test.ts": "test/inspectJsonContract.test.ts", + "test/jsonContract.test.ts": "test/jsonContract.test.ts", + "test/jsonOutput.test.ts": "test/jsonOutput.test.ts", + "test/logFilter.test.ts": "test/logFilter.test.ts", + "test/namespaceAdapter.test.ts": "test/namespaceAdapter.test.ts", + "test/ndjsonHeartbeat.test.ts": "test/ndjsonHeartbeat.test.ts", + "test/rateLimit.test.ts": "test/rateLimit.test.ts", + "test/rerun.test.ts": "test/rerun.test.ts", + "test/runSelection.test.ts": "test/runSelection.test.ts", + "test/runnerIdentity.test.ts": "test/runnerIdentity.test.ts", + "test/toolFailure.test.ts": "test/toolFailure.test.ts", + "test/watchPlan.test.ts": "test/watchPlan.test.ts", + "tsconfig.json": "tsconfig.json", + }, + workspace_dist = { + "node_modules/@overeng/otel-contract/dist": "//packages/@overeng/otel-contract:dist", + "node_modules/@overeng/otel-contract/package.json": "//packages/@overeng/otel-contract:package.json", + "node_modules/@overeng/tui-react/dist": "//packages/@overeng/tui-react:dist", + "node_modules/@overeng/tui-react/package.json": "//packages/@overeng/tui-react:package.json", + "node_modules/@overeng/utils/dist": "//packages/@overeng/utils:dist", + "node_modules/@overeng/utils/package.json": "//packages/@overeng/utils:package.json", + }, + workspace_dependency_views = { + "node_modules/@overeng/otel-contract/node_modules": "//packages/@overeng/otel-contract:package_tree", + "node_modules/@overeng/tui-react/node_modules": "//packages/@overeng/tui-react:package_tree", + "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", + }, + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", + runtime_entry = "package-tree.ts", + visibility = ["PUBLIC"], +) + +package_view( + name = "test_package_tree", + dependency_view = "//buck2/dependencies:view_packages_overeng_gh_ci_utils_a08905b5a8f3", + files = { + "bin/gh-ci-utils.ts": "bin/gh-ci-utils.ts", + "package.json": "package.json", + "src/cli.ts": "src/cli.ts", + "src/isomorphic/Errors.ts": "src/isomorphic/Errors.ts", + "src/isomorphic/GitHubSchemas.ts": "src/isomorphic/GitHubSchemas.ts", + "src/isomorphic/lib/apiMeta.ts": "src/isomorphic/lib/apiMeta.ts", + "src/isomorphic/lib/constants.ts": "src/isomorphic/lib/constants.ts", + "src/isomorphic/lib/format.ts": "src/isomorphic/lib/format.ts", + "src/isomorphic/lib/inspectAssessment.ts": "src/isomorphic/lib/inspectAssessment.ts", + "src/isomorphic/lib/inspectFacts.ts": "src/isomorphic/lib/inspectFacts.ts", + "src/isomorphic/lib/logFilter.ts": "src/isomorphic/lib/logFilter.ts", + "src/isomorphic/lib/rateLimit.ts": "src/isomorphic/lib/rateLimit.ts", + "src/isomorphic/lib/summary.ts": "src/isomorphic/lib/summary.ts", + "src/isomorphic/lib/viewModels.ts": "src/isomorphic/lib/viewModels.ts", + "src/isomorphic/lib/watchPlan.ts": "src/isomorphic/lib/watchPlan.ts", + "src/isomorphic/renderers/CiOutput/app.ts": "src/isomorphic/renderers/CiOutput/app.ts", + "src/isomorphic/renderers/CiOutput/mod.ts": "src/isomorphic/renderers/CiOutput/mod.ts", + "src/isomorphic/renderers/CiOutput/ndjson.ts": "src/isomorphic/renderers/CiOutput/ndjson.ts", + "src/isomorphic/renderers/CiOutput/schema.ts": "src/isomorphic/renderers/CiOutput/schema.ts", + "src/isomorphic/renderers/CiOutput/stories/AllPassing.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/AllPassing.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/AllQueued.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/AllQueued.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/AuthError.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/AuthError.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/BranchBehind.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/BranchBehind.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/CancelledRun.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/CancelledRun.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/ConflictsWithFailure.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/ConflictsWithFailure.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/InProgress.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/InProgress.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/LintFailure.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/LintFailure.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/Loading.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/Loading.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/MergeConflicts.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/MergeConflicts.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/NixHashMismatch.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/NixHashMismatch.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/NoRuns.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/NoRuns.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/RateLimitWarning.stories.tsx": "src/isomorphic/renderers/CiOutput/stories/RateLimitWarning.stories.tsx", + "src/isomorphic/renderers/CiOutput/stories/_fixtures.ts": "src/isomorphic/renderers/CiOutput/stories/_fixtures.ts", + "src/isomorphic/renderers/CiOutput/view.tsx": "src/isomorphic/renderers/CiOutput/view.tsx", + "src/isomorphic/renderers/InspectOutput/app.ts": "src/isomorphic/renderers/InspectOutput/app.ts", + "src/isomorphic/renderers/InspectOutput/mod.ts": "src/isomorphic/renderers/InspectOutput/mod.ts", + "src/isomorphic/renderers/InspectOutput/schema.ts": "src/isomorphic/renderers/InspectOutput/schema.ts", + "src/isomorphic/renderers/InspectOutput/stories/Active.stories.tsx": "src/isomorphic/renderers/InspectOutput/stories/Active.stories.tsx", + "src/isomorphic/renderers/InspectOutput/stories/Error.stories.tsx": "src/isomorphic/renderers/InspectOutput/stories/Error.stories.tsx", + "src/isomorphic/renderers/InspectOutput/stories/Idle.stories.tsx": "src/isomorphic/renderers/InspectOutput/stories/Idle.stories.tsx", + "src/isomorphic/renderers/InspectOutput/stories/Loading.stories.tsx": "src/isomorphic/renderers/InspectOutput/stories/Loading.stories.tsx", + "src/isomorphic/renderers/InspectOutput/stories/NotNamespaceRunner.stories.tsx": "src/isomorphic/renderers/InspectOutput/stories/NotNamespaceRunner.stories.tsx", + "src/isomorphic/renderers/InspectOutput/stories/NscMissing.stories.tsx": "src/isomorphic/renderers/InspectOutput/stories/NscMissing.stories.tsx", + "src/isomorphic/renderers/InspectOutput/stories/ResourcePressure.stories.tsx": "src/isomorphic/renderers/InspectOutput/stories/ResourcePressure.stories.tsx", + "src/isomorphic/renderers/InspectOutput/stories/_fixtures.ts": "src/isomorphic/renderers/InspectOutput/stories/_fixtures.ts", + "src/isomorphic/renderers/InspectOutput/view.tsx": "src/isomorphic/renderers/InspectOutput/view.tsx", + "src/isomorphic/renderers/LogsOutput/app.ts": "src/isomorphic/renderers/LogsOutput/app.ts", + "src/isomorphic/renderers/LogsOutput/mod.ts": "src/isomorphic/renderers/LogsOutput/mod.ts", + "src/isomorphic/renderers/LogsOutput/schema.ts": "src/isomorphic/renderers/LogsOutput/schema.ts", + "src/isomorphic/renderers/LogsOutput/stories/ErrorFiltered.stories.tsx": "src/isomorphic/renderers/LogsOutput/stories/ErrorFiltered.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/Failed.stories.tsx": "src/isomorphic/renderers/LogsOutput/stories/Failed.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/GrepFiltered.stories.tsx": "src/isomorphic/renderers/LogsOutput/stories/GrepFiltered.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/Loading.stories.tsx": "src/isomorphic/renderers/LogsOutput/stories/Loading.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/LongOutput.stories.tsx": "src/isomorphic/renderers/LogsOutput/stories/LongOutput.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/NoLogs.stories.tsx": "src/isomorphic/renderers/LogsOutput/stories/NoLogs.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/Success.stories.tsx": "src/isomorphic/renderers/LogsOutput/stories/Success.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/Truncated.stories.tsx": "src/isomorphic/renderers/LogsOutput/stories/Truncated.stories.tsx", + "src/isomorphic/renderers/LogsOutput/stories/_fixtures.ts": "src/isomorphic/renderers/LogsOutput/stories/_fixtures.ts", + "src/isomorphic/renderers/LogsOutput/view.tsx": "src/isomorphic/renderers/LogsOutput/view.tsx", + "src/isomorphic/renderers/MutationOutput/app.ts": "src/isomorphic/renderers/MutationOutput/app.ts", + "src/isomorphic/renderers/MutationOutput/mod.ts": "src/isomorphic/renderers/MutationOutput/mod.ts", + "src/isomorphic/renderers/MutationOutput/schema.ts": "src/isomorphic/renderers/MutationOutput/schema.ts", + "src/isomorphic/renderers/MutationOutput/view.tsx": "src/isomorphic/renderers/MutationOutput/view.tsx", + "src/isomorphic/renderers/RunnersOutput/app.ts": "src/isomorphic/renderers/RunnersOutput/app.ts", + "src/isomorphic/renderers/RunnersOutput/mod.ts": "src/isomorphic/renderers/RunnersOutput/mod.ts", + "src/isomorphic/renderers/RunnersOutput/schema.ts": "src/isomorphic/renderers/RunnersOutput/schema.ts", + "src/isomorphic/renderers/RunnersOutput/stories/AllActive.stories.tsx": "src/isomorphic/renderers/RunnersOutput/stories/AllActive.stories.tsx", + "src/isomorphic/renderers/RunnersOutput/stories/AllIdle.stories.tsx": "src/isomorphic/renderers/RunnersOutput/stories/AllIdle.stories.tsx", + "src/isomorphic/renderers/RunnersOutput/stories/AllUnreachable.stories.tsx": "src/isomorphic/renderers/RunnersOutput/stories/AllUnreachable.stories.tsx", + "src/isomorphic/renderers/RunnersOutput/stories/Loading.stories.tsx": "src/isomorphic/renderers/RunnersOutput/stories/Loading.stories.tsx", + "src/isomorphic/renderers/RunnersOutput/stories/MixedStatus.stories.tsx": "src/isomorphic/renderers/RunnersOutput/stories/MixedStatus.stories.tsx", + "src/isomorphic/renderers/RunnersOutput/stories/_fixtures.ts": "src/isomorphic/renderers/RunnersOutput/stories/_fixtures.ts", + "src/isomorphic/renderers/RunnersOutput/view.tsx": "src/isomorphic/renderers/RunnersOutput/view.tsx", + "src/mod.ts": "src/mod.ts", + "src/node/Config.ts": "src/node/Config.ts", + "src/node/GitHubClient.ts": "src/node/GitHubClient.ts", + "src/node/GitHubInternal.ts": "src/node/GitHubInternal.ts", + "src/node/GitHubSession.ts": "src/node/GitHubSession.ts", + "src/node/NamespaceClient.ts": "src/node/NamespaceClient.ts", + "src/node/RunId.ts": "src/node/RunId.ts", + "src/node/RunnerClient.ts": "src/node/RunnerClient.ts", + "src/node/commands/auth.ts": "src/node/commands/auth.ts", + "src/node/commands/inspect.ts": "src/node/commands/inspect.ts", + "src/node/commands/logs.ts": "src/node/commands/logs.ts", + "src/node/commands/rerun.ts": "src/node/commands/rerun.ts", + "src/node/commands/runners.ts": "src/node/commands/runners.ts", + "src/node/commands/status.ts": "src/node/commands/status.ts", + "src/node/lib/apiMeta.ts": "src/node/lib/apiMeta.ts", + "src/node/lib/toolFailure.ts": "src/node/lib/toolFailure.ts", + "src/node/observability.ts": "src/node/observability.ts", + "src/vite-env.d.ts": "src/vite-env.d.ts", + "test/GitHubClient.test.ts": "test/GitHubClient.test.ts", + "test/GitHubClientLogs.test.ts": "test/GitHubClientLogs.test.ts", + "test/GitHubInternal.test.ts": "test/GitHubInternal.test.ts", + "test/GitHubSchemas.test.ts": "test/GitHubSchemas.test.ts", + "test/GitHubSession.test.ts": "test/GitHubSession.test.ts", + "test/RunId.test.ts": "test/RunId.test.ts", + "test/RunnerClient.test.ts": "test/RunnerClient.test.ts", + "test/azureBlobError.test.ts": "test/azureBlobError.test.ts", + "test/cliTokenFallback.test.ts": "test/cliTokenFallback.test.ts", + "test/exitCode.test.ts": "test/exitCode.test.ts", + "test/format.test.ts": "test/format.test.ts", + "test/inspectAssessment.test.ts": "test/inspectAssessment.test.ts", + "test/inspectJsonContract.test.ts": "test/inspectJsonContract.test.ts", + "test/jsonContract.test.ts": "test/jsonContract.test.ts", + "test/jsonOutput.test.ts": "test/jsonOutput.test.ts", + "test/logFilter.test.ts": "test/logFilter.test.ts", + "test/namespaceAdapter.test.ts": "test/namespaceAdapter.test.ts", + "test/ndjsonHeartbeat.test.ts": "test/ndjsonHeartbeat.test.ts", + "test/rateLimit.test.ts": "test/rateLimit.test.ts", + "test/rerun.test.ts": "test/rerun.test.ts", + "test/runSelection.test.ts": "test/runSelection.test.ts", + "test/runnerIdentity.test.ts": "test/runnerIdentity.test.ts", + "test/toolFailure.test.ts": "test/toolFailure.test.ts", + "test/watchPlan.test.ts": "test/watchPlan.test.ts", + "tsconfig.json": "tsconfig.json", + "vitest.config.ts": "vitest.config.ts", + }, + workspace_dist = { + "node_modules/@overeng/otel-contract/dist": "//packages/@overeng/otel-contract:dist", + "node_modules/@overeng/otel-contract/package.json": "//packages/@overeng/otel-contract:package.json", + "node_modules/@overeng/tui-react/dist": "//packages/@overeng/tui-react:dist", + "node_modules/@overeng/tui-react/package.json": "//packages/@overeng/tui-react:package.json", + "node_modules/@overeng/utils/dist": "//packages/@overeng/utils:dist", + "node_modules/@overeng/utils/package.json": "//packages/@overeng/utils:package.json", + }, + workspace_dependency_views = { + "node_modules/@overeng/otel-contract/node_modules": "//packages/@overeng/otel-contract:package_tree", + "node_modules/@overeng/tui-react/node_modules": "//packages/@overeng/tui-react:package_tree", + "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", + }, + strip_project_references = True, + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", + runtime_entry = "package-tree.ts", + visibility = ["PUBLIC"], +) + +editor_view_inputs( + name = "editor_view_inputs", + editor_inputs = ":editor_inputs", + package_tree = ":package_tree", + visibility = ["PUBLIC"], +) + +tsgo_typecheck( + name = "typecheck", + package_tree = ":package_tree", + visibility = ["PUBLIC"], +) + +tsgo_emit( + name = "dist", + package_tree = ":package_tree", + declaration_sources = { + "src/vite-env.d.ts": "src/vite-env.d.ts", + }, + declaration_entrypoint = "src/mod.d.ts", + visibility = ["PUBLIC"], +) + +vitest_test( + name = "test", + package_tree = ":test_package_tree", + visibility = ["PUBLIC"], +) + +vitest_collect( + name = "test_collect", + package_tree = ":test_package_tree", + visibility = ["PUBLIC"], +) diff --git a/packages/@overeng/gh-ci-utils/BUCK.genie.ts b/packages/@overeng/gh-ci-utils/BUCK.genie.ts new file mode 100644 index 0000000000..6a7347d19a --- /dev/null +++ b/packages/@overeng/gh-ci-utils/BUCK.genie.ts @@ -0,0 +1,35 @@ +import { withJavaScriptCandidates } from '../../../genie/buck2/javascript-candidates.ts' +import type { Buck2TypeScriptAdmission } from '../../../genie/buck2/typescript-admissions.ts' +import { buck2TypeScriptPackageProjection } from '../../../genie/buck2/typescript-package-projection.ts' + +export const buck2TypeScriptAdmission = { + dependencyImporter: '//buck2/dependencies:importer_packages_overeng_gh_ci_utils_a08905b5a8f3', + packageName: '@overeng/gh-ci-utils', + packagePath: 'packages/@overeng/gh-ci-utils', + projectionSource: 'packages/@overeng/gh-ci-utils/BUCK.genie.ts', + sourceRoots: ['src', 'bin', 'test'], + workspaceSiblings: [ + { + packageName: '@overeng/otel-contract', + packagePath: 'packages/@overeng/otel-contract', + distTarget: '//packages/@overeng/otel-contract:dist', + }, + { + packageName: '@overeng/tui-react', + packagePath: 'packages/@overeng/tui-react', + distTarget: '//packages/@overeng/tui-react:dist', + }, + { + packageName: '@overeng/utils', + packagePath: 'packages/@overeng/utils', + distTarget: '//packages/@overeng/utils:dist', + }, + ], + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], + tests: [{ name: 'test', runner: 'vitest' }], +} as const satisfies Buck2TypeScriptAdmission + +export default withJavaScriptCandidates({ + projection: buck2TypeScriptPackageProjection(buck2TypeScriptAdmission), + products: [], +}) diff --git a/packages/@overeng/gh-ci-utils/nix/build.nix b/packages/@overeng/gh-ci-utils/nix/build.nix index 4d45782314..54fb36736c 100644 --- a/packages/@overeng/gh-ci-utils/nix/build.nix +++ b/packages/@overeng/gh-ci-utils/nix/build.nix @@ -20,7 +20,7 @@ let workspaceRoot = src; # Managed by the repo FOD refresh workflow — do not edit manually. depsBuilds = { - "." = mkSharedHash "sha256-QuYwdBGfpVbQdjNpIrQjbzLCdyt4n5MgrvUJdLFmN+A="; + "." = mkSharedHash "sha256-EVa3ZO2k0Uygs8zlH+Xyppr3bqB6T+JNVmq96Po7VT0="; }; nativeNodePackages = opentuiCoreNative.packages; smokeTestArgs = [ "--version" ]; diff --git a/packages/@overeng/gh-ci-utils/src/node/Config.ts b/packages/@overeng/gh-ci-utils/src/node/Config.ts index 038cc83abf..cda4664225 100644 --- a/packages/@overeng/gh-ci-utils/src/node/Config.ts +++ b/packages/@overeng/gh-ci-utils/src/node/Config.ts @@ -82,7 +82,7 @@ const loadFileConfig = ( (cause) => new ConfigError({ message: `Failed to read config: ${configPath}`, cause }), ), ) - return yield* Schema.decodeUnknownEffect(Schema.fromJsonString(GhCiUtilsFileConfig))(raw).pipe( + return yield* Schema.decodeEffect(Schema.fromJsonString(GhCiUtilsFileConfig))(raw).pipe( Effect.mapError( (cause) => new ConfigError({ message: 'Invalid gh-ci-utils config format', cause }), ), diff --git a/packages/@overeng/gh-ci-utils/src/node/GitHubSession.ts b/packages/@overeng/gh-ci-utils/src/node/GitHubSession.ts index c66d9f03ea..32830436f0 100644 --- a/packages/@overeng/gh-ci-utils/src/node/GitHubSession.ts +++ b/packages/@overeng/gh-ci-utils/src/node/GitHubSession.ts @@ -49,7 +49,7 @@ export const loadSession = Effect.gen(function* () { ), ) - const data = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(SessionData))(content).pipe( + const data = yield* Schema.decodeEffect(Schema.fromJsonString(SessionData))(content).pipe( Effect.mapError((cause) => new ConfigError({ message: 'Failed to parse session data', cause })), ) diff --git a/packages/@overeng/gh-ci-utils/src/node/RunId.ts b/packages/@overeng/gh-ci-utils/src/node/RunId.ts index 4ccf602b83..76851ac3b5 100644 --- a/packages/@overeng/gh-ci-utils/src/node/RunId.ts +++ b/packages/@overeng/gh-ci-utils/src/node/RunId.ts @@ -386,16 +386,15 @@ const resolveActiveBranchRun = Effect.fn('resolve-active-branch-run')( ) const requireLocalRepo = (localRepo: Option.Option) => - Option.match(localRepo, { - onNone: () => - Effect.fail( + Effect.fromOption(localRepo).pipe( + Effect.mapError( + () => new ConfigError({ message: 'No local repo available. Use owner/repo as target to specify.', cause: 'no local repo', }), - ), - onSome: Effect.succeed, - }) + ), + ) /** Resolve a supported branch or repository-default workflow dispatch target. */ export const resolveWorkflowDispatchTarget = Effect.fn('resolve-workflow-dispatch-target')( diff --git a/packages/@overeng/gh-ci-utils/src/node/RunnerClient.ts b/packages/@overeng/gh-ci-utils/src/node/RunnerClient.ts index 4709f571d2..557e9271c4 100644 --- a/packages/@overeng/gh-ci-utils/src/node/RunnerClient.ts +++ b/packages/@overeng/gh-ci-utils/src/node/RunnerClient.ts @@ -57,7 +57,7 @@ export const fetchRunnerHostJobs = ( /** Fetch active jobs from all runner hosts. */ export const fetchAllRunnerJobs = (hosts: readonly string[]) => - Effect.all(hosts.map(fetchRunnerHostJobs), { concurrency: 'unbounded' }).pipe( + Effect.forEach(hosts, fetchRunnerHostJobs, { concurrency: 'unbounded' }).pipe( Effect.map((results) => results.flatMap((result) => (result.status === 'reachable' ? result.jobs : [])), ), diff --git a/packages/@overeng/gh-ci-utils/src/node/commands/auth.ts b/packages/@overeng/gh-ci-utils/src/node/commands/auth.ts index fadb003d24..239726b05d 100644 --- a/packages/@overeng/gh-ci-utils/src/node/commands/auth.ts +++ b/packages/@overeng/gh-ci-utils/src/node/commands/auth.ts @@ -169,9 +169,7 @@ const performLogin = Effect.gen(function* () { }) } - const parsed = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(LoginResult))( - child.stdout, - ).pipe( + const parsed = yield* Schema.decodeEffect(Schema.fromJsonString(LoginResult))(child.stdout).pipe( Effect.mapError((cause) => new ConfigError({ message: 'Failed to parse login result', cause })), ) diff --git a/packages/@overeng/gh-ci-utils/src/node/commands/runners.ts b/packages/@overeng/gh-ci-utils/src/node/commands/runners.ts index 90c6f5fc55..16a74d4ffc 100644 --- a/packages/@overeng/gh-ci-utils/src/node/commands/runners.ts +++ b/packages/@overeng/gh-ci-utils/src/node/commands/runners.ts @@ -24,8 +24,9 @@ export const runnersCommand = Cli.Command.make('runners', { output: outputOption ) const config = yield* resolveConfig({}) - const results = yield* Effect.all( - config.runnerHosts.map((host) => + const results = yield* Effect.forEach( + config.runnerHosts, + (host) => fetchRunnerHostJobs(host).pipe( Effect.map( (result) => @@ -40,7 +41,6 @@ export const runnersCommand = Cli.Command.make('runners', { output: outputOption }) satisfies HostResult, ), ), - ), { concurrency: 'unbounded' }, ) diff --git a/packages/@overeng/gh-ci-utils/test/GitHubSchemas.test.ts b/packages/@overeng/gh-ci-utils/test/GitHubSchemas.test.ts index 781df6af9e..52f573b703 100644 --- a/packages/@overeng/gh-ci-utils/test/GitHubSchemas.test.ts +++ b/packages/@overeng/gh-ci-utils/test/GitHubSchemas.test.ts @@ -110,7 +110,7 @@ describe('GitHubSchemas', () => { it.each(['stale', 'startup_failure'] as const)( 'decodes the documented %s conclusion for jobs and steps', (conclusion) => { - const result = Schema.decodeUnknownSync(GH.WorkflowJob)({ + const result = Schema.decodeSync(GH.WorkflowJob)({ id: 456, run_id: 123, name: 'synthetic-conclusion', diff --git a/packages/@overeng/gh-ci-utils/test/cliTokenFallback.test.ts b/packages/@overeng/gh-ci-utils/test/cliTokenFallback.test.ts index f10642bc4d..c29ab15ad4 100644 --- a/packages/@overeng/gh-ci-utils/test/cliTokenFallback.test.ts +++ b/packages/@overeng/gh-ci-utils/test/cliTokenFallback.test.ts @@ -77,8 +77,9 @@ const runFallbackScenario = async (repos: readonly string[]) => { await Effect.gen(function* () { const client = yield* GitHubClient - yield* Effect.all( - repos.map((repo) => client.listWorkflowRunsByStatus({ repo, status: 'completed' })), + yield* Effect.forEach( + repos, + (repo) => client.listWorkflowRunsByStatus({ repo, status: 'completed' }), { concurrency: 'unbounded' }, ) }).pipe( diff --git a/packages/@overeng/gh-ci-utils/test/inspectJsonContract.test.ts b/packages/@overeng/gh-ci-utils/test/inspectJsonContract.test.ts index 736109b9da..bbe8e9aff5 100644 --- a/packages/@overeng/gh-ci-utils/test/inspectJsonContract.test.ts +++ b/packages/@overeng/gh-ci-utils/test/inspectJsonContract.test.ts @@ -146,9 +146,9 @@ describe('inspect --output json contract', () => { it('round-trips a loaded state through the schema unchanged', () => { const state = loadedState(reportedNamespace) - expect( - Schema.decodeUnknownSync(Schema.fromJsonString(InspectStateSchema))(encodeJson(state)), - ).toEqual(state) + expect(Schema.decodeSync(Schema.fromJsonString(InspectStateSchema))(encodeJson(state))).toEqual( + state, + ) }) it('rejects a disposition outside the four it is allowed to claim', () => { @@ -157,9 +157,7 @@ describe('inspect --output json contract', () => { ...(typeof encoded === 'object' && encoded !== null ? encoded : {}), assessment: { disposition: 'healthy', evidence: [], limitations: [] }, }) - expect(() => - Schema.decodeUnknownSync(Schema.fromJsonString(InspectStateSchema))(tampered), - ).toThrow() + expect(() => Schema.decodeSync(Schema.fromJsonString(InspectStateSchema))(tampered)).toThrow() }) }) diff --git a/packages/@overeng/gh-ci-utils/test/jsonContract.test.ts b/packages/@overeng/gh-ci-utils/test/jsonContract.test.ts index c10a771688..d13a4fb523 100644 --- a/packages/@overeng/gh-ci-utils/test/jsonContract.test.ts +++ b/packages/@overeng/gh-ci-utils/test/jsonContract.test.ts @@ -195,7 +195,7 @@ describe('status --output json job contract (#927)', () => { it('still decodes job payloads written before completion finality was tracked', () => { const legacyJob = job() - expect(Schema.decodeUnknownSync(WorkflowJobViewModel)(legacyJob)).toEqual(legacyJob) + expect(Schema.decodeSync(WorkflowJobViewModel)(legacyJob)).toEqual(legacyJob) }) it('exposes a top-level summary in the status state', () => { diff --git a/packages/@overeng/kdl-effect/BUCK b/packages/@overeng/kdl-effect/BUCK index 73a4b51902..30806388f0 100644 --- a/packages/@overeng/kdl-effect/BUCK +++ b/packages/@overeng/kdl-effect/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/kdl-effect/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:773319d5889c52e6fd43a635bd45bb4b4a8ff2394253b2c8a0005a6f971d7caa -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/kdl-effect/BUCK.genie.ts, packages/@overeng/kdl-effect/BUCK.genie.ts, packages/@overeng/kdl-effect/package.json.genie.ts, packages/@overeng/kdl-effect/src/**/*.cts, packages/@overeng/kdl-effect/src/**/*.js, packages/@overeng/kdl-effect/src/**/*.mts, packages/@overeng/kdl-effect/src/**/*.spec.cjs, packages/@overeng/kdl-effect/src/**/*.spec.jsx, packages/@overeng/kdl-effect/src/**/*.spec.mjs, packages/@overeng/kdl-effect/src/**/*.test.cjs, packages/@overeng/kdl-effect/src/**/*.test.jsx, packages/@overeng/kdl-effect/src/**/*.test.mjs, packages/@overeng/kdl-effect/src/**/*.ts, packages/@overeng/kdl-effect/src/**/*.tsx, packages/@overeng/kdl-effect/src/**/__snapshots__/*.snap, packages/@overeng/kdl-effect/tsconfig.json.genie.ts, packages/@overeng/kdl/BUCK.genie.ts, packages/@overeng/kdl/package.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts +# Semantic fingerprint: sha256:c33d473151a092040937f505be3551f1b368b93260268b43529d86d4da1c852d +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/kdl-effect/BUCK.genie.ts, packages/@overeng/kdl-effect/BUCK.genie.ts, packages/@overeng/kdl-effect/package.json.genie.ts, packages/@overeng/kdl-effect/src/**/*.cts, packages/@overeng/kdl-effect/src/**/*.js, packages/@overeng/kdl-effect/src/**/*.mts, packages/@overeng/kdl-effect/src/**/*.spec.cjs, packages/@overeng/kdl-effect/src/**/*.spec.jsx, packages/@overeng/kdl-effect/src/**/*.spec.mjs, packages/@overeng/kdl-effect/src/**/*.test.cjs, packages/@overeng/kdl-effect/src/**/*.test.jsx, packages/@overeng/kdl-effect/src/**/*.test.mjs, packages/@overeng/kdl-effect/src/**/*.ts, packages/@overeng/kdl-effect/src/**/*.tsx, packages/@overeng/kdl-effect/src/**/__snapshots__/*.snap, packages/@overeng/kdl-effect/tsconfig.json.genie.ts, packages/@overeng/kdl/BUCK.genie.ts, packages/@overeng/kdl/package.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -27,6 +28,14 @@ export_materialization_inputs([ "src/parse.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/kdl-effect", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_kdl_effect_bdfdc416cbf6", @@ -61,7 +70,7 @@ package_view( "node_modules/@overeng/kdl/node_modules": "//packages/@overeng/kdl:package_tree", "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -90,7 +99,7 @@ package_view( "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -113,6 +122,7 @@ tsgo_emit( package_tree = ":package_tree", declaration_sources = { }, + declaration_entrypoint = "src/mod.d.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/kdl-effect/BUCK.genie.ts b/packages/@overeng/kdl-effect/BUCK.genie.ts index 580377dad3..2ca1dbde95 100644 --- a/packages/@overeng/kdl-effect/BUCK.genie.ts +++ b/packages/@overeng/kdl-effect/BUCK.genie.ts @@ -19,7 +19,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils-dev:dist', }, ], - editorViewConsumer: false, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/kdl-effect/package.json b/packages/@overeng/kdl-effect/package.json index af76ceb9b2..363a8bd383 100644 --- a/packages/@overeng/kdl-effect/package.json +++ b/packages/@overeng/kdl-effect/package.json @@ -13,7 +13,10 @@ "type": "module", "private": true, "exports": { - ".": "./src/mod.ts" + ".": { + "types": "./dist/src/mod.d.ts", + "default": "./src/mod.ts" + } }, "dependencies": { "@overeng/kdl": "workspace:^" diff --git a/packages/@overeng/kdl-effect/package.json.genie.ts b/packages/@overeng/kdl-effect/package.json.genie.ts index b5d25f3007..0251287f40 100644 --- a/packages/@overeng/kdl-effect/package.json.genie.ts +++ b/packages/@overeng/kdl-effect/package.json.genie.ts @@ -34,7 +34,10 @@ export default packageJson( name: '@overeng/kdl-effect', ...privatePackageDefaults, exports: { - '.': exportEntry('./src/mod.ts', { environment: 'isomorphic-es2024' }), + '.': exportEntry( + { types: './dist/src/mod.d.ts', default: './src/mod.ts' }, + { environment: 'isomorphic-es2024' }, + ), }, publishConfig: { access: 'public', diff --git a/packages/@overeng/kdl-effect/tsconfig.json b/packages/@overeng/kdl-effect/tsconfig.json index 17f67afc83..4309b8538f 100644 --- a/packages/@overeng/kdl-effect/tsconfig.json +++ b/packages/@overeng/kdl-effect/tsconfig.json @@ -48,7 +48,8 @@ "tsBuildInfoFile": "./dist/tsconfig.tsbuildinfo", "types": [ "node" - ] + ], + "noEmit": true }, "include": [ "src/**/*" diff --git a/packages/@overeng/kdl-effect/tsconfig.json.genie.ts b/packages/@overeng/kdl-effect/tsconfig.json.genie.ts index 31150c8deb..c6a83b6c04 100644 --- a/packages/@overeng/kdl-effect/tsconfig.json.genie.ts +++ b/packages/@overeng/kdl-effect/tsconfig.json.genie.ts @@ -10,6 +10,7 @@ export default tsconfigJson({ ...baseTsconfigCompilerOptions, ...packageTsconfigCompilerOptions, ...nodeTypes, + noEmit: true, }, include: ['src/**/*'], } satisfies TSConfigArgs) diff --git a/packages/@overeng/kdl/BUCK b/packages/@overeng/kdl/BUCK index f0cf211817..25ac04d667 100644 --- a/packages/@overeng/kdl/BUCK +++ b/packages/@overeng/kdl/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/kdl/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:35b78ce855754d5187b550cdffcb1e475b7f387c3b7107dcdee61b1de61d94f7 -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/kdl/BUCK.genie.ts, packages/@overeng/kdl/BUCK.genie.ts, packages/@overeng/kdl/package.json.genie.ts, packages/@overeng/kdl/src/**/*.cts, packages/@overeng/kdl/src/**/*.js, packages/@overeng/kdl/src/**/*.mts, packages/@overeng/kdl/src/**/*.spec.cjs, packages/@overeng/kdl/src/**/*.spec.jsx, packages/@overeng/kdl/src/**/*.spec.mjs, packages/@overeng/kdl/src/**/*.test.cjs, packages/@overeng/kdl/src/**/*.test.jsx, packages/@overeng/kdl/src/**/*.test.mjs, packages/@overeng/kdl/src/**/*.ts, packages/@overeng/kdl/src/**/*.tsx, packages/@overeng/kdl/src/**/__snapshots__/*.snap, packages/@overeng/kdl/test-fixtures/**/*.kdl, packages/@overeng/kdl/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts +# Semantic fingerprint: sha256:640b4c55bf502a73cc5f2b043401d515736b5d95d2eb6ff115a42ed9ac9bd9b0 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/kdl/BUCK.genie.ts, packages/@overeng/kdl/BUCK.genie.ts, packages/@overeng/kdl/package.json.genie.ts, packages/@overeng/kdl/src/**/*.cts, packages/@overeng/kdl/src/**/*.js, packages/@overeng/kdl/src/**/*.mts, packages/@overeng/kdl/src/**/*.spec.cjs, packages/@overeng/kdl/src/**/*.spec.jsx, packages/@overeng/kdl/src/**/*.spec.mjs, packages/@overeng/kdl/src/**/*.test.cjs, packages/@overeng/kdl/src/**/*.test.jsx, packages/@overeng/kdl/src/**/*.test.mjs, packages/@overeng/kdl/src/**/*.ts, packages/@overeng/kdl/src/**/*.tsx, packages/@overeng/kdl/src/**/__snapshots__/*.snap, packages/@overeng/kdl/test-fixtures/**/*.kdl, packages/@overeng/kdl/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -47,6 +48,14 @@ export_materialization_inputs([ "src/upstream.test.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/kdl", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_kdl_d22c24f7367b", @@ -98,7 +107,7 @@ package_view( workspace_dependency_views = { "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -721,7 +730,7 @@ package_view( "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/kdl/BUCK.genie.ts b/packages/@overeng/kdl/BUCK.genie.ts index ac5926795f..1a691d36ed 100644 --- a/packages/@overeng/kdl/BUCK.genie.ts +++ b/packages/@overeng/kdl/BUCK.genie.ts @@ -15,11 +15,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils-dev:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/megarepo/BUCK b/packages/@overeng/megarepo/BUCK index 7daeab18a0..fda1eef19c 100644 --- a/packages/@overeng/megarepo/BUCK +++ b/packages/@overeng/megarepo/BUCK @@ -5,14 +5,15 @@ load("//buck2:package_tools.bzl", "package_bin_artifact") load("//buck2/products:defs.bzl", "javascript_product") # Projection source: packages/@overeng/megarepo/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:7331fe78ac16e0b983cff45515bd8bcdbfbbc26d05303c92203d4f02fd9a4407 -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/effect-path/BUCK.genie.ts, packages/@overeng/effect-path/package.json.genie.ts, packages/@overeng/kdl-effect/BUCK.genie.ts, packages/@overeng/kdl-effect/package.json.genie.ts, packages/@overeng/kdl/BUCK.genie.ts, packages/@overeng/kdl/package.json.genie.ts, packages/@overeng/megarepo/BUCK.genie.ts, packages/@overeng/megarepo/BUCK.genie.ts, packages/@overeng/megarepo/bin/**/*.cts, packages/@overeng/megarepo/bin/**/*.js, packages/@overeng/megarepo/bin/**/*.mts, packages/@overeng/megarepo/bin/**/*.spec.cjs, packages/@overeng/megarepo/bin/**/*.spec.jsx, packages/@overeng/megarepo/bin/**/*.spec.mjs, packages/@overeng/megarepo/bin/**/*.test.cjs, packages/@overeng/megarepo/bin/**/*.test.jsx, packages/@overeng/megarepo/bin/**/*.test.mjs, packages/@overeng/megarepo/bin/**/*.ts, packages/@overeng/megarepo/bin/**/*.tsx, packages/@overeng/megarepo/bin/**/__snapshots__/*.snap, packages/@overeng/megarepo/package.json.genie.ts, packages/@overeng/megarepo/src/**/*.cts, packages/@overeng/megarepo/src/**/*.js, packages/@overeng/megarepo/src/**/*.mts, packages/@overeng/megarepo/src/**/*.spec.cjs, packages/@overeng/megarepo/src/**/*.spec.jsx, packages/@overeng/megarepo/src/**/*.spec.mjs, packages/@overeng/megarepo/src/**/*.test.cjs, packages/@overeng/megarepo/src/**/*.test.jsx, packages/@overeng/megarepo/src/**/*.test.mjs, packages/@overeng/megarepo/src/**/*.ts, packages/@overeng/megarepo/src/**/*.tsx, packages/@overeng/megarepo/src/**/__snapshots__/*.snap, packages/@overeng/megarepo/tsconfig.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/tui-core/BUCK.genie.ts, packages/@overeng/tui-core/package.json.genie.ts, packages/@overeng/tui-react/BUCK.genie.ts, packages/@overeng/tui-react/package.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts +# Semantic fingerprint: sha256:cae06b9e300b2816ce528e7a9b75598b272b0150ac4d3178c35d3d6afd43ca95 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/effect-path/BUCK.genie.ts, packages/@overeng/effect-path/package.json.genie.ts, packages/@overeng/kdl-effect/BUCK.genie.ts, packages/@overeng/kdl-effect/package.json.genie.ts, packages/@overeng/kdl/BUCK.genie.ts, packages/@overeng/kdl/package.json.genie.ts, packages/@overeng/megarepo/BUCK.genie.ts, packages/@overeng/megarepo/BUCK.genie.ts, packages/@overeng/megarepo/bin/**/*.cts, packages/@overeng/megarepo/bin/**/*.js, packages/@overeng/megarepo/bin/**/*.mts, packages/@overeng/megarepo/bin/**/*.spec.cjs, packages/@overeng/megarepo/bin/**/*.spec.jsx, packages/@overeng/megarepo/bin/**/*.spec.mjs, packages/@overeng/megarepo/bin/**/*.test.cjs, packages/@overeng/megarepo/bin/**/*.test.jsx, packages/@overeng/megarepo/bin/**/*.test.mjs, packages/@overeng/megarepo/bin/**/*.ts, packages/@overeng/megarepo/bin/**/*.tsx, packages/@overeng/megarepo/bin/**/__snapshots__/*.snap, packages/@overeng/megarepo/package.json.genie.ts, packages/@overeng/megarepo/src/**/*.cts, packages/@overeng/megarepo/src/**/*.js, packages/@overeng/megarepo/src/**/*.mts, packages/@overeng/megarepo/src/**/*.spec.cjs, packages/@overeng/megarepo/src/**/*.spec.jsx, packages/@overeng/megarepo/src/**/*.spec.mjs, packages/@overeng/megarepo/src/**/*.test.cjs, packages/@overeng/megarepo/src/**/*.test.jsx, packages/@overeng/megarepo/src/**/*.test.mjs, packages/@overeng/megarepo/src/**/*.ts, packages/@overeng/megarepo/src/**/*.tsx, packages/@overeng/megarepo/src/**/__snapshots__/*.snap, packages/@overeng/megarepo/tsconfig.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/tui-core/BUCK.genie.ts, packages/@overeng/tui-core/package.json.genie.ts, packages/@overeng/tui-react/BUCK.genie.ts, packages/@overeng/tui-react/package.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -195,6 +196,7 @@ export_materialization_inputs([ "src/composition/apply/workspace-update-lock-schema.unit.test.ts", "src/composition/apply/workspace-update-lock.integration.test.ts", "src/composition/apply/workspace-update-lock.ts", + "src/composition/capabilities/capability-projection.ts", "src/composition/capabilities/composition-capability-resolver-schema.ts", "src/composition/capabilities/composition-capability-resolver.integration.test.ts", "src/composition/capabilities/composition-capability-resolver.ts", @@ -304,6 +306,14 @@ export_materialization_inputs([ "src/test-utils/temp-root.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/megarepo", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_megarepo_b89b4c18f380", @@ -493,6 +503,7 @@ package_view( "src/composition/apply/workspace-update-lock-schema.unit.test.ts": "src/composition/apply/workspace-update-lock-schema.unit.test.ts", "src/composition/apply/workspace-update-lock.integration.test.ts": "src/composition/apply/workspace-update-lock.integration.test.ts", "src/composition/apply/workspace-update-lock.ts": "src/composition/apply/workspace-update-lock.ts", + "src/composition/capabilities/capability-projection.ts": "src/composition/capabilities/capability-projection.ts", "src/composition/capabilities/composition-capability-resolver-schema.ts": "src/composition/capabilities/composition-capability-resolver-schema.ts", "src/composition/capabilities/composition-capability-resolver.integration.test.ts": "src/composition/capabilities/composition-capability-resolver.integration.test.ts", "src/composition/capabilities/composition-capability-resolver.ts": "src/composition/capabilities/composition-capability-resolver.ts", @@ -602,35 +613,7 @@ package_view( "src/test-utils/temp-root.ts": "src/test-utils/temp-root.ts", "tsconfig.json": "tsconfig.json", }, - workspace_dist = { - "node_modules/@overeng/effect-path/dist": "//packages/@overeng/effect-path:dist", - "node_modules/@overeng/effect-path/package.json": "//packages/@overeng/effect-path:package.json", - "node_modules/@overeng/kdl-effect/dist": "//packages/@overeng/kdl-effect:dist", - "node_modules/@overeng/kdl-effect/package.json": "//packages/@overeng/kdl-effect:package.json", - "node_modules/@overeng/kdl/dist": "//packages/@overeng/kdl:dist", - "node_modules/@overeng/kdl/package.json": "//packages/@overeng/kdl:package.json", - "node_modules/@overeng/otel-contract/dist": "//packages/@overeng/otel-contract:dist", - "node_modules/@overeng/otel-contract/package.json": "//packages/@overeng/otel-contract:package.json", - "node_modules/@overeng/tui-core/dist": "//packages/@overeng/tui-core:dist", - "node_modules/@overeng/tui-core/package.json": "//packages/@overeng/tui-core:package.json", - "node_modules/@overeng/tui-react/dist": "//packages/@overeng/tui-react:dist", - "node_modules/@overeng/tui-react/package.json": "//packages/@overeng/tui-react:package.json", - "node_modules/@overeng/utils-dev/dist": "//packages/@overeng/utils-dev:dist", - "node_modules/@overeng/utils-dev/package.json": "//packages/@overeng/utils-dev:package.json", - "node_modules/@overeng/utils/dist": "//packages/@overeng/utils:dist", - "node_modules/@overeng/utils/package.json": "//packages/@overeng/utils:package.json", - }, - workspace_dependency_views = { - "node_modules/@overeng/effect-path/node_modules": "//packages/@overeng/effect-path:package_tree", - "node_modules/@overeng/kdl-effect/node_modules": "//packages/@overeng/kdl-effect:package_tree", - "node_modules/@overeng/kdl/node_modules": "//packages/@overeng/kdl:package_tree", - "node_modules/@overeng/otel-contract/node_modules": "//packages/@overeng/otel-contract:package_tree", - "node_modules/@overeng/tui-core/node_modules": "//packages/@overeng/tui-core:package_tree", - "node_modules/@overeng/tui-react/node_modules": "//packages/@overeng/tui-react:package_tree", - "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", - "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", - }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -815,6 +798,7 @@ package_view( "src/composition/apply/workspace-update-lock-schema.unit.test.ts": "src/composition/apply/workspace-update-lock-schema.unit.test.ts", "src/composition/apply/workspace-update-lock.integration.test.ts": "src/composition/apply/workspace-update-lock.integration.test.ts", "src/composition/apply/workspace-update-lock.ts": "src/composition/apply/workspace-update-lock.ts", + "src/composition/capabilities/capability-projection.ts": "src/composition/capabilities/capability-projection.ts", "src/composition/capabilities/composition-capability-resolver-schema.ts": "src/composition/capabilities/composition-capability-resolver-schema.ts", "src/composition/capabilities/composition-capability-resolver.integration.test.ts": "src/composition/capabilities/composition-capability-resolver.integration.test.ts", "src/composition/capabilities/composition-capability-resolver.ts": "src/composition/capabilities/composition-capability-resolver.ts", @@ -925,36 +909,8 @@ package_view( "tsconfig.json": "tsconfig.json", "vitest.config.ts": "vitest.config.ts", }, - workspace_dist = { - "node_modules/@overeng/effect-path/dist": "//packages/@overeng/effect-path:dist", - "node_modules/@overeng/effect-path/package.json": "//packages/@overeng/effect-path:package.json", - "node_modules/@overeng/kdl-effect/dist": "//packages/@overeng/kdl-effect:dist", - "node_modules/@overeng/kdl-effect/package.json": "//packages/@overeng/kdl-effect:package.json", - "node_modules/@overeng/kdl/dist": "//packages/@overeng/kdl:dist", - "node_modules/@overeng/kdl/package.json": "//packages/@overeng/kdl:package.json", - "node_modules/@overeng/otel-contract/dist": "//packages/@overeng/otel-contract:dist", - "node_modules/@overeng/otel-contract/package.json": "//packages/@overeng/otel-contract:package.json", - "node_modules/@overeng/tui-core/dist": "//packages/@overeng/tui-core:dist", - "node_modules/@overeng/tui-core/package.json": "//packages/@overeng/tui-core:package.json", - "node_modules/@overeng/tui-react/dist": "//packages/@overeng/tui-react:dist", - "node_modules/@overeng/tui-react/package.json": "//packages/@overeng/tui-react:package.json", - "node_modules/@overeng/utils-dev/dist": "//packages/@overeng/utils-dev:dist", - "node_modules/@overeng/utils-dev/package.json": "//packages/@overeng/utils-dev:package.json", - "node_modules/@overeng/utils/dist": "//packages/@overeng/utils:dist", - "node_modules/@overeng/utils/package.json": "//packages/@overeng/utils:package.json", - }, - workspace_dependency_views = { - "node_modules/@overeng/effect-path/node_modules": "//packages/@overeng/effect-path:package_tree", - "node_modules/@overeng/kdl-effect/node_modules": "//packages/@overeng/kdl-effect:package_tree", - "node_modules/@overeng/kdl/node_modules": "//packages/@overeng/kdl:package_tree", - "node_modules/@overeng/otel-contract/node_modules": "//packages/@overeng/otel-contract:package_tree", - "node_modules/@overeng/tui-core/node_modules": "//packages/@overeng/tui-core:package_tree", - "node_modules/@overeng/tui-react/node_modules": "//packages/@overeng/tui-react:package_tree", - "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", - "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", - }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -977,6 +933,7 @@ tsgo_emit( package_tree = ":package_tree", declaration_sources = { }, + declaration_entrypoint = "src/mod.d.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/megarepo/BUCK.genie.ts b/packages/@overeng/megarepo/BUCK.genie.ts index 96ab654562..0c7b9fde22 100644 --- a/packages/@overeng/megarepo/BUCK.genie.ts +++ b/packages/@overeng/megarepo/BUCK.genie.ts @@ -51,7 +51,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils-dev:dist', }, ], - editorViewConsumer: false, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/megarepo/package.json b/packages/@overeng/megarepo/package.json index 543bea6604..6b1424789d 100644 --- a/packages/@overeng/megarepo/package.json +++ b/packages/@overeng/megarepo/package.json @@ -21,9 +21,18 @@ "type": "module", "private": true, "exports": { - ".": "./src/mod.ts", - "./buck2-manifest": "./src/buck2-manifest.ts", - "./cli": "./src/cli/mod.ts" + ".": { + "types": "./dist/src/mod.d.ts", + "default": "./src/mod.ts" + }, + "./buck2-manifest": { + "types": "./dist/src/buck2-manifest.d.ts", + "default": "./src/buck2-manifest.ts" + }, + "./cli": { + "types": "./dist/src/cli/mod.d.ts", + "default": "./src/cli/mod.ts" + } }, "scripts": { "storybook": "storybook dev -p 6007", diff --git a/packages/@overeng/megarepo/package.json.genie.ts b/packages/@overeng/megarepo/package.json.genie.ts index e7c748e961..3e102a929e 100644 --- a/packages/@overeng/megarepo/package.json.genie.ts +++ b/packages/@overeng/megarepo/package.json.genie.ts @@ -63,9 +63,18 @@ export default packageJson( 'storybook:build': 'storybook build', }, exports: { - '.': exportEntry('./src/mod.ts', { environment: 'node' }), - './buck2-manifest': exportEntry('./src/buck2-manifest.ts', { environment: 'node' }), - './cli': exportEntry('./src/cli/mod.ts', { environment: 'node' }), + '.': exportEntry( + { types: './dist/src/mod.d.ts', default: './src/mod.ts' }, + { environment: 'node' }, + ), + './buck2-manifest': exportEntry( + { types: './dist/src/buck2-manifest.d.ts', default: './src/buck2-manifest.ts' }, + { environment: 'node' }, + ), + './cli': exportEntry( + { types: './dist/src/cli/mod.d.ts', default: './src/cli/mod.ts' }, + { environment: 'node' }, + ), }, publishConfig: { access: 'public', diff --git a/packages/@overeng/megarepo/src/cli/commands/composition.integration.test.ts b/packages/@overeng/megarepo/src/cli/commands/composition.integration.test.ts index e2f4454a0f..20a899a856 100644 --- a/packages/@overeng/megarepo/src/cli/commands/composition.integration.test.ts +++ b/packages/@overeng/megarepo/src/cli/commands/composition.integration.test.ts @@ -1,3 +1,4 @@ +import { lstat } from 'node:fs/promises' import * as NodePath from 'node:path' import { NodeServices } from '@effect/platform-node' @@ -10,12 +11,14 @@ import { EffectPath } from '@overeng/effect-path' import { COMPOSITION_ROOT_SCHEMA_VERSION } from '../../composition/root/composition-root.ts' import * as Git from '../../core/git.ts' +import { LockFile, LockedMember } from '../../core/lock.ts' import type { MegarepoStore } from '../../store/store.ts' import { Store } from '../../store/store.ts' import { makeCanonicalTempDirectoryScoped } from '../../test-utils/temp-root.ts' import { compositionCacheSections, preflightCompositionCommand, + resolveLockedCompositionMembers, runCompositionApply, } from './composition.ts' @@ -106,6 +109,48 @@ describe('compositionCacheSections', () => { }) }) +describe('locked composition sources', () => { + it.effect('protects an exact detached source before composition reads it', () => + Effect.gen(function* () { + const fs = yield* FileSystem.FileSystem + const fixture = yield* makeLegacyWorkspace + const commit = yield* Git.getCurrentCommit(fixture.workspaceRoot) + const commitRoot = NodePath.join(fixture.tmp, 'refs', 'commits', commit) + yield* fs.makeDirectory(EffectPath.unsafe.absoluteDir(`${NodePath.dirname(commitRoot)}/`), { + recursive: true, + }) + yield* fixture.git(fixture.bareRepo, 'worktree', 'add', '--detach', commitRoot, commit) + const store: MegarepoStore = { + ...fixture.store, + getWorktreePath: () => EffectPath.unsafe.absoluteDir(`${commitRoot}/`), + } + const lockFile = new LockFile({ + version: 1, + members: { + hub: new LockedMember({ + url: 'https://github.com/test-owner/hub', + ref: 'main', + commit, + pinned: true, + lockedAt: '2026-09-11T00:00:00.000Z', + }), + }, + }) + + yield* resolveLockedCompositionMembers({ + configMembers: { hub: 'test-owner/hub#main' }, + lockFile, + store, + }) + const rootInfo = yield* Effect.promise(() => lstat(commitRoot)) + const gitInfo = yield* Effect.promise(() => lstat(NodePath.join(commitRoot, '.git'))) + expect(rootInfo.mode & 0o777).toBe(0o755) + expect(gitInfo.mode & 0o777).toBe(0o444) + yield* fs.chmod(EffectPath.unsafe.absoluteDir(`${commitRoot}/`), 0o755) + }).pipe(Effect.provide(NodeServices.layer), Effect.scoped), + ) +}) + describe('routine composition apply is shape-preserving', () => { it.effect('returns a typed recreate instruction for a legacy flat root without mutation', () => Effect.gen(function* () { diff --git a/packages/@overeng/megarepo/src/cli/commands/composition.ts b/packages/@overeng/megarepo/src/cli/commands/composition.ts index e04daf132f..9b95753dcf 100644 --- a/packages/@overeng/megarepo/src/cli/commands/composition.ts +++ b/packages/@overeng/megarepo/src/cli/commands/composition.ts @@ -1,5 +1,5 @@ import { execFile as execFileCallback } from 'node:child_process' -import { lstat } from 'node:fs/promises' +import { chmod, lstat, readdir } from 'node:fs/promises' import * as NodePath from 'node:path' import { promisify } from 'node:util' @@ -299,6 +299,23 @@ export const preflightCompositionCommand = ({ return identity }).pipe(Effect.mapError(preserveCompositionError)) +const protectImmutableSource = async (path: string): Promise => { + const info = await lstat(path) + if (info.isSymbolicLink() === true) return + if (info.isDirectory() === true) { + await Promise.all( + (await readdir(path)).map((child) => protectImmutableSource(NodePath.join(path, child))), + ) + await chmod(path, 0o755) + return + } + if (info.isFile() === true) { + await chmod(path, (info.mode & 0o111) === 0 ? 0o444 : 0o555) + return + } + throw new TypeError(`Immutable source contains unsupported entry '${path}'`) +} + /** Admit exact clean detached commit worktrees before any composition side effect. */ export const resolveLockedCompositionMembers = ({ configMembers, @@ -404,6 +421,16 @@ export const resolveLockedCompositionMembers = ({ message: `Immutable source '${sourcePath}' contains ignored files; ignored bytes cannot enter R6`, }) } + yield* Effect.tryPromise({ + try: () => protectImmutableSource(sourcePath), + catch: (cause) => + compositionFailure({ + reason: 'LockedSourceRefused', + path: sourcePath, + message: `Immutable source '${sourcePath}' could not be protected`, + cause, + }), + }) values.push({ key, sourcePath, lockedCommit: locked.commit }) } return values diff --git a/packages/@overeng/megarepo/src/composition/apply/composition-apply-schema.ts b/packages/@overeng/megarepo/src/composition/apply/composition-apply-schema.ts index d0308a0819..1022a9f019 100644 --- a/packages/@overeng/megarepo/src/composition/apply/composition-apply-schema.ts +++ b/packages/@overeng/megarepo/src/composition/apply/composition-apply-schema.ts @@ -120,7 +120,12 @@ export const CompositionOwnedCapabilityProjectionPlanSchema = Schema.Struct({ projectionPath: AbsolutePath, operation: Schema.Literal('InstallOwnedCapabilityProjection'), steps: Schema.Array( - Schema.Literals(['ValidateOwnedMember', 'InstallProjectionAtomically', 'CheckProjection']), + Schema.Literals([ + 'ValidateOwnedMember', + 'InstallProjectionAtomically', + 'CheckProjection', + 'RetainProjectionRoots', + ]), ), }).annotate({ identifier: 'Megarepo.CompositionOwnedCapabilityProjectionPlan' }) export type CompositionOwnedCapabilityProjectionPlan = diff --git a/packages/@overeng/megarepo/src/composition/apply/composition-apply.integration.test.ts b/packages/@overeng/megarepo/src/composition/apply/composition-apply.integration.test.ts index f09a6215b7..c870b40ad1 100644 --- a/packages/@overeng/megarepo/src/composition/apply/composition-apply.integration.test.ts +++ b/packages/@overeng/megarepo/src/composition/apply/composition-apply.integration.test.ts @@ -78,7 +78,10 @@ interface FixtureOptions { readonly allowDarwin?: boolean readonly recovery?: boolean readonly cacheSections?: CompositionApplyRequest['cacheSections'] + readonly alreadyCurrent?: boolean + readonly currentOverlayCount?: number readonly releaseFailures?: ReadonlyArray + readonly retainFailure?: string } const fixture = async (options: FixtureOptions = {}) => { @@ -117,11 +120,25 @@ const fixture = async (options: FixtureOptions = {}) => { const inspections = new Map( locked.map(({ key }) => { const manifest = manifests.get(NodePath.join(root, 'store', key))! + const baseMetadata = mountMetadata({ workspaceRoot, key, manifest }) + const currentOverlayCount = + options.alreadyCurrent === true ? manifest.distOverlays.length : options.currentOverlayCount return [ key, { identity: { dev: 1, ino: key.length + 10 }, - metadata: mountMetadata({ workspaceRoot, key, manifest }), + metadata: + currentOverlayCount !== undefined + ? { + ...baseMetadata, + overlays: manifest.distOverlays.slice(0, currentOverlayCount).map((overlay) => ({ + target: overlay.target, + destination: overlay.destination, + digest, + count: 1, + })), + } + : baseMetadata, }, ] as const }), @@ -220,16 +237,29 @@ const fixture = async (options: FixtureOptions = {}) => { 'MaterializeCpAMemberMount', ], }), - materializeMount: async ({ request: mount }) => { + materializeMount: async ({ request: mount, runtime }) => { calls.push(`mount:${mount.member}:${mount.allowVerifiedDarwinAdvance}`) if (options.mountFailure === mount.member) throw new Error('mount failed') const manifest = manifests.get(mount.sourcePath)! - return { - _tag: 'Published', - operation: 'FirstPublish', + const current = inspections.get(mount.member)! + if (options.alreadyCurrent === true || options.currentOverlayCount !== undefined) { + return { + _tag: 'AlreadyCurrent', + destinationPath: NodePath.join(workspaceRoot, 'repos', mount.member), + metadata: current.metadata, + } + } + const published = { + _tag: 'Published' as const, + operation: 'FirstPublish' as const, destinationPath: NodePath.join(workspaceRoot, 'repos', mount.member), metadata: mountMetadata({ workspaceRoot, key: mount.member, manifest }), } + await runtime.retainPublishedCapabilities?.({ + destinationPath: published.destinationPath, + }) + calls.push(`mount-committed:${mount.member}`) + return published }, listPublishedMemberKeys: async () => [], teardownMount: async () => { @@ -323,10 +353,16 @@ const fixture = async (options: FixtureOptions = {}) => { plan: async (input) => ({ ...input, operation: 'InstallOwnedCapabilityProjection', - steps: ['ValidateOwnedMember', 'InstallProjectionAtomically', 'CheckProjection'], + steps: [ + 'ValidateOwnedMember', + 'InstallProjectionAtomically', + 'CheckProjection', + 'RetainProjectionRoots', + ], }), install: async (input) => { calls.push(`owned:${input.memberKey}:install`) + await input.retainPublishedCapabilities() return { memberKey: input.memberKey, projectionPath: input.projectionPath, @@ -335,6 +371,13 @@ const fixture = async (options: FixtureOptions = {}) => { } }, }, + retainCapabilityRoots: async ({ memberKey }) => { + calls.push(`retain:${memberKey}`) + if (options.retainFailure === memberKey) throw new Error('capability retention failed') + }, + pruneCapabilityRoots: async ({ memberKey }) => { + calls.push(`prune:${memberKey}`) + }, system: options.allowDarwin === true ? 'aarch64-darwin' : 'x86_64-linux', platform: options.allowDarwin === true ? 'darwin' : 'linux', buck2Path: '/nix/store/buck/bin/buck2', @@ -452,6 +495,22 @@ describe('composition apply integration', () => { expect(rootIndex).toBeGreaterThan(overlayIndex) } expect(value.calls.indexOf('cap:owned:release')).toBeGreaterThan(overlayIndex) + expect(value.calls.indexOf('retain:owned')).toBeGreaterThan( + value.calls.indexOf('owned:owned:install'), + ) + expect(value.calls.indexOf('retain:owned')).toBeLessThan( + value.calls.indexOf('mount:dep:false'), + ) + expect(value.calls.indexOf('retain:dep')).toBeGreaterThan( + value.calls.indexOf('mount:dep:false'), + ) + expect(value.calls.indexOf('prune:dep')).toBeGreaterThan( + value.calls.indexOf('mount-committed:dep'), + ) + expect(value.calls.indexOf('prune:dep')).toBeGreaterThan(value.calls.indexOf('retain:dep')) + expect(value.calls.indexOf('cap:owned:release')).toBeGreaterThan( + value.calls.indexOf('prune:dep'), + ) if (rootMode !== 'first') { expect(rootIndex).toBeGreaterThan(value.calls.indexOf('cap:owned:release')) } @@ -507,6 +566,64 @@ describe('composition apply integration', () => { expect(command).toContain('|--out|') } expect(value.calls.at(-1)).toBe('lock:release') + expect(value.calls.filter((call) => call.startsWith('retain:'))).toEqual([ + 'retain:owned', + 'retain:beta', + 'retain:alpha', + ]) + expect(value.calls.filter((call) => call.startsWith('prune:'))).toEqual([ + 'prune:owned', + 'prune:beta', + 'prune:alpha', + ]) + } finally { + await value.cleanup() + } + }) + + it('skips Buck and overlay publication for validated already-current overlays', async () => { + const value = await fixture({ alreadyCurrent: true }) + try { + const result = await Effect.runPromise( + compositionApply({ request: value.request, runtime: value.runtime }), + ) + expect(result._tag).toBe('Applied') + if (result._tag !== 'Applied') return + expect(result.members.every((member) => member.overlays.length === 0)).toBe(true) + const mountedMembers = result.members.filter((member) => member.owned === false) + expect(mountedMembers).toHaveLength(1) + for (const member of mountedMembers) { + expect(member.mount?._tag).toBe('AlreadyCurrent') + } + expect(value.calls.some((call) => call.startsWith('scratch:'))).toBe(false) + expect(value.calls.some((call) => call.startsWith('buck:'))).toBe(false) + expect(value.calls.some((call) => call.startsWith('overlay:'))).toBe(false) + } finally { + await value.cleanup() + } + }) + + it('builds only missing overlays for an otherwise current mount', async () => { + const value = await fixture({ + members: [{ key: 'dep', overlays: 2 }], + currentOverlayCount: 1, + }) + try { + const result = await Effect.runPromise( + compositionApply({ request: value.request, runtime: value.runtime }), + ) + expect(result._tag).toBe('Applied') + if (result._tag !== 'Applied') return + const mountedMember = result.members.find((member) => member.owned === false) + expect(mountedMember?.mount?._tag).toBe('AlreadyCurrent') + expect(mountedMember?.overlays.map((overlay) => overlay.destinationPath)).toEqual([ + NodePath.join(value.root, 'workspace', 'repos', 'dep', 'pkg/dist1'), + ]) + expect(value.calls.filter((call) => call.startsWith('scratch:dep:create'))).toHaveLength(1) + expect(value.calls.filter((call) => call.startsWith('buck:'))).toHaveLength(1) + expect(value.calls.filter((call) => call.startsWith('overlay:dep://pkg:'))).toEqual([ + 'overlay:dep://pkg:dist1', + ]) } finally { await value.cleanup() } @@ -534,6 +651,54 @@ describe('composition apply integration', () => { } }) + it('propagates owned root retention failure before mounts and releases resolver scratch', async () => { + const value = await fixture({ retainFailure: 'owned' }) + try { + const result = await Effect.runPromise( + compositionApply({ request: value.request, runtime: value.runtime }).pipe(Effect.result), + ) + expect(result._tag).toBe('Failure') + if (result._tag !== 'Failure') return + expect(result.failure).toMatchObject({ + reason: 'CapabilityFailure', + phase: 'Capability', + memberKey: 'owned', + }) + expect(value.calls).toContain('owned:owned:install') + expect(value.calls).toContain('retain:owned') + expect(value.calls.some((call) => call.startsWith('mount:'))).toBe(false) + expect(value.calls).toContain('cap:owned:release') + expect(value.calls.at(-1)).toBe('lock:release') + } finally { + await value.cleanup() + } + }) + + it('propagates mounted root retention failure after mount publication', async () => { + const value = await fixture({ retainFailure: 'dep' }) + try { + const result = await Effect.runPromise( + compositionApply({ request: value.request, runtime: value.runtime }).pipe(Effect.result), + ) + expect(result._tag).toBe('Failure') + if (result._tag !== 'Failure') return + expect(result.failure).toMatchObject({ + reason: 'CapabilityFailure', + phase: 'Capability', + memberKey: 'dep', + }) + expect(value.calls.indexOf('retain:dep')).toBeGreaterThan( + value.calls.indexOf('mount:dep:false'), + ) + expect(value.calls.some((call) => call.startsWith('root:'))).toBe(false) + expect(value.calls).toContain('cap:dep:release') + expect(value.calls).toContain('cap:owned:release') + expect(value.calls.at(-1)).toBe('lock:release') + } finally { + await value.cleanup() + } + }) + it('keeps already-published mounts and old root authority on a later mount failure', async () => { const value = await fixture({ members: [ diff --git a/packages/@overeng/megarepo/src/composition/apply/composition-apply.ts b/packages/@overeng/megarepo/src/composition/apply/composition-apply.ts index 4b4411cc9c..57a59fd5f7 100644 --- a/packages/@overeng/megarepo/src/composition/apply/composition-apply.ts +++ b/packages/@overeng/megarepo/src/composition/apply/composition-apply.ts @@ -26,6 +26,7 @@ import { type ResolveCompositionCapabilitiesResult, } from '../capabilities/composition-capability-resolver.ts' import { + CpAMemberMountError, cpAMemberMountTransactionPath, type CpAMemberMountRecoveryRequest, type CpAMemberMountRequest, @@ -205,8 +206,21 @@ export interface CompositionApplyRuntime { readonly ownedMemberPath: string readonly projectionPath: string readonly projectionDigest: string + readonly retainPublishedCapabilities: () => Promise }) => Promise } + /** Retain one published projection's Nix outputs before its resolver scratch is released. */ + readonly retainCapabilityRoots: (input: { + readonly memberKey: string + readonly memberRoot: string + readonly resolution: CompositionCapabilityResolutionHandle + }) => Promise + /** Verify the retained generation and prune stale roots only after publication commits. */ + readonly pruneCapabilityRoots: (input: { + readonly memberKey: string + readonly memberRoot: string + readonly resolution: CompositionCapabilityResolutionHandle + }) => Promise readonly system: CompositionCapabilitySystem readonly platform: RuntimePlatform readonly buck2Path: string @@ -1146,6 +1160,25 @@ const applyComposition = async ({ recoveryPaths: [], }) } + const retainOwnedCapabilityRoots = async (): Promise => { + try { + await runtime.retainCapabilityRoots({ + memberKey: request.ownedMemberKey, + memberRoot: request.ownedMemberPath, + resolution: ownedHandle, + }) + } catch (cause) { + throw normalizeFailure({ + cause, + reason: 'CapabilityFailure', + phase: 'Capability', + memberKey: request.ownedMemberKey, + path: request.ownedMemberPath, + message: `Could not retain owned capability roots for '${request.ownedMemberKey}'`, + recoveryPaths: [], + }) + } + } let ownedProjection: CompositionOwnedCapabilityProjectionResult try { ownedProjection = await runtime.ownedCapabilityProjection.install({ @@ -1153,6 +1186,24 @@ const applyComposition = async ({ ownedMemberPath: request.ownedMemberPath, projectionPath: ownedHandle.projectionPath, projectionDigest: ownedHandle.projectionDigest, + retainPublishedCapabilities: retainOwnedCapabilityRoots, + }) + } catch (cause) { + throw normalizeFailure({ + cause, + reason: 'CapabilityFailure', + phase: 'Capability', + memberKey: request.ownedMemberKey, + path: request.ownedMemberPath, + message: `Could not install and retain owned capability projection for '${request.ownedMemberKey}'`, + recoveryPaths: [], + }) + } + try { + await runtime.pruneCapabilityRoots({ + memberKey: request.ownedMemberKey, + memberRoot: request.ownedMemberPath, + resolution: ownedHandle, }) } catch (cause) { throw normalizeFailure({ @@ -1161,7 +1212,7 @@ const applyComposition = async ({ phase: 'Capability', memberKey: request.ownedMemberKey, path: request.ownedMemberPath, - message: `Could not install owned capability projection for '${request.ownedMemberKey}'`, + message: `Could not prune stale owned capability roots for '${request.ownedMemberKey}'`, recoveryPaths: [], }) } @@ -1180,6 +1231,46 @@ const applyComposition = async ({ }) } let mount: CpAMemberMountResult + let retainedDuringPublish = false + const mountedRoot = NodePath.join(request.workspaceRoot, 'repos', member.key) + const retainMountedCapabilityRoots = async (): Promise => { + try { + await runtime.retainCapabilityRoots({ + memberKey: member.key, + memberRoot: mountedRoot, + resolution: capability, + }) + } catch (cause) { + throw normalizeFailure({ + cause, + reason: 'CapabilityFailure', + phase: 'Capability', + memberKey: member.key, + path: mountedRoot, + message: `Could not retain capability roots for '${member.key}'`, + recoveryPaths: [], + }) + } + } + const pruneMountedCapabilityRoots = async (): Promise => { + try { + await runtime.pruneCapabilityRoots({ + memberKey: member.key, + memberRoot: mountedRoot, + resolution: capability, + }) + } catch (cause) { + throw normalizeFailure({ + cause, + reason: 'CapabilityFailure', + phase: 'Capability', + memberKey: member.key, + path: mountedRoot, + message: `Could not prune stale capability roots for '${member.key}'`, + recoveryPaths: [], + }) + } + } try { await primitives.assertLockedSourceClean({ sourcePath: member.root, @@ -1196,11 +1287,22 @@ const applyComposition = async ({ dryRun: false, allowVerifiedDarwinAdvance: request.allowVerifiedDarwinAdvance, }, - runtime: runtime.mountRuntime, + runtime: { + ...runtime.mountRuntime, + retainPublishedCapabilities: async ({ destinationPath }) => { + if (destinationPath !== mountedRoot) { + throw new TypeError('Mount retention path is outside the published member root') + } + await retainMountedCapabilityRoots() + retainedDuringPublish = true + }, + }, }) if (mount._tag !== 'Published' && mount._tag !== 'AlreadyCurrent') { throw new TypeError(`Unexpected mount result '${mount._tag}'`) } + if (retainedDuringPublish === false) await retainMountedCapabilityRoots() + await pruneMountedCapabilityRoots() mountResults.set(member.key, mount) mountInspections.set( member.key, @@ -1210,19 +1312,27 @@ const applyComposition = async ({ }), ) } catch (cause) { + const retentionFailure = + cause instanceof CpAMemberMountError && cause.reason === 'CapabilityRetentionFailed' throw normalizeFailure({ cause, - reason: 'MountFailure', - phase: 'Mount', + reason: retentionFailure === true ? 'CapabilityFailure' : 'MountFailure', + phase: retentionFailure === true ? 'Capability' : 'Mount', memberKey: member.key, - path: member.root, - message: `Could not materialize member mount '${member.key}'`, - recoveryPaths: [ - cpAMemberMountTransactionPath({ - workspaceRoot: request.workspaceRoot, - member: member.key, - }), - ], + path: retentionFailure === true ? mountedRoot : member.root, + message: + retentionFailure === true + ? `Could not retain capability roots for '${member.key}'` + : `Could not materialize member mount '${member.key}'`, + recoveryPaths: + retentionFailure === true + ? [] + : [ + cpAMemberMountTransactionPath({ + workspaceRoot: request.workspaceRoot, + member: member.key, + }), + ], }) } } @@ -1238,7 +1348,18 @@ const applyComposition = async ({ for (const member of lockedMembers) { let inspection = mountInspections.get(member.key)! const results: Array = [] - for (const declaration of member.manifest.distOverlays) { + const declarations = + mountResults.get(member.key)?._tag === 'AlreadyCurrent' + ? member.manifest.distOverlays.filter( + (declaration) => + inspection.metadata.overlays.some( + (overlay) => + overlay.target === declaration.target && + overlay.destination === declaration.destination, + ) === false, + ) + : member.manifest.distOverlays + for (const declaration of declarations) { const scratch = await runtime.overlayScratch.create({ workspaceRoot: request.workspaceRoot, memberKey: member.key, diff --git a/packages/@overeng/megarepo/src/composition/apply/composition-apply.unit.test.ts b/packages/@overeng/megarepo/src/composition/apply/composition-apply.unit.test.ts index f274ee33e2..8d65fffd1f 100644 --- a/packages/@overeng/megarepo/src/composition/apply/composition-apply.unit.test.ts +++ b/packages/@overeng/megarepo/src/composition/apply/composition-apply.unit.test.ts @@ -189,13 +189,24 @@ const fake = ({ return { ...input, operation: 'InstallOwnedCapabilityProjection', - steps: ['ValidateOwnedMember', 'InstallProjectionAtomically', 'CheckProjection'], + steps: [ + 'ValidateOwnedMember', + 'InstallProjectionAtomically', + 'CheckProjection', + 'RetainProjectionRoots', + ], } }, install: async () => { throw new Error('dry-run installed owned projection') }, }, + retainCapabilityRoots: async () => { + throw new Error('dry-run retained capability roots') + }, + pruneCapabilityRoots: async () => { + throw new Error('dry-run pruned capability roots') + }, system: 'x86_64-linux', platform: 'linux', buck2Path: '/nix/store/buck/bin/buck2', diff --git a/packages/@overeng/megarepo/src/composition/apply/composition-runtime.ts b/packages/@overeng/megarepo/src/composition/apply/composition-runtime.ts index de3d640e99..97baef8f4f 100644 --- a/packages/@overeng/megarepo/src/composition/apply/composition-runtime.ts +++ b/packages/@overeng/megarepo/src/composition/apply/composition-runtime.ts @@ -6,6 +6,8 @@ import * as NodePath from 'node:path' import { checkCompositionCapabilityProjection, compositionCapabilityRuntimeFromEnv, + retainCompositionCapabilityProjection, + pruneCompositionCapabilityProjectionRoots, } from '../capabilities/composition-capability-resolver.ts' import { installOwnedCapabilityProjection, @@ -148,7 +150,7 @@ export const compositionApplyRuntimeFromEnv = ({ readonly env?: Readonly> }): CompositionApplyRuntime => { const workspaceRoot = normalizedAbsolute({ value: rawWorkspaceRoot, name: 'workspaceRoot' }) - const capabilityRuntime = { ...compositionCapabilityRuntimeFromEnv(env), env } + const capabilityRuntime = { ...compositionCapabilityRuntimeFromEnv(env), env, nonce } const cpPath = normalizedAbsolute({ value: required({ env, name: compositionRuntimeEnvironmentNames.cpPath }), name: compositionRuntimeEnvironmentNames.cpPath, @@ -181,17 +183,34 @@ export const compositionApplyRuntimeFromEnv = ({ return { ownedCapabilityProjection: { plan: planOwnedCapabilityProjection, - install: (input) => + install: ({ retainPublishedCapabilities, ...input }) => installOwnedCapabilityProjection({ ...input, - runtime: { cpPath, mvPath, nonce }, + runtime: { + cpPath, + mvPath, + nonce, + retainPublishedCapabilities: () => retainPublishedCapabilities(), + }, }), }, + retainCapabilityRoots: ({ memberRoot, resolution }) => + retainCompositionCapabilityProjection({ + memberRoot, + resolution, + runtime: capabilityRuntime, + }), + pruneCapabilityRoots: ({ memberRoot, resolution }) => + pruneCompositionCapabilityProjectionRoots({ + memberRoot, + resolution, + runtime: capabilityRuntime, + }), system, platform, buck2Path, buck2Protocol, - capabilityRuntime: { ...capabilityRuntime, nonce }, + capabilityRuntime, mountRuntime: { cpPath, mvPath, diff --git a/packages/@overeng/megarepo/src/composition/capabilities/capability-projection.ts b/packages/@overeng/megarepo/src/composition/capabilities/capability-projection.ts new file mode 100644 index 0000000000..8983302a50 --- /dev/null +++ b/packages/@overeng/megarepo/src/composition/capabilities/capability-projection.ts @@ -0,0 +1,229 @@ +import { createHash } from 'node:crypto' +import { access, mkdir, readFile, realpath, stat, symlink, writeFile } from 'node:fs/promises' +import * as NodePath from 'node:path' +import process from 'node:process' + +import type { BuckMemberCapability } from '../../buck2-manifest.ts' +import type { ResolvedCompositionCapability } from './composition-capability-resolver-schema.ts' + +export type CapabilityProjectionPlatform = 'aarch64-linux' | 'aarch64-macos' | 'x86_64-linux' + +export type CapabilityProjectionManifest = { + readonly closureIdentity: string + readonly closureStorePaths: readonly string[] + readonly contentDigest: string + readonly executableStorePath: string + readonly executionPlatform: CapabilityProjectionPlatform + readonly protocol: string + readonly runtimeContract: 'native-executable/v1' + readonly schema: 'effect-utils/buck2-support-tools/v1' + readonly toolId: string +} + +export const makeCapabilityProjectionManifest = ({ + platform, + resolved, +}: { + readonly platform: CapabilityProjectionPlatform + readonly resolved: ResolvedCompositionCapability +}): CapabilityProjectionManifest => ({ + closureIdentity: resolved.nixOutputPath, + closureStorePaths: resolved.closureStorePaths, + contentDigest: resolved.executableDigest.slice('sha256:'.length), + executableStorePath: resolved.executablePath, + executionPlatform: platform, + protocol: resolved.capability.protocol, + runtimeContract: 'native-executable/v1', + schema: 'effect-utils/buck2-support-tools/v1', + toolId: resolved.capability.toolId, +}) + +export const capabilityToolBuckBytes = + 'export_file(name = "executable", src = "executable", visibility = ["PUBLIC"])\n' + + 'export_file(name = "manifest", src = "manifest.json", visibility = ["PUBLIC"])\n' +export const capabilityRootBuckBytes = '# Generated from exact Nix realizations.\n' + +const manifestBytes = (manifest: CapabilityProjectionManifest): string => + `${JSON.stringify(manifest)}\n` + +export const computeCapabilityProjectionGeneration = ( + files: ReadonlyArray<{ readonly path: string; readonly bytes: string }>, +): string => { + const framed = files + .toSorted((left, right) => (left.path < right.path ? -1 : left.path > right.path ? 1 : 0)) + .map(({ path, bytes }) => `${createHash('sha256').update(bytes).digest('hex')} ./${path}\n`) + .join('') + const payloadDigest = createHash('sha256').update(framed).digest('hex') + return createHash('sha256').update(`${payloadDigest} -\n`).digest('hex') +} + +export const renderCapabilityProjectionDefs = ({ + generation, + platform, + manifests, +}: { + readonly generation: string + readonly platform: CapabilityProjectionPlatform + readonly manifests: ReadonlyArray +}): string => + [ + `GENERATION = "${generation}"`, + 'CAPABILITIES = {', + ` "${platform}": {`, + ...manifests.map( + (manifest) => + ` "${manifest.toolId}": {"generation": "${generation}", "contentDigest": "${manifest.contentDigest}", "closureIdentity": "${manifest.closureIdentity}", "executableStorePath": "${manifest.executableStorePath}", "closureStorePaths": [${manifest.closureStorePaths.map((path) => `"${path}"`).join(', ')}]},`, + ), + ' },', + '}', + '', + ].join('\n') + +export const projectResolvedCapabilities = async ({ + projectionPath, + platform, + resolved, +}: { + readonly projectionPath: string + readonly platform: CapabilityProjectionPlatform + readonly resolved: ReadonlyArray +}): Promise<{ readonly projectionPath: string; readonly generation: string }> => { + const manifests = resolved.map((resolvedCapability) => + makeCapabilityProjectionManifest({ platform, resolved: resolvedCapability }), + ) + const files = manifests.flatMap((manifest) => [ + { path: `${platform}/${manifest.toolId}/BUCK`, bytes: capabilityToolBuckBytes }, + { path: `${platform}/${manifest.toolId}/manifest.json`, bytes: manifestBytes(manifest) }, + ]) + const generation = computeCapabilityProjectionGeneration(files) + const generationRoot = NodePath.join(projectionPath, 'generations', generation, platform) + await mkdir(generationRoot, { recursive: true }) + await Promise.all( + manifests.map(async (manifest) => { + const directory = NodePath.join(generationRoot, manifest.toolId) + await mkdir(directory) + await symlink(manifest.executableStorePath, NodePath.join(directory, 'executable')) + await writeFile(NodePath.join(directory, 'manifest.json'), manifestBytes(manifest), { + flag: 'wx', + }) + await writeFile(NodePath.join(directory, 'BUCK'), capabilityToolBuckBytes, { flag: 'wx' }) + }), + ) + await writeFile(NodePath.join(projectionPath, 'BUCK'), capabilityRootBuckBytes, { flag: 'wx' }) + await writeFile( + NodePath.join(projectionPath, 'defs.bzl'), + renderCapabilityProjectionDefs({ generation, platform, manifests }), + { flag: 'wx' }, + ) + return { projectionPath, generation } +} + +type NixCapabilityProjectionInput = { + readonly capability: BuckMemberCapability + readonly closurePathsFile: string + readonly nixOutputPath: string +} + +const decodeNixProjectionInput = (value: unknown): readonly NixCapabilityProjectionInput[] => { + if (Array.isArray(value) === false) + throw new TypeError('capability projection input must be an array') + return value.map((entry) => { + if ( + typeof entry !== 'object' || + entry === null || + Array.isArray(entry) === true || + 'capability' in entry === false || + typeof entry.capability !== 'object' || + entry.capability === null || + Array.isArray(entry.capability) === true + ) { + throw new TypeError('capability projection entry must contain a capability') + } + const capability = entry.capability + const toolId = 'toolId' in capability ? capability.toolId : undefined + const protocol = 'protocol' in capability ? capability.protocol : undefined + const flakePackage = 'flakePackage' in capability ? capability.flakePackage : undefined + const executable = 'executable' in capability ? capability.executable : undefined + const closurePathsFile = 'closurePathsFile' in entry ? entry.closurePathsFile : undefined + const nixOutputPath = 'nixOutputPath' in entry ? entry.nixOutputPath : undefined + if ( + typeof toolId !== 'string' || + typeof protocol !== 'string' || + typeof flakePackage !== 'string' || + typeof executable !== 'string' || + typeof closurePathsFile !== 'string' || + typeof nixOutputPath !== 'string' + ) { + throw new TypeError('capability projection entry contains a non-string field') + } + return { + capability: { toolId, protocol, flakePackage, executable }, + closurePathsFile, + nixOutputPath, + } + }) +} + +const executableDigest = async (path: string): Promise<`sha256:${string}`> => + `sha256:${createHash('sha256') + .update(await readFile(path)) + .digest('hex')}` + +const resolveNixProjectionInput = async ( + input: NixCapabilityProjectionInput, +): Promise => { + const outputRoot = await realpath(input.nixOutputPath) + const executablePath = await realpath(NodePath.join(outputRoot, input.capability.executable)) + const outputInfo = await stat(outputRoot) + const executableInfo = await stat(executablePath) + if ( + outputInfo.isDirectory() === false || + executableInfo.isFile() === false || + (executablePath !== outputRoot && + executablePath.startsWith(`${outputRoot}${NodePath.sep}`) === false) + ) { + throw new TypeError(`capability executable escapes its Nix output: ${input.capability.toolId}`) + } + await access(executablePath, 1) + const closureStorePaths = [ + ...new Set( + (await readFile(input.closurePathsFile, 'utf8')) + .split(/\r?\n/u) + .filter((path) => path.length > 0), + ), + ].toSorted() + if (closureStorePaths.includes(outputRoot) === false) { + throw new TypeError(`capability closure omits its Nix output: ${input.capability.toolId}`) + } + return { + capability: input.capability, + nixOutputPath: outputRoot, + executablePath, + executableDigest: await executableDigest(executablePath), + closureStorePaths, + } +} + +const main = async (): Promise => { + const [inputFlag, inputPath, outputFlag, outputPath, platformFlag, platform, ...unexpected] = + process.argv.slice(2) + if ( + inputFlag !== '--input' || + inputPath === undefined || + outputFlag !== '--output' || + outputPath === undefined || + platformFlag !== '--platform' || + (platform !== 'x86_64-linux' && platform !== 'aarch64-linux' && platform !== 'aarch64-macos') || + unexpected.length > 0 + ) { + throw new TypeError( + 'usage: capability-projection.ts --input --output --platform ', + ) + } + const input = decodeNixProjectionInput(JSON.parse(await readFile(inputPath, 'utf8'))) + const resolved: ResolvedCompositionCapability[] = [] + for (const capability of input) resolved.push(await resolveNixProjectionInput(capability)) + await projectResolvedCapabilities({ projectionPath: outputPath, platform, resolved }) +} + +if (import.meta.main === true) await main() diff --git a/packages/@overeng/megarepo/src/composition/capabilities/composition-capability-resolver.integration.test.ts b/packages/@overeng/megarepo/src/composition/capabilities/composition-capability-resolver.integration.test.ts index 021cdf90ab..8a02957dc1 100644 --- a/packages/@overeng/megarepo/src/composition/capabilities/composition-capability-resolver.integration.test.ts +++ b/packages/@overeng/megarepo/src/composition/capabilities/composition-capability-resolver.integration.test.ts @@ -2,11 +2,13 @@ import { execFileSync } from 'node:child_process' import { realpathSync } from 'node:fs' import { chmod, + cp, lstat, mkdtemp, mkdir, readFile, readdir, + readlink, rm, symlink, writeFile, @@ -26,8 +28,10 @@ import { import { checkCompositionCapabilityProjection, makeCapabilityProjectionManifest, + pruneCompositionCapabilityProjectionRoots, resolveCompositionCapabilities, resolvedCompositionCapabilityByToolId, + retainCompositionCapabilityProjection, type CompositionCapabilityRuntime, } from './composition-capability-resolver.ts' @@ -47,6 +51,8 @@ const bashExecutable = realpathSync(commandPath('bash')) const bashOutput = NodePath.dirname(NodePath.dirname(bashExecutable)) const alternateExecutable = realpathSync(commandPath('grep')) const alternateOutput = NodePath.dirname(NodePath.dirname(alternateExecutable)) +const lnExecutable = commandPath('ln') +const rmExecutable = commandPath('rm') const escapingStoreOutput = [rawShell, commandPath('nix'), commandPath('grep')] .filter((path) => /^\/nix\/store\/[^/]+\/bin\/[^/]+$/u.test(path)) .map((path) => ({ output: NodePath.dirname(NodePath.dirname(path)), target: realpathSync(path) })) @@ -108,7 +114,7 @@ const makeFixture = async ({ ]) await writeFile( nixPath, - `#!${shell}\nset -eu\nprintf '%s\\n' "$*" >>"${nixLog}"\nIFS= read -r mode <"${nixModePath}"\nIFS= read -r output <"${nixOutputPath}"\ncase " $* " in\n *" path-info "*)\n case "$mode" in\n closure-missing) exit 0 ;;\n closure-nonstore) printf '/tmp/not-a-store-output\\n'; exit 0 ;;\n closure-omits-output) printf '%s\\n' "${alternateOutput}"; exit 0 ;;\n esac\n ;;\nesac\ncase "$mode" in\n missing) exit 0 ;;\n duplicate) printf '%s\\n%s\\n' "$output" "$output" ;;\n nonstore) printf '/tmp/not-a-store-output\\n' ;;\n lock-write-attempt)\n case " $* " in\n *" --no-write-lock-file --no-update-lock-file "*) exit 73 ;;\n *) printf 'mutated\\n' >"${memberRoot}/flake.lock"; exit 74 ;;\n esac ;;\n fail) exit 37 ;;\n *) printf '%s\\n' "$output" ;;\nesac\n`, + `#!${shell}\nset -eu\nprintf '%s\\n' "$*" >>"${nixLog}"\nIFS= read -r mode <"${nixModePath}"\nIFS= read -r output <"${nixOutputPath}"\ncase " $* " in\n *" path-info "*)\n case "$mode" in\n closure-missing) exit 0 ;;\n closure-nonstore) printf '/tmp/not-a-store-output\\n'; exit 0 ;;\n closure-omits-output) printf '%s\\n' "${alternateOutput}"; exit 0 ;;\n esac\n ;;\nesac\ncase "$mode" in\n missing) exit 0 ;;\n duplicate) printf '%s\\n%s\\n' "$output" "$output" ;;\n nonstore) printf '/tmp/not-a-store-output\\n' ;;\n lock-write-attempt)\n case " $* " in\n *" --no-write-lock-file --no-update-lock-file "*) exit 73 ;;\n *) printf 'mutated\\n' >"${memberRoot}/flake.lock"; exit 74 ;;\n esac ;;\n fail) exit 37 ;;\n *)\n previous=\n for arg in "$@"; do\n if [ "$previous" = '--out-link' ]; then\n "${rmExecutable}" -f "$arg"\n "${lnExecutable}" -s "$output" "$arg"\n break\n fi\n previous="$arg"\n done\n printf '%s\\n' "$output"\n ;;\nesac\n`, { mode: 0o755 }, ) await writeFile( @@ -264,10 +270,11 @@ describe('composition capability resolver', () => { 'a-tool', 'z-tool', ]) + const privateRoot = NodePath.dirname(result.candidateRoot) expect(await readFile(fixture.nixLog, 'utf8')).toBe( - `build --no-link --print-out-paths --no-write-lock-file --no-update-lock-file ${fixture.memberRoot}#a-package^out\n` + + `build --out-link ${NodePath.join(privateRoot, 'gc-root-a-tool')} --print-out-paths --no-write-lock-file --no-update-lock-file ${fixture.memberRoot}#a-package^out\n` + `path-info --recursive --offline --no-write-lock-file --no-update-lock-file ${fixture.memberRoot}#a-package^out\n` + - `build --no-link --print-out-paths --no-write-lock-file --no-update-lock-file ${fixture.memberRoot}#z-package^out\n` + + `build --out-link ${NodePath.join(privateRoot, 'gc-root-z-tool')} --print-out-paths --no-write-lock-file --no-update-lock-file ${fixture.memberRoot}#z-package^out\n` + `path-info --recursive --offline --no-write-lock-file --no-update-lock-file ${fixture.memberRoot}#z-package^out\n`, ) expect(result.capabilities[0]?.closureStorePaths).toEqual([bashOutput]) @@ -293,6 +300,250 @@ describe('composition capability resolver', () => { } }) + it('retains durable generation roots idempotently and prunes stale generation directories', async () => { + const fixture = await makeFixture() + try { + const result = await resolve(fixture, { + manifest: manifest({ + capabilities: [ + { + toolId: 'z-tool', + protocol: 'test/z/v1', + flakePackage: 'z-package', + executable: 'bin/bash', + }, + { + toolId: 'a-tool', + protocol: 'test/a/v1', + flakePackage: 'a-package', + executable: 'bin/bash', + }, + ], + }), + }) + if (result._tag !== 'Resolved') throw new Error('unreachable') + const publishedRoot = NodePath.join(fixture.root, 'published') + const buck2Path = NodePath.join(publishedRoot, '.buck2') + await mkdir(buck2Path, { recursive: true }) + await cp(result.projectionPath, NodePath.join(buck2Path, 'capabilities'), { + recursive: true, + }) + await chmod(buck2Path, 0o555) + const rootsPath = NodePath.join(buck2Path, 'capability-roots') + const generationRoot = NodePath.join(rootsPath, result.projectionDigest) + const fsyncEvents: string[] = [] + const durableRuntime: CompositionCapabilityRuntime = { + ...fixture.runtime, + directoryFsync: async ({ path, reason, sync }) => { + await sync() + fsyncEvents.push(`${reason}:${path}`) + }, + } + + await retainCompositionCapabilityProjection({ + memberRoot: publishedRoot, + resolution: result, + runtime: durableRuntime, + }) + expect((await lstat(buck2Path)).mode & 0o777).toBe(0o555) + const staleGeneration = NodePath.join(rootsPath, 'a'.repeat(64)) + const recoveryRoot = NodePath.join(rootsPath, 'operator-recovery') + await mkdir(staleGeneration, { recursive: true }) + await writeFile(NodePath.join(staleGeneration, 'sentinel'), 'stale\n') + await mkdir(recoveryRoot) + await Promise.all( + [generationRoot, staleGeneration, recoveryRoot, rootsPath].map((path) => + chmod(path, 0o555), + ), + ) + await retainCompositionCapabilityProjection({ + memberRoot: publishedRoot, + resolution: result, + runtime: durableRuntime, + }) + expect(fsyncEvents).toEqual([ + `CapabilityLinks:${generationRoot}`, + `GenerationLink:${rootsPath}`, + `RootsLink:${buck2Path}`, + `CapabilityLinks:${generationRoot}`, + `GenerationLink:${rootsPath}`, + `RootsLink:${buck2Path}`, + ]) + expect(await readdir(rootsPath)).toContain('a'.repeat(64)) + await pruneCompositionCapabilityProjectionRoots({ + memberRoot: publishedRoot, + resolution: result, + runtime: fixture.runtime, + }) + + const aRoot = NodePath.join(rootsPath, result.projectionDigest, 'a-tool') + const zRoot = NodePath.join(rootsPath, result.projectionDigest, 'z-tool') + for (const rootPath of [aRoot, zRoot]) { + expect((await lstat(rootPath)).isSymbolicLink()).toBe(true) + expect(await readlink(rootPath)).toBe(bashOutput) + } + expect((await lstat(generationRoot)).mode & 0o777).toBe(0o555) + expect((await lstat(rootsPath)).mode & 0o777).toBe(0o555) + expect((await readdir(rootsPath)).toSorted()).toEqual([ + result.projectionDigest, + 'operator-recovery', + ]) + expect(await readFile(fixture.nixLog, 'utf8')).toContain( + `build --out-link ${aRoot} ${bashOutput}\n` + + `build --out-link ${zRoot} ${bashOutput}\n` + + `build --out-link ${aRoot} ${bashOutput}\n` + + `build --out-link ${zRoot} ${bashOutput}\n`, + ) + await Promise.all( + [generationRoot, recoveryRoot, rootsPath, buck2Path].map((path) => chmod(path, 0o755)), + ) + await result.release() + } finally { + await clean(fixture) + } + }) + + it('fsyncs pre-existing parent links on retry after a post-mkdir retention failure', async () => { + const fixture = await makeFixture() + try { + const result = await resolve(fixture) + if (result._tag !== 'Resolved') throw new Error('unreachable') + const publishedRoot = NodePath.join(fixture.root, 'published') + const buck2Path = NodePath.join(publishedRoot, '.buck2') + await mkdir(buck2Path, { recursive: true }) + await cp(result.projectionPath, NodePath.join(buck2Path, 'capabilities'), { + recursive: true, + }) + const lostRoot = NodePath.join( + buck2Path, + 'capability-roots', + result.projectionDigest, + 'buck2', + ) + + const retentionError = await failure( + retainCompositionCapabilityProjection({ + memberRoot: publishedRoot, + resolution: result, + runtime: { + ...fixture.runtime, + directoryFsync: async ({ path, reason }) => { + if (reason !== 'CapabilityLinks') return + await rm(lostRoot, { force: true }) + throw new Error(`simulated loss before syncing '${path}'`) + }, + }, + }), + ) + expect(retentionError.reason).toBe('ProjectionFailure') + await expect(lstat(lostRoot)).rejects.toMatchObject({ code: 'ENOENT' }) + const syncedParents = new Set() + await retainCompositionCapabilityProjection({ + memberRoot: publishedRoot, + resolution: result, + runtime: { + ...fixture.runtime, + directoryFsync: async ({ path, reason, sync }) => { + await sync() + if (reason !== 'CapabilityLinks') syncedParents.add(path) + }, + }, + }) + const rootsPath = NodePath.join(buck2Path, 'capability-roots') + const generationRoot = NodePath.join(rootsPath, result.projectionDigest) + if (syncedParents.has(rootsPath) === false) { + await rm(generationRoot, { recursive: true, force: true }) + } + if (syncedParents.has(buck2Path) === false) { + await rm(rootsPath, { recursive: true, force: true }) + } + expect(syncedParents).toEqual(new Set([rootsPath, buck2Path])) + expect((await lstat(lostRoot)).isSymbolicLink()).toBe(true) + await result.release() + } finally { + await clean(fixture) + } + }) + + it('restores a protected Buck parent mode when root verification fails', async () => { + const fixture = await makeFixture() + try { + const result = await resolve(fixture) + if (result._tag !== 'Resolved') throw new Error('unreachable') + const publishedRoot = NodePath.join(fixture.root, 'published') + const buck2Path = NodePath.join(publishedRoot, '.buck2') + await mkdir(buck2Path, { recursive: true }) + await cp(result.projectionPath, NodePath.join(buck2Path, 'capabilities'), { + recursive: true, + }) + await chmod(buck2Path, 0o555) + await writeFile(fixture.nixOutputPath, `${alternateOutput}\n`) + + const error = await failure( + retainCompositionCapabilityProjection({ + memberRoot: publishedRoot, + resolution: result, + runtime: fixture.runtime, + }), + ) + expect(error.reason).toBe('ProjectionFailure') + expect((await lstat(buck2Path)).mode & 0o777).toBe(0o555) + await chmod(buck2Path, 0o755) + await result.release() + } finally { + await clean(fixture) + } + }) + + it('rejects a published generation mismatch without deleting prior roots', async () => { + const fixture = await makeFixture() + try { + const expected = await resolve(fixture) + const published = await resolve(fixture, { + manifest: manifest({ + capabilities: [ + { + toolId: 'buck2', + protocol: 'test/different-generation/v1', + flakePackage: 'buck2', + executable: 'bin/bash', + }, + ], + }), + }) + if (expected._tag !== 'Resolved' || published._tag !== 'Resolved') { + throw new Error('unreachable') + } + const publishedRoot = NodePath.join(fixture.root, 'published') + await mkdir(NodePath.join(publishedRoot, '.buck2'), { recursive: true }) + await cp(published.projectionPath, NodePath.join(publishedRoot, '.buck2', 'capabilities'), { + recursive: true, + }) + const priorRoot = NodePath.join( + publishedRoot, + '.buck2', + 'capability-roots', + expected.projectionDigest, + ) + await mkdir(priorRoot, { recursive: true }) + await writeFile(NodePath.join(priorRoot, 'sentinel'), 'keep\n') + + const error = await failure( + retainCompositionCapabilityProjection({ + memberRoot: publishedRoot, + resolution: expected, + runtime: fixture.runtime, + }), + ) + expect(error.reason).toBe('ProjectionFailure') + expect(await readFile(NodePath.join(priorRoot, 'sentinel'), 'utf8')).toBe('keep\n') + await expected.release() + await published.release() + } finally { + await clean(fixture) + } + }) + it('never executes a malicious member projector script', async () => { const fixture = await makeFixture({ projector: `#!${shell}\nprintf executed >${NodePath.join('/tmp', 'member-projector-must-not-run')}\nexit 91\n`, @@ -463,7 +714,12 @@ describe('composition capability resolver', () => { }) expect(result.nixCommands[0]?.args).toEqual([ 'build', - '--no-link', + '--out-link', + NodePath.join( + NodePath.resolve(tmpdir()), + '.megarepo-capabilities-planned-candidate', + 'gc-root-buck2', + ), '--print-out-paths', '--no-write-lock-file', '--no-update-lock-file', @@ -647,4 +903,18 @@ describe('composition capability resolver', () => { await Promise.all([clean(first), clean(second)]) } }) + it('does not require flake.lock when a member projects no capabilities', async () => { + const fixture = await makeFixture() + try { + await rm(NodePath.join(fixture.memberRoot, 'flake.lock')) + const result = await resolve(fixture, { manifest: manifest({ capabilities: [] }) }) + expect(result._tag).toBe('Resolved') + if (result._tag !== 'Resolved') throw new Error('unreachable') + expect(result.capabilities).toEqual([]) + expect(result.nixCommands).toEqual([]) + await result.release() + } finally { + await clean(fixture) + } + }) }) diff --git a/packages/@overeng/megarepo/src/composition/capabilities/composition-capability-resolver.ts b/packages/@overeng/megarepo/src/composition/capabilities/composition-capability-resolver.ts index 6ceb0c5e4e..a2d75b6ca2 100644 --- a/packages/@overeng/megarepo/src/composition/capabilities/composition-capability-resolver.ts +++ b/packages/@overeng/megarepo/src/composition/capabilities/composition-capability-resolver.ts @@ -10,6 +10,7 @@ import { open, readFile, readdir, + readlink, realpath, rename, rm, @@ -54,6 +55,12 @@ export interface CompositionCapabilityRuntime { readonly projectionPath: string }) => Promise readonly createPrivateScratch?: () => Promise + /** Durability seam for published capability-root directory entries. */ + readonly directoryFsync?: (input: { + readonly path: string + readonly reason: 'CapabilityLinks' | 'GenerationLink' | 'RootsLink' + readonly sync: () => Promise + }) => Promise } /** Resolver-owned private scratch capability. Callers may inject creation, never a mutable path. */ @@ -75,6 +82,12 @@ export interface ResolveCompositionCapabilitiesInput { readonly dryRun: boolean readonly runtime: CompositionCapabilityRuntime } +/** Stable publication target plus the exact resolution whose Nix outputs must survive GC. */ +export interface RetainCompositionCapabilityProjectionInput { + readonly memberRoot: string + readonly resolution: CompositionCapabilityResolutionHandle + readonly runtime: CompositionCapabilityRuntime +} /** Validated dry-run plan or completed scratch projection. */ export type ResolveCompositionCapabilitiesResult = @@ -103,6 +116,15 @@ export const checkCompositionCapabilityProjection = (input: { readonly memberRoo export const resolveCompositionCapabilities = (input: ResolveCompositionCapabilitiesInput) => resolveCompositionCapabilitiesInternal(input) +/** Retain every published capability output as a durable generation-scoped Nix GC root. */ +export const retainCompositionCapabilityProjection = ( + input: RetainCompositionCapabilityProjectionInput, +): Promise => retainCompositionCapabilityProjectionInternal(input) +/** Verify the retained generation, then remove stale generation roots after publication commits. */ +export const pruneCompositionCapabilityProjectionRoots = ( + input: RetainCompositionCapabilityProjectionInput, +): Promise => pruneCompositionCapabilityProjectionRootsInternal(input) + /** Fail-closed resolved capability lookup used by Buck/tool consumers. */ export const resolvedCompositionCapabilityByToolId = (input: { readonly resolution: CompositionCapabilityResolutionHandle @@ -310,17 +332,20 @@ const assertRegularFileIdentity = async (identity: RegularFileIdentity): Promise const validateMember = async ({ memberRoot, + requireLock, }: { readonly memberRoot: string + readonly requireLock: boolean }): Promise<{ readonly memberRoot: string - readonly lock: RegularFileIdentity + readonly lock?: RegularFileIdentity }> => { assertAbsoluteNormalized({ value: memberRoot, name: 'memberRoot' }) const canonicalMemberRoot = await realpath(memberRoot) if ((await stat(canonicalMemberRoot)).isDirectory() === false) { throw invalidInput({ message: 'memberRoot must be a directory', path: memberRoot }) } + if (requireLock === false) return { memberRoot: canonicalMemberRoot } try { const lock = await captureContainedRegularFile({ root: canonicalMemberRoot, @@ -331,7 +356,7 @@ const validateMember = async ({ } catch (cause) { throw new CompositionCapabilityResolutionError({ reason: 'InvalidLock', - message: 'Member must contain a regular, contained, immutable flake.lock', + message: 'Member with projected capabilities must contain a regular, contained flake.lock', path: NodePath.join(canonicalMemberRoot, 'flake.lock'), cause, }) @@ -837,18 +862,33 @@ const assertProjectedClosure = async ({ }), ) } -/** Validate a capability projection without executing member-controlled code. */ -const checkCompositionCapabilityProjectionInternal = async ({ +const readPublishedProjectionGeneration = async ({ memberRoot, }: { readonly memberRoot: string -}): Promise => { +}): Promise<{ + readonly defs: string + readonly generation: string + readonly projectionPath: string +}> => { const projectionPath = NodePath.join(memberRoot, '.buck2', 'capabilities') const defs = await readFile(NodePath.join(projectionPath, 'defs.bzl'), 'utf8') const match = /^GENERATION = "([0-9a-f]{64})"$/mu.exec(defs) - if (match === null) + if (match === null) { throw invalidInput({ message: 'Capability defs generation is invalid', path: projectionPath }) - const generation = match[1]! + } + return { defs, generation: match[1]!, projectionPath } +} + +/** Validate a capability projection without executing member-controlled code. */ +const checkCompositionCapabilityProjectionInternal = async ({ + memberRoot, +}: { + readonly memberRoot: string +}): Promise => { + const { defs, generation, projectionPath } = await readPublishedProjectionGeneration({ + memberRoot, + }) if ((await readFile(NodePath.join(projectionPath, 'BUCK'), 'utf8')) !== rootBuckBytes) { throw invalidInput({ message: 'Capability root BUCK is invalid', path: projectionPath }) } @@ -907,6 +947,264 @@ const checkCompositionCapabilityProjectionInternal = async ({ } } +const withOwnerWritableDirectory = async ({ + path, + use, +}: { + readonly path: string + readonly use: () => Promise +}): Promise => { + const handle = await open(path, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW) + const before = await handle.stat() + if (before.isDirectory() === false) { + await handle.close() + throw new Error(`Capability root parent is not a directory: '${path}'`) + } + const originalMode = before.mode & 0o777 + const needsOwnerWrite = (originalMode & 0o200) === 0 + let outcome: + | { readonly _tag: 'Success'; readonly value: A } + | { readonly _tag: 'Failure'; readonly cause: unknown } + | undefined + try { + if (needsOwnerWrite === true) await handle.chmod(originalMode | 0o200) + try { + outcome = { _tag: 'Success', value: await use() } + } catch (cause) { + outcome = { _tag: 'Failure', cause } + } + } finally { + try { + if (needsOwnerWrite === true) await handle.chmod(originalMode) + } finally { + await handle.close() + } + } + const after = await lstat(path) + if ( + after.isDirectory() === false || + after.isSymbolicLink() === true || + after.dev !== before.dev || + after.ino !== before.ino || + (after.mode & 0o777) !== originalMode + ) { + throw new Error(`Capability root parent identity or mode changed: '${path}'`) + } + if (outcome === undefined) { + throw new Error(`Capability root parent write did not complete: '${path}'`) + } + if (outcome._tag === 'Failure') throw outcome.cause + return outcome.value +} + +const syncCapabilityRootDirectory = async ({ + path, + reason, + runtime, +}: { + readonly path: string + readonly reason: 'CapabilityLinks' | 'GenerationLink' | 'RootsLink' + readonly runtime: CompositionCapabilityRuntime +}): Promise => { + const sync = async (): Promise => { + const handle = await open(path, 'r') + try { + await handle.sync() + } finally { + await handle.close() + } + } + await (runtime.directoryFsync?.({ path, reason, sync }) ?? sync()) +} + +const ensureCapabilityRootDirectory = async ({ + parentPath, + path, +}: { + readonly parentPath: string + readonly path: string +}): Promise => { + try { + const info = await lstat(path) + if (info.isDirectory() === false || info.isSymbolicLink() === true) { + throw new Error(`Capability root path is not a directory: '${path}'`) + } + return + } catch (cause) { + if ( + typeof cause !== 'object' || + cause === null || + 'code' in cause === false || + cause.code !== 'ENOENT' + ) { + throw cause + } + } + await withOwnerWritableDirectory({ + path: parentPath, + use: () => mkdir(path, { recursive: false }), + }) +} + +const assertPublishedCapabilityGeneration = async ({ + memberRoot, + resolution, +}: { + readonly memberRoot: string + readonly resolution: CompositionCapabilityResolutionHandle +}): Promise => { + await checkCompositionCapabilityProjection({ memberRoot }) + const { generation, projectionPath } = await readPublishedProjectionGeneration({ memberRoot }) + if (generation !== resolution.projectionDigest) { + throw new CompositionCapabilityResolutionError({ + reason: 'ProjectionFailure', + message: 'Published capability generation does not match its resolved projection', + path: projectionPath, + }) + } +} + +const retainCompositionCapabilityProjectionInternal = async ({ + memberRoot, + resolution, + runtime, +}: RetainCompositionCapabilityProjectionInput): Promise => { + assertAbsoluteNormalized({ value: memberRoot, name: 'memberRoot' }) + await validateRuntime(runtime) + + const assertPublishedGeneration = (): Promise => + assertPublishedCapabilityGeneration({ memberRoot, resolution }) + + await assertPublishedGeneration() + const buck2Path = NodePath.join(memberRoot, '.buck2') + const rootsPath = NodePath.join(buck2Path, 'capability-roots') + const generationRoot = NodePath.join(rootsPath, resolution.projectionDigest) + try { + await ensureCapabilityRootDirectory({ + parentPath: buck2Path, + path: rootsPath, + }) + await ensureCapabilityRootDirectory({ + parentPath: rootsPath, + path: generationRoot, + }) + + const env = safeNixEnvironment({ + runtime, + privateRoot: NodePath.dirname(resolution.candidateRoot), + }) + const capabilities = resolution.capabilities.toSorted((left, right) => + left.capability.toolId < right.capability.toolId + ? -1 + : left.capability.toolId > right.capability.toolId + ? 1 + : 0, + ) + await withOwnerWritableDirectory({ + path: generationRoot, + use: async () => { + for (const resolved of capabilities) { + const rootPath = NodePath.join(generationRoot, resolved.capability.toolId) + const retainCommand = command({ + executable: runtime.nixPath, + args: ['build', '--out-link', rootPath, resolved.nixOutputPath], + }) + await run({ value: retainCommand, env }) + const rootInfo = await lstat(rootPath) + if ( + rootInfo.isSymbolicLink() === false || + (await readlink(rootPath)) !== resolved.nixOutputPath + ) { + throw new CompositionCapabilityResolutionError({ + reason: 'ProjectionFailure', + message: `Capability GC root '${resolved.capability.toolId}' has the wrong identity`, + path: rootPath, + }) + } + } + }, + }) + await syncCapabilityRootDirectory({ + path: generationRoot, + reason: 'CapabilityLinks', + runtime, + }) + await syncCapabilityRootDirectory({ + path: rootsPath, + reason: 'GenerationLink', + runtime, + }) + await syncCapabilityRootDirectory({ + path: buck2Path, + reason: 'RootsLink', + runtime, + }) + } catch (cause) { + if (cause instanceof CompositionCapabilityResolutionError) throw cause + throw new CompositionCapabilityResolutionError({ + reason: 'ProjectionFailure', + message: 'Could not retain the published capability generation', + path: generationRoot, + cause, + }) + } +} + +const pruneCompositionCapabilityProjectionRootsInternal = async ({ + memberRoot, + resolution, + runtime, +}: RetainCompositionCapabilityProjectionInput): Promise => { + assertAbsoluteNormalized({ value: memberRoot, name: 'memberRoot' }) + await validateRuntime(runtime) + + const rootsPath = NodePath.join(memberRoot, '.buck2', 'capability-roots') + const generationRoot = NodePath.join(rootsPath, resolution.projectionDigest) + try { + await assertPublishedCapabilityGeneration({ memberRoot, resolution }) + const generationInfo = await lstat(generationRoot) + if (generationInfo.isDirectory() === false || generationInfo.isSymbolicLink() === true) { + throw new Error(`Capability generation root is not a directory: '${generationRoot}'`) + } + for (const resolved of resolution.capabilities) { + const rootPath = NodePath.join(generationRoot, resolved.capability.toolId) + const rootInfo = await lstat(rootPath) + if ( + rootInfo.isSymbolicLink() === false || + (await readlink(rootPath)) !== resolved.nixOutputPath + ) { + throw new Error(`Capability GC root has the wrong identity: '${rootPath}'`) + } + } + await assertPublishedCapabilityGeneration({ memberRoot, resolution }) + await withOwnerWritableDirectory({ + path: rootsPath, + use: async () => { + const entries = await readdir(rootsPath, { withFileTypes: true }) + for (const entry of entries) { + if ( + entry.name !== resolution.projectionDigest && + /^[0-9a-f]{64}$/u.test(entry.name) === true && + entry.isDirectory() === true + ) { + const staleRoot = NodePath.join(rootsPath, entry.name) + await makeDirectoriesOwnerWritable(staleRoot) + await rm(staleRoot, { recursive: true }) + } + } + }, + }) + } catch (cause) { + if (cause instanceof CompositionCapabilityResolutionError) throw cause + throw new CompositionCapabilityResolutionError({ + reason: 'ProjectionFailure', + message: 'Could not prune stale capability generations', + path: rootsPath, + cause, + }) + } +} + interface ProjectionIdentity { readonly path: string readonly realpath: string @@ -1042,10 +1340,13 @@ const resolveCompositionCapabilitiesInternal = async ( strictParseOptions, )(input.system) await validateRuntime(input.runtime) - const roots = await validateMember(input) const capabilities = buckMemberProjectedCapabilities(manifest).toSorted((left, right) => left.toolId < right.toolId ? -1 : left.toolId > right.toolId ? 1 : 0, ) + const roots = await validateMember({ + memberRoot: input.memberRoot, + requireLock: capabilities.length > 0, + }) const nonce = (input.runtime.nonce ?? randomUUID)() if (/^[A-Za-z0-9._-]+$/u.test(nonce) === false) { throw invalidInput({ @@ -1058,42 +1359,48 @@ const resolveCompositionCapabilitiesInternal = async ( ) const plannedCandidateRoot = NodePath.join(plannedPrivateRoot, 'candidate') const projectorPlatform = platformFor(system) - const capabilityCommands = capabilities.map((capability) => { - const installable = `${roots.memberRoot}#${capability.flakePackage}^out` - return { - build: command({ - executable: input.runtime.nixPath, - args: [ - 'build', - '--no-link', - '--print-out-paths', - '--no-write-lock-file', - '--no-update-lock-file', - installable, - ], - }), - // The realization already exists, so the closure query stays offline. - closure: command({ - executable: input.runtime.nixPath, - args: [ - 'path-info', - '--recursive', - '--offline', - '--no-write-lock-file', - '--no-update-lock-file', - installable, - ], - }), - } - }) - const nixCommands = capabilityCommands.flatMap(({ build, closure }) => [build, closure]) + const capabilityCommandsFor = (privateRoot: string) => + capabilities.map((capability) => { + const installable = `${roots.memberRoot}#${capability.flakePackage}^out` + return { + build: command({ + executable: input.runtime.nixPath, + args: [ + 'build', + '--out-link', + NodePath.join(privateRoot, `gc-root-${capability.toolId}`), + '--print-out-paths', + '--no-write-lock-file', + '--no-update-lock-file', + installable, + ], + }), + // The realization already exists, so the closure query stays offline. + closure: command({ + executable: input.runtime.nixPath, + args: [ + 'path-info', + '--recursive', + '--offline', + '--no-write-lock-file', + '--no-update-lock-file', + installable, + ], + }), + } + }) + const plannedCapabilityCommands = capabilityCommandsFor(plannedPrivateRoot) + const plannedNixCommands = plannedCapabilityCommands.flatMap(({ build, closure }) => [ + build, + closure, + ]) if (input.dryRun === true) { return { _tag: 'Planned', system, projectorPlatform, candidateRoot: plannedCandidateRoot, - nixCommands, + nixCommands: plannedNixCommands, } } @@ -1101,13 +1408,18 @@ const resolveCompositionCapabilitiesInternal = async ( const scratchIdentity = await capturePrivateScratchIdentity(scratch) release = makeScratchRelease({ scratch, identity: scratchIdentity }) const env = safeNixEnvironment({ runtime: input.runtime, privateRoot: scratchIdentity.path }) - const resolved = await resolveCapabilitiesInOrder({ - capabilities, - nixCommands: capabilityCommands, - env, - lock: roots.lock, - }) - await assertRegularFileIdentity(roots.lock) + const capabilityCommands = capabilityCommandsFor(scratchIdentity.path) + const nixCommands = capabilityCommands.flatMap(({ build, closure }) => [build, closure]) + const resolved = + roots.lock === undefined + ? [] + : await resolveCapabilitiesInOrder({ + capabilities, + nixCommands: capabilityCommands, + env, + lock: roots.lock, + }) + if (roots.lock !== undefined) await assertRegularFileIdentity(roots.lock) const candidateRoot = NodePath.join(scratchIdentity.path, 'candidate') await mkdir(candidateRoot, { mode: 0o700 }) const candidateIdentity = await captureCandidateRootIdentity({ @@ -1133,7 +1445,7 @@ const resolveCompositionCapabilitiesInternal = async ( }) const digest = await projectionDigest({ projection, candidate: candidateIdentity }) await normalizeR6SourceModes(projectionPath) - await assertRegularFileIdentity(roots.lock) + if (roots.lock !== undefined) await assertRegularFileIdentity(roots.lock) return { _tag: 'Resolved', system, diff --git a/packages/@overeng/megarepo/src/composition/capabilities/owned-capability-projection.integration.test.ts b/packages/@overeng/megarepo/src/composition/capabilities/owned-capability-projection.integration.test.ts index 868e6bcf83..956ff2e6c5 100644 --- a/packages/@overeng/megarepo/src/composition/capabilities/owned-capability-projection.integration.test.ts +++ b/packages/@overeng/megarepo/src/composition/capabilities/owned-capability-projection.integration.test.ts @@ -43,6 +43,7 @@ describe('owned capability projection', () => { let value = 0 return () => `fixture-${value++}` })(), + retainPublishedCapabilities: async () => undefined, } const published = await installOwnedCapabilityProjection({ @@ -78,6 +79,88 @@ describe('owned capability projection', () => { } }) + it('rolls an owned projection swap back when stable-root retention fails', async () => { + const fixture = await mkdtemp(NodePath.join(tmpdir(), 'owned-capability-retention-')) + try { + const owned = NodePath.join(fixture, 'owned') + const first = NodePath.join(fixture, 'first') + const second = NodePath.join(fixture, 'second') + const firstGeneration = 'a'.repeat(64) + const secondGeneration = 'b'.repeat(64) + await mkdir(owned) + await writeFile(NodePath.join(owned, '.git'), 'gitdir: fixture\n') + await writeProjection({ root: first, generation: firstGeneration }) + await writeProjection({ root: second, generation: secondGeneration }) + const coreutils = await resolvePinnedCoreutils() + await installOwnedCapabilityProjection({ + memberKey: 'owned', + ownedMemberPath: owned, + projectionPath: first, + projectionDigest: firstGeneration, + runtime: { + ...coreutils, + nonce: () => 'first', + retainPublishedCapabilities: async () => undefined, + }, + }) + const oldRoot = NodePath.join( + owned, + '.buck2', + 'capability-roots', + firstGeneration, + 'buck2', + ) + const newRoot = NodePath.join( + owned, + '.buck2', + 'capability-roots', + secondGeneration, + 'buck2', + ) + await mkdir(NodePath.dirname(oldRoot), { recursive: true }) + await writeFile(oldRoot, 'old root\n') + + await expect( + installOwnedCapabilityProjection({ + memberKey: 'owned', + ownedMemberPath: owned, + projectionPath: second, + projectionDigest: secondGeneration, + runtime: { + ...coreutils, + nonce: () => 'advance', + retainPublishedCapabilities: async ({ destinationPath }) => { + expect(await readFile(NodePath.join(destinationPath, 'defs.bzl'), 'utf8')).toBe( + `GENERATION = "${secondGeneration}" +`, + ) + expect(await readFile(oldRoot, 'utf8')).toBe('old root\n') + await mkdir(NodePath.dirname(newRoot), { recursive: true }) + await writeFile(newRoot, 'partial new root\n') + throw new Error('stable-root retention failed') + }, + }, + }), + ).rejects.toMatchObject({ + _tag: 'OwnedCapabilityProjectionError', + reason: 'RetentionFailed', + }) + expect(await readFile(NodePath.join(owned, '.buck2/capabilities/defs.bzl'), 'utf8')).toBe( + `GENERATION = "${firstGeneration}" +`, + ) + expect(await readFile(oldRoot, 'utf8')).toBe('old root\n') + expect(await readFile(newRoot, 'utf8')).toBe('partial new root\n') + expect( + (await readdir(NodePath.join(owned, '.buck2'))).some((name) => + name.startsWith('.capabilities.stage-'), + ), + ).toBe(false) + } finally { + await rm(fixture, { recursive: true, force: true }) + } + }) + it.each(['symlink', 'file'] as const)( 'rejects a %s .buck2 parent without writing outside', async (kind) => { @@ -103,6 +186,7 @@ describe('owned capability projection', () => { runtime: { ...coreutils, nonce: () => 'parent-kind', + retainPublishedCapabilities: async () => undefined, }, }), ).rejects.toMatchObject({ @@ -143,6 +227,7 @@ describe('owned capability projection', () => { runtime: { ...coreutils, nonce: () => `race-${phase}`, + retainPublishedCapabilities: async () => undefined, ...(phase === 'copy' ? { beforeCopy: replaceParent } : { beforePublish: replaceParent }), diff --git a/packages/@overeng/megarepo/src/composition/capabilities/owned-capability-projection.ts b/packages/@overeng/megarepo/src/composition/capabilities/owned-capability-projection.ts index 7aa0cbf0b0..ec5bbdc3e9 100644 --- a/packages/@overeng/megarepo/src/composition/capabilities/owned-capability-projection.ts +++ b/packages/@overeng/megarepo/src/composition/capabilities/owned-capability-projection.ts @@ -19,7 +19,13 @@ const generationPattern = /^[0-9a-f]{64}$/u export class OwnedCapabilityProjectionError extends Schema.TaggedError()( 'OwnedCapabilityProjectionError', { - reason: Schema.Literals(['InvalidInput', 'CopyFailed', 'VerificationFailed', 'PublishFailed']), + reason: Schema.Literals([ + 'InvalidInput', + 'CopyFailed', + 'VerificationFailed', + 'PublishFailed', + 'RetentionFailed', + ]), path: Schema.String, message: Schema.String, cause: Schema.optional(Schema.Defect()), @@ -35,6 +41,11 @@ export interface OwnedCapabilityProjectionRuntime { readonly beforeCopy?: (capabilityParent: string) => Promise /** Deterministic race seam; production runtimes must not provide it. */ readonly beforePublish?: (capabilityParent: string) => Promise + /** Retain the newly active projection before the old projection is removed. */ + readonly retainPublishedCapabilities: (input: { + readonly ownedMemberPath: string + readonly destinationPath: string + }) => Promise } const failure = ({ @@ -202,13 +213,18 @@ export const planOwnedCapabilityProjection = async ({ ownedMemberPath, projectionPath, operation: 'InstallOwnedCapabilityProjection', - steps: ['ValidateOwnedMember', 'InstallProjectionAtomically', 'CheckProjection'], + steps: [ + 'ValidateOwnedMember', + 'InstallProjectionAtomically', + 'CheckProjection', + 'RetainProjectionRoots', + ], } } /** - * Copy a checked scratch projection into the writable member and publish it with one atomic - * directory exchange. Existing equal projections are left untouched. + * Copy a checked scratch projection into the writable member, publish it with one atomic directory + * exchange, and roll the exchange back unless stable-root retention succeeds. */ export const installOwnedCapabilityProjection = async ({ memberKey, @@ -346,7 +362,25 @@ export const installOwnedCapabilityProjection = async ({ } if (currentGeneration === projectionDigest) { - await removeStage() + try { + await runtime.retainPublishedCapabilities?.({ + ownedMemberPath, + destinationPath: destination, + }) + await removeStage() + } catch (cause) { + try { + await removeStage() + } catch { + // Never clean through a replaced parent path. + } + throw failure({ + reason: 'RetentionFailed', + path: destination, + message: 'Could not retain the current owned capability projection', + cause, + }) + } return { memberKey, projectionPath: destination, projectionDigest, changed: false } } @@ -394,6 +428,57 @@ export const installOwnedCapabilityProjection = async ({ }) } + try { + await runtime.retainPublishedCapabilities?.({ + ownedMemberPath, + destinationPath: destination, + }) + } catch (cause) { + try { + await assertDirectoryIdentity(capabilityParentIdentity) + if (destinationExists === true) { + await runExact({ + executable: runtime.mvPath, + args: ['-T', '--exchange', '--', stage, destination], + }) + if ( + currentGeneration === undefined || + (await readGeneration({ + projectionPath: destination, + expectedParent: capabilityParentIdentity.realpath, + })) !== currentGeneration + ) { + throw new TypeError('retention rollback did not restore the prior projection') + } + } else { + await runExact({ + executable: runtime.mvPath, + args: ['-T', '--no-clobber', '--', destination, stage], + }) + try { + await lstat(destination) + throw new TypeError('retention rollback left the first projection published') + } catch (missingCause) { + if (isErrno({ cause: missingCause, code: 'ENOENT' }) === false) throw missingCause + } + } + await removeStage() + } catch (rollbackCause) { + throw failure({ + reason: 'RetentionFailed', + path: destination, + message: 'Capability retention failed and owned projection rollback was not proven', + cause: { retentionCause: cause, rollbackCause }, + }) + } + throw failure({ + reason: 'RetentionFailed', + path: destination, + message: 'Capability retention failed; the owned projection was rolled back', + cause, + }) + } + await removeStage() return { memberKey, projectionPath: destination, projectionDigest, changed: true } } diff --git a/packages/@overeng/megarepo/src/composition/mounts/member-mount-cp-a-schema.ts b/packages/@overeng/megarepo/src/composition/mounts/member-mount-cp-a-schema.ts index d33fb8ae87..dec19cf7a6 100644 --- a/packages/@overeng/megarepo/src/composition/mounts/member-mount-cp-a-schema.ts +++ b/packages/@overeng/megarepo/src/composition/mounts/member-mount-cp-a-schema.ts @@ -91,12 +91,13 @@ export const CpAMemberMountOperation = Schema.Literals([ ]) export type CpAMemberMountOperation = typeof CpAMemberMountOperation.Type -/** Diagnostic phase hint; recovery never trusts this field. */ +/** Durable phase state; `CapabilitiesRetained` is the publication commit marker. */ export const CpAMemberMountPhaseHint = Schema.Literals([ 'Intent', 'CandidateCreated', 'Staged', 'Exchanged', + 'CapabilitiesRetained', 'MetadataPublished', 'Cleanup', ]) @@ -194,6 +195,7 @@ export class CpAMemberMountError extends Schema.TaggedError 'PlatformAdvanceRefused', 'CommandFailure', 'CapabilityCheckFailed', + 'CapabilityRetentionFailed', 'SourceChanged', 'StageInvalid', 'ExchangeValidationFailed', diff --git a/packages/@overeng/megarepo/src/composition/mounts/member-mount-cp-a.integration.test.ts b/packages/@overeng/megarepo/src/composition/mounts/member-mount-cp-a.integration.test.ts index e41949f031..1ecae52c00 100644 --- a/packages/@overeng/megarepo/src/composition/mounts/member-mount-cp-a.integration.test.ts +++ b/packages/@overeng/megarepo/src/composition/mounts/member-mount-cp-a.integration.test.ts @@ -23,6 +23,7 @@ import { expect } from 'vitest' import { resolvePinnedCoreutils } from '../../test-utils/coreutils.ts' import { makeCanonicalTempDirectoryScoped } from '../../test-utils/temp-root.ts' +import { publishDistOverlay } from '../overlays/dist-overlay-lifecycle.ts' import { cpAMemberMountDestinationPath, cpAMemberMountTransactionPath, @@ -275,6 +276,70 @@ describe('cp-a member mount lifecycle', () => { }, withNode), ) + it.effect( + 'preserves validated published overlays when the immutable mount authority is unchanged', + Effect.fnUntraced(function* () { + const fixture = yield* makeFixture() + const declaration = { target: '//pkg:dist', destination: 'dir/dist' } as const + const mountRequest = requestFor({ + fixture, + sourcePath: fixture.sourceA, + lockedCommit: 'a'.repeat(40), + distOverlays: [declaration], + }) + const mounted = yield* materializeCpAMemberMount({ + request: mountRequest, + runtime: runtimeFor(fixture), + }) + expect(mounted._tag).toBe('Published') + if (mounted._tag !== 'Published') return + + const artifactPath = NodePath.join(fixture.workspaceRoot, 'artifact') + yield* Effect.promise(async () => { + await mkdir(artifactPath) + await writeFile(NodePath.join(artifactPath, 'bundle.js'), 'built\n') + await chmod(NodePath.join(artifactPath, 'bundle.js'), 0o444) + }) + const mountInfo = yield* Effect.promise(() => lstat(fixture.destinationPath)) + const overlay = yield* publishDistOverlay({ + request: { + workspaceRoot: fixture.workspaceRoot, + member: fixture.member, + expectedMountIdentity: { dev: mountInfo.dev, ino: mountInfo.ino }, + expectedMetadata: mounted.metadata, + target: declaration.target, + destination: declaration.destination, + artifactPath, + cpPath: fixture.cpPath, + mvPath: fixture.mvPath, + dryRun: false, + }, + runtime: { + assertUpdateLockOwned: async () => undefined, + nonce: () => 'mount-current', + }, + }) + expect(overlay._tag).toBe('Published') + if (overlay._tag !== 'Published') return + + const repeated = yield* materializeCpAMemberMount({ + request: mountRequest, + runtime: runtimeFor(fixture), + }) + expect(repeated._tag).toBe('AlreadyCurrent') + if (repeated._tag !== 'AlreadyCurrent') return + expect(repeated.metadata).toEqual(overlay.metadata) + expect( + yield* Effect.promise(() => + readFile( + NodePath.join(fixture.destinationPath, declaration.destination, 'bundle.js'), + 'utf8', + ), + ), + ).toBe('built\n') + }, withNode), + ) + it.effect( 'first-publishes independent protected inodes, literal symlinks, and replaced capabilities without touching source', Effect.fnUntraced(function* () { @@ -345,6 +410,86 @@ describe('cp-a member mount lifecycle', () => { }, withNode), ) + it.effect( + 'strips capability roots copied from a locked source before publishing the protected mount', + Effect.fnUntraced(function* () { + const fixture = yield* makeFixture() + const sourceRoot = NodePath.join( + fixture.sourceA, + '.buck2', + 'capability-roots', + 'a'.repeat(64), + ) + yield* Effect.promise(async () => { + await mkdir(sourceRoot, { recursive: true }) + await writeFile(NodePath.join(sourceRoot, 'old-tool'), 'source runtime sidecar\n') + }) + + const result = yield* firstPublish(fixture) + expect(result).toMatchObject({ _tag: 'Published', operation: 'FirstPublish' }) + expect(yield* pathExists(NodePath.join(sourceRoot, 'old-tool'))).toBe(true) + expect( + yield* pathExists(NodePath.join(fixture.destinationPath, '.buck2', 'capability-roots')), + ).toBe(false) + }, withNode), + ) + + it.effect( + 'rolls an advance back without deleting prior capability roots when retention fails', + Effect.fnUntraced(function* () { + const fixture = yield* makeFixture() + yield* firstPublish(fixture) + const oldRoot = NodePath.join( + fixture.destinationPath, + '.buck2', + 'capability-roots', + 'a'.repeat(64), + ) + yield* Effect.promise(async () => { + const buckDirectory = NodePath.join(fixture.destinationPath, '.buck2') + await chmod(buckDirectory, 0o755) + try { + await mkdir(oldRoot, { recursive: true }) + await writeFile(NodePath.join(oldRoot, 'old-tool'), 'keep\n') + } finally { + await chmod(buckDirectory, 0o555) + } + }) + + const result = yield* advance(fixture, { + retainPublishedCapabilities: async ({ destinationPath }) => { + expect( + await readFile( + NodePath.join( + destinationPath, + '.buck2', + 'capability-roots', + 'a'.repeat(64), + 'old-tool', + ), + 'utf8', + ), + ).toBe('keep\n') + throw new Error('retention failed') + }, + }).pipe(Effect.result) + expect(result._tag).toBe('Failure') + if (result._tag === 'Failure') { + expect(result.failure.reason).toBe('CapabilityRetentionFailed') + } + expect( + yield* Effect.promise(() => + readFile(NodePath.join(fixture.destinationPath, 'version.txt'), 'utf8'), + ), + ).toBe('A\n') + expect( + yield* Effect.promise(() => readFile(NodePath.join(oldRoot, 'old-tool'), 'utf8')), + ).toBe('keep\n') + expect(yield* pathExists(stagePath(fixture))).toBe(false) + expect(yield* pathExists(fixture.transactionPath)).toBe(false) + }, withNode), + ) + it.effect( 'makes only identity-bound Darwin rename roots writable and re-protects first-publish and exchange results', Effect.fnUntraced(function* () { @@ -608,7 +753,7 @@ describe('cp-a member mount lifecycle', () => { ) it.effect( - 'restores retained Darwin stage and destination roots after an exchange command failure', + 'restores retained Darwin roots and rolls an unretained candidate back after exchange failure', Effect.fnUntraced(function* () { const fixture = yield* makeFixture() yield* firstPublish(fixture) @@ -649,12 +794,13 @@ describe('cp-a member mount lifecycle', () => { }, runtime: { mvPath: fixture.mvPath, platform: 'darwin' }, }) - expect(recovered).toMatchObject({ _tag: 'Recovered', action: 'RolledForward' }) + expect(recovered).toMatchObject({ _tag: 'Recovered', action: 'RolledBack' }) expect( yield* Effect.promise(() => readFile(NodePath.join(fixture.destinationPath, 'version.txt'), 'utf8'), ), - ).toBe('B\n') + ).toBe('A\n') + expect(yield* pathExists(stagePath(fixture))).toBe(false) expect(yield* modeOf(fixture.destinationPath)).toBe(0o555) }, withNode), ) @@ -734,6 +880,8 @@ describe('cp-a member mount lifecycle', () => { 'fsync:FirstPublish', 'fsync:TransactionReplace', 'phase:Exchanged', + 'fsync:TransactionReplace', + 'phase:CapabilitiesRetained', 'fsync:MetadataPublish', 'fsync:TransactionReplace', 'phase:MetadataPublished', @@ -776,10 +924,7 @@ describe('cp-a member mount lifecycle', () => { }) expect(recovered).toMatchObject({ _tag: 'Recovered', - action: - failureReason === 'TransactionCreate' || failureReason === 'StageCreate' - ? 'RolledBack' - : 'RolledForward', + action: failureReason === 'MetadataPublish' ? 'RolledForward' : 'RolledBack', }) expect(yield* pathExists(fixture.transactionPath)).toBe(false) } @@ -949,20 +1094,38 @@ describe('cp-a transaction recovery fault matrix', () => { ) it.effect( - 're-protects a writable staged root before rolling forward a Darwin first publish', + 'rolls back first publication when an unsynced root is lost before the retention marker', Effect.fnUntraced(function* () { const fixture = yield* makeFixture() + const unsyncedRoot = NodePath.join( + fixture.destinationPath, + '.buck2', + 'capability-roots', + 'b'.repeat(64), + 'buck2', + ) yield* firstPublish(fixture, { afterPhase: async (phase) => { - if (phase === 'Staged') throw new Error('crash') + if (phase !== 'Exchanged') return + const buck2Path = NodePath.join(fixture.destinationPath, '.buck2') + await chmod(buck2Path, 0o755) + try { + await mkdir(NodePath.dirname(unsyncedRoot), { recursive: true }) + await writeFile(unsyncedRoot, 'unsynced\n') + } finally { + await chmod(buck2Path, 0o555) + } + throw new Error('crash') }, }).pipe(Effect.result) + yield* Effect.promise(() => unlink(unsyncedRoot)) + expect(yield* pathExists(unsyncedRoot)).toBe(false) expect( yield* Effect.promise(() => - readFile(NodePath.join(stagePath(fixture), 'version.txt'), 'utf8'), + readFile(NodePath.join(fixture.destinationPath, 'version.txt'), 'utf8'), ), ).toBe('A\n') - yield* Effect.promise(() => chmod(stagePath(fixture), 0o755)) + yield* Effect.promise(() => chmod(fixture.destinationPath, 0o755)) const recovered = yield* recoverCpAMemberMount({ request: { workspaceRoot: fixture.workspaceRoot, @@ -971,18 +1134,15 @@ describe('cp-a transaction recovery fault matrix', () => { }, runtime: { mvPath: fixture.mvPath, platform: 'darwin' }, }) - expect(recovered).toMatchObject({ _tag: 'Recovered', action: 'RolledForward' }) - expect( - yield* Effect.promise(() => - readFile(NodePath.join(fixture.destinationPath, 'version.txt'), 'utf8'), - ), - ).toBe('A\n') - expect(yield* modeOf(fixture.destinationPath)).toBe(0o555) + expect(recovered).toMatchObject({ _tag: 'Recovered', action: 'RolledBack' }) + expect(yield* pathExists(fixture.destinationPath)).toBe(false) + expect(yield* pathExists(stagePath(fixture))).toBe(false) + expect(yield* pathExists(fixture.transactionPath)).toBe(false) }, withNode), ) it.effect( - 're-protects exchanged roots left writable by a Darwin crash before rolling forward', + 'rolls an interrupted advance back when exchange landed before the retention marker', Effect.fnUntraced(function* () { const fixture = yield* makeFixture() yield* firstPublish(fixture) @@ -1008,6 +1168,75 @@ describe('cp-a transaction recovery fault matrix', () => { }, runtime: { mvPath: fixture.mvPath, platform: 'darwin' }, }) + expect(recovered).toMatchObject({ _tag: 'Recovered', action: 'RolledBack' }) + expect( + yield* Effect.promise(() => + readFile(NodePath.join(fixture.destinationPath, 'version.txt'), 'utf8'), + ), + ).toBe('A\n') + expect(yield* pathExists(stagePath(fixture))).toBe(false) + expect(yield* pathExists(fixture.transactionPath)).toBe(false) + expect(yield* modeOf(fixture.destinationPath)).toBe(0o555) + }, withNode), + ) + + it.effect( + 'rolls a first publication forward after the durable retention marker', + Effect.fnUntraced(function* () { + const fixture = yield* makeFixture() + let retained = false + yield* firstPublish(fixture, { + retainPublishedCapabilities: async () => { + retained = true + }, + afterPhase: async (phase) => { + if (phase !== 'CapabilitiesRetained') return + expect(retained).toBe(true) + throw new Error('crash') + }, + }).pipe(Effect.result) + const recovered = yield* recoverCpAMemberMount({ + request: { + workspaceRoot: fixture.workspaceRoot, + member: fixture.member, + allowVerifiedDarwinAdvance: false, + }, + runtime: { mvPath: fixture.mvPath, platform: 'linux' }, + }) + expect(recovered).toMatchObject({ _tag: 'Recovered', action: 'RolledForward' }) + expect( + yield* Effect.promise(() => + readFile(NodePath.join(fixture.destinationPath, 'version.txt'), 'utf8'), + ), + ).toBe('A\n') + expect(yield* pathExists(fixture.transactionPath)).toBe(false) + }, withNode), + ) + + it.effect( + 'rolls an advance forward after the durable retention marker', + Effect.fnUntraced(function* () { + const fixture = yield* makeFixture() + yield* firstPublish(fixture) + let retained = false + yield* advance(fixture, { + retainPublishedCapabilities: async () => { + retained = true + }, + afterPhase: async (phase) => { + if (phase !== 'CapabilitiesRetained') return + expect(retained).toBe(true) + throw new Error('crash') + }, + }).pipe(Effect.result) + const recovered = yield* recoverCpAMemberMount({ + request: { + workspaceRoot: fixture.workspaceRoot, + member: fixture.member, + allowVerifiedDarwinAdvance: false, + }, + runtime: { mvPath: fixture.mvPath, platform: 'linux' }, + }) expect(recovered).toMatchObject({ _tag: 'Recovered', action: 'RolledForward' }) expect( yield* Effect.promise(() => @@ -1015,7 +1244,7 @@ describe('cp-a transaction recovery fault matrix', () => { ), ).toBe('B\n') expect(yield* pathExists(stagePath(fixture))).toBe(false) - expect(yield* modeOf(fixture.destinationPath)).toBe(0o555) + expect(yield* pathExists(fixture.transactionPath)).toBe(false) }, withNode), ) diff --git a/packages/@overeng/megarepo/src/composition/mounts/member-mount-cp-a.ts b/packages/@overeng/megarepo/src/composition/mounts/member-mount-cp-a.ts index cf56d05f93..4043f9dea6 100644 --- a/packages/@overeng/megarepo/src/composition/mounts/member-mount-cp-a.ts +++ b/packages/@overeng/megarepo/src/composition/mounts/member-mount-cp-a.ts @@ -118,6 +118,13 @@ export interface CpAMemberMountRuntime extends CpAMemberMountDurabilityRuntime { readonly stagePath: string readonly capabilitiesPath: string }) => Promise + /** + * Retain runtime capability sidecars after publication but before old-tree cleanup. + * Rejection rolls the filesystem publication back. + */ + readonly retainPublishedCapabilities?: (input: { + readonly destinationPath: string + }) => Promise /** Deterministic crash-boundary seam. Throwing preserves the transaction for recovery. */ readonly afterPhase?: (phase: CpAMemberMountPhaseHint) => Promise /** Boundary after the final missing check and immediately before no-clobber first publish. */ @@ -295,7 +302,7 @@ const metadataScanMatches = ({ ) } -const metadataEqual = ({ +const mountAuthorityEqual = ({ left, right, }: { @@ -320,17 +327,6 @@ const metadataEqual = ({ overlay.target === other.target && overlay.destination === other.destination ) - }) && - left.overlays.length === right.overlays.length && - left.overlays.every((overlay, index) => { - const other = right.overlays[index] - return ( - other !== undefined && - overlay.target === other.target && - overlay.destination === other.destination && - overlay.digest === other.digest && - overlay.count === other.count - ) }) interface SourceEntrySnapshot { @@ -1499,7 +1495,7 @@ export const materializeCpAMemberMount = ({ ? 'FirstPublish' : oldIdentity._tag === 'LegacySymlink' ? 'LegacyConversion' - : metadataEqual({ left: oldIdentity.metadata, right: newMetadata }) === true + : mountAuthorityEqual({ left: oldIdentity.metadata, right: newMetadata }) === true ? 'AlreadyCurrent' : 'Advance' const nonce = runtime.nonce?.() ?? `${process.pid}-${randomBytes(8).toString('hex')}` @@ -1524,14 +1520,20 @@ export const materializeCpAMemberMount = ({ stagePath, transactionPath, oldIdentity, - newMetadata, + newMetadata: + operation === 'AlreadyCurrent' && oldIdentity._tag === 'Owned' + ? oldIdentity.metadata + : newMetadata, steps: [...planSteps(operation)], } if (operation === 'AlreadyCurrent') { + if (oldIdentity._tag !== 'Owned') { + throw new TypeError(`Already-current mount '${request.member}' has no owned metadata`) + } return request.dryRun === true ? { _tag: 'DryRun' as const, plan } - : { _tag: 'AlreadyCurrent' as const, destinationPath, metadata: newMetadata } + : { _tag: 'AlreadyCurrent' as const, destinationPath, metadata: oldIdentity.metadata } } if (operation !== 'FirstPublish') { yield* ensureExchangeAllowed({ @@ -1613,6 +1615,43 @@ export const materializeCpAMemberMount = ({ capabilitiesPath: request.capabilitiesPath, cpPath: runtime.cpPath, }) + yield* io({ + path: NodePath.join(stagePath, '.buck2', 'capability-roots'), + message: `Cannot strip runtime capability roots from candidate '${stagePath}'`, + reason: 'StageInvalid', + try: () => + rm(NodePath.join(stagePath, '.buck2', 'capability-roots'), { + recursive: true, + force: true, + }), + }) + if (oldIdentity._tag === 'Owned') { + const liveRootsPath = NodePath.join(destinationPath, '.buck2', 'capability-roots') + const liveRoots = yield* lstatMaybe(liveRootsPath) + if (liveRoots !== undefined) { + if (liveRoots.isDirectory() === false || liveRoots.isSymbolicLink() === true) { + return yield* error({ + reason: 'DestinationRefused', + path: liveRootsPath, + message: `Published capability roots are not a directory for '${request.member}'`, + recoveryPaths: [destinationPath, stagePath, transactionPath], + }) + } + const stagedRootsPath = NodePath.join(stagePath, '.buck2', 'capability-roots') + yield* io({ + path: stagedRootsPath, + message: `Cannot prepare retained capability roots in candidate '${stagePath}'`, + reason: 'StageInvalid', + try: () => mkdir(stagedRootsPath, { recursive: true }), + }) + yield* runCommand({ + binary: runtime.cpPath, + args: ['-a', `${liveRootsPath}${NodePath.sep}.`, stagedRootsPath], + path: stagedRootsPath, + commandName: 'GNU cp -a retained capability roots copy', + }) + } + } yield* io({ path: stagePath, message: `Capability check failed for cp-a candidate '${stagePath}'`, @@ -1764,6 +1803,78 @@ export const materializeCpAMemberMount = ({ } yield* assertOldAtStage({ stagePath, oldIdentity }) } + if (runtime.retainPublishedCapabilities !== undefined) { + const retentionResult = yield* io({ + path: destinationPath, + message: `Cannot retain published capabilities for '${request.member}'`, + reason: 'CapabilityRetentionFailed', + recoveryPaths: [destinationPath, stagePath, transactionPath], + try: () => runtime.retainPublishedCapabilities!({ destinationPath }), + }).pipe(Effect.result) + if (retentionResult._tag === 'Failure') { + const rollbackRoots = [ + { path: destinationPath, identity: candidateIdentity }, + ...(operation !== 'FirstPublish' && oldIdentity._tag === 'Owned' + ? [{ path: stagePath, identity: oldIdentity.identity }] + : []), + ] + yield* withDarwinMovableProtectedRoots({ + platform: runtime.platform ?? process.platform, + roots: rollbackRoots, + recoveryPaths: [destinationPath, stagePath, transactionPath], + effect: runCommand({ + binary: runtime.mvPath, + args: + operation === 'FirstPublish' + ? ['-T', '--no-clobber', '--no-copy', destinationPath, stagePath] + : ['-T', '--exchange', '--no-copy', stagePath, destinationPath], + path: destinationPath, + commandName: 'GNU mv capability-retention rollback', + recoveryPaths: [destinationPath, stagePath, transactionPath], + }), + }) + yield* syncDirectory({ + runtime, + path: NodePath.dirname(destinationPath), + reason: 'Exchange', + }) + if (operation === 'FirstPublish') { + if ((yield* lstatMaybe(destinationPath)) !== undefined) { + return yield* error({ + reason: 'ExchangeValidationFailed', + path: destinationPath, + message: 'Capability-retention rollback left the first-published candidate live', + recoveryPaths: [destinationPath, stagePath, transactionPath], + }) + } + } else { + if (oldIdentity._tag === 'Missing') { + return yield* error({ + reason: 'ExchangeValidationFailed', + path: destinationPath, + message: 'Capability-retention rollback lost its recorded old identity', + recoveryPaths: [destinationPath, stagePath, transactionPath], + }) + } + yield* assertOldAtStage({ stagePath: destinationPath, oldIdentity }) + } + yield* teardownBoundDirectory({ path: stagePath, identity: candidateIdentity }) + yield* syncDirectory({ + runtime, + path: NodePath.dirname(stagePath), + reason: 'CandidateCleanup', + }) + yield* removeTransaction({ path: transactionPath, runtime }) + return yield* retentionResult.failure + } + } + transaction = yield* updatePhase({ + transactionPath, + transaction, + phaseHint: 'CapabilitiesRetained', + runtime, + }) + yield* runPhaseHook({ runtime, phase: 'CapabilitiesRetained', transaction }) yield* writeOwnedCpAMountMetadata({ workspaceRoot: request.workspaceRoot, metadata: newMetadata, @@ -1949,9 +2060,9 @@ const publishMetadataFromTransaction = ({ }) /** - * Reconcile process interruption from observed inode and R6 identities, never phase hints. Directory - * fsync checkpoints order namespace durability across power loss; they do not fsync every staged file - * byte, so recovery treats failed R6 observation as ambiguous rather than claiming full byte durability. + * Reconcile process interruption from observed inode/R6 identities plus the fsync'd capability + * retention commit marker. Before that marker recovery rolls publication back; afterward it may + * safely publish metadata and clean the old tree. */ export const recoverCpAMemberMount = ({ request: untrustedRequest, @@ -2001,6 +2112,145 @@ export const recoverCpAMemberMount = ({ } }) + const capabilitiesRetained = + transaction.phaseHint === 'CapabilitiesRetained' || + transaction.phaseHint === 'MetadataPublished' || + transaction.phaseHint === 'Cleanup' + + if (capabilitiesRetained === false) { + if (transaction.operation === 'FirstPublish') { + if (destination._tag === 'Missing' && stage._tag === 'Missing') { + yield* removeTransaction({ path: transactionPath, runtime }) + return { + _tag: 'Recovered' as const, + action: 'RolledBack' as const, + destinationPath: transaction.destinationPath, + } + } + if ( + destination._tag === 'Missing' && + (stage._tag === 'New' || stage._tag === 'NewPartial') + ) { + return yield* rollbackCandidate + } + if (destination._tag === 'New' && stage._tag === 'Missing') { + const candidateIdentity = transaction.newIdentity.candidateIdentity + if (candidateIdentity === null) { + return yield* error({ + reason: 'AmbiguousRecovery', + path: transaction.destinationPath, + message: 'Cannot roll back an unretained publication without its candidate identity', + recoveryPaths: [transaction.destinationPath, transaction.stagePath, transactionPath], + }) + } + const recoveryPaths = [ + transaction.destinationPath, + transaction.stagePath, + transactionPath, + ] + yield* withDarwinMovableProtectedRoots({ + platform, + roots: [{ path: transaction.destinationPath, identity: candidateIdentity }], + recoveryPaths, + effect: runCommand({ + binary: runtime.mvPath, + args: [ + '-T', + '--no-clobber', + '--no-copy', + transaction.destinationPath, + transaction.stagePath, + ], + path: transaction.destinationPath, + commandName: 'GNU mv recovery capability-retention rollback', + recoveryPaths, + }), + }) + yield* syncDirectory({ + runtime, + path: NodePath.dirname(transaction.destinationPath), + reason: 'Exchange', + }) + return yield* rollbackCandidate + } + } else { + if (destination._tag === 'Old' && stage._tag === 'Missing') { + yield* removeTransaction({ path: transactionPath, runtime }) + return { + _tag: 'Recovered' as const, + action: 'RolledBack' as const, + destinationPath: transaction.destinationPath, + } + } + if (destination._tag === 'Old' && (stage._tag === 'New' || stage._tag === 'NewPartial')) { + return yield* rollbackCandidate + } + if (destination._tag === 'New' && stage._tag === 'Old') { + const candidateIdentity = transaction.newIdentity.candidateIdentity + const recoveryPaths = [ + transaction.destinationPath, + transaction.stagePath, + transactionPath, + ] + yield* withDarwinMovableProtectedRoots({ + platform, + roots: [ + ...(candidateIdentity === null + ? [] + : [{ path: transaction.destinationPath, identity: candidateIdentity }]), + ...(transaction.oldIdentity._tag === 'Owned' + ? [ + { + path: transaction.stagePath, + identity: transaction.oldIdentity.identity, + }, + ] + : []), + ], + recoveryPaths, + effect: runCommand({ + binary: runtime.mvPath, + args: [ + '-T', + '--exchange', + '--no-copy', + transaction.stagePath, + transaction.destinationPath, + ], + path: transaction.destinationPath, + commandName: 'GNU mv recovery capability-retention exchange rollback', + recoveryPaths, + }), + }) + yield* syncDirectory({ + runtime, + path: NodePath.dirname(transaction.destinationPath), + reason: 'Exchange', + }) + if (transaction.oldIdentity._tag === 'Missing') { + return yield* error({ + reason: 'AmbiguousRecovery', + path: transaction.destinationPath, + message: 'Recovery exchange rollback lacks the recorded old identity', + recoveryPaths, + }) + } + yield* assertOldAtStage({ + stagePath: transaction.destinationPath, + oldIdentity: transaction.oldIdentity, + }) + return yield* rollbackCandidate + } + } + return yield* error({ + reason: 'AmbiguousRecovery', + path: transactionPath, + message: 'Unretained mount transaction cannot be rolled back from observed identities', + recoveryPaths: [transaction.destinationPath, transaction.stagePath, transactionPath], + cause: { destination: destination._tag, stage: stage._tag }, + }) + } + if (transaction.operation === 'FirstPublish') { if (destination._tag === 'Missing' && stage._tag === 'Missing') { yield* removeTransaction({ path: transactionPath, runtime }) diff --git a/packages/@overeng/megarepo/src/composition/mounts/member-mount-r6.integration.test.ts b/packages/@overeng/megarepo/src/composition/mounts/member-mount-r6.integration.test.ts index 149be35142..fcbdfe769e 100644 --- a/packages/@overeng/megarepo/src/composition/mounts/member-mount-r6.integration.test.ts +++ b/packages/@overeng/megarepo/src/composition/mounts/member-mount-r6.integration.test.ts @@ -33,9 +33,11 @@ const withNode = ( const makeTree = ({ root, capabilities = true, + capabilityRoots = false, }: { root: string capabilities?: boolean + capabilityRoots?: boolean }): Effect.Effect => Effect.gen(function* () { const fs = yield* FileSystem.FileSystem @@ -58,6 +60,15 @@ const makeTree = ({ recursive: true, }) } + if (capabilityRoots === true) { + yield* fs.makeDirectory(NodePath.join(root, '.buck2', 'capability-roots', 'a'.repeat(64)), { + recursive: true, + }) + yield* fs.writeFileString( + NodePath.join(root, '.buck2', 'capability-roots', 'a'.repeat(64), 'sentinel'), + 'ignored by repository identity\n', + ) + } }) const setTreeModes = ({ @@ -108,7 +119,7 @@ const setTreeWritable = (root: string): Effect.Effect => const makeFixture = ( policy: 'artifact' | 'source' | 'protected', - options?: { capabilities?: boolean }, + options?: { capabilities?: boolean; capabilityRoots?: boolean }, ): Effect.Effect => Effect.gen(function* () { const fs = yield* FileSystem.FileSystem @@ -119,6 +130,9 @@ const makeFixture = ( yield* makeTree({ root, ...(options?.capabilities === undefined ? {} : { capabilities: options.capabilities }), + ...(options?.capabilityRoots === undefined + ? {} + : { capabilityRoots: options.capabilityRoots }), }) yield* setTreeModes({ root, policy }) return root @@ -241,6 +255,24 @@ describe('R6 source and protected scans', () => { }, withNode), ) + it.effect( + 'excludes durable capability roots from protected repository identity', + Effect.fnUntraced(function* () { + const unrooted = yield* makeFixture('protected') + const rooted = yield* makeFixture('protected', { capabilityRoots: true }) + const unrootedScan = yield* scanR6ProtectedMount({ root: unrooted }) + const rootedScan = yield* scanR6ProtectedMount({ root: rooted }) + + expect(rootedScan.repository).toEqual(unrootedScan.repository) + expect(rootedScan.capabilities).toEqual(unrootedScan.capabilities) + expect( + rootedScan.repository.manifest.entries.some((entry) => + entry.path.startsWith('.buck2/capability-roots'), + ), + ).toBe(false) + }, withNode), + ) + it.effect( 'normalizes writable Buck artifact modes into the protected R6 identity', Effect.fnUntraced(function* () { diff --git a/packages/@overeng/megarepo/src/composition/mounts/member-mount-r6.ts b/packages/@overeng/megarepo/src/composition/mounts/member-mount-r6.ts index d66255a068..9eb4bc00c0 100644 --- a/packages/@overeng/megarepo/src/composition/mounts/member-mount-r6.ts +++ b/packages/@overeng/megarepo/src/composition/mounts/member-mount-r6.ts @@ -46,6 +46,8 @@ import { inspectMemberMount } from './member-mount.ts' export const R6_MANIFEST_VERSION = 1 as const /** Owned cp-a mount metadata wire version. */ export const OWNED_CP_A_MOUNT_METADATA_VERSION = 2 as const +/** Runtime-managed Nix roots must not alter immutable repository identity. */ +const R6_CAPABILITY_ROOTS_DESTINATION = '.buck2/capability-roots' const Sha256 = Schema.String.check(Schema.isPattern(/^sha256:[0-9a-f]{64}$/u)) const CanonicalRelativePath = Schema.String.check( @@ -611,7 +613,11 @@ const scanTreePromise = async ({ entries.push({ path: manifestChild, kind: 'symlink', mode: null, payload: target }) } else if (info.isDirectory() === true) { validateMode({ policy, kind: 'directory', mode: info.mode, path: childPath }) - if (manifestChild !== '.buck2' || excludedSubtrees.has('.buck2/capabilities') === false) { + if ( + manifestChild !== '.buck2' || + (excludedSubtrees.has(R6_CAPABILITIES_DESTINATION) === false && + excludedSubtrees.has(R6_CAPABILITY_ROOTS_DESTINATION) === false) + ) { entries.push({ path: manifestChild, kind: 'directory', mode: 0o555, payload: null }) } await visit({ actualRelative: actualChild, manifestRelative: manifestChild }) @@ -750,6 +756,7 @@ const scanMount = ({ } const excludedSubtrees = new Set([ R6_CAPABILITIES_DESTINATION, + R6_CAPABILITY_ROOTS_DESTINATION, ...canonicalOverlays.map((overlay) => overlay.destination), ]) const repositoryResult = await scanTreePromise({ diff --git a/packages/@overeng/megarepo/src/composition/root/composition-root-publisher.integration.test.ts b/packages/@overeng/megarepo/src/composition/root/composition-root-publisher.integration.test.ts index 7155b89e46..2c47d47a8e 100644 --- a/packages/@overeng/megarepo/src/composition/root/composition-root-publisher.integration.test.ts +++ b/packages/@overeng/megarepo/src/composition/root/composition-root-publisher.integration.test.ts @@ -46,6 +46,7 @@ const generatedPaths = [ '.buckroot', '.megarepo/bin/buck2', COMPOSITION_GENERATION_MANIFEST_PATH, + '.watchmanconfig', 'BUCK', '.buckconfig', ] as const @@ -304,6 +305,22 @@ const addLegacyGeneratedStubs = async (fixture: Fixture): Promise => { await writeFile(manifestPath, `${JSON.stringify(manifest, undefined, 2)}\n`) } +const removeGenerationManifestRecord = async ({ + fixture, + path, +}: { + readonly fixture: Fixture + readonly path: string +}): Promise => { + const manifestPath = NodePath.join(fixture.root, COMPOSITION_GENERATION_MANIFEST_PATH) + const manifest = JSON.parse(await readFile(manifestPath, 'utf8')) as { + schemaVersion: 1 + files: Array<{ path: string; mode: number; sha256: string }> + } + manifest.files = manifest.files.filter((file) => file.path !== path) + await writeFile(manifestPath, `${JSON.stringify(manifest, undefined, 2)}\n`) +} + describe('composition root publisher', () => { it.effect('plans first-create bytes without mutating the filesystem', () => Effect.scoped( @@ -370,6 +387,61 @@ describe('composition root publisher', () => { ), ) + it.effect('upgrades an old valid manifest when its newly required path is absent', () => + Effect.scoped( + Effect.gen(function* () { + const fixture = yield* makeFixture() + yield* publishCompositionRoot( + optionsFor({ fixture, lockToken: 'missing-required-seed-token' }), + ) + yield* Effect.promise(async () => { + await removeGenerationManifestRecord({ fixture, path: '.watchmanconfig' }) + await rm(NodePath.join(fixture.root, '.watchmanconfig')) + }) + + const result = yield* publishCompositionRoot( + optionsFor({ fixture, lockToken: 'missing-required-upgrade-token' }), + ) + + expect(result.changedPaths).toContain('.watchmanconfig') + expect((yield* readGenerated(fixture, '.watchmanconfig')).toString()).toBe('{}\n') + const upgradedManifest = JSON.parse( + (yield* readGenerated(fixture, COMPOSITION_GENERATION_MANIFEST_PATH)).toString(), + ) as { files: Array<{ path: string }> } + expect(upgradedManifest.files.map((file) => file.path)).toContain('.watchmanconfig') + }), + ), + ) + + it.effect('refuses an unowned path omitted from an old valid manifest', () => + Effect.scoped( + Effect.gen(function* () { + const fixture = yield* makeFixture() + yield* publishCompositionRoot( + optionsFor({ fixture, lockToken: 'unowned-required-seed-token' }), + ) + yield* Effect.promise(() => + removeGenerationManifestRecord({ fixture, path: '.watchmanconfig' }), + ) + const manifestBefore = yield* readGenerated(fixture, COMPOSITION_GENERATION_MANIFEST_PATH) + const watchmanBefore = yield* readGenerated(fixture, '.watchmanconfig') + + const error = yield* failureReason( + publishCompositionRoot( + optionsFor({ fixture, lockToken: 'unowned-required-conflict-token' }), + ), + ) + + expect(error.reason).toBe('ForeignPath') + expect(error.path).toBe(NodePath.join(fixture.root, '.watchmanconfig')) + expect(yield* readGenerated(fixture, COMPOSITION_GENERATION_MANIFEST_PATH)).toEqual( + manifestBefore, + ) + expect(yield* readGenerated(fixture, '.watchmanconfig')).toEqual(watchmanBefore) + }), + ), + ) + it.effect('plans foreign ownership as Refused without repairing or mutating it', () => Effect.scoped( Effect.gen(function* () { diff --git a/packages/@overeng/megarepo/src/composition/root/composition-root-publisher.ts b/packages/@overeng/megarepo/src/composition/root/composition-root-publisher.ts index 5d6bd2b68b..29c93e27eb 100644 --- a/packages/@overeng/megarepo/src/composition/root/composition-root-publisher.ts +++ b/packages/@overeng/megarepo/src/composition/root/composition-root-publisher.ts @@ -1473,16 +1473,6 @@ const validatePublicationState = async ({ }) } manifest = decodeGenerationManifest({ snapshot: manifestSnapshot, path: manifestPath }) - const manifestPaths = new Set(manifest.files.map((file) => file.path)) - for (const expectedPath of expectedGeneratedPaths(files)) { - if (manifestPaths.has(expectedPath) === false) { - throw failure({ - reason: 'InvalidGenerationManifest', - path: manifestPath, - message: `Generation manifest does not own required path ${expectedPath}: ${manifestPath}`, - }) - } - } } const configPath = finalPathFor(workspaceRoot, '.buckconfig') if (manifest === undefined && (await snapshotMaybe(configPath)) !== undefined) { @@ -1494,6 +1484,7 @@ const validatePublicationState = async ({ } const desiredPaths = new Set(expectedGeneratedPaths(files)) + const manifestPaths = new Set(manifest?.files.map((file) => file.path)) const obsoleteFiles: ObsoleteGeneratedFile[] = [] if (manifest !== undefined) { for (const record of manifest.files) { @@ -1532,6 +1523,18 @@ const validatePublicationState = async ({ ? manifestSnapshot : await snapshotMaybe(path) snapshots.set(file.path, snapshot) + if ( + manifest !== undefined && + file.path !== COMPOSITION_GENERATION_MANIFEST_PATH && + manifestPaths.has(file.path) === false && + snapshot !== undefined + ) { + throw failure({ + reason: 'ForeignPath', + path, + message: `Refusing unowned path missing from generation manifest: ${path}`, + }) + } if ( manifest === undefined && snapshot !== undefined && @@ -2312,7 +2315,13 @@ const validateTeardownState = async ({ }) } const manifest = decodeGenerationManifest({ snapshot: manifestSnapshot, path: manifestPath }) - const canonical = ['.buckconfig', '.buckroot', '.megarepo/bin/buck2', 'BUCK'].toSorted() + const canonical = [ + '.buckconfig', + '.buckroot', + '.megarepo/bin/buck2', + '.watchmanconfig', + 'BUCK', + ].toSorted() assertManifestShape({ manifest, expectedPaths: canonical, path: manifestPath }) const files = new Map() for (const record of manifest.files) { diff --git a/packages/@overeng/megarepo/src/composition/root/composition-root.ts b/packages/@overeng/megarepo/src/composition/root/composition-root.ts index b8f0c6e13b..9d39ad0ff1 100644 --- a/packages/@overeng/megarepo/src/composition/root/composition-root.ts +++ b/packages/@overeng/megarepo/src/composition/root/composition-root.ts @@ -940,6 +940,7 @@ export const generateCompositionRoot = (rawInput: CompositionRootInput): Composi }) const ownedFiles: ReadonlyArray = [ generatedFile({ path: '.buckroot', mode: 0o644, content: '' }), + generatedFile({ path: '.watchmanconfig', mode: 0o644, content: '{}\n' }), generatedFile({ path: 'BUCK', mode: 0o644, content: '' }), generatedFile({ path: '.megarepo/bin/buck2', diff --git a/packages/@overeng/megarepo/src/composition/root/composition-root.unit.test.ts b/packages/@overeng/megarepo/src/composition/root/composition-root.unit.test.ts index e645c7ac0a..a88cd68bd7 100644 --- a/packages/@overeng/megarepo/src/composition/root/composition-root.unit.test.ts +++ b/packages/@overeng/megarepo/src/composition/root/composition-root.unit.test.ts @@ -481,6 +481,7 @@ describe('composition root goldens', () => { ignore = **/node_modules,**/node_modules/**,**/target,**/target/**,.buck2/capabilities.candidate.*,.devenv,.git,buck-out,node_modules,repos/.staging-*,repos/alpha/**/dist,repos/alpha/.git,target,tmp `) expect(output.get('.buckroot')?.bytes).toHaveLength(0) + expect(text(output.get('.watchmanconfig')!)).toBe('{}\n') expect(output.get('BUCK')?.bytes).toHaveLength(0) }) @@ -747,6 +748,7 @@ describe('generation manifest and output schema', () => { '.buckroot', '.megarepo/bin/buck2', '.megarepo/composition-generation.json', + '.watchmanconfig', 'BUCK', '.buckconfig', ]) diff --git a/packages/@overeng/megarepo/src/generators/generators.unit.test.ts b/packages/@overeng/megarepo/src/generators/generators.unit.test.ts index 2a2dbdd126..5462d4305a 100644 --- a/packages/@overeng/megarepo/src/generators/generators.unit.test.ts +++ b/packages/@overeng/megarepo/src/generators/generators.unit.test.ts @@ -235,6 +235,20 @@ describe('getEnabledGenerators', () => { expect(files).toContain('.vscode/megarepo.code-workspace') expect(files).not.toContain('schema/megarepo.schema.json') }) + it('should include every composition root file when composition generation is enabled', () => { + const files = getEnabledGenerators({ + members: {}, + generators: { composition: { enabled: true, platformHub: 'effect-utils' } }, + }) + + expect(files).toEqual([ + '.buckroot', + '.buckconfig', + '.watchmanconfig', + 'BUCK', + '.megarepo/bin/buck2', + ]) + }) it('should return empty array when generators explicitly disabled', () => { const files = getEnabledGenerators({ diff --git a/packages/@overeng/megarepo/src/generators/mod.ts b/packages/@overeng/megarepo/src/generators/mod.ts index da96e236a7..c6c8dcd12a 100644 --- a/packages/@overeng/megarepo/src/generators/mod.ts +++ b/packages/@overeng/megarepo/src/generators/mod.ts @@ -34,7 +34,7 @@ export const getEnabledGenerators = (config: MegarepoConfig): string[] => { generators.push('.vscode/megarepo.code-workspace') } if (config.generators?.composition?.enabled === true) { - generators.push('.buckroot', '.buckconfig', 'BUCK', '.megarepo/bin/buck2') + generators.push('.buckroot', '.buckconfig', '.watchmanconfig', 'BUCK', '.megarepo/bin/buck2') } return generators } diff --git a/packages/@overeng/megarepo/tsconfig.json b/packages/@overeng/megarepo/tsconfig.json index 50fb610fa0..7d5a81fd04 100644 --- a/packages/@overeng/megarepo/tsconfig.json +++ b/packages/@overeng/megarepo/tsconfig.json @@ -50,16 +50,12 @@ "node", "bun" ], - "jsx": "react-jsx" + "jsx": "react-jsx", + "noEmit": true }, "include": [ "src/**/*", "test/**/*", "bin/**/*" - ], - "references": [ - { - "path": "../kdl-effect" - } ] } diff --git a/packages/@overeng/megarepo/tsconfig.json.genie.ts b/packages/@overeng/megarepo/tsconfig.json.genie.ts index ad9d96881a..e3e674775d 100644 --- a/packages/@overeng/megarepo/tsconfig.json.genie.ts +++ b/packages/@overeng/megarepo/tsconfig.json.genie.ts @@ -13,7 +13,7 @@ export default tsconfigJson({ ...nodeTypes, ...reactJsx, types: ['node', 'bun'], + noEmit: true, }, include: ['src/**/*', 'test/**/*', 'bin/**/*'], - references: [{ path: '../kdl-effect' }], } satisfies TSConfigArgs) diff --git a/packages/@overeng/notion-cli/BUCK b/packages/@overeng/notion-cli/BUCK index c0f6a29477..df5f78632b 100644 --- a/packages/@overeng/notion-cli/BUCK +++ b/packages/@overeng/notion-cli/BUCK @@ -5,14 +5,15 @@ load("//buck2:package_tools.bzl", "package_bin_artifact") load("//buck2/products:defs.bzl", "javascript_product") # Projection source: packages/@overeng/notion-cli/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:78c3dbc30a361b9d2944429d071ee08e0216e29a4f68af2e5f5f0284cc3fc4ec -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/effect-path/BUCK.genie.ts, packages/@overeng/effect-path/package.json.genie.ts, packages/@overeng/notion-cli/BUCK.genie.ts, packages/@overeng/notion-cli/BUCK.genie.ts, packages/@overeng/notion-cli/package.json.genie.ts, packages/@overeng/notion-cli/src/**/*.cts, packages/@overeng/notion-cli/src/**/*.js, packages/@overeng/notion-cli/src/**/*.mts, packages/@overeng/notion-cli/src/**/*.spec.cjs, packages/@overeng/notion-cli/src/**/*.spec.jsx, packages/@overeng/notion-cli/src/**/*.spec.mjs, packages/@overeng/notion-cli/src/**/*.test.cjs, packages/@overeng/notion-cli/src/**/*.test.jsx, packages/@overeng/notion-cli/src/**/*.test.mjs, packages/@overeng/notion-cli/src/**/*.ts, packages/@overeng/notion-cli/src/**/*.tsx, packages/@overeng/notion-cli/src/**/__snapshots__/*.snap, packages/@overeng/notion-cli/tsconfig.json.genie.ts, packages/@overeng/notion-datasource-sync/BUCK.genie.ts, packages/@overeng/notion-datasource-sync/package.json.genie.ts, packages/@overeng/notion-effect-client/BUCK.genie.ts, packages/@overeng/notion-effect-client/package.json.genie.ts, packages/@overeng/notion-effect-schema/BUCK.genie.ts, packages/@overeng/notion-effect-schema/package.json.genie.ts, packages/@overeng/notion-md/BUCK.genie.ts, packages/@overeng/notion-md/package.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/tui-core/BUCK.genie.ts, packages/@overeng/tui-core/package.json.genie.ts, packages/@overeng/tui-react/BUCK.genie.ts, packages/@overeng/tui-react/package.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts +# Semantic fingerprint: sha256:3a9e7d71f53dd033a883cfa101b02374a987fa02395f5f02f8fab9ca9efc7f03 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/effect-path/BUCK.genie.ts, packages/@overeng/effect-path/package.json.genie.ts, packages/@overeng/notion-cli/BUCK.genie.ts, packages/@overeng/notion-cli/BUCK.genie.ts, packages/@overeng/notion-cli/package.json.genie.ts, packages/@overeng/notion-cli/src/**/*.cts, packages/@overeng/notion-cli/src/**/*.js, packages/@overeng/notion-cli/src/**/*.mts, packages/@overeng/notion-cli/src/**/*.spec.cjs, packages/@overeng/notion-cli/src/**/*.spec.jsx, packages/@overeng/notion-cli/src/**/*.spec.mjs, packages/@overeng/notion-cli/src/**/*.test.cjs, packages/@overeng/notion-cli/src/**/*.test.jsx, packages/@overeng/notion-cli/src/**/*.test.mjs, packages/@overeng/notion-cli/src/**/*.ts, packages/@overeng/notion-cli/src/**/*.tsx, packages/@overeng/notion-cli/src/**/__snapshots__/*.snap, packages/@overeng/notion-cli/tsconfig.json.genie.ts, packages/@overeng/notion-datasource-sync/BUCK.genie.ts, packages/@overeng/notion-datasource-sync/package.json.genie.ts, packages/@overeng/notion-effect-client/BUCK.genie.ts, packages/@overeng/notion-effect-client/package.json.genie.ts, packages/@overeng/notion-effect-schema/BUCK.genie.ts, packages/@overeng/notion-effect-schema/package.json.genie.ts, packages/@overeng/notion-md/BUCK.genie.ts, packages/@overeng/notion-md/package.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/tui-core/BUCK.genie.ts, packages/@overeng/tui-core/package.json.genie.ts, packages/@overeng/tui-react/BUCK.genie.ts, packages/@overeng/tui-react/package.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -74,6 +75,14 @@ export_materialization_inputs([ "src/renderers/shared/mod.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/notion-cli", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_notion_cli_b91b1e6ae4c6", @@ -176,7 +185,7 @@ package_view( "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -274,7 +283,7 @@ package_view( "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/notion-cli/BUCK.genie.ts b/packages/@overeng/notion-cli/BUCK.genie.ts index b380488a1a..d71141b424 100644 --- a/packages/@overeng/notion-cli/BUCK.genie.ts +++ b/packages/@overeng/notion-cli/BUCK.genie.ts @@ -61,11 +61,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils-dev:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/notion-cli/docs/spec.md b/packages/@overeng/notion-cli/docs/spec.md index 31296eb251..ba1faef8ef 100644 --- a/packages/@overeng/notion-cli/docs/spec.md +++ b/packages/@overeng/notion-cli/docs/spec.md @@ -159,7 +159,7 @@ Trace: R14-R16. | `devenv tasks run test:notion-cli` | root command composition, help/completion drift, schema/db package tests | | `devenv tasks run test:notion-datasource-sync` | datasource-backed `db` leaves and export behavior | | `devenv tasks run genie:check` | generated package metadata is current | -| `devenv tasks run ts:check` | TypeScript surface is valid | +| `devenv tasks run buck2:check` | TypeScript surface is valid | | `devenv tasks run lint:check` | formatting, lint, lockfile, and generated-source coverage are valid | | `devenv tasks run check:quick` | aggregate quick gate for branch readiness | | `nix build .#notion-cli --no-link` | packaged wrapper includes all runtime files and routes Node-backed `db` leaves | diff --git a/packages/@overeng/notion-core/BUCK b/packages/@overeng/notion-core/BUCK index b8321ea0f0..97bc2b79e7 100644 --- a/packages/@overeng/notion-core/BUCK +++ b/packages/@overeng/notion-core/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/notion-core/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:b085ab52cb2d3b11f737882f810c993333eb948cfdc6758b2c65113684f9b9a7 -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/notion-core/BUCK.genie.ts, packages/@overeng/notion-core/BUCK.genie.ts, packages/@overeng/notion-core/package.json.genie.ts, packages/@overeng/notion-core/src/**/*.cts, packages/@overeng/notion-core/src/**/*.js, packages/@overeng/notion-core/src/**/*.mts, packages/@overeng/notion-core/src/**/*.spec.cjs, packages/@overeng/notion-core/src/**/*.spec.jsx, packages/@overeng/notion-core/src/**/*.spec.mjs, packages/@overeng/notion-core/src/**/*.test.cjs, packages/@overeng/notion-core/src/**/*.test.jsx, packages/@overeng/notion-core/src/**/*.test.mjs, packages/@overeng/notion-core/src/**/*.ts, packages/@overeng/notion-core/src/**/*.tsx, packages/@overeng/notion-core/src/**/__snapshots__/*.snap, packages/@overeng/notion-core/tsconfig.json.genie.ts +# Semantic fingerprint: sha256:50972e98bdfb44723ee83d1e1c335da599ec2ff227c7cf99a642dbd80e39a409 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/notion-core/BUCK.genie.ts, packages/@overeng/notion-core/BUCK.genie.ts, packages/@overeng/notion-core/package.json.genie.ts, packages/@overeng/notion-core/src/**/*.cts, packages/@overeng/notion-core/src/**/*.js, packages/@overeng/notion-core/src/**/*.mts, packages/@overeng/notion-core/src/**/*.spec.cjs, packages/@overeng/notion-core/src/**/*.spec.jsx, packages/@overeng/notion-core/src/**/*.spec.mjs, packages/@overeng/notion-core/src/**/*.test.cjs, packages/@overeng/notion-core/src/**/*.test.jsx, packages/@overeng/notion-core/src/**/*.test.mjs, packages/@overeng/notion-core/src/**/*.ts, packages/@overeng/notion-core/src/**/*.tsx, packages/@overeng/notion-core/src/**/__snapshots__/*.snap, packages/@overeng/notion-core/tsconfig.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -35,6 +36,14 @@ export_materialization_inputs([ "src/rich-text.unit.test.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/notion-core", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_notion_core_bbf3eb334469", @@ -71,7 +80,7 @@ package_view( }, workspace_dependency_views = { }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -102,7 +111,7 @@ package_view( workspace_dependency_views = { }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/notion-core/BUCK.genie.ts b/packages/@overeng/notion-core/BUCK.genie.ts index 36485b1c4c..8cc90a9454 100644 --- a/packages/@overeng/notion-core/BUCK.genie.ts +++ b/packages/@overeng/notion-core/BUCK.genie.ts @@ -7,11 +7,7 @@ export const buck2TypeScriptAdmission = { packagePath: 'packages/@overeng/notion-core', projectionSource: 'packages/@overeng/notion-core/BUCK.genie.ts', sourceRoots: ['src'], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/notion-datasource-sync/BUCK b/packages/@overeng/notion-datasource-sync/BUCK index 1f79b6506e..d2a0dcf184 100644 --- a/packages/@overeng/notion-datasource-sync/BUCK +++ b/packages/@overeng/notion-datasource-sync/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/notion-datasource-sync/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:4e7b78dd99efbaa4d900aee6930d32ad79a386ae8e1069819edfc1fce3f354f3 -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/content-address/BUCK.genie.ts, packages/@overeng/content-address/package.json.genie.ts, packages/@overeng/notion-core/BUCK.genie.ts, packages/@overeng/notion-core/package.json.genie.ts, packages/@overeng/notion-datasource-sync/BUCK.genie.ts, packages/@overeng/notion-datasource-sync/BUCK.genie.ts, packages/@overeng/notion-datasource-sync/package.json.genie.ts, packages/@overeng/notion-datasource-sync/src/**/*.cts, packages/@overeng/notion-datasource-sync/src/**/*.js, packages/@overeng/notion-datasource-sync/src/**/*.mts, packages/@overeng/notion-datasource-sync/src/**/*.spec.cjs, packages/@overeng/notion-datasource-sync/src/**/*.spec.jsx, packages/@overeng/notion-datasource-sync/src/**/*.spec.mjs, packages/@overeng/notion-datasource-sync/src/**/*.test.cjs, packages/@overeng/notion-datasource-sync/src/**/*.test.jsx, packages/@overeng/notion-datasource-sync/src/**/*.test.mjs, packages/@overeng/notion-datasource-sync/src/**/*.ts, packages/@overeng/notion-datasource-sync/src/**/*.tsx, packages/@overeng/notion-datasource-sync/src/**/__snapshots__/*.snap, packages/@overeng/notion-datasource-sync/tsconfig.json.genie.ts, packages/@overeng/notion-effect-client/BUCK.genie.ts, packages/@overeng/notion-effect-client/package.json.genie.ts, packages/@overeng/notion-effect-schema/BUCK.genie.ts, packages/@overeng/notion-effect-schema/package.json.genie.ts, packages/@overeng/notion-md/BUCK.genie.ts, packages/@overeng/notion-md/package.json.genie.ts, packages/@overeng/notion-property-write/BUCK.genie.ts, packages/@overeng/notion-property-write/package.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/tui-react/BUCK.genie.ts, packages/@overeng/tui-react/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts +# Semantic fingerprint: sha256:8536b26d6fecfe3d7bb1ccc3132c7dfd198f739600369b2796aba8d41aa2825e +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/content-address/BUCK.genie.ts, packages/@overeng/content-address/package.json.genie.ts, packages/@overeng/notion-core/BUCK.genie.ts, packages/@overeng/notion-core/package.json.genie.ts, packages/@overeng/notion-datasource-sync/BUCK.genie.ts, packages/@overeng/notion-datasource-sync/BUCK.genie.ts, packages/@overeng/notion-datasource-sync/package.json.genie.ts, packages/@overeng/notion-datasource-sync/src/**/*.cts, packages/@overeng/notion-datasource-sync/src/**/*.js, packages/@overeng/notion-datasource-sync/src/**/*.mts, packages/@overeng/notion-datasource-sync/src/**/*.spec.cjs, packages/@overeng/notion-datasource-sync/src/**/*.spec.jsx, packages/@overeng/notion-datasource-sync/src/**/*.spec.mjs, packages/@overeng/notion-datasource-sync/src/**/*.test.cjs, packages/@overeng/notion-datasource-sync/src/**/*.test.jsx, packages/@overeng/notion-datasource-sync/src/**/*.test.mjs, packages/@overeng/notion-datasource-sync/src/**/*.ts, packages/@overeng/notion-datasource-sync/src/**/*.tsx, packages/@overeng/notion-datasource-sync/src/**/__snapshots__/*.snap, packages/@overeng/notion-datasource-sync/tsconfig.json.genie.ts, packages/@overeng/notion-effect-client/BUCK.genie.ts, packages/@overeng/notion-effect-client/package.json.genie.ts, packages/@overeng/notion-effect-schema/BUCK.genie.ts, packages/@overeng/notion-effect-schema/package.json.genie.ts, packages/@overeng/notion-md/BUCK.genie.ts, packages/@overeng/notion-md/package.json.genie.ts, packages/@overeng/notion-property-write/BUCK.genie.ts, packages/@overeng/notion-property-write/package.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/tui-react/BUCK.genie.ts, packages/@overeng/tui-react/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -113,6 +114,14 @@ export_materialization_inputs([ "src/webhook/tailscale.unit.test.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/notion-datasource-sync", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_notion_datasource_sync_60c433be3a75", @@ -254,7 +263,7 @@ package_view( "node_modules/@overeng/tui-react/node_modules": "//packages/@overeng/tui-react:package_tree", "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -391,7 +400,7 @@ package_view( "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/notion-datasource-sync/BUCK.genie.ts b/packages/@overeng/notion-datasource-sync/BUCK.genie.ts index 3f8ec1e1f7..1dcce28c77 100644 --- a/packages/@overeng/notion-datasource-sync/BUCK.genie.ts +++ b/packages/@overeng/notion-datasource-sync/BUCK.genie.ts @@ -55,11 +55,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/notion-effect-client/BUCK b/packages/@overeng/notion-effect-client/BUCK index 3d3b4a972d..b9090cee60 100644 --- a/packages/@overeng/notion-effect-client/BUCK +++ b/packages/@overeng/notion-effect-client/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/notion-effect-client/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:d68ee6e34191bb73a51e75fa30dd31adfe77027e54bc029ed0171d380c3cab96 -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/content-address/BUCK.genie.ts, packages/@overeng/content-address/package.json.genie.ts, packages/@overeng/notion-core/BUCK.genie.ts, packages/@overeng/notion-core/package.json.genie.ts, packages/@overeng/notion-effect-client/BUCK.genie.ts, packages/@overeng/notion-effect-client/BUCK.genie.ts, packages/@overeng/notion-effect-client/package.json.genie.ts, packages/@overeng/notion-effect-client/src/**/*.cts, packages/@overeng/notion-effect-client/src/**/*.js, packages/@overeng/notion-effect-client/src/**/*.mts, packages/@overeng/notion-effect-client/src/**/*.spec.cjs, packages/@overeng/notion-effect-client/src/**/*.spec.jsx, packages/@overeng/notion-effect-client/src/**/*.spec.mjs, packages/@overeng/notion-effect-client/src/**/*.test.cjs, packages/@overeng/notion-effect-client/src/**/*.test.jsx, packages/@overeng/notion-effect-client/src/**/*.test.mjs, packages/@overeng/notion-effect-client/src/**/*.ts, packages/@overeng/notion-effect-client/src/**/*.tsx, packages/@overeng/notion-effect-client/src/**/__snapshots__/*.snap, packages/@overeng/notion-effect-client/tsconfig.json.genie.ts, packages/@overeng/notion-effect-schema/BUCK.genie.ts, packages/@overeng/notion-effect-schema/package.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts +# Semantic fingerprint: sha256:36ebb877860e9e614afe14ea9ee850bb12bc7ea0ecaf0b153593b24e56b4fdf2 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/content-address/BUCK.genie.ts, packages/@overeng/content-address/package.json.genie.ts, packages/@overeng/notion-core/BUCK.genie.ts, packages/@overeng/notion-core/package.json.genie.ts, packages/@overeng/notion-effect-client/BUCK.genie.ts, packages/@overeng/notion-effect-client/BUCK.genie.ts, packages/@overeng/notion-effect-client/package.json.genie.ts, packages/@overeng/notion-effect-client/src/**/*.cts, packages/@overeng/notion-effect-client/src/**/*.js, packages/@overeng/notion-effect-client/src/**/*.mts, packages/@overeng/notion-effect-client/src/**/*.spec.cjs, packages/@overeng/notion-effect-client/src/**/*.spec.jsx, packages/@overeng/notion-effect-client/src/**/*.spec.mjs, packages/@overeng/notion-effect-client/src/**/*.test.cjs, packages/@overeng/notion-effect-client/src/**/*.test.jsx, packages/@overeng/notion-effect-client/src/**/*.test.mjs, packages/@overeng/notion-effect-client/src/**/*.ts, packages/@overeng/notion-effect-client/src/**/*.tsx, packages/@overeng/notion-effect-client/src/**/__snapshots__/*.snap, packages/@overeng/notion-effect-client/tsconfig.json.genie.ts, packages/@overeng/notion-effect-schema/BUCK.genie.ts, packages/@overeng/notion-effect-schema/package.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -78,6 +79,14 @@ export_materialization_inputs([ "src/views.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/notion-effect-client", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_notion_effect_client_6a05720e6f76", @@ -175,7 +184,7 @@ package_view( "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -267,7 +276,7 @@ package_view( "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/notion-effect-client/BUCK.genie.ts b/packages/@overeng/notion-effect-client/BUCK.genie.ts index a2a9216c2b..0a2b10ce26 100644 --- a/packages/@overeng/notion-effect-client/BUCK.genie.ts +++ b/packages/@overeng/notion-effect-client/BUCK.genie.ts @@ -40,11 +40,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils-dev:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/notion-effect-schema/BUCK b/packages/@overeng/notion-effect-schema/BUCK index 713a5a645d..3f4360867e 100644 --- a/packages/@overeng/notion-effect-schema/BUCK +++ b/packages/@overeng/notion-effect-schema/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/notion-effect-schema/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:9d8305bc24d31843aa318195bb81c6872a87334c6d942aec0573e85db1c6065c -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/notion-core/BUCK.genie.ts, packages/@overeng/notion-core/package.json.genie.ts, packages/@overeng/notion-effect-schema/BUCK.genie.ts, packages/@overeng/notion-effect-schema/BUCK.genie.ts, packages/@overeng/notion-effect-schema/package.json.genie.ts, packages/@overeng/notion-effect-schema/src/**/*.cts, packages/@overeng/notion-effect-schema/src/**/*.js, packages/@overeng/notion-effect-schema/src/**/*.mts, packages/@overeng/notion-effect-schema/src/**/*.spec.cjs, packages/@overeng/notion-effect-schema/src/**/*.spec.jsx, packages/@overeng/notion-effect-schema/src/**/*.spec.mjs, packages/@overeng/notion-effect-schema/src/**/*.test.cjs, packages/@overeng/notion-effect-schema/src/**/*.test.jsx, packages/@overeng/notion-effect-schema/src/**/*.test.mjs, packages/@overeng/notion-effect-schema/src/**/*.ts, packages/@overeng/notion-effect-schema/src/**/*.tsx, packages/@overeng/notion-effect-schema/src/**/__snapshots__/*.snap, packages/@overeng/notion-effect-schema/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts +# Semantic fingerprint: sha256:0975db5b4a70e909e7b4722f82e737a4e81743468bc351611bf1a58da2141169 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/notion-core/BUCK.genie.ts, packages/@overeng/notion-core/package.json.genie.ts, packages/@overeng/notion-effect-schema/BUCK.genie.ts, packages/@overeng/notion-effect-schema/BUCK.genie.ts, packages/@overeng/notion-effect-schema/package.json.genie.ts, packages/@overeng/notion-effect-schema/src/**/*.cts, packages/@overeng/notion-effect-schema/src/**/*.js, packages/@overeng/notion-effect-schema/src/**/*.mts, packages/@overeng/notion-effect-schema/src/**/*.spec.cjs, packages/@overeng/notion-effect-schema/src/**/*.spec.jsx, packages/@overeng/notion-effect-schema/src/**/*.spec.mjs, packages/@overeng/notion-effect-schema/src/**/*.test.cjs, packages/@overeng/notion-effect-schema/src/**/*.test.jsx, packages/@overeng/notion-effect-schema/src/**/*.test.mjs, packages/@overeng/notion-effect-schema/src/**/*.ts, packages/@overeng/notion-effect-schema/src/**/*.tsx, packages/@overeng/notion-effect-schema/src/**/__snapshots__/*.snap, packages/@overeng/notion-effect-schema/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -51,6 +52,14 @@ export_materialization_inputs([ "src/webhook.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/notion-effect-schema", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_notion_effect_schema_4393910d3e7b", @@ -109,7 +118,7 @@ package_view( "node_modules/@overeng/notion-core/node_modules": "//packages/@overeng/notion-core:package_tree", "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -162,7 +171,7 @@ package_view( "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/notion-effect-schema/BUCK.genie.ts b/packages/@overeng/notion-effect-schema/BUCK.genie.ts index 1ab5bbf0e9..e625d4d6e3 100644 --- a/packages/@overeng/notion-effect-schema/BUCK.genie.ts +++ b/packages/@overeng/notion-effect-schema/BUCK.genie.ts @@ -20,11 +20,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils-dev:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/notion-md/BUCK b/packages/@overeng/notion-md/BUCK index f5f63bb578..3d05367a3b 100644 --- a/packages/@overeng/notion-md/BUCK +++ b/packages/@overeng/notion-md/BUCK @@ -5,14 +5,15 @@ load("//buck2:package_tools.bzl", "package_bin_artifact") load("//buck2/products:defs.bzl", "javascript_product") # Projection source: packages/@overeng/notion-md/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:6921519403d336f31fc37205c7f399def943da6b1c710c3549c2d525d89c766b -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/content-address/BUCK.genie.ts, packages/@overeng/content-address/package.json.genie.ts, packages/@overeng/notion-core/BUCK.genie.ts, packages/@overeng/notion-core/package.json.genie.ts, packages/@overeng/notion-effect-client/BUCK.genie.ts, packages/@overeng/notion-effect-client/package.json.genie.ts, packages/@overeng/notion-effect-schema/BUCK.genie.ts, packages/@overeng/notion-effect-schema/package.json.genie.ts, packages/@overeng/notion-md/BUCK.genie.ts, packages/@overeng/notion-md/BUCK.genie.ts, packages/@overeng/notion-md/demo/**/*.nmd, packages/@overeng/notion-md/package.json.genie.ts, packages/@overeng/notion-md/src/**/*.cts, packages/@overeng/notion-md/src/**/*.js, packages/@overeng/notion-md/src/**/*.mts, packages/@overeng/notion-md/src/**/*.spec.cjs, packages/@overeng/notion-md/src/**/*.spec.jsx, packages/@overeng/notion-md/src/**/*.spec.mjs, packages/@overeng/notion-md/src/**/*.test.cjs, packages/@overeng/notion-md/src/**/*.test.jsx, packages/@overeng/notion-md/src/**/*.test.mjs, packages/@overeng/notion-md/src/**/*.ts, packages/@overeng/notion-md/src/**/*.tsx, packages/@overeng/notion-md/src/**/__snapshots__/*.snap, packages/@overeng/notion-md/tsconfig.json.genie.ts, packages/@overeng/notion-property-write/BUCK.genie.ts, packages/@overeng/notion-property-write/package.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/tui-react/BUCK.genie.ts, packages/@overeng/tui-react/package.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts +# Semantic fingerprint: sha256:5e1b73d9976af228de0e6fbb105e9262b09ecfb937bb03bc697e97795d0208ab +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/content-address/BUCK.genie.ts, packages/@overeng/content-address/package.json.genie.ts, packages/@overeng/notion-core/BUCK.genie.ts, packages/@overeng/notion-core/package.json.genie.ts, packages/@overeng/notion-effect-client/BUCK.genie.ts, packages/@overeng/notion-effect-client/package.json.genie.ts, packages/@overeng/notion-effect-schema/BUCK.genie.ts, packages/@overeng/notion-effect-schema/package.json.genie.ts, packages/@overeng/notion-md/BUCK.genie.ts, packages/@overeng/notion-md/BUCK.genie.ts, packages/@overeng/notion-md/demo/**/*.nmd, packages/@overeng/notion-md/package.json.genie.ts, packages/@overeng/notion-md/src/**/*.cts, packages/@overeng/notion-md/src/**/*.js, packages/@overeng/notion-md/src/**/*.mts, packages/@overeng/notion-md/src/**/*.spec.cjs, packages/@overeng/notion-md/src/**/*.spec.jsx, packages/@overeng/notion-md/src/**/*.spec.mjs, packages/@overeng/notion-md/src/**/*.test.cjs, packages/@overeng/notion-md/src/**/*.test.jsx, packages/@overeng/notion-md/src/**/*.test.mjs, packages/@overeng/notion-md/src/**/*.ts, packages/@overeng/notion-md/src/**/*.tsx, packages/@overeng/notion-md/src/**/__snapshots__/*.snap, packages/@overeng/notion-md/tsconfig.json.genie.ts, packages/@overeng/notion-property-write/BUCK.genie.ts, packages/@overeng/notion-property-write/package.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/tui-react/BUCK.genie.ts, packages/@overeng/tui-react/package.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -97,6 +98,14 @@ export_materialization_inputs([ "src/webhook.unit.test.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/notion-md", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_notion_md_42a8cb2f2027", @@ -219,7 +228,7 @@ package_view( "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -337,7 +346,7 @@ package_view( "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/notion-md/BUCK.genie.ts b/packages/@overeng/notion-md/BUCK.genie.ts index 060ae21c26..18868bc06f 100644 --- a/packages/@overeng/notion-md/BUCK.genie.ts +++ b/packages/@overeng/notion-md/BUCK.genie.ts @@ -56,11 +56,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils-dev:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], // The golden-file fixpoint reads the committed `demo/showcase.nmd`, which no source // root carries. testDataRoots: [{ root: 'demo', extensions: ['.nmd'] }], diff --git a/packages/@overeng/notion-property-write/BUCK b/packages/@overeng/notion-property-write/BUCK index f5f5ab8fa0..0ec08970ab 100644 --- a/packages/@overeng/notion-property-write/BUCK +++ b/packages/@overeng/notion-property-write/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/notion-property-write/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:f354d9f77afd6def70648b289b6182e803a38ae5bb117e14cf7b3059d5bf7b8c -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/notion-effect-schema/BUCK.genie.ts, packages/@overeng/notion-effect-schema/package.json.genie.ts, packages/@overeng/notion-property-write/BUCK.genie.ts, packages/@overeng/notion-property-write/BUCK.genie.ts, packages/@overeng/notion-property-write/package.json.genie.ts, packages/@overeng/notion-property-write/src/**/*.cts, packages/@overeng/notion-property-write/src/**/*.js, packages/@overeng/notion-property-write/src/**/*.mts, packages/@overeng/notion-property-write/src/**/*.spec.cjs, packages/@overeng/notion-property-write/src/**/*.spec.jsx, packages/@overeng/notion-property-write/src/**/*.spec.mjs, packages/@overeng/notion-property-write/src/**/*.test.cjs, packages/@overeng/notion-property-write/src/**/*.test.jsx, packages/@overeng/notion-property-write/src/**/*.test.mjs, packages/@overeng/notion-property-write/src/**/*.ts, packages/@overeng/notion-property-write/src/**/*.tsx, packages/@overeng/notion-property-write/src/**/__snapshots__/*.snap, packages/@overeng/notion-property-write/tsconfig.json.genie.ts +# Semantic fingerprint: sha256:51ee74825992dda4685089059a2f155ea9f4733915b753b3917ede692bc0b2f8 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/notion-effect-schema/BUCK.genie.ts, packages/@overeng/notion-effect-schema/package.json.genie.ts, packages/@overeng/notion-property-write/BUCK.genie.ts, packages/@overeng/notion-property-write/BUCK.genie.ts, packages/@overeng/notion-property-write/package.json.genie.ts, packages/@overeng/notion-property-write/src/**/*.cts, packages/@overeng/notion-property-write/src/**/*.js, packages/@overeng/notion-property-write/src/**/*.mts, packages/@overeng/notion-property-write/src/**/*.spec.cjs, packages/@overeng/notion-property-write/src/**/*.spec.jsx, packages/@overeng/notion-property-write/src/**/*.spec.mjs, packages/@overeng/notion-property-write/src/**/*.test.cjs, packages/@overeng/notion-property-write/src/**/*.test.jsx, packages/@overeng/notion-property-write/src/**/*.test.mjs, packages/@overeng/notion-property-write/src/**/*.ts, packages/@overeng/notion-property-write/src/**/*.tsx, packages/@overeng/notion-property-write/src/**/__snapshots__/*.snap, packages/@overeng/notion-property-write/tsconfig.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -29,6 +30,14 @@ export_materialization_inputs([ "src/proof.unit.test.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/notion-property-write", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_notion_property_write_2cd3804e08be", @@ -62,7 +71,7 @@ package_view( workspace_dependency_views = { "node_modules/@overeng/notion-effect-schema/node_modules": "//packages/@overeng/notion-effect-schema:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -90,7 +99,7 @@ package_view( "node_modules/@overeng/notion-effect-schema/node_modules": "//packages/@overeng/notion-effect-schema:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/notion-property-write/BUCK.genie.ts b/packages/@overeng/notion-property-write/BUCK.genie.ts index 6f15ba143c..2a5dd1013b 100644 --- a/packages/@overeng/notion-property-write/BUCK.genie.ts +++ b/packages/@overeng/notion-property-write/BUCK.genie.ts @@ -15,11 +15,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/notion-effect-schema:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/notion-react/BUCK b/packages/@overeng/notion-react/BUCK index c8ad015654..7c7228fbb6 100644 --- a/packages/@overeng/notion-react/BUCK +++ b/packages/@overeng/notion-react/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/notion-react/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:f096a8b95861b92779624d46799f628b5234f3fe9f5ff8e52c258b79f1e52180 -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/notion-effect-client/BUCK.genie.ts, packages/@overeng/notion-effect-client/package.json.genie.ts, packages/@overeng/notion-effect-schema/BUCK.genie.ts, packages/@overeng/notion-effect-schema/package.json.genie.ts, packages/@overeng/notion-md/BUCK.genie.ts, packages/@overeng/notion-md/package.json.genie.ts, packages/@overeng/notion-react/BUCK.genie.ts, packages/@overeng/notion-react/BUCK.genie.ts, packages/@overeng/notion-react/package.json.genie.ts, packages/@overeng/notion-react/src/**/*.cts, packages/@overeng/notion-react/src/**/*.js, packages/@overeng/notion-react/src/**/*.mts, packages/@overeng/notion-react/src/**/*.spec.cjs, packages/@overeng/notion-react/src/**/*.spec.jsx, packages/@overeng/notion-react/src/**/*.spec.mjs, packages/@overeng/notion-react/src/**/*.test.cjs, packages/@overeng/notion-react/src/**/*.test.jsx, packages/@overeng/notion-react/src/**/*.test.mjs, packages/@overeng/notion-react/src/**/*.ts, packages/@overeng/notion-react/src/**/*.tsx, packages/@overeng/notion-react/src/**/__snapshots__/*.snap, packages/@overeng/notion-react/tsconfig.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts +# Semantic fingerprint: sha256:497ebc167a97d629ac9163cc371797a0580fa820f50aa32a542f926c5db7c8de +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/notion-effect-client/BUCK.genie.ts, packages/@overeng/notion-effect-client/package.json.genie.ts, packages/@overeng/notion-effect-schema/BUCK.genie.ts, packages/@overeng/notion-effect-schema/package.json.genie.ts, packages/@overeng/notion-md/BUCK.genie.ts, packages/@overeng/notion-md/package.json.genie.ts, packages/@overeng/notion-react/BUCK.genie.ts, packages/@overeng/notion-react/BUCK.genie.ts, packages/@overeng/notion-react/package.json.genie.ts, packages/@overeng/notion-react/src/**/*.cts, packages/@overeng/notion-react/src/**/*.js, packages/@overeng/notion-react/src/**/*.mts, packages/@overeng/notion-react/src/**/*.spec.cjs, packages/@overeng/notion-react/src/**/*.spec.jsx, packages/@overeng/notion-react/src/**/*.spec.mjs, packages/@overeng/notion-react/src/**/*.test.cjs, packages/@overeng/notion-react/src/**/*.test.jsx, packages/@overeng/notion-react/src/**/*.test.mjs, packages/@overeng/notion-react/src/**/*.ts, packages/@overeng/notion-react/src/**/*.tsx, packages/@overeng/notion-react/src/**/__snapshots__/*.snap, packages/@overeng/notion-react/tsconfig.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -126,6 +127,14 @@ export_materialization_inputs([ "src/web/toggle.unit.test.tsx", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/notion-react", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_notion_react_7158c0aeaa96", @@ -265,7 +274,7 @@ package_view( "node_modules/@overeng/notion-md/node_modules": "//packages/@overeng/notion-md:package_tree", "node_modules/@overeng/otel-contract/node_modules": "//packages/@overeng/otel-contract:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -399,7 +408,7 @@ package_view( "node_modules/@overeng/otel-contract/node_modules": "//packages/@overeng/otel-contract:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/notion-react/BUCK.genie.ts b/packages/@overeng/notion-react/BUCK.genie.ts index 4afec4faca..ec6a72a446 100644 --- a/packages/@overeng/notion-react/BUCK.genie.ts +++ b/packages/@overeng/notion-react/BUCK.genie.ts @@ -29,11 +29,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/otel-contract:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/notion-react/docs/contributing.md b/packages/@overeng/notion-react/docs/contributing.md index f522c8ca7b..85eb34a356 100644 --- a/packages/@overeng/notion-react/docs/contributing.md +++ b/packages/@overeng/notion-react/docs/contributing.md @@ -24,7 +24,7 @@ All common tasks run under `packages/@overeng/notion-react/`: | Live E2E (real Notion) | `pnpm --filter @overeng/notion-react test:integration:e2e` | | Storybook dev server | `pnpm --filter @overeng/notion-react storybook` | | Storybook static build | `pnpm --filter @overeng/notion-react storybook:build` | -| Type-check | `tsc --build --watch tsconfig.check.json` (from repo root) | +| Type-check | `devenv tasks run buck2:check` (from repo root) | | Lint | `oxlint` | | Format check / fix | `oxfmt --check` / `oxfmt` | @@ -33,8 +33,8 @@ see [Testing](./testing.md#pointing-at-a-different-notion-workspace). ## Edit / test loop -Run `tsc --build --watch tsconfig.check.json` in one pane and -`pnpm vitest` in another. Use Storybook when changing web-renderer +Run `devenv tasks run buck2:check` after TypeScript changes and use +`pnpm vitest` as the test watch loop. Use Storybook when changing web-renderer visuals. For renderer changes, the mock-client integration tests (`pnpm --filter @overeng/notion-react test:integration`) are the cheapest way to verify op sequences without paying for Notion API diff --git a/packages/@overeng/npm-release/BUCK b/packages/@overeng/npm-release/BUCK index 7154bcf5ea..f7efd4c3f3 100644 --- a/packages/@overeng/npm-release/BUCK +++ b/packages/@overeng/npm-release/BUCK @@ -5,14 +5,15 @@ load("//buck2:package_tools.bzl", "package_bin_artifact") load("//buck2/products:defs.bzl", "javascript_product") # Projection source: packages/@overeng/npm-release/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:18c6db5d253af2e576391f3e6b9dfcf3cb00d2cb4b7a30fb96675bac0d609c7d -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/npm-release/BUCK.genie.ts, packages/@overeng/npm-release/BUCK.genie.ts, packages/@overeng/npm-release/package.json.genie.ts, packages/@overeng/npm-release/src/**/*.cts, packages/@overeng/npm-release/src/**/*.js, packages/@overeng/npm-release/src/**/*.mts, packages/@overeng/npm-release/src/**/*.spec.cjs, packages/@overeng/npm-release/src/**/*.spec.jsx, packages/@overeng/npm-release/src/**/*.spec.mjs, packages/@overeng/npm-release/src/**/*.test.cjs, packages/@overeng/npm-release/src/**/*.test.jsx, packages/@overeng/npm-release/src/**/*.test.mjs, packages/@overeng/npm-release/src/**/*.ts, packages/@overeng/npm-release/src/**/*.tsx, packages/@overeng/npm-release/src/**/__snapshots__/*.snap, packages/@overeng/npm-release/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts +# Semantic fingerprint: sha256:9153418b8801b74e90b1e8f013138ac7b219bc3d05a39cf4f4ef206eae748979 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/npm-release/BUCK.genie.ts, packages/@overeng/npm-release/BUCK.genie.ts, packages/@overeng/npm-release/package.json.genie.ts, packages/@overeng/npm-release/src/**/*.cts, packages/@overeng/npm-release/src/**/*.js, packages/@overeng/npm-release/src/**/*.mts, packages/@overeng/npm-release/src/**/*.spec.cjs, packages/@overeng/npm-release/src/**/*.spec.jsx, packages/@overeng/npm-release/src/**/*.spec.mjs, packages/@overeng/npm-release/src/**/*.test.cjs, packages/@overeng/npm-release/src/**/*.test.jsx, packages/@overeng/npm-release/src/**/*.test.mjs, packages/@overeng/npm-release/src/**/*.ts, packages/@overeng/npm-release/src/**/*.tsx, packages/@overeng/npm-release/src/**/__snapshots__/*.snap, packages/@overeng/npm-release/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -30,6 +31,14 @@ export_materialization_inputs([ "src/verify.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/npm-release", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_npm_release_4d3d9fe00538", @@ -61,7 +70,7 @@ package_view( workspace_dependency_views = { "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -88,7 +97,7 @@ package_view( "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/npm-release/BUCK.genie.ts b/packages/@overeng/npm-release/BUCK.genie.ts index cca42f0573..7f227d9857 100644 --- a/packages/@overeng/npm-release/BUCK.genie.ts +++ b/packages/@overeng/npm-release/BUCK.genie.ts @@ -16,11 +16,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils-dev:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/otel-contract/BUCK b/packages/@overeng/otel-contract/BUCK index 41b1c7ab0e..673161814f 100644 --- a/packages/@overeng/otel-contract/BUCK +++ b/packages/@overeng/otel-contract/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/otel-contract/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:d56dd093d0c217b27936ab6c6990853f55d498ab3092199927929c32253edf53 -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/content-address/BUCK.genie.ts, packages/@overeng/content-address/package.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/otel-contract/src/**/*.cts, packages/@overeng/otel-contract/src/**/*.js, packages/@overeng/otel-contract/src/**/*.mts, packages/@overeng/otel-contract/src/**/*.spec.cjs, packages/@overeng/otel-contract/src/**/*.spec.jsx, packages/@overeng/otel-contract/src/**/*.spec.mjs, packages/@overeng/otel-contract/src/**/*.test.cjs, packages/@overeng/otel-contract/src/**/*.test.jsx, packages/@overeng/otel-contract/src/**/*.test.mjs, packages/@overeng/otel-contract/src/**/*.ts, packages/@overeng/otel-contract/src/**/*.tsx, packages/@overeng/otel-contract/src/**/__snapshots__/*.snap, packages/@overeng/otel-contract/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts +# Semantic fingerprint: sha256:89ced27cf8fbaab47615be9459a05f02f72708c505cd6b8fe4ff455f40316dc4 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/content-address/BUCK.genie.ts, packages/@overeng/content-address/package.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/otel-contract/src/**/*.cts, packages/@overeng/otel-contract/src/**/*.js, packages/@overeng/otel-contract/src/**/*.mts, packages/@overeng/otel-contract/src/**/*.spec.cjs, packages/@overeng/otel-contract/src/**/*.spec.jsx, packages/@overeng/otel-contract/src/**/*.spec.mjs, packages/@overeng/otel-contract/src/**/*.test.cjs, packages/@overeng/otel-contract/src/**/*.test.jsx, packages/@overeng/otel-contract/src/**/*.test.mjs, packages/@overeng/otel-contract/src/**/*.ts, packages/@overeng/otel-contract/src/**/*.tsx, packages/@overeng/otel-contract/src/**/__snapshots__/*.snap, packages/@overeng/otel-contract/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -36,6 +37,14 @@ export_materialization_inputs([ "src/registry.unit.test.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/otel-contract", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_otel_contract_071b3792a33c", @@ -79,7 +88,7 @@ package_view( "node_modules/@overeng/content-address/node_modules": "//packages/@overeng/content-address:package_tree", "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -117,7 +126,7 @@ package_view( "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/otel-contract/BUCK.genie.ts b/packages/@overeng/otel-contract/BUCK.genie.ts index 66e90e9571..1a0b4a6427 100644 --- a/packages/@overeng/otel-contract/BUCK.genie.ts +++ b/packages/@overeng/otel-contract/BUCK.genie.ts @@ -19,11 +19,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils-dev:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/otel-scrape/BUCK b/packages/@overeng/otel-scrape/BUCK index aa0f8d9fed..edbc5c7fc9 100644 --- a/packages/@overeng/otel-scrape/BUCK +++ b/packages/@overeng/otel-scrape/BUCK @@ -4,7 +4,7 @@ # Projection source: packages/@overeng/otel-scrape/BUCK.genie.ts # Projection schema version: 1 # Projection generator: effect-utils/rust/cargo-buck2-package-projection -# Semantic fingerprint: sha256:648719d0c122f82605df4c6bb865e47a6aa009f11993530c4f20a75aff152ba1 +# Semantic fingerprint: sha256:c2b3e910591781a1a79ef5eecf1e7bc67b318be806f5406d8b77e86ec757782f # Semantic inputs: genie/buck2/mod.ts, packages/@overeng/otel-scrape/BUCK.genie.ts, packages/@overeng/otel-scrape/Cargo.toml, packages/@overeng/otel-scrape/src/**/*.rs, packages/@overeng/otel-scrape/tests/**/*.rs, packages/@overeng/otelite/Cargo.toml, rust/Cargo.lock, rust/Cargo.toml, rust/buck2-tools/archive-tool/Cargo.toml, rust/buck2-tools/core/Cargo.toml, rust/buck2-tools/core/cargo-buck2-package-projection.ts, rust/buck2-tools/product/Cargo.toml, rust/reindeer.toml, rust/third-party/BUCK # Regenerate: devenv tasks run genie:run @@ -37,6 +37,7 @@ native.rust_library( env = { "CARGO_PKG_NAME": "otel-scrape", "CARGO_PKG_VERSION": "0.0.0", + "CLI_BUILD_STAMP": read_config("build_identity", "cli_build_stamp", ""), }, visibility = [ "PUBLIC", @@ -62,6 +63,7 @@ native.rust_binary( env = { "CARGO_PKG_NAME": "otel-scrape", "CARGO_PKG_VERSION": "0.0.0", + "CLI_BUILD_STAMP": read_config("build_identity", "cli_build_stamp", ""), }, visibility = [ "PUBLIC", diff --git a/packages/@overeng/otel-scrape/BUCK.genie.ts b/packages/@overeng/otel-scrape/BUCK.genie.ts index 1a24d398f8..3b9bc8fa21 100644 --- a/packages/@overeng/otel-scrape/BUCK.genie.ts +++ b/packages/@overeng/otel-scrape/BUCK.genie.ts @@ -1,3 +1,7 @@ import { cargoBuck2PackageProjection } from '../../../rust/buck2-tools/core/cargo-buck2-package-projection.ts' -export default cargoBuck2PackageProjection({ buildProduct: true, sourceUrl: import.meta.url }) +export default cargoBuck2PackageProjection({ + buildProduct: true, + cliBuildStamp: true, + sourceUrl: import.meta.url, +}) diff --git a/packages/@overeng/otel-scrape/nix/build.nix b/packages/@overeng/otel-scrape/nix/build.nix deleted file mode 100644 index 3568aa1b86..0000000000 --- a/packages/@overeng/otel-scrape/nix/build.nix +++ /dev/null @@ -1,72 +0,0 @@ -# Nix build for the otel-scrape Rust crate. -# Hermetic workspace-aware source remains stable across unrelated repo edits. -# cargoLock.lockFile vendors deps from the shared committed workspace lock. -# -# Build-id correlation (H5, decision 0019): the flake git rev is injected as a -# NixStamp `CLI_BUILD_STAMP` env var so the binary reflects its build without -# breaking purity (the rev is a flake input, not an impure read). Rust reads it -# at compile time via `option_env!` and derives `machineVersion` per the shared -# build-versioning contract. The shape matches the fleet's TS/Nix stamp -# (`@overeng/utils/node/cli-version` NixStamp: type/version/rev/commitTs/dirty); -# it is constructed inline via `builtins.toJSON` exactly like the notion-cli -# build, because the shared shell `cliBuildStamp` helper only produces LocalStamps. -{ - pkgs, - gitRev ? "unknown", - commitTs ? 0, - dirty ? false, -}: -let - lib = pkgs.lib; - repositoryRoot = ../../../..; - workspaceRoot = repositoryRoot + "/rust"; - crateRoot = ../.; - mkRustWorkspaceSource = import ../../../../nix/workspace-tools/lib/mk-rust-workspace-source.nix { - inherit lib pkgs; - }; - # NixStamp JSON (same contract as @overeng/utils/node/cli-version NixStamp). - # baseVersion pinned to the crate version below so machineVersion is - # `0.0.0+` (and `+…-dirty` for a dirty tree). - buildStamp = builtins.toJSON { - type = "nix"; - version = "0.0.0"; - rev = gitRev; - inherit commitTs dirty; - }; - src = mkRustWorkspaceSource { - inherit repositoryRoot workspaceRoot; - packageRoot = crateRoot; - includeReadme = true; - }; -in -pkgs.rustPlatform.buildRustPackage { - pname = "otel-scrape"; - version = "0.0.0"; - inherit src; - cargoRoot = "rust"; - buildAndTestSubdir = "rust"; - cargoLock.lockFile = workspaceRoot + "/Cargo.lock"; - cargoBuildFlags = [ - "--package" - "otel-scrape" - ]; - cargoTestFlags = [ - "--package" - "otel-scrape" - ]; - # Reaches rustc as a plain env var; `option_env!("CLI_BUILD_STAMP")` captures - # it at compile time (decision 0019). Because it is a derivation env var, a new - # rev changes the derivation hash so Nix rebuilds the crate — the binary tracks - # its build. (The cargo `rerun-if-env-changed` incremental path is not relied on; - # each `nix build` is a fresh sandbox.) - CLI_BUILD_STAMP = buildStamp; - doCheck = true; - nativeCheckInputs = [ - pkgs.nodejs - ]; - meta = { - description = "Process wrapper for command telemetry and profile artifact links"; - license = lib.licenses.mit; - mainProgram = "otel-scrape"; - }; -} diff --git a/packages/@overeng/otelite/BUCK b/packages/@overeng/otelite/BUCK index ca5d8aaac4..1b75f4971c 100644 --- a/packages/@overeng/otelite/BUCK +++ b/packages/@overeng/otelite/BUCK @@ -4,7 +4,7 @@ # Projection source: packages/@overeng/otelite/BUCK.genie.ts # Projection schema version: 1 # Projection generator: effect-utils/rust/cargo-buck2-package-projection -# Semantic fingerprint: sha256:9ebac3409331ba89087bc80204067dae41038b92415d07fc0ba4d911dba5a504 +# Semantic fingerprint: sha256:e92ae6f427716c1999dca38d516ab48f3f2e6222d42077889d8e2d63feca0853 # Semantic inputs: genie/buck2/mod.ts, packages/@overeng/otel-scrape/Cargo.toml, packages/@overeng/otelite/BUCK.genie.ts, packages/@overeng/otelite/Cargo.toml, packages/@overeng/otelite/src/**/*.rs, packages/@overeng/otelite/tests/**/*.rs, rust/Cargo.lock, rust/Cargo.toml, rust/buck2-tools/archive-tool/Cargo.toml, rust/buck2-tools/core/Cargo.toml, rust/buck2-tools/core/cargo-buck2-package-projection.ts, rust/buck2-tools/product/Cargo.toml, rust/reindeer.toml, rust/third-party/BUCK # Regenerate: devenv tasks run genie:run diff --git a/packages/@overeng/otelite/nix/build.nix b/packages/@overeng/otelite/nix/build.nix deleted file mode 100644 index 0d5dff256b..0000000000 --- a/packages/@overeng/otelite/nix/build.nix +++ /dev/null @@ -1,41 +0,0 @@ -# Nix build for the otelite Rust crate — effect-utils' first Rust package. -# Hermetic workspace-aware source remains stable across unrelated repo edits. -# cargoLock.lockFile vendors deps from the shared committed workspace lock. -{ pkgs }: -let - lib = pkgs.lib; - repositoryRoot = ../../../..; - workspaceRoot = repositoryRoot + "/rust"; - crateRoot = ../.; - mkRustWorkspaceSource = import ../../../../nix/workspace-tools/lib/mk-rust-workspace-source.nix { - inherit lib pkgs; - }; - src = mkRustWorkspaceSource { - inherit repositoryRoot workspaceRoot; - packageRoot = crateRoot; - # The whole test tree contains integration sources plus conformance - # goldens/fixtures (`.json`/`.ndjson`/`.snap`). - }; -in -pkgs.rustPlatform.buildRustPackage { - pname = "otelite"; - version = "0.0.0"; - inherit src; - cargoRoot = "rust"; - buildAndTestSubdir = "rust"; - cargoLock.lockFile = workspaceRoot + "/Cargo.lock"; - cargoBuildFlags = [ - "--package" - "otelite" - ]; - cargoTestFlags = [ - "--package" - "otelite" - ]; - doCheck = true; - meta = { - description = "Local OTLP capture tool for E2E and instrumentation tests"; - license = lib.licenses.mit; - mainProgram = "otelite"; - }; -} diff --git a/packages/@overeng/oxc-config/BUCK b/packages/@overeng/oxc-config/BUCK index e68aff432d..8d81a3baeb 100644 --- a/packages/@overeng/oxc-config/BUCK +++ b/packages/@overeng/oxc-config/BUCK @@ -5,14 +5,15 @@ load("//buck2:package_tools.bzl", "package_bin_artifact") load("//buck2/products:defs.bzl", "javascript_product") # Projection source: packages/@overeng/oxc-config/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:97c102d46470e5a07408c360cc27780efb7dccb7ecc858f39a14e711dafb8aa9 -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/oxc-config/BUCK.genie.ts, packages/@overeng/oxc-config/BUCK.genie.ts, packages/@overeng/oxc-config/package.json.genie.ts, packages/@overeng/oxc-config/src/**/*.cts, packages/@overeng/oxc-config/src/**/*.js, packages/@overeng/oxc-config/src/**/*.mts, packages/@overeng/oxc-config/src/**/*.spec.cjs, packages/@overeng/oxc-config/src/**/*.spec.jsx, packages/@overeng/oxc-config/src/**/*.spec.mjs, packages/@overeng/oxc-config/src/**/*.test.cjs, packages/@overeng/oxc-config/src/**/*.test.jsx, packages/@overeng/oxc-config/src/**/*.test.mjs, packages/@overeng/oxc-config/src/**/*.ts, packages/@overeng/oxc-config/src/**/*.tsx, packages/@overeng/oxc-config/src/**/__snapshots__/*.snap, packages/@overeng/oxc-config/tsconfig.json.genie.ts +# Semantic fingerprint: sha256:fe39a799bb8b456fd7be3606a5439d057d888f46c81989013e87b8a423a09ad9 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/oxc-config/BUCK.genie.ts, packages/@overeng/oxc-config/BUCK.genie.ts, packages/@overeng/oxc-config/package.json.genie.ts, packages/@overeng/oxc-config/src/**/*.cts, packages/@overeng/oxc-config/src/**/*.js, packages/@overeng/oxc-config/src/**/*.mts, packages/@overeng/oxc-config/src/**/*.spec.cjs, packages/@overeng/oxc-config/src/**/*.spec.jsx, packages/@overeng/oxc-config/src/**/*.spec.mjs, packages/@overeng/oxc-config/src/**/*.test.cjs, packages/@overeng/oxc-config/src/**/*.test.jsx, packages/@overeng/oxc-config/src/**/*.test.mjs, packages/@overeng/oxc-config/src/**/*.ts, packages/@overeng/oxc-config/src/**/*.tsx, packages/@overeng/oxc-config/src/**/__snapshots__/*.snap, packages/@overeng/oxc-config/tsconfig.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -65,6 +66,14 @@ export_materialization_inputs([ "src/stylex-upstream-plugin.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/oxc-config", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_oxc_config_0c9db47f45b6", @@ -128,7 +137,7 @@ package_view( }, workspace_dependency_views = { }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -186,7 +195,7 @@ package_view( workspace_dependency_views = { }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -244,3 +253,23 @@ javascript_product( product_name = "oxc-config", visibility = ["PUBLIC"], ) + +package_bin_artifact( + name = "oxc-config-stylex-upstream-plugin-candidate-module", + entrypoint = "src/stylex-upstream-plugin.ts", + external = [], + external_capabilities = [], + kind = "module", + output = "oxc-config-stylex-upstream-plugin.js", + package_tree = ":package_tree", + target = "node", + visibility = ["PUBLIC"], +) + +javascript_product( + name = "oxc-config-stylex-upstream-plugin-candidate", + module = ":oxc-config-stylex-upstream-plugin-candidate-module", + product_kind = "module", + product_name = "oxc-config-stylex-upstream-plugin", + visibility = ["PUBLIC"], +) diff --git a/packages/@overeng/oxc-config/BUCK.genie.ts b/packages/@overeng/oxc-config/BUCK.genie.ts index 1576bcb269..c02bae22c1 100644 --- a/packages/@overeng/oxc-config/BUCK.genie.ts +++ b/packages/@overeng/oxc-config/BUCK.genie.ts @@ -9,11 +9,7 @@ export const buck2TypeScriptAdmission = { packagePath: 'packages/@overeng/oxc-config', projectionSource: 'packages/@overeng/oxc-config/BUCK.genie.ts', sourceRoots: ['src'], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/oxc-config/nix/build.nix b/packages/@overeng/oxc-config/nix/build.nix index d260fa9809..6739fa10ce 100644 --- a/packages/@overeng/oxc-config/nix/build.nix +++ b/packages/@overeng/oxc-config/nix/build.nix @@ -14,7 +14,7 @@ import ../../../../nix/oxc-config-plugin.nix { ; # Managed by Evergreen FOD refresh — do not edit manually. depsBuilds = { - "." = mkSharedHash "sha256-0KW9XRnBr9XjmQSx9W5PRLf8JNCMc1oOBOujNMhJ/+c="; + "." = mkSharedHash "sha256-K8So7qjTSQHPewaDOGVJqdTxWHqSVOxutxgOxgnGoTs="; }; hashSourcePath = "packages/@overeng/oxc-config/nix/build.nix"; } diff --git a/packages/@overeng/pty-effect/BUCK b/packages/@overeng/pty-effect/BUCK index f2c17b7a41..f07e2699eb 100644 --- a/packages/@overeng/pty-effect/BUCK +++ b/packages/@overeng/pty-effect/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/pty-effect/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:acebd083950f6e97498dcbda23cc85fc4f5204dd9e6e676a4533ca4531632d28 -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/pty-effect/BUCK.genie.ts, packages/@overeng/pty-effect/BUCK.genie.ts, packages/@overeng/pty-effect/package.json.genie.ts, packages/@overeng/pty-effect/src/**/*.cts, packages/@overeng/pty-effect/src/**/*.js, packages/@overeng/pty-effect/src/**/*.mts, packages/@overeng/pty-effect/src/**/*.spec.cjs, packages/@overeng/pty-effect/src/**/*.spec.jsx, packages/@overeng/pty-effect/src/**/*.spec.mjs, packages/@overeng/pty-effect/src/**/*.test.cjs, packages/@overeng/pty-effect/src/**/*.test.jsx, packages/@overeng/pty-effect/src/**/*.test.mjs, packages/@overeng/pty-effect/src/**/*.ts, packages/@overeng/pty-effect/src/**/*.tsx, packages/@overeng/pty-effect/src/**/__snapshots__/*.snap, packages/@overeng/pty-effect/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts +# Semantic fingerprint: sha256:0f737fc38e0f3ea4e15ad29355b14d8c7f625d93b33720a56740209ac4ed316c +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/pty-effect/BUCK.genie.ts, packages/@overeng/pty-effect/BUCK.genie.ts, packages/@overeng/pty-effect/package.json.genie.ts, packages/@overeng/pty-effect/src/**/*.cts, packages/@overeng/pty-effect/src/**/*.js, packages/@overeng/pty-effect/src/**/*.mts, packages/@overeng/pty-effect/src/**/*.spec.cjs, packages/@overeng/pty-effect/src/**/*.spec.jsx, packages/@overeng/pty-effect/src/**/*.spec.mjs, packages/@overeng/pty-effect/src/**/*.test.cjs, packages/@overeng/pty-effect/src/**/*.test.jsx, packages/@overeng/pty-effect/src/**/*.test.mjs, packages/@overeng/pty-effect/src/**/*.ts, packages/@overeng/pty-effect/src/**/*.tsx, packages/@overeng/pty-effect/src/**/__snapshots__/*.snap, packages/@overeng/pty-effect/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -28,6 +29,7 @@ export_materialization_inputs([ "src/PtySpawner.ts", "src/PtySpec.ts", "src/Screenshot.ts", + "src/bundle-smoke.unit.test.ts", "src/client.test.ts", "src/client.ts", "src/client.unit.test.ts", @@ -35,6 +37,14 @@ export_materialization_inputs([ "src/pty.contract.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/pty-effect", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_pty_effect_ec6c01cbf1c8", @@ -60,6 +70,7 @@ package_view( "src/PtySpawner.ts": "src/PtySpawner.ts", "src/PtySpec.ts": "src/PtySpec.ts", "src/Screenshot.ts": "src/Screenshot.ts", + "src/bundle-smoke.unit.test.ts": "src/bundle-smoke.unit.test.ts", "src/client.test.ts": "src/client.test.ts", "src/client.ts": "src/client.ts", "src/client.unit.test.ts": "src/client.unit.test.ts", @@ -77,7 +88,7 @@ package_view( "node_modules/@overeng/otel-contract/node_modules": "//packages/@overeng/otel-contract:package_tree", "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -95,6 +106,7 @@ package_view( "src/PtySpawner.ts": "src/PtySpawner.ts", "src/PtySpec.ts": "src/PtySpec.ts", "src/Screenshot.ts": "src/Screenshot.ts", + "src/bundle-smoke.unit.test.ts": "src/bundle-smoke.unit.test.ts", "src/client.test.ts": "src/client.test.ts", "src/client.ts": "src/client.ts", "src/client.unit.test.ts": "src/client.unit.test.ts", @@ -114,7 +126,7 @@ package_view( "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -146,6 +158,7 @@ vitest_test( package_tree = ":test_package_tree", excludes = [ "src/PtySession.test.ts", + "src/bundle-smoke.unit.test.ts", "src/client.test.ts", ], visibility = ["PUBLIC"], @@ -156,7 +169,27 @@ vitest_collect( package_tree = ":test_package_tree", excludes = [ "src/PtySession.test.ts", + "src/bundle-smoke.unit.test.ts", "src/client.test.ts", ], visibility = ["PUBLIC"], ) + +vitest_test( + name = "bundle_smoke", + package_tree = ":test_package_tree", + test_files = [ + "src/bundle-smoke.unit.test.ts", + ], + timeout_ms = 120000, + visibility = ["PUBLIC"], +) + +vitest_collect( + name = "bundle_smoke_collect", + package_tree = ":test_package_tree", + test_files = [ + "src/bundle-smoke.unit.test.ts", + ], + visibility = ["PUBLIC"], +) diff --git a/packages/@overeng/pty-effect/BUCK.genie.ts b/packages/@overeng/pty-effect/BUCK.genie.ts index 09db8de398..8d80d2b964 100644 --- a/packages/@overeng/pty-effect/BUCK.genie.ts +++ b/packages/@overeng/pty-effect/BUCK.genie.ts @@ -19,20 +19,26 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils-dev:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', runner: 'vitest', - // Only the pure client suite is bounded: the session and compiled-binary suites need a - // real PTY, the Nix-built `node-pty` addon, and `bun build --compile`, so they stay - // unbounded (decision 0026) under the devenv `test:pty-effect` task. - excludes: ['src/PtySession.test.ts', 'src/client.test.ts'], - unboundedAfter: ['pnpm:link-native-node-packages'], + // The native session and compiled-binary suites remain source-owned (decision 0026). + // The Vite contract gets a separate Buck lane so CI retains its bundle-specific signal. + excludes: ['src/PtySession.test.ts', 'src/bundle-smoke.unit.test.ts', 'src/client.test.ts'], + sourceOwners: { 'src/bundle-smoke.unit.test.ts': 'bundle:smoke' }, + }, + { + name: 'bundle_smoke', + runner: 'vitest', + testFiles: ['src/bundle-smoke.unit.test.ts'], + sourceOwners: { + 'src/PtySession.test.ts': 'test:pty-effect:unbounded', + 'src/client.test.ts': 'test:pty-effect:unbounded', + 'src/client.unit.test.ts': 'test:pty-effect', + }, + timeoutMs: 120_000, }, ], } as const satisfies Buck2TypeScriptAdmission diff --git a/packages/@overeng/pty-effect/package.json b/packages/@overeng/pty-effect/package.json index 5d7977ada4..3528cf315d 100644 --- a/packages/@overeng/pty-effect/package.json +++ b/packages/@overeng/pty-effect/package.json @@ -23,9 +23,6 @@ "default": "./src/client.ts" } }, - "scripts": { - "bundle:smoke": "bun ../../../genie/ci-scripts/bundle-smoke.ts" - }, "dependencies": { "@myobie/pty": "0.10.0", "@overeng/otel-contract": "workspace:^" diff --git a/packages/@overeng/pty-effect/package.json.genie.ts b/packages/@overeng/pty-effect/package.json.genie.ts index 79bd1b4470..ce2b4f8d39 100644 --- a/packages/@overeng/pty-effect/package.json.genie.ts +++ b/packages/@overeng/pty-effect/package.json.genie.ts @@ -40,9 +40,6 @@ export default packageJson( { name: '@overeng/pty-effect', ...privatePackageDefaults, - scripts: { - 'bundle:smoke': 'bun ../../../genie/ci-scripts/bundle-smoke.ts', - }, exports: { '.': exportEntry( { types: './dist/src/mod.d.ts', default: './src/mod.ts' }, diff --git a/packages/@overeng/pty-effect/src/bundle-smoke.unit.test.ts b/packages/@overeng/pty-effect/src/bundle-smoke.unit.test.ts new file mode 100644 index 0000000000..475a8a2999 --- /dev/null +++ b/packages/@overeng/pty-effect/src/bundle-smoke.unit.test.ts @@ -0,0 +1,47 @@ +import { builtinModules } from 'node:module' +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +import { describe, it } from 'vitest' + +const builtinSpecifiers = new Set([ + ...builtinModules, + ...builtinModules.map((moduleName) => `node:${moduleName}`), +]) +const nativePtySpecifiers = new Set(['node-pty', '@homebridge/node-pty-prebuilt-multiarch']) +const external = (id: string): boolean => + builtinSpecifiers.has(id) || nativePtySpecifiers.has(id) || id.endsWith('.node') + +const smokeEntries = [ + { name: 'pty-effect', entry: 'src/mod.ts' }, + { name: 'pty-effect-client', entry: 'src/client.ts' }, +] as const + +const packageRoot = fileURLToPath(new URL('..', import.meta.url)) + +describe('public Vite/Rollup bundle surface', () => { + it('bundles every public entry with dependency resolution', async () => { + const { build } = await import('vite') + await Promise.all( + smokeEntries.map((smokeEntry) => + build({ + root: packageRoot, + configFile: false, + logLevel: 'warn', + ssr: { noExternal: true }, + build: { + emptyOutDir: false, + minify: false, + outDir: path.join(packageRoot, 'tmp', 'bundle-smoke', smokeEntry.name), + ssr: path.join(packageRoot, smokeEntry.entry), + write: false, + rolldownOptions: { + external, + output: { entryFileNames: `${smokeEntry.name}.mjs` }, + }, + }, + }), + ), + ) + }, 120_000) +}) diff --git a/packages/@overeng/pty-effect/test/node-pty-native-hook.ts b/packages/@overeng/pty-effect/test/node-pty-native-hook.ts new file mode 100644 index 0000000000..59faf17f4e --- /dev/null +++ b/packages/@overeng/pty-effect/test/node-pty-native-hook.ts @@ -0,0 +1,22 @@ +import { existsSync } from 'node:fs' +import { registerHooks } from 'node:module' +import { isAbsolute, resolve } from 'node:path' +import { pathToFileURL } from 'node:url' + +const packageRoot = process.env.NODE_PTY_NATIVE_PACKAGE +if (packageRoot === undefined || isAbsolute(packageRoot) === false) { + throw new Error('NODE_PTY_NATIVE_PACKAGE must name the absolute Nix node-pty package root') +} + +const entrypoint = resolve(packageRoot, 'lib/index.js') +if (existsSync(entrypoint) === false) { + throw new Error(`NODE_PTY_NATIVE_PACKAGE has no lib/index.js: ${packageRoot}`) +} +const entrypointUrl = pathToFileURL(entrypoint).href + +registerHooks({ + resolve(specifier, context, nextResolve) { + if (specifier === 'node-pty') return { shortCircuit: true, url: entrypointUrl } + return nextResolve(specifier, context) + }, +}) diff --git a/packages/@overeng/react-inspector/BUCK b/packages/@overeng/react-inspector/BUCK index 125cdf619d..c85b0949e8 100644 --- a/packages/@overeng/react-inspector/BUCK +++ b/packages/@overeng/react-inspector/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/react-inspector/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:4ffdf2a0939c7c2760b915b3ac7b4e3699a2d7fd0b5b65dc8062bfb30778f8af -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/react-inspector/BUCK.genie.ts, packages/@overeng/react-inspector/BUCK.genie.ts, packages/@overeng/react-inspector/package.json.genie.ts, packages/@overeng/react-inspector/src/**/*.cts, packages/@overeng/react-inspector/src/**/*.js, packages/@overeng/react-inspector/src/**/*.mts, packages/@overeng/react-inspector/src/**/*.spec.cjs, packages/@overeng/react-inspector/src/**/*.spec.jsx, packages/@overeng/react-inspector/src/**/*.spec.mjs, packages/@overeng/react-inspector/src/**/*.test.cjs, packages/@overeng/react-inspector/src/**/*.test.jsx, packages/@overeng/react-inspector/src/**/*.test.mjs, packages/@overeng/react-inspector/src/**/*.ts, packages/@overeng/react-inspector/src/**/*.tsx, packages/@overeng/react-inspector/src/**/__snapshots__/*.snap, packages/@overeng/react-inspector/tsconfig.json.genie.ts +# Semantic fingerprint: sha256:022473a0b8dbf444ff6d39cbb9599b56e3bcefced9e13da315ab66c7ecf5b874 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/react-inspector/BUCK.genie.ts, packages/@overeng/react-inspector/BUCK.genie.ts, packages/@overeng/react-inspector/package.json.genie.ts, packages/@overeng/react-inspector/src/**/*.cts, packages/@overeng/react-inspector/src/**/*.js, packages/@overeng/react-inspector/src/**/*.mts, packages/@overeng/react-inspector/src/**/*.spec.cjs, packages/@overeng/react-inspector/src/**/*.spec.jsx, packages/@overeng/react-inspector/src/**/*.spec.mjs, packages/@overeng/react-inspector/src/**/*.test.cjs, packages/@overeng/react-inspector/src/**/*.test.jsx, packages/@overeng/react-inspector/src/**/*.test.mjs, packages/@overeng/react-inspector/src/**/*.ts, packages/@overeng/react-inspector/src/**/*.tsx, packages/@overeng/react-inspector/src/**/__snapshots__/*.snap, packages/@overeng/react-inspector/test-d/**/*.cts, packages/@overeng/react-inspector/test-d/**/*.js, packages/@overeng/react-inspector/test-d/**/*.mts, packages/@overeng/react-inspector/test-d/**/*.spec.cjs, packages/@overeng/react-inspector/test-d/**/*.spec.jsx, packages/@overeng/react-inspector/test-d/**/*.spec.mjs, packages/@overeng/react-inspector/test-d/**/*.test.cjs, packages/@overeng/react-inspector/test-d/**/*.test.jsx, packages/@overeng/react-inspector/test-d/**/*.test.mjs, packages/@overeng/react-inspector/test-d/**/*.ts, packages/@overeng/react-inspector/test-d/**/*.tsx, packages/@overeng/react-inspector/test-d/**/__snapshots__/*.snap, packages/@overeng/react-inspector/tsconfig.json.genie.ts, packages/@overeng/react-inspector/tsconfig.strict-consumer.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -57,8 +58,17 @@ export_materialization_inputs([ "src/tree-view/pathUtils.ts", "src/utils/objectPrototype.tsx", "src/utils/propertyUtils.tsx", + "test-d/exact-optional-consumer.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/react-inspector", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_react_inspector_57d1a5b765ed", @@ -113,13 +123,15 @@ package_view( "src/tree-view/pathUtils.ts": "src/tree-view/pathUtils.ts", "src/utils/objectPrototype.tsx": "src/utils/objectPrototype.tsx", "src/utils/propertyUtils.tsx": "src/utils/propertyUtils.tsx", + "test-d/exact-optional-consumer.ts": "test-d/exact-optional-consumer.ts", "tsconfig.json": "tsconfig.json", + "tsconfig.strict-consumer.json": "tsconfig.strict-consumer.json", }, workspace_dist = { }, workspace_dependency_views = { }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -174,7 +186,9 @@ package_view( "src/tree-view/pathUtils.ts": "src/tree-view/pathUtils.ts", "src/utils/objectPrototype.tsx": "src/utils/objectPrototype.tsx", "src/utils/propertyUtils.tsx": "src/utils/propertyUtils.tsx", + "test-d/exact-optional-consumer.ts": "test-d/exact-optional-consumer.ts", "tsconfig.json": "tsconfig.json", + "tsconfig.strict-consumer.json": "tsconfig.strict-consumer.json", "vitest.config.ts": "vitest.config.ts", "vitest.setup.ts": "vitest.setup.ts", }, @@ -183,7 +197,7 @@ package_view( workspace_dependency_views = { }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -210,6 +224,13 @@ tsgo_emit( visibility = ["PUBLIC"], ) +tsgo_typecheck( + name = "strict_consumer_typecheck", + package_tree = ":package_tree", + project = "tsconfig.strict-consumer.json", + visibility = ["PUBLIC"], +) + vitest_test( name = "test", package_tree = ":test_package_tree", diff --git a/packages/@overeng/react-inspector/BUCK.genie.ts b/packages/@overeng/react-inspector/BUCK.genie.ts index 3d6efd436a..d02a963522 100644 --- a/packages/@overeng/react-inspector/BUCK.genie.ts +++ b/packages/@overeng/react-inspector/BUCK.genie.ts @@ -6,12 +6,15 @@ export const buck2TypeScriptAdmission = { packageName: '@overeng/react-inspector', packagePath: 'packages/@overeng/react-inspector', projectionSource: 'packages/@overeng/react-inspector/BUCK.genie.ts', - sourceRoots: ['src'], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/index.d.ts', - projectFile: 'tsconfig.json', - }, + sourceRoots: ['src', 'test-d'], + authorities: [ + { declarationEntrypoint: 'src/index.d.ts', projectFile: 'tsconfig.json' }, + { + projectFile: 'tsconfig.strict-consumer.json', + projectPath: 'packages/@overeng/react-inspector/tsconfig.strict-consumer.json', + typecheckTargetName: 'strict_consumer_typecheck', + }, + ], tests: [ { name: 'test', diff --git a/packages/@overeng/react-inspector/src/schema/mod.tsx b/packages/@overeng/react-inspector/src/schema/mod.tsx index 55955fcdc1..2ee266169c 100644 --- a/packages/@overeng/react-inspector/src/schema/mod.tsx +++ b/packages/@overeng/react-inspector/src/schema/mod.tsx @@ -1,5 +1,3 @@ -/* oxlint-disable oxc/no-barrel-file -- This module is the package's intentional public schema API. */ - export { type LineageBundle, type SchemaAnnotations, diff --git a/packages/@overeng/restate-effect/BUCK b/packages/@overeng/restate-effect/BUCK index ada74f6174..a8f08e2031 100644 --- a/packages/@overeng/restate-effect/BUCK +++ b/packages/@overeng/restate-effect/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/restate-effect/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:15be4cd58cfa64aa26c7c4425006f7899743743871dbff008e8d3419c6b6e098 -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/restate-effect/BUCK.genie.ts, packages/@overeng/restate-effect/BUCK.genie.ts, packages/@overeng/restate-effect/examples/**/*.cts, packages/@overeng/restate-effect/examples/**/*.js, packages/@overeng/restate-effect/examples/**/*.mts, packages/@overeng/restate-effect/examples/**/*.spec.cjs, packages/@overeng/restate-effect/examples/**/*.spec.jsx, packages/@overeng/restate-effect/examples/**/*.spec.mjs, packages/@overeng/restate-effect/examples/**/*.test.cjs, packages/@overeng/restate-effect/examples/**/*.test.jsx, packages/@overeng/restate-effect/examples/**/*.test.mjs, packages/@overeng/restate-effect/examples/**/*.ts, packages/@overeng/restate-effect/examples/**/*.tsx, packages/@overeng/restate-effect/examples/**/__snapshots__/*.snap, packages/@overeng/restate-effect/package.json.genie.ts, packages/@overeng/restate-effect/src/**/*.cts, packages/@overeng/restate-effect/src/**/*.js, packages/@overeng/restate-effect/src/**/*.mts, packages/@overeng/restate-effect/src/**/*.spec.cjs, packages/@overeng/restate-effect/src/**/*.spec.jsx, packages/@overeng/restate-effect/src/**/*.spec.mjs, packages/@overeng/restate-effect/src/**/*.test.cjs, packages/@overeng/restate-effect/src/**/*.test.jsx, packages/@overeng/restate-effect/src/**/*.test.mjs, packages/@overeng/restate-effect/src/**/*.ts, packages/@overeng/restate-effect/src/**/*.tsx, packages/@overeng/restate-effect/src/**/__snapshots__/*.snap, packages/@overeng/restate-effect/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts +# Semantic fingerprint: sha256:0ba4c73d3360bd389d6cc7c83b58e7aa31c01b277eab7abb49b4993e69421abe +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/restate-effect/BUCK.genie.ts, packages/@overeng/restate-effect/BUCK.genie.ts, packages/@overeng/restate-effect/examples/**/*.cts, packages/@overeng/restate-effect/examples/**/*.js, packages/@overeng/restate-effect/examples/**/*.mts, packages/@overeng/restate-effect/examples/**/*.spec.cjs, packages/@overeng/restate-effect/examples/**/*.spec.jsx, packages/@overeng/restate-effect/examples/**/*.spec.mjs, packages/@overeng/restate-effect/examples/**/*.test.cjs, packages/@overeng/restate-effect/examples/**/*.test.jsx, packages/@overeng/restate-effect/examples/**/*.test.mjs, packages/@overeng/restate-effect/examples/**/*.ts, packages/@overeng/restate-effect/examples/**/*.tsx, packages/@overeng/restate-effect/examples/**/__snapshots__/*.snap, packages/@overeng/restate-effect/package.json.genie.ts, packages/@overeng/restate-effect/src/**/*.cts, packages/@overeng/restate-effect/src/**/*.js, packages/@overeng/restate-effect/src/**/*.mts, packages/@overeng/restate-effect/src/**/*.spec.cjs, packages/@overeng/restate-effect/src/**/*.spec.jsx, packages/@overeng/restate-effect/src/**/*.spec.mjs, packages/@overeng/restate-effect/src/**/*.test.cjs, packages/@overeng/restate-effect/src/**/*.test.jsx, packages/@overeng/restate-effect/src/**/*.test.mjs, packages/@overeng/restate-effect/src/**/*.ts, packages/@overeng/restate-effect/src/**/*.tsx, packages/@overeng/restate-effect/src/**/__snapshots__/*.snap, packages/@overeng/restate-effect/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -96,6 +97,14 @@ export_materialization_inputs([ "src/testing/testing.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/restate-effect", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_restate_effect_1d9088e92885", @@ -202,7 +211,7 @@ package_view( "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -303,7 +312,7 @@ package_view( "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/restate-effect/BUCK.genie.ts b/packages/@overeng/restate-effect/BUCK.genie.ts index a28eef2079..0a9938153a 100644 --- a/packages/@overeng/restate-effect/BUCK.genie.ts +++ b/packages/@overeng/restate-effect/BUCK.genie.ts @@ -24,11 +24,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils-dev:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/restate-effect/README.md b/packages/@overeng/restate-effect/README.md index 78f07600c2..abf8b54987 100644 --- a/packages/@overeng/restate-effect/README.md +++ b/packages/@overeng/restate-effect/README.md @@ -129,7 +129,7 @@ page-per-concern guide where every code block is a verified example: - [The endpoint](./docs/guide/endpoint.md), [Cancellation](./docs/guide/cancellation.md), [Self-reschedule](./docs/guide/scheduling.md). - [OpenTelemetry](./docs/guide/observability.md), [Testing](./docs/guide/testing.md), [API reference](./docs/guide/api-reference.md). -The [`examples/`](./examples) are type-checked by `devenv tasks run ts:check` and driven against a +The [`examples/`](./examples) are type-checked by `devenv tasks run buck2:check` and driven against a native `restate-server` by `src/examples.integration.test.ts` (under `devenv tasks run check:all`), so a documented snippet that stopped working would fail CI. diff --git a/packages/@overeng/restate-effect/docs/guide/verification.md b/packages/@overeng/restate-effect/docs/guide/verification.md index c50db5fde9..1a33bcd22e 100644 --- a/packages/@overeng/restate-effect/docs/guide/verification.md +++ b/packages/@overeng/restate-effect/docs/guide/verification.md @@ -5,7 +5,7 @@ ## How the examples are verified The [`examples/`](../../examples) directory holds runnable `.ts` files (covered by -the package `tsconfig` and `devenv tasks run ts:check`). +the package `tsconfig` and `devenv tasks run buck2:check`). [`src/endpoint/examples.integration.test.ts`](../../src/endpoint/examples.integration.test.ts) imports the example contracts/impls and drives them through the [`./testing`](./testing.md) harness against a real native `restate-server`, and @@ -21,12 +21,12 @@ block in this handbook is drawn from one of these verified files: | Service + typed error boundary | [`01-service.ts`](../../examples/01-service.ts) | `examples.integration.test.ts` | | Virtual Object + typed State | [`02-virtual-object.ts`](../../examples/02-virtual-object.ts) | `examples.integration.test.ts` | | Workflow + durable promise | [`03-workflow.ts`](../../examples/03-workflow.ts) | `examples.integration.test.ts` | -| Endpoint (`layer` / `serve`) | [`04-endpoint.ts`](../../examples/04-endpoint.ts) | `ts:check` | -| Determinism + descriptors | [`05-determinism.ts`](../../examples/05-determinism.ts) | `ts:check` | +| Endpoint (`layer` / `serve`) | [`04-endpoint.ts`](../../examples/04-endpoint.ts) | `buck2:check` | +| Determinism + descriptors | [`05-determinism.ts`](../../examples/05-determinism.ts) | `buck2:check` | | Typed ingress client | [`06-ingress-client.ts`](../../examples/06-ingress-client.ts) | `examples.integration.test.ts` | | Calls / idempotency / awakeables | [`07-clients-idempotency-awakeables.ts`](../../examples/07-clients-idempotency-awakeables.ts) | `examples.integration.test.ts` | -| Annotations + redaction | [`08-annotations.ts`](../../examples/08-annotations.ts) | `ts:check` | -| OTel bridge | [`09-otel.ts`](../../examples/09-otel.ts) | `ts:check` | +| Annotations + redaction | [`08-annotations.ts`](../../examples/08-annotations.ts) | `buck2:check` | +| OTel bridge | [`09-otel.ts`](../../examples/09-otel.ts) | `buck2:check` | | Cancellation | [`10-cancellation.ts`](../../examples/10-cancellation.ts) | `cancellation.integration.test.ts` | | Testing harness | [`11-testing.ts`](../../examples/11-testing.ts) | `examples.integration.test.ts` | | Self-reschedule | [`12-self-reschedule.ts`](../../examples/12-self-reschedule.ts) | `scheduled.integration.test.ts` | diff --git a/packages/@overeng/stylex-tokens/BUCK b/packages/@overeng/stylex-tokens/BUCK index b92f9e41d3..121a89c1c9 100644 --- a/packages/@overeng/stylex-tokens/BUCK +++ b/packages/@overeng/stylex-tokens/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/stylex-tokens/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:69063496fad691ed79cd1b4d5930186b7d38ca0bbc2e72117e6ef6f2b1a0aa6b -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/stylex-tokens/BUCK.genie.ts, packages/@overeng/stylex-tokens/BUCK.genie.ts, packages/@overeng/stylex-tokens/package.json.genie.ts, packages/@overeng/stylex-tokens/src/**/*.cts, packages/@overeng/stylex-tokens/src/**/*.js, packages/@overeng/stylex-tokens/src/**/*.mts, packages/@overeng/stylex-tokens/src/**/*.spec.cjs, packages/@overeng/stylex-tokens/src/**/*.spec.jsx, packages/@overeng/stylex-tokens/src/**/*.spec.mjs, packages/@overeng/stylex-tokens/src/**/*.test.cjs, packages/@overeng/stylex-tokens/src/**/*.test.jsx, packages/@overeng/stylex-tokens/src/**/*.test.mjs, packages/@overeng/stylex-tokens/src/**/*.ts, packages/@overeng/stylex-tokens/src/**/*.tsx, packages/@overeng/stylex-tokens/src/**/__snapshots__/*.snap, packages/@overeng/stylex-tokens/tsconfig.json.genie.ts +# Semantic fingerprint: sha256:35e8c8cd2d2526f531ad131d964a2316293eba50230d18d598c946eeb364b414 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/stylex-tokens/BUCK.genie.ts, packages/@overeng/stylex-tokens/BUCK.genie.ts, packages/@overeng/stylex-tokens/package.json.genie.ts, packages/@overeng/stylex-tokens/src/**/*.cts, packages/@overeng/stylex-tokens/src/**/*.js, packages/@overeng/stylex-tokens/src/**/*.mts, packages/@overeng/stylex-tokens/src/**/*.spec.cjs, packages/@overeng/stylex-tokens/src/**/*.spec.jsx, packages/@overeng/stylex-tokens/src/**/*.spec.mjs, packages/@overeng/stylex-tokens/src/**/*.test.cjs, packages/@overeng/stylex-tokens/src/**/*.test.jsx, packages/@overeng/stylex-tokens/src/**/*.test.mjs, packages/@overeng/stylex-tokens/src/**/*.ts, packages/@overeng/stylex-tokens/src/**/*.tsx, packages/@overeng/stylex-tokens/src/**/__snapshots__/*.snap, packages/@overeng/stylex-tokens/tsconfig.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") export_file( @@ -22,6 +23,14 @@ export_materialization_inputs([ "src/tokens.stylex.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/stylex-tokens", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_stylex_tokens_61644ffb4ebc", @@ -46,7 +55,7 @@ package_view( }, workspace_dependency_views = { }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/stylex-tokens/BUCK.genie.ts b/packages/@overeng/stylex-tokens/BUCK.genie.ts index 7bbdd5d290..35e055011f 100644 --- a/packages/@overeng/stylex-tokens/BUCK.genie.ts +++ b/packages/@overeng/stylex-tokens/BUCK.genie.ts @@ -7,11 +7,7 @@ export const buck2TypeScriptAdmission = { packagePath: 'packages/@overeng/stylex-tokens', projectionSource: 'packages/@overeng/stylex-tokens/BUCK.genie.ts', sourceRoots: ['src'], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/tokens.stylex.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/tokens.stylex.d.ts', projectFile: 'tsconfig.json' }], } as const satisfies Buck2TypeScriptAdmission export default buck2TypeScriptPackageProjection(buck2TypeScriptAdmission) diff --git a/packages/@overeng/tui-core/BUCK b/packages/@overeng/tui-core/BUCK index ef021c8554..f20edafea0 100644 --- a/packages/@overeng/tui-core/BUCK +++ b/packages/@overeng/tui-core/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/tui-core/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:ac8d512311afd17fa680bed3b3b12a70537b23a8dce71e71c67c1620e58409ec -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/tui-core/BUCK.genie.ts, packages/@overeng/tui-core/BUCK.genie.ts, packages/@overeng/tui-core/package.json.genie.ts, packages/@overeng/tui-core/src/**/*.cts, packages/@overeng/tui-core/src/**/*.js, packages/@overeng/tui-core/src/**/*.mts, packages/@overeng/tui-core/src/**/*.spec.cjs, packages/@overeng/tui-core/src/**/*.spec.jsx, packages/@overeng/tui-core/src/**/*.spec.mjs, packages/@overeng/tui-core/src/**/*.test.cjs, packages/@overeng/tui-core/src/**/*.test.jsx, packages/@overeng/tui-core/src/**/*.test.mjs, packages/@overeng/tui-core/src/**/*.ts, packages/@overeng/tui-core/src/**/*.tsx, packages/@overeng/tui-core/src/**/__snapshots__/*.snap, packages/@overeng/tui-core/test/**/*.cts, packages/@overeng/tui-core/test/**/*.js, packages/@overeng/tui-core/test/**/*.mts, packages/@overeng/tui-core/test/**/*.spec.cjs, packages/@overeng/tui-core/test/**/*.spec.jsx, packages/@overeng/tui-core/test/**/*.spec.mjs, packages/@overeng/tui-core/test/**/*.test.cjs, packages/@overeng/tui-core/test/**/*.test.jsx, packages/@overeng/tui-core/test/**/*.test.mjs, packages/@overeng/tui-core/test/**/*.ts, packages/@overeng/tui-core/test/**/*.tsx, packages/@overeng/tui-core/test/**/__snapshots__/*.snap, packages/@overeng/tui-core/tsconfig.json.genie.ts +# Semantic fingerprint: sha256:37976eca81035fc2815735feb1dd4d5eb06cf15365dc57d19b3154e80196183e +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/tui-core/BUCK.genie.ts, packages/@overeng/tui-core/BUCK.genie.ts, packages/@overeng/tui-core/package.json.genie.ts, packages/@overeng/tui-core/src/**/*.cts, packages/@overeng/tui-core/src/**/*.js, packages/@overeng/tui-core/src/**/*.mts, packages/@overeng/tui-core/src/**/*.spec.cjs, packages/@overeng/tui-core/src/**/*.spec.jsx, packages/@overeng/tui-core/src/**/*.spec.mjs, packages/@overeng/tui-core/src/**/*.test.cjs, packages/@overeng/tui-core/src/**/*.test.jsx, packages/@overeng/tui-core/src/**/*.test.mjs, packages/@overeng/tui-core/src/**/*.ts, packages/@overeng/tui-core/src/**/*.tsx, packages/@overeng/tui-core/src/**/__snapshots__/*.snap, packages/@overeng/tui-core/test/**/*.cts, packages/@overeng/tui-core/test/**/*.js, packages/@overeng/tui-core/test/**/*.mts, packages/@overeng/tui-core/test/**/*.spec.cjs, packages/@overeng/tui-core/test/**/*.spec.jsx, packages/@overeng/tui-core/test/**/*.spec.mjs, packages/@overeng/tui-core/test/**/*.test.cjs, packages/@overeng/tui-core/test/**/*.test.jsx, packages/@overeng/tui-core/test/**/*.test.mjs, packages/@overeng/tui-core/test/**/*.ts, packages/@overeng/tui-core/test/**/*.tsx, packages/@overeng/tui-core/test/**/__snapshots__/*.snap, packages/@overeng/tui-core/tsconfig.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -29,6 +30,14 @@ export_materialization_inputs([ "test/renderer.test.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/tui-core", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_tui_core_45029ece7ddb", @@ -59,7 +68,7 @@ package_view( }, workspace_dependency_views = { }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -84,7 +93,7 @@ package_view( workspace_dependency_views = { }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/tui-core/BUCK.genie.ts b/packages/@overeng/tui-core/BUCK.genie.ts index 45532ec081..bb8443dca0 100644 --- a/packages/@overeng/tui-core/BUCK.genie.ts +++ b/packages/@overeng/tui-core/BUCK.genie.ts @@ -7,11 +7,7 @@ export const buck2TypeScriptAdmission = { packagePath: 'packages/@overeng/tui-core', projectionSource: 'packages/@overeng/tui-core/BUCK.genie.ts', sourceRoots: ['src', 'test'], - editorViewConsumer: true, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/tui-react/BUCK b/packages/@overeng/tui-react/BUCK index 6eaed27c68..437d790966 100644 --- a/packages/@overeng/tui-react/BUCK +++ b/packages/@overeng/tui-react/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/tui-react/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:f029384f29181161e10d703083a9bb2d4f02fdf61cd1184081d45fe11084bae4 -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/tui-core/BUCK.genie.ts, packages/@overeng/tui-core/package.json.genie.ts, packages/@overeng/tui-react/BUCK.genie.ts, packages/@overeng/tui-react/BUCK.genie.ts, packages/@overeng/tui-react/e2e/**/*.cts, packages/@overeng/tui-react/e2e/**/*.js, packages/@overeng/tui-react/e2e/**/*.mts, packages/@overeng/tui-react/e2e/**/*.spec.cjs, packages/@overeng/tui-react/e2e/**/*.spec.jsx, packages/@overeng/tui-react/e2e/**/*.spec.mjs, packages/@overeng/tui-react/e2e/**/*.test.cjs, packages/@overeng/tui-react/e2e/**/*.test.jsx, packages/@overeng/tui-react/e2e/**/*.test.mjs, packages/@overeng/tui-react/e2e/**/*.ts, packages/@overeng/tui-react/e2e/**/*.tsx, packages/@overeng/tui-react/e2e/**/__snapshots__/*.snap, packages/@overeng/tui-react/examples/**/*.cts, packages/@overeng/tui-react/examples/**/*.js, packages/@overeng/tui-react/examples/**/*.mts, packages/@overeng/tui-react/examples/**/*.spec.cjs, packages/@overeng/tui-react/examples/**/*.spec.jsx, packages/@overeng/tui-react/examples/**/*.spec.mjs, packages/@overeng/tui-react/examples/**/*.test.cjs, packages/@overeng/tui-react/examples/**/*.test.jsx, packages/@overeng/tui-react/examples/**/*.test.mjs, packages/@overeng/tui-react/examples/**/*.ts, packages/@overeng/tui-react/examples/**/*.tsx, packages/@overeng/tui-react/examples/**/__snapshots__/*.snap, packages/@overeng/tui-react/package.json.genie.ts, packages/@overeng/tui-react/src/**/*.cts, packages/@overeng/tui-react/src/**/*.js, packages/@overeng/tui-react/src/**/*.mts, packages/@overeng/tui-react/src/**/*.spec.cjs, packages/@overeng/tui-react/src/**/*.spec.jsx, packages/@overeng/tui-react/src/**/*.spec.mjs, packages/@overeng/tui-react/src/**/*.test.cjs, packages/@overeng/tui-react/src/**/*.test.jsx, packages/@overeng/tui-react/src/**/*.test.mjs, packages/@overeng/tui-react/src/**/*.ts, packages/@overeng/tui-react/src/**/*.tsx, packages/@overeng/tui-react/src/**/__snapshots__/*.snap, packages/@overeng/tui-react/test/**/*.cts, packages/@overeng/tui-react/test/**/*.js, packages/@overeng/tui-react/test/**/*.mts, packages/@overeng/tui-react/test/**/*.spec.cjs, packages/@overeng/tui-react/test/**/*.spec.jsx, packages/@overeng/tui-react/test/**/*.spec.mjs, packages/@overeng/tui-react/test/**/*.test.cjs, packages/@overeng/tui-react/test/**/*.test.jsx, packages/@overeng/tui-react/test/**/*.test.mjs, packages/@overeng/tui-react/test/**/*.ts, packages/@overeng/tui-react/test/**/*.tsx, packages/@overeng/tui-react/test/**/__snapshots__/*.snap, packages/@overeng/tui-react/tsconfig.buck.json.genie.ts, packages/@overeng/tui-react/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts +# Semantic fingerprint: sha256:356577d8e2f9e4cbdf712ad6a9950f5f2ee7ad52918ff7b2f4a30c422669fdc7 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/tui-core/BUCK.genie.ts, packages/@overeng/tui-core/package.json.genie.ts, packages/@overeng/tui-react/BUCK.genie.ts, packages/@overeng/tui-react/BUCK.genie.ts, packages/@overeng/tui-react/e2e/**/*.cts, packages/@overeng/tui-react/e2e/**/*.js, packages/@overeng/tui-react/e2e/**/*.mts, packages/@overeng/tui-react/e2e/**/*.spec.cjs, packages/@overeng/tui-react/e2e/**/*.spec.jsx, packages/@overeng/tui-react/e2e/**/*.spec.mjs, packages/@overeng/tui-react/e2e/**/*.test.cjs, packages/@overeng/tui-react/e2e/**/*.test.jsx, packages/@overeng/tui-react/e2e/**/*.test.mjs, packages/@overeng/tui-react/e2e/**/*.ts, packages/@overeng/tui-react/e2e/**/*.tsx, packages/@overeng/tui-react/e2e/**/__snapshots__/*.snap, packages/@overeng/tui-react/examples/**/*.cts, packages/@overeng/tui-react/examples/**/*.js, packages/@overeng/tui-react/examples/**/*.mts, packages/@overeng/tui-react/examples/**/*.spec.cjs, packages/@overeng/tui-react/examples/**/*.spec.jsx, packages/@overeng/tui-react/examples/**/*.spec.mjs, packages/@overeng/tui-react/examples/**/*.test.cjs, packages/@overeng/tui-react/examples/**/*.test.jsx, packages/@overeng/tui-react/examples/**/*.test.mjs, packages/@overeng/tui-react/examples/**/*.ts, packages/@overeng/tui-react/examples/**/*.tsx, packages/@overeng/tui-react/examples/**/__snapshots__/*.snap, packages/@overeng/tui-react/package.json.genie.ts, packages/@overeng/tui-react/src/**/*.cts, packages/@overeng/tui-react/src/**/*.js, packages/@overeng/tui-react/src/**/*.mts, packages/@overeng/tui-react/src/**/*.spec.cjs, packages/@overeng/tui-react/src/**/*.spec.jsx, packages/@overeng/tui-react/src/**/*.spec.mjs, packages/@overeng/tui-react/src/**/*.test.cjs, packages/@overeng/tui-react/src/**/*.test.jsx, packages/@overeng/tui-react/src/**/*.test.mjs, packages/@overeng/tui-react/src/**/*.ts, packages/@overeng/tui-react/src/**/*.tsx, packages/@overeng/tui-react/src/**/__snapshots__/*.snap, packages/@overeng/tui-react/test/**/*.cts, packages/@overeng/tui-react/test/**/*.js, packages/@overeng/tui-react/test/**/*.mts, packages/@overeng/tui-react/test/**/*.spec.cjs, packages/@overeng/tui-react/test/**/*.spec.jsx, packages/@overeng/tui-react/test/**/*.spec.mjs, packages/@overeng/tui-react/test/**/*.test.cjs, packages/@overeng/tui-react/test/**/*.test.jsx, packages/@overeng/tui-react/test/**/*.test.mjs, packages/@overeng/tui-react/test/**/*.ts, packages/@overeng/tui-react/test/**/*.tsx, packages/@overeng/tui-react/test/**/__snapshots__/*.snap, packages/@overeng/tui-react/tsconfig.buck.json.genie.ts, packages/@overeng/tui-react/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -128,6 +129,14 @@ export_materialization_inputs([ "test/unit/viewport.test.tsx", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/tui-react", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_tui_react_f20a858a9232", @@ -267,7 +276,7 @@ package_view( "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -401,7 +410,7 @@ package_view( "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/tui-react/BUCK.genie.ts b/packages/@overeng/tui-react/BUCK.genie.ts index 84e65d791f..11fe2ddfec 100644 --- a/packages/@overeng/tui-react/BUCK.genie.ts +++ b/packages/@overeng/tui-react/BUCK.genie.ts @@ -24,11 +24,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils-dev:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/mod.d.ts', - projectFile: 'tsconfig.buck.json', - }, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.buck.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/tui-stories/BUCK b/packages/@overeng/tui-stories/BUCK index f51c7810d8..922562f9ae 100644 --- a/packages/@overeng/tui-stories/BUCK +++ b/packages/@overeng/tui-stories/BUCK @@ -5,14 +5,15 @@ load("//buck2:package_tools.bzl", "package_bin_artifact") load("//buck2/products:defs.bzl", "javascript_product") # Projection source: packages/@overeng/tui-stories/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:45d6187731707d5f1d81cea743db2544ce9c74bf7eebce6274153ead4272f3cf -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/megarepo/BUCK.genie.ts, packages/@overeng/megarepo/package.json.genie.ts, packages/@overeng/megarepo/src/**/*.cts, packages/@overeng/megarepo/src/**/*.js, packages/@overeng/megarepo/src/**/*.mts, packages/@overeng/megarepo/src/**/*.ts, packages/@overeng/megarepo/src/**/*.tsx, packages/@overeng/tui-react/BUCK.genie.ts, packages/@overeng/tui-react/package.json.genie.ts, packages/@overeng/tui-stories/.storybook/**/*.cts, packages/@overeng/tui-stories/.storybook/**/*.js, packages/@overeng/tui-stories/.storybook/**/*.mts, packages/@overeng/tui-stories/.storybook/**/*.spec.cjs, packages/@overeng/tui-stories/.storybook/**/*.spec.jsx, packages/@overeng/tui-stories/.storybook/**/*.spec.mjs, packages/@overeng/tui-stories/.storybook/**/*.test.cjs, packages/@overeng/tui-stories/.storybook/**/*.test.jsx, packages/@overeng/tui-stories/.storybook/**/*.test.mjs, packages/@overeng/tui-stories/.storybook/**/*.ts, packages/@overeng/tui-stories/.storybook/**/*.tsx, packages/@overeng/tui-stories/.storybook/**/__snapshots__/*.snap, packages/@overeng/tui-stories/BUCK.genie.ts, packages/@overeng/tui-stories/BUCK.genie.ts, packages/@overeng/tui-stories/bin/**/*.cts, packages/@overeng/tui-stories/bin/**/*.js, packages/@overeng/tui-stories/bin/**/*.mts, packages/@overeng/tui-stories/bin/**/*.spec.cjs, packages/@overeng/tui-stories/bin/**/*.spec.jsx, packages/@overeng/tui-stories/bin/**/*.spec.mjs, packages/@overeng/tui-stories/bin/**/*.test.cjs, packages/@overeng/tui-stories/bin/**/*.test.jsx, packages/@overeng/tui-stories/bin/**/*.test.mjs, packages/@overeng/tui-stories/bin/**/*.ts, packages/@overeng/tui-stories/bin/**/*.tsx, packages/@overeng/tui-stories/bin/**/__snapshots__/*.snap, packages/@overeng/tui-stories/package.json.genie.ts, packages/@overeng/tui-stories/src/**/*.cts, packages/@overeng/tui-stories/src/**/*.js, packages/@overeng/tui-stories/src/**/*.mts, packages/@overeng/tui-stories/src/**/*.spec.cjs, packages/@overeng/tui-stories/src/**/*.spec.jsx, packages/@overeng/tui-stories/src/**/*.spec.mjs, packages/@overeng/tui-stories/src/**/*.test.cjs, packages/@overeng/tui-stories/src/**/*.test.jsx, packages/@overeng/tui-stories/src/**/*.test.mjs, packages/@overeng/tui-stories/src/**/*.ts, packages/@overeng/tui-stories/src/**/*.tsx, packages/@overeng/tui-stories/src/**/__snapshots__/*.snap, packages/@overeng/tui-stories/test/**/*.cts, packages/@overeng/tui-stories/test/**/*.js, packages/@overeng/tui-stories/test/**/*.mts, packages/@overeng/tui-stories/test/**/*.spec.cjs, packages/@overeng/tui-stories/test/**/*.spec.jsx, packages/@overeng/tui-stories/test/**/*.spec.mjs, packages/@overeng/tui-stories/test/**/*.test.cjs, packages/@overeng/tui-stories/test/**/*.test.jsx, packages/@overeng/tui-stories/test/**/*.test.mjs, packages/@overeng/tui-stories/test/**/*.ts, packages/@overeng/tui-stories/test/**/*.tsx, packages/@overeng/tui-stories/test/**/__snapshots__/*.snap, packages/@overeng/tui-stories/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts +# Semantic fingerprint: sha256:78ebd2e488d70d16c91454b5d5411be1aeb6603b028a8d261a1cbd958a8e76c3 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/megarepo/BUCK.genie.ts, packages/@overeng/megarepo/package.json.genie.ts, packages/@overeng/megarepo/src/**/*.cts, packages/@overeng/megarepo/src/**/*.js, packages/@overeng/megarepo/src/**/*.mts, packages/@overeng/megarepo/src/**/*.ts, packages/@overeng/megarepo/src/**/*.tsx, packages/@overeng/tui-react/BUCK.genie.ts, packages/@overeng/tui-react/package.json.genie.ts, packages/@overeng/tui-stories/.storybook/**/*.cts, packages/@overeng/tui-stories/.storybook/**/*.js, packages/@overeng/tui-stories/.storybook/**/*.mts, packages/@overeng/tui-stories/.storybook/**/*.spec.cjs, packages/@overeng/tui-stories/.storybook/**/*.spec.jsx, packages/@overeng/tui-stories/.storybook/**/*.spec.mjs, packages/@overeng/tui-stories/.storybook/**/*.test.cjs, packages/@overeng/tui-stories/.storybook/**/*.test.jsx, packages/@overeng/tui-stories/.storybook/**/*.test.mjs, packages/@overeng/tui-stories/.storybook/**/*.ts, packages/@overeng/tui-stories/.storybook/**/*.tsx, packages/@overeng/tui-stories/.storybook/**/__snapshots__/*.snap, packages/@overeng/tui-stories/BUCK.genie.ts, packages/@overeng/tui-stories/BUCK.genie.ts, packages/@overeng/tui-stories/bin/**/*.cts, packages/@overeng/tui-stories/bin/**/*.js, packages/@overeng/tui-stories/bin/**/*.mts, packages/@overeng/tui-stories/bin/**/*.spec.cjs, packages/@overeng/tui-stories/bin/**/*.spec.jsx, packages/@overeng/tui-stories/bin/**/*.spec.mjs, packages/@overeng/tui-stories/bin/**/*.test.cjs, packages/@overeng/tui-stories/bin/**/*.test.jsx, packages/@overeng/tui-stories/bin/**/*.test.mjs, packages/@overeng/tui-stories/bin/**/*.ts, packages/@overeng/tui-stories/bin/**/*.tsx, packages/@overeng/tui-stories/bin/**/__snapshots__/*.snap, packages/@overeng/tui-stories/package.json.genie.ts, packages/@overeng/tui-stories/src/**/*.cts, packages/@overeng/tui-stories/src/**/*.js, packages/@overeng/tui-stories/src/**/*.mts, packages/@overeng/tui-stories/src/**/*.spec.cjs, packages/@overeng/tui-stories/src/**/*.spec.jsx, packages/@overeng/tui-stories/src/**/*.spec.mjs, packages/@overeng/tui-stories/src/**/*.test.cjs, packages/@overeng/tui-stories/src/**/*.test.jsx, packages/@overeng/tui-stories/src/**/*.test.mjs, packages/@overeng/tui-stories/src/**/*.ts, packages/@overeng/tui-stories/src/**/*.tsx, packages/@overeng/tui-stories/src/**/__snapshots__/*.snap, packages/@overeng/tui-stories/test/**/*.cts, packages/@overeng/tui-stories/test/**/*.js, packages/@overeng/tui-stories/test/**/*.mts, packages/@overeng/tui-stories/test/**/*.spec.cjs, packages/@overeng/tui-stories/test/**/*.spec.jsx, packages/@overeng/tui-stories/test/**/*.spec.mjs, packages/@overeng/tui-stories/test/**/*.test.cjs, packages/@overeng/tui-stories/test/**/*.test.jsx, packages/@overeng/tui-stories/test/**/*.test.mjs, packages/@overeng/tui-stories/test/**/*.ts, packages/@overeng/tui-stories/test/**/*.tsx, packages/@overeng/tui-stories/test/**/__snapshots__/*.snap, packages/@overeng/tui-stories/tsconfig.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -64,6 +65,14 @@ export_materialization_inputs([ "test/render-wire-baseline.test.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/tui-stories", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_tui_stories_e7d895529eb9", @@ -122,300 +131,8 @@ package_view( "test/render-wire-baseline.test.ts": "test/render-wire-baseline.test.ts", "tsconfig.json": "tsconfig.json", }, - workspace_dist = { - "node_modules/@overeng/megarepo/package.json": "//packages/@overeng/megarepo:package.json", - "node_modules/@overeng/megarepo/src/buck2-manifest.ts": "//packages/@overeng/megarepo:src/buck2-manifest.ts", - "node_modules/@overeng/megarepo/src/buck2-manifest.unit.test.ts": "//packages/@overeng/megarepo:src/buck2-manifest.unit.test.ts", - "node_modules/@overeng/megarepo/src/cli.contract.test.ts": "//packages/@overeng/megarepo:src/cli.contract.test.ts", - "node_modules/@overeng/megarepo/src/cli/cli.integration.test.ts": "//packages/@overeng/megarepo:src/cli/cli.integration.test.ts", - "node_modules/@overeng/megarepo/src/cli/commands/add.ts": "//packages/@overeng/megarepo:src/cli/commands/add.ts", - "node_modules/@overeng/megarepo/src/cli/commands/apply.ts": "//packages/@overeng/megarepo:src/cli/commands/apply.ts", - "node_modules/@overeng/megarepo/src/cli/commands/check.ts": "//packages/@overeng/megarepo:src/cli/commands/check.ts", - "node_modules/@overeng/megarepo/src/cli/commands/composition.integration.test.ts": "//packages/@overeng/megarepo:src/cli/commands/composition.integration.test.ts", - "node_modules/@overeng/megarepo/src/cli/commands/composition.ts": "//packages/@overeng/megarepo:src/cli/commands/composition.ts", - "node_modules/@overeng/megarepo/src/cli/commands/config/mod.ts": "//packages/@overeng/megarepo:src/cli/commands/config/mod.ts", - "node_modules/@overeng/megarepo/src/cli/commands/config/push-refs.ts": "//packages/@overeng/megarepo:src/cli/commands/config/push-refs.ts", - "node_modules/@overeng/megarepo/src/cli/commands/deps.ts": "//packages/@overeng/megarepo:src/cli/commands/deps.ts", - "node_modules/@overeng/megarepo/src/cli/commands/engine.ts": "//packages/@overeng/megarepo:src/cli/commands/engine.ts", - "node_modules/@overeng/megarepo/src/cli/commands/env.ts": "//packages/@overeng/megarepo:src/cli/commands/env.ts", - "node_modules/@overeng/megarepo/src/cli/commands/exec.ts": "//packages/@overeng/megarepo:src/cli/commands/exec.ts", - "node_modules/@overeng/megarepo/src/cli/commands/fetch.ts": "//packages/@overeng/megarepo:src/cli/commands/fetch.ts", - "node_modules/@overeng/megarepo/src/cli/commands/generate/mod.ts": "//packages/@overeng/megarepo:src/cli/commands/generate/mod.ts", - "node_modules/@overeng/megarepo/src/cli/commands/init.ts": "//packages/@overeng/megarepo:src/cli/commands/init.ts", - "node_modules/@overeng/megarepo/src/cli/commands/lock.ts": "//packages/@overeng/megarepo:src/cli/commands/lock.ts", - "node_modules/@overeng/megarepo/src/cli/commands/ls.ts": "//packages/@overeng/megarepo:src/cli/commands/ls.ts", - "node_modules/@overeng/megarepo/src/cli/commands/mod.ts": "//packages/@overeng/megarepo:src/cli/commands/mod.ts", - "node_modules/@overeng/megarepo/src/cli/commands/pin.ts": "//packages/@overeng/megarepo:src/cli/commands/pin.ts", - "node_modules/@overeng/megarepo/src/cli/commands/root.ts": "//packages/@overeng/megarepo:src/cli/commands/root.ts", - "node_modules/@overeng/megarepo/src/cli/commands/status.ts": "//packages/@overeng/megarepo:src/cli/commands/status.ts", - "node_modules/@overeng/megarepo/src/cli/commands/store/composed-worktrees.integration.test.ts": "//packages/@overeng/megarepo:src/cli/commands/store/composed-worktrees.integration.test.ts", - "node_modules/@overeng/megarepo/src/cli/commands/store/mod.ts": "//packages/@overeng/megarepo:src/cli/commands/store/mod.ts", - "node_modules/@overeng/megarepo/src/cli/components/Header.stories.tsx": "//packages/@overeng/megarepo:src/cli/components/Header.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/components/Header.tsx": "//packages/@overeng/megarepo:src/cli/components/Header.tsx", - "node_modules/@overeng/megarepo/src/cli/components/LogLine.stories.tsx": "//packages/@overeng/megarepo:src/cli/components/LogLine.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/components/LogLine.tsx": "//packages/@overeng/megarepo:src/cli/components/LogLine.tsx", - "node_modules/@overeng/megarepo/src/cli/components/MemberRow.tsx": "//packages/@overeng/megarepo:src/cli/components/MemberRow.tsx", - "node_modules/@overeng/megarepo/src/cli/components/Scope.tsx": "//packages/@overeng/megarepo:src/cli/components/Scope.tsx", - "node_modules/@overeng/megarepo/src/cli/components/Separator.stories.tsx": "//packages/@overeng/megarepo:src/cli/components/Separator.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/components/Separator.tsx": "//packages/@overeng/megarepo:src/cli/components/Separator.tsx", - "node_modules/@overeng/megarepo/src/cli/components/StatusIcon.stories.tsx": "//packages/@overeng/megarepo:src/cli/components/StatusIcon.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/components/StatusIcon.tsx": "//packages/@overeng/megarepo:src/cli/components/StatusIcon.tsx", - "node_modules/@overeng/megarepo/src/cli/components/Summary.stories.tsx": "//packages/@overeng/megarepo:src/cli/components/Summary.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/components/Summary.tsx": "//packages/@overeng/megarepo:src/cli/components/Summary.tsx", - "node_modules/@overeng/megarepo/src/cli/components/TaskItem.stories.tsx": "//packages/@overeng/megarepo:src/cli/components/TaskItem.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/components/TaskItem.tsx": "//packages/@overeng/megarepo:src/cli/components/TaskItem.tsx", - "node_modules/@overeng/megarepo/src/cli/components/mod.ts": "//packages/@overeng/megarepo:src/cli/components/mod.ts", - "node_modules/@overeng/megarepo/src/cli/components/tokens.ts": "//packages/@overeng/megarepo:src/cli/components/tokens.ts", - "node_modules/@overeng/megarepo/src/cli/context.ts": "//packages/@overeng/megarepo:src/cli/context.ts", - "node_modules/@overeng/megarepo/src/cli/errors.ts": "//packages/@overeng/megarepo:src/cli/errors.ts", - "node_modules/@overeng/megarepo/src/cli/mod.ts": "//packages/@overeng/megarepo:src/cli/mod.ts", - "node_modules/@overeng/megarepo/src/cli/observability.ts": "//packages/@overeng/megarepo:src/cli/observability.ts", - "node_modules/@overeng/megarepo/src/cli/pin.integration.test.ts": "//packages/@overeng/megarepo:src/cli/pin.integration.test.ts", - "node_modules/@overeng/megarepo/src/cli/prompt-select-pty-fixture.ts": "//packages/@overeng/megarepo:src/cli/prompt-select-pty-fixture.ts", - "node_modules/@overeng/megarepo/src/cli/prompt-select-pty.test.ts": "//packages/@overeng/megarepo:src/cli/prompt-select-pty.test.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/AddOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/AddOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/AddOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/AddOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/AddOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/AddOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/AddOutput/stories/Errors.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/AddOutput/stories/Errors.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/AddOutput/stories/Success.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/AddOutput/stories/Success.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/AddOutput/stories/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/AddOutput/stories/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/AddOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/AddOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/DepsOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/DepsOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/DepsOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/DepsOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/DepsOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/DepsOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/DepsOutput/stories/Basic.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/DepsOutput/stories/Basic.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/DepsOutput/stories/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/DepsOutput/stories/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/DepsOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/DepsOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/EnvOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/EnvOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/EnvOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/EnvOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/EnvOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/EnvOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/EnvOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/EnvOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/ExecOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/ExecOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/ExecOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/ExecOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/ExecOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/ExecOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/ExecOutput/stories/Complete.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/ExecOutput/stories/Complete.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/ExecOutput/stories/Errors.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/ExecOutput/stories/Errors.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/ExecOutput/stories/Running.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/ExecOutput/stories/Running.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/ExecOutput/stories/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/ExecOutput/stories/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/ExecOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/ExecOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/GenerateOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/GenerateOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/GenerateOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/GenerateOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/GenerateOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/GenerateOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/GenerateOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/GenerateOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/InitOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/InitOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/InitOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/InitOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/InitOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/InitOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/InitOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/InitOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/LsOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/LsOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/LsOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/LsOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/LsOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/LsOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/LsOutput/stories/Basic.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/LsOutput/stories/Basic.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/LsOutput/stories/Nested.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/LsOutput/stories/Nested.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/LsOutput/stories/Sources.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/LsOutput/stories/Sources.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/LsOutput/stories/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/LsOutput/stories/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/LsOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/LsOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/PinOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/PinOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/PinOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/PinOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/PinOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/PinOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/PinOutput/stories/Errors.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/PinOutput/stories/Errors.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/PinOutput/stories/Success.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/PinOutput/stories/Success.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/PinOutput/stories/Warnings.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/PinOutput/stories/Warnings.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/PinOutput/stories/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/PinOutput/stories/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/PinOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/PinOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/PushRefsOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/PushRefsOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/PushRefsOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/PushRefsOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/PushRefsOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/PushRefsOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/PushRefsOutput/stories/Errors.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/PushRefsOutput/stories/Errors.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/PushRefsOutput/stories/Results.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/PushRefsOutput/stories/Results.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/PushRefsOutput/stories/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/PushRefsOutput/stories/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/PushRefsOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/PushRefsOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/RootOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/RootOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/RootOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/RootOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/RootOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/RootOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/RootOutput/stories/Errors.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/RootOutput/stories/Errors.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/RootOutput/stories/Success.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/RootOutput/stories/Success.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/RootOutput/stories/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/RootOutput/stories/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/RootOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/RootOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StatusOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/StatusOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/StatusOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/StatusOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/StatusOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/StatusOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/StatusOutput/stories/Basic.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StatusOutput/stories/Basic.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StatusOutput/stories/Complex.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StatusOutput/stories/Complex.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StatusOutput/stories/LockIssues.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StatusOutput/stories/LockIssues.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StatusOutput/stories/RefIssues.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StatusOutput/stories/RefIssues.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StatusOutput/stories/WorktreeIssues.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StatusOutput/stories/WorktreeIssues.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StatusOutput/stories/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/StatusOutput/stories/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/StatusOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StatusOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/stories/Add.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/stories/Add.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/stories/Fetch.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/stories/Fetch.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/stories/Fix.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/stories/Fix.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/stories/GC.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/stories/GC.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/stories/List.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/stories/List.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/stories/Status.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/stories/Status.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/stories/WorktreeNew.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/stories/WorktreeNew.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/stories/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/stories/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/view.unit.test.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/view.unit.test.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/apply/Results.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/apply/Results.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/apply/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/apply/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/fetch/Issues.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/fetch/Issues.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/fetch/LockSync.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/fetch/LockSync.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/fetch/Nested.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/fetch/Nested.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/fetch/Results.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/fetch/Results.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/fetch/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/fetch/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/lock/Results.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/lock/Results.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/lock/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/lock/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/preflight/PreflightFailed.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/preflight/PreflightFailed.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/ui.ts": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/ui.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/_story-constants.ts": "//packages/@overeng/megarepo:src/cli/renderers/_story-constants.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/mod.ts", - "node_modules/@overeng/megarepo/src/cli/status.integration.test.ts": "//packages/@overeng/megarepo:src/cli/status.integration.test.ts", - "node_modules/@overeng/megarepo/src/cli/store-gc-cold.integration.test.ts": "//packages/@overeng/megarepo:src/cli/store-gc-cold.integration.test.ts", - "node_modules/@overeng/megarepo/src/cli/store-gc-generated.integration.test.ts": "//packages/@overeng/megarepo:src/cli/store-gc-generated.integration.test.ts", - "node_modules/@overeng/megarepo/src/cli/store-gc-otel.integration.test.ts": "//packages/@overeng/megarepo:src/cli/store-gc-otel.integration.test.ts", - "node_modules/@overeng/megarepo/src/cli/store.integration.test.ts": "//packages/@overeng/megarepo:src/cli/store.integration.test.ts", - "node_modules/@overeng/megarepo/src/cli/sync.integration.test.ts": "//packages/@overeng/megarepo:src/cli/sync.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/acquisition/owned-worktree-acquisition-schema.ts": "//packages/@overeng/megarepo:src/composition/acquisition/owned-worktree-acquisition-schema.ts", - "node_modules/@overeng/megarepo/src/composition/acquisition/owned-worktree-acquisition.integration.test.ts": "//packages/@overeng/megarepo:src/composition/acquisition/owned-worktree-acquisition.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/acquisition/owned-worktree-acquisition.ts": "//packages/@overeng/megarepo:src/composition/acquisition/owned-worktree-acquisition.ts", - "node_modules/@overeng/megarepo/src/composition/apply/composition-apply-schema.ts": "//packages/@overeng/megarepo:src/composition/apply/composition-apply-schema.ts", - "node_modules/@overeng/megarepo/src/composition/apply/composition-apply.integration.test.ts": "//packages/@overeng/megarepo:src/composition/apply/composition-apply.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/apply/composition-apply.ts": "//packages/@overeng/megarepo:src/composition/apply/composition-apply.ts", - "node_modules/@overeng/megarepo/src/composition/apply/composition-apply.unit.test.ts": "//packages/@overeng/megarepo:src/composition/apply/composition-apply.unit.test.ts", - "node_modules/@overeng/megarepo/src/composition/apply/composition-runtime.ts": "//packages/@overeng/megarepo:src/composition/apply/composition-runtime.ts", - "node_modules/@overeng/megarepo/src/composition/apply/workspace-update-lock-schema.ts": "//packages/@overeng/megarepo:src/composition/apply/workspace-update-lock-schema.ts", - "node_modules/@overeng/megarepo/src/composition/apply/workspace-update-lock-schema.unit.test.ts": "//packages/@overeng/megarepo:src/composition/apply/workspace-update-lock-schema.unit.test.ts", - "node_modules/@overeng/megarepo/src/composition/apply/workspace-update-lock.integration.test.ts": "//packages/@overeng/megarepo:src/composition/apply/workspace-update-lock.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/apply/workspace-update-lock.ts": "//packages/@overeng/megarepo:src/composition/apply/workspace-update-lock.ts", - "node_modules/@overeng/megarepo/src/composition/capabilities/composition-capability-resolver-schema.ts": "//packages/@overeng/megarepo:src/composition/capabilities/composition-capability-resolver-schema.ts", - "node_modules/@overeng/megarepo/src/composition/capabilities/composition-capability-resolver.integration.test.ts": "//packages/@overeng/megarepo:src/composition/capabilities/composition-capability-resolver.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/capabilities/composition-capability-resolver.ts": "//packages/@overeng/megarepo:src/composition/capabilities/composition-capability-resolver.ts", - "node_modules/@overeng/megarepo/src/composition/capabilities/owned-capability-projection.integration.test.ts": "//packages/@overeng/megarepo:src/composition/capabilities/owned-capability-projection.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/capabilities/owned-capability-projection.ts": "//packages/@overeng/megarepo:src/composition/capabilities/owned-capability-projection.ts", - "node_modules/@overeng/megarepo/src/composition/mounts/member-mount-cp-a-schema.ts": "//packages/@overeng/megarepo:src/composition/mounts/member-mount-cp-a-schema.ts", - "node_modules/@overeng/megarepo/src/composition/mounts/member-mount-cp-a-schema.unit.test.ts": "//packages/@overeng/megarepo:src/composition/mounts/member-mount-cp-a-schema.unit.test.ts", - "node_modules/@overeng/megarepo/src/composition/mounts/member-mount-cp-a.integration.test.ts": "//packages/@overeng/megarepo:src/composition/mounts/member-mount-cp-a.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/mounts/member-mount-cp-a.ts": "//packages/@overeng/megarepo:src/composition/mounts/member-mount-cp-a.ts", - "node_modules/@overeng/megarepo/src/composition/mounts/member-mount-r6.integration.test.ts": "//packages/@overeng/megarepo:src/composition/mounts/member-mount-r6.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/mounts/member-mount-r6.ts": "//packages/@overeng/megarepo:src/composition/mounts/member-mount-r6.ts", - "node_modules/@overeng/megarepo/src/composition/mounts/member-mount-r6.unit.test.ts": "//packages/@overeng/megarepo:src/composition/mounts/member-mount-r6.unit.test.ts", - "node_modules/@overeng/megarepo/src/composition/mounts/member-mount.ts": "//packages/@overeng/megarepo:src/composition/mounts/member-mount.ts", - "node_modules/@overeng/megarepo/src/composition/overlays/dist-overlay-lifecycle-schema.ts": "//packages/@overeng/megarepo:src/composition/overlays/dist-overlay-lifecycle-schema.ts", - "node_modules/@overeng/megarepo/src/composition/overlays/dist-overlay-lifecycle.integration.test.ts": "//packages/@overeng/megarepo:src/composition/overlays/dist-overlay-lifecycle.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/overlays/dist-overlay-lifecycle.ts": "//packages/@overeng/megarepo:src/composition/overlays/dist-overlay-lifecycle.ts", - "node_modules/@overeng/megarepo/src/composition/overlays/dist-overlay-schema.ts": "//packages/@overeng/megarepo:src/composition/overlays/dist-overlay-schema.ts", - "node_modules/@overeng/megarepo/src/composition/overlays/dist-overlay-schema.unit.test.ts": "//packages/@overeng/megarepo:src/composition/overlays/dist-overlay-schema.unit.test.ts", - "node_modules/@overeng/megarepo/src/composition/root/composition-root-publisher.integration.test.ts": "//packages/@overeng/megarepo:src/composition/root/composition-root-publisher.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/root/composition-root-publisher.ts": "//packages/@overeng/megarepo:src/composition/root/composition-root-publisher.ts", - "node_modules/@overeng/megarepo/src/composition/root/composition-root.integration.test.ts": "//packages/@overeng/megarepo:src/composition/root/composition-root.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/root/composition-root.ts": "//packages/@overeng/megarepo:src/composition/root/composition-root.ts", - "node_modules/@overeng/megarepo/src/composition/root/composition-root.unit.test.ts": "//packages/@overeng/megarepo:src/composition/root/composition-root.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/config.ts": "//packages/@overeng/megarepo:src/core/config.ts", - "node_modules/@overeng/megarepo/src/core/config.unit.test.ts": "//packages/@overeng/megarepo:src/core/config.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/git-memory.integration.test.ts": "//packages/@overeng/megarepo:src/core/git-memory.integration.test.ts", - "node_modules/@overeng/megarepo/src/core/git-streaming-parsers.integration.test.ts": "//packages/@overeng/megarepo:src/core/git-streaming-parsers.integration.test.ts", - "node_modules/@overeng/megarepo/src/core/git-timeout.integration.test.ts": "//packages/@overeng/megarepo:src/core/git-timeout.integration.test.ts", - "node_modules/@overeng/megarepo/src/core/git.ts": "//packages/@overeng/megarepo:src/core/git.ts", - "node_modules/@overeng/megarepo/src/core/git.unit.test.ts": "//packages/@overeng/megarepo:src/core/git.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/issues.ts": "//packages/@overeng/megarepo:src/core/issues.ts", - "node_modules/@overeng/megarepo/src/core/lock.ts": "//packages/@overeng/megarepo:src/core/lock.ts", - "node_modules/@overeng/megarepo/src/core/lock.unit.test.ts": "//packages/@overeng/megarepo:src/core/lock.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/megarepo-traversal.ts": "//packages/@overeng/megarepo:src/core/megarepo-traversal.ts", - "node_modules/@overeng/megarepo/src/core/megarepo-traversal.unit.test.ts": "//packages/@overeng/megarepo:src/core/megarepo-traversal.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/flake-url.ts": "//packages/@overeng/megarepo:src/core/nix-lock/flake-url.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/flake-url.unit.test.ts": "//packages/@overeng/megarepo:src/core/nix-lock/flake-url.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/input-discovery.ts": "//packages/@overeng/megarepo:src/core/nix-lock/input-discovery.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/input-discovery.unit.test.ts": "//packages/@overeng/megarepo:src/core/nix-lock/input-discovery.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/matcher.ts": "//packages/@overeng/megarepo:src/core/nix-lock/matcher.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/mod.ts": "//packages/@overeng/megarepo:src/core/nix-lock/mod.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/mod.unit.test.ts": "//packages/@overeng/megarepo:src/core/nix-lock/mod.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/schema.ts": "//packages/@overeng/megarepo:src/core/nix-lock/schema.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/schema.unit.test.ts": "//packages/@overeng/megarepo:src/core/nix-lock/schema.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/source-rewriter.ts": "//packages/@overeng/megarepo:src/core/nix-lock/source-rewriter.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/source-rewriter.unit.test.ts": "//packages/@overeng/megarepo:src/core/nix-lock/source-rewriter.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/observability.ts": "//packages/@overeng/megarepo:src/core/observability.ts", - "node_modules/@overeng/megarepo/src/core/ref.ts": "//packages/@overeng/megarepo:src/core/ref.ts", - "node_modules/@overeng/megarepo/src/core/ref.unit.test.ts": "//packages/@overeng/megarepo:src/core/ref.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/source-policy.ts": "//packages/@overeng/megarepo:src/core/source-policy.ts", - "node_modules/@overeng/megarepo/src/core/source-policy.unit.test.ts": "//packages/@overeng/megarepo:src/core/source-policy.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/version.ts": "//packages/@overeng/megarepo:src/core/version.ts", - "node_modules/@overeng/megarepo/src/generators/generators.unit.test.ts": "//packages/@overeng/megarepo:src/generators/generators.unit.test.ts", - "node_modules/@overeng/megarepo/src/generators/mod.ts": "//packages/@overeng/megarepo:src/generators/mod.ts", - "node_modules/@overeng/megarepo/src/generators/schema.ts": "//packages/@overeng/megarepo:src/generators/schema.ts", - "node_modules/@overeng/megarepo/src/generators/vscode.ts": "//packages/@overeng/megarepo:src/generators/vscode.ts", - "node_modules/@overeng/megarepo/src/git.contract.ts": "//packages/@overeng/megarepo:src/git.contract.ts", - "node_modules/@overeng/megarepo/src/json-wire-baseline.test.ts": "//packages/@overeng/megarepo:src/json-wire-baseline.test.ts", - "node_modules/@overeng/megarepo/src/megarepo.contract.ts": "//packages/@overeng/megarepo:src/megarepo.contract.ts", - "node_modules/@overeng/megarepo/src/mod.ts": "//packages/@overeng/megarepo:src/mod.ts", - "node_modules/@overeng/megarepo/src/nix.contract.ts": "//packages/@overeng/megarepo:src/nix.contract.ts", - "node_modules/@overeng/megarepo/src/store/store-archive.integration.test.ts": "//packages/@overeng/megarepo:src/store/store-archive.integration.test.ts", - "node_modules/@overeng/megarepo/src/store/store-archive.ts": "//packages/@overeng/megarepo:src/store/store-archive.ts", - "node_modules/@overeng/megarepo/src/store/store-deletion-lease.integration.test.ts": "//packages/@overeng/megarepo:src/store/store-deletion-lease.integration.test.ts", - "node_modules/@overeng/megarepo/src/store/store-deletion-lease.ts": "//packages/@overeng/megarepo:src/store/store-deletion-lease.ts", - "node_modules/@overeng/megarepo/src/store/store-fs-atomic.ts": "//packages/@overeng/megarepo:src/store/store-fs-atomic.ts", - "node_modules/@overeng/megarepo/src/store/store-fs-atomic.unit.test.ts": "//packages/@overeng/megarepo:src/store/store-fs-atomic.unit.test.ts", - "node_modules/@overeng/megarepo/src/store/store-gc-config.ts": "//packages/@overeng/megarepo:src/store/store-gc-config.ts", - "node_modules/@overeng/megarepo/src/store/store-gc-config.unit.test.ts": "//packages/@overeng/megarepo:src/store/store-gc-config.unit.test.ts", - "node_modules/@overeng/megarepo/src/store/store-gc-observations.ts": "//packages/@overeng/megarepo:src/store/store-gc-observations.ts", - "node_modules/@overeng/megarepo/src/store/store-gc-observations.unit.test.ts": "//packages/@overeng/megarepo:src/store/store-gc-observations.unit.test.ts", - "node_modules/@overeng/megarepo/src/store/store-gc-plan-order.unit.test.ts": "//packages/@overeng/megarepo:src/store/store-gc-plan-order.unit.test.ts", - "node_modules/@overeng/megarepo/src/store/store-hygiene.ts": "//packages/@overeng/megarepo:src/store/store-hygiene.ts", - "node_modules/@overeng/megarepo/src/store/store-hygiene.unit.test.ts": "//packages/@overeng/megarepo:src/store/store-hygiene.unit.test.ts", - "node_modules/@overeng/megarepo/src/store/store-inuse.integration.test.ts": "//packages/@overeng/megarepo:src/store/store-inuse.integration.test.ts", - "node_modules/@overeng/megarepo/src/store/store-inuse.ts": "//packages/@overeng/megarepo:src/store/store-inuse.ts", - "node_modules/@overeng/megarepo/src/store/store-liveness.integration.test.ts": "//packages/@overeng/megarepo:src/store/store-liveness.integration.test.ts", - "node_modules/@overeng/megarepo/src/store/store-liveness.ts": "//packages/@overeng/megarepo:src/store/store-liveness.ts", - "node_modules/@overeng/megarepo/src/store/store-lock.ts": "//packages/@overeng/megarepo:src/store/store-lock.ts", - "node_modules/@overeng/megarepo/src/store/store-lock.unit.test.ts": "//packages/@overeng/megarepo:src/store/store-lock.unit.test.ts", - "node_modules/@overeng/megarepo/src/store/store-lossless.integration.test.ts": "//packages/@overeng/megarepo:src/store/store-lossless.integration.test.ts", - "node_modules/@overeng/megarepo/src/store/store-lossless.ts": "//packages/@overeng/megarepo:src/store/store-lossless.ts", - "node_modules/@overeng/megarepo/src/store/store-path.ts": "//packages/@overeng/megarepo:src/store/store-path.ts", - "node_modules/@overeng/megarepo/src/store/store-path.unit.test.ts": "//packages/@overeng/megarepo:src/store/store-path.unit.test.ts", - "node_modules/@overeng/megarepo/src/store/store-pr-state.ts": "//packages/@overeng/megarepo:src/store/store-pr-state.ts", - "node_modules/@overeng/megarepo/src/store/store-pr-state.unit.test.ts": "//packages/@overeng/megarepo:src/store/store-pr-state.unit.test.ts", - "node_modules/@overeng/megarepo/src/store/store-symlink.unit.test.ts": "//packages/@overeng/megarepo:src/store/store-symlink.unit.test.ts", - "node_modules/@overeng/megarepo/src/store/store-worktree-policy.ts": "//packages/@overeng/megarepo:src/store/store-worktree-policy.ts", - "node_modules/@overeng/megarepo/src/store/store-worktree-policy.unit.test.ts": "//packages/@overeng/megarepo:src/store/store-worktree-policy.unit.test.ts", - "node_modules/@overeng/megarepo/src/store/store.ts": "//packages/@overeng/megarepo:src/store/store.ts", - "node_modules/@overeng/megarepo/src/sync/member.ts": "//packages/@overeng/megarepo:src/sync/member.ts", - "node_modules/@overeng/megarepo/src/sync/member.unit.test.ts": "//packages/@overeng/megarepo:src/sync/member.unit.test.ts", - "node_modules/@overeng/megarepo/src/sync/mod.ts": "//packages/@overeng/megarepo:src/sync/mod.ts", - "node_modules/@overeng/megarepo/src/sync/schema.ts": "//packages/@overeng/megarepo:src/sync/schema.ts", - "node_modules/@overeng/megarepo/src/sync/types.ts": "//packages/@overeng/megarepo:src/sync/types.ts", - "node_modules/@overeng/megarepo/src/test-utils/consoleCapture.ts": "//packages/@overeng/megarepo:src/test-utils/consoleCapture.ts", - "node_modules/@overeng/megarepo/src/test-utils/coreutils.ts": "//packages/@overeng/megarepo:src/test-utils/coreutils.ts", - "node_modules/@overeng/megarepo/src/test-utils/coreutils.unit.test.ts": "//packages/@overeng/megarepo:src/test-utils/coreutils.unit.test.ts", - "node_modules/@overeng/megarepo/src/test-utils/git-env-setup.ts": "//packages/@overeng/megarepo:src/test-utils/git-env-setup.ts", - "node_modules/@overeng/megarepo/src/test-utils/json.ts": "//packages/@overeng/megarepo:src/test-utils/json.ts", - "node_modules/@overeng/megarepo/src/test-utils/memory-probe.ts": "//packages/@overeng/megarepo:src/test-utils/memory-probe.ts", - "node_modules/@overeng/megarepo/src/test-utils/mod.ts": "//packages/@overeng/megarepo:src/test-utils/mod.ts", - "node_modules/@overeng/megarepo/src/test-utils/setup.ts": "//packages/@overeng/megarepo:src/test-utils/setup.ts", - "node_modules/@overeng/megarepo/src/test-utils/setup.unit.test.ts": "//packages/@overeng/megarepo:src/test-utils/setup.unit.test.ts", - "node_modules/@overeng/megarepo/src/test-utils/store-setup.integration.test.ts": "//packages/@overeng/megarepo:src/test-utils/store-setup.integration.test.ts", - "node_modules/@overeng/megarepo/src/test-utils/store-setup.ts": "//packages/@overeng/megarepo:src/test-utils/store-setup.ts", - "node_modules/@overeng/megarepo/src/test-utils/temp-root.ts": "//packages/@overeng/megarepo:src/test-utils/temp-root.ts", - "node_modules/@overeng/tui-react/dist": "//packages/@overeng/tui-react:dist", - "node_modules/@overeng/tui-react/package.json": "//packages/@overeng/tui-react:package.json", - "node_modules/@overeng/utils-dev/dist": "//packages/@overeng/utils-dev:dist", - "node_modules/@overeng/utils-dev/package.json": "//packages/@overeng/utils-dev:package.json", - "node_modules/@overeng/utils/dist": "//packages/@overeng/utils:dist", - "node_modules/@overeng/utils/package.json": "//packages/@overeng/utils:package.json", - }, - workspace_dependency_views = { - "node_modules/@overeng/megarepo/node_modules": "//packages/@overeng/megarepo:package_tree", - "node_modules/@overeng/tui-react/node_modules": "//packages/@overeng/tui-react:package_tree", - "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", - "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", - }, - runtime = "//:package_tree_runtime", + + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -468,301 +185,9 @@ package_view( "tsconfig.json": "tsconfig.json", "vitest.config.ts": "vitest.config.ts", }, - workspace_dist = { - "node_modules/@overeng/megarepo/package.json": "//packages/@overeng/megarepo:package.json", - "node_modules/@overeng/megarepo/src/buck2-manifest.ts": "//packages/@overeng/megarepo:src/buck2-manifest.ts", - "node_modules/@overeng/megarepo/src/buck2-manifest.unit.test.ts": "//packages/@overeng/megarepo:src/buck2-manifest.unit.test.ts", - "node_modules/@overeng/megarepo/src/cli.contract.test.ts": "//packages/@overeng/megarepo:src/cli.contract.test.ts", - "node_modules/@overeng/megarepo/src/cli/cli.integration.test.ts": "//packages/@overeng/megarepo:src/cli/cli.integration.test.ts", - "node_modules/@overeng/megarepo/src/cli/commands/add.ts": "//packages/@overeng/megarepo:src/cli/commands/add.ts", - "node_modules/@overeng/megarepo/src/cli/commands/apply.ts": "//packages/@overeng/megarepo:src/cli/commands/apply.ts", - "node_modules/@overeng/megarepo/src/cli/commands/check.ts": "//packages/@overeng/megarepo:src/cli/commands/check.ts", - "node_modules/@overeng/megarepo/src/cli/commands/composition.integration.test.ts": "//packages/@overeng/megarepo:src/cli/commands/composition.integration.test.ts", - "node_modules/@overeng/megarepo/src/cli/commands/composition.ts": "//packages/@overeng/megarepo:src/cli/commands/composition.ts", - "node_modules/@overeng/megarepo/src/cli/commands/config/mod.ts": "//packages/@overeng/megarepo:src/cli/commands/config/mod.ts", - "node_modules/@overeng/megarepo/src/cli/commands/config/push-refs.ts": "//packages/@overeng/megarepo:src/cli/commands/config/push-refs.ts", - "node_modules/@overeng/megarepo/src/cli/commands/deps.ts": "//packages/@overeng/megarepo:src/cli/commands/deps.ts", - "node_modules/@overeng/megarepo/src/cli/commands/engine.ts": "//packages/@overeng/megarepo:src/cli/commands/engine.ts", - "node_modules/@overeng/megarepo/src/cli/commands/env.ts": "//packages/@overeng/megarepo:src/cli/commands/env.ts", - "node_modules/@overeng/megarepo/src/cli/commands/exec.ts": "//packages/@overeng/megarepo:src/cli/commands/exec.ts", - "node_modules/@overeng/megarepo/src/cli/commands/fetch.ts": "//packages/@overeng/megarepo:src/cli/commands/fetch.ts", - "node_modules/@overeng/megarepo/src/cli/commands/generate/mod.ts": "//packages/@overeng/megarepo:src/cli/commands/generate/mod.ts", - "node_modules/@overeng/megarepo/src/cli/commands/init.ts": "//packages/@overeng/megarepo:src/cli/commands/init.ts", - "node_modules/@overeng/megarepo/src/cli/commands/lock.ts": "//packages/@overeng/megarepo:src/cli/commands/lock.ts", - "node_modules/@overeng/megarepo/src/cli/commands/ls.ts": "//packages/@overeng/megarepo:src/cli/commands/ls.ts", - "node_modules/@overeng/megarepo/src/cli/commands/mod.ts": "//packages/@overeng/megarepo:src/cli/commands/mod.ts", - "node_modules/@overeng/megarepo/src/cli/commands/pin.ts": "//packages/@overeng/megarepo:src/cli/commands/pin.ts", - "node_modules/@overeng/megarepo/src/cli/commands/root.ts": "//packages/@overeng/megarepo:src/cli/commands/root.ts", - "node_modules/@overeng/megarepo/src/cli/commands/status.ts": "//packages/@overeng/megarepo:src/cli/commands/status.ts", - "node_modules/@overeng/megarepo/src/cli/commands/store/composed-worktrees.integration.test.ts": "//packages/@overeng/megarepo:src/cli/commands/store/composed-worktrees.integration.test.ts", - "node_modules/@overeng/megarepo/src/cli/commands/store/mod.ts": "//packages/@overeng/megarepo:src/cli/commands/store/mod.ts", - "node_modules/@overeng/megarepo/src/cli/components/Header.stories.tsx": "//packages/@overeng/megarepo:src/cli/components/Header.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/components/Header.tsx": "//packages/@overeng/megarepo:src/cli/components/Header.tsx", - "node_modules/@overeng/megarepo/src/cli/components/LogLine.stories.tsx": "//packages/@overeng/megarepo:src/cli/components/LogLine.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/components/LogLine.tsx": "//packages/@overeng/megarepo:src/cli/components/LogLine.tsx", - "node_modules/@overeng/megarepo/src/cli/components/MemberRow.tsx": "//packages/@overeng/megarepo:src/cli/components/MemberRow.tsx", - "node_modules/@overeng/megarepo/src/cli/components/Scope.tsx": "//packages/@overeng/megarepo:src/cli/components/Scope.tsx", - "node_modules/@overeng/megarepo/src/cli/components/Separator.stories.tsx": "//packages/@overeng/megarepo:src/cli/components/Separator.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/components/Separator.tsx": "//packages/@overeng/megarepo:src/cli/components/Separator.tsx", - "node_modules/@overeng/megarepo/src/cli/components/StatusIcon.stories.tsx": "//packages/@overeng/megarepo:src/cli/components/StatusIcon.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/components/StatusIcon.tsx": "//packages/@overeng/megarepo:src/cli/components/StatusIcon.tsx", - "node_modules/@overeng/megarepo/src/cli/components/Summary.stories.tsx": "//packages/@overeng/megarepo:src/cli/components/Summary.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/components/Summary.tsx": "//packages/@overeng/megarepo:src/cli/components/Summary.tsx", - "node_modules/@overeng/megarepo/src/cli/components/TaskItem.stories.tsx": "//packages/@overeng/megarepo:src/cli/components/TaskItem.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/components/TaskItem.tsx": "//packages/@overeng/megarepo:src/cli/components/TaskItem.tsx", - "node_modules/@overeng/megarepo/src/cli/components/mod.ts": "//packages/@overeng/megarepo:src/cli/components/mod.ts", - "node_modules/@overeng/megarepo/src/cli/components/tokens.ts": "//packages/@overeng/megarepo:src/cli/components/tokens.ts", - "node_modules/@overeng/megarepo/src/cli/context.ts": "//packages/@overeng/megarepo:src/cli/context.ts", - "node_modules/@overeng/megarepo/src/cli/errors.ts": "//packages/@overeng/megarepo:src/cli/errors.ts", - "node_modules/@overeng/megarepo/src/cli/mod.ts": "//packages/@overeng/megarepo:src/cli/mod.ts", - "node_modules/@overeng/megarepo/src/cli/observability.ts": "//packages/@overeng/megarepo:src/cli/observability.ts", - "node_modules/@overeng/megarepo/src/cli/pin.integration.test.ts": "//packages/@overeng/megarepo:src/cli/pin.integration.test.ts", - "node_modules/@overeng/megarepo/src/cli/prompt-select-pty-fixture.ts": "//packages/@overeng/megarepo:src/cli/prompt-select-pty-fixture.ts", - "node_modules/@overeng/megarepo/src/cli/prompt-select-pty.test.ts": "//packages/@overeng/megarepo:src/cli/prompt-select-pty.test.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/AddOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/AddOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/AddOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/AddOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/AddOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/AddOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/AddOutput/stories/Errors.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/AddOutput/stories/Errors.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/AddOutput/stories/Success.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/AddOutput/stories/Success.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/AddOutput/stories/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/AddOutput/stories/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/AddOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/AddOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/DepsOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/DepsOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/DepsOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/DepsOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/DepsOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/DepsOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/DepsOutput/stories/Basic.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/DepsOutput/stories/Basic.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/DepsOutput/stories/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/DepsOutput/stories/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/DepsOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/DepsOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/EnvOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/EnvOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/EnvOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/EnvOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/EnvOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/EnvOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/EnvOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/EnvOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/ExecOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/ExecOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/ExecOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/ExecOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/ExecOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/ExecOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/ExecOutput/stories/Complete.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/ExecOutput/stories/Complete.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/ExecOutput/stories/Errors.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/ExecOutput/stories/Errors.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/ExecOutput/stories/Running.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/ExecOutput/stories/Running.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/ExecOutput/stories/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/ExecOutput/stories/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/ExecOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/ExecOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/GenerateOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/GenerateOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/GenerateOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/GenerateOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/GenerateOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/GenerateOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/GenerateOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/GenerateOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/InitOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/InitOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/InitOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/InitOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/InitOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/InitOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/InitOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/InitOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/LsOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/LsOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/LsOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/LsOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/LsOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/LsOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/LsOutput/stories/Basic.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/LsOutput/stories/Basic.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/LsOutput/stories/Nested.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/LsOutput/stories/Nested.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/LsOutput/stories/Sources.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/LsOutput/stories/Sources.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/LsOutput/stories/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/LsOutput/stories/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/LsOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/LsOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/PinOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/PinOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/PinOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/PinOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/PinOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/PinOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/PinOutput/stories/Errors.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/PinOutput/stories/Errors.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/PinOutput/stories/Success.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/PinOutput/stories/Success.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/PinOutput/stories/Warnings.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/PinOutput/stories/Warnings.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/PinOutput/stories/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/PinOutput/stories/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/PinOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/PinOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/PushRefsOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/PushRefsOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/PushRefsOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/PushRefsOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/PushRefsOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/PushRefsOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/PushRefsOutput/stories/Errors.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/PushRefsOutput/stories/Errors.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/PushRefsOutput/stories/Results.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/PushRefsOutput/stories/Results.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/PushRefsOutput/stories/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/PushRefsOutput/stories/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/PushRefsOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/PushRefsOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/RootOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/RootOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/RootOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/RootOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/RootOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/RootOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/RootOutput/stories/Errors.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/RootOutput/stories/Errors.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/RootOutput/stories/Success.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/RootOutput/stories/Success.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/RootOutput/stories/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/RootOutput/stories/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/RootOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/RootOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StatusOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/StatusOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/StatusOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/StatusOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/StatusOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/StatusOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/StatusOutput/stories/Basic.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StatusOutput/stories/Basic.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StatusOutput/stories/Complex.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StatusOutput/stories/Complex.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StatusOutput/stories/LockIssues.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StatusOutput/stories/LockIssues.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StatusOutput/stories/RefIssues.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StatusOutput/stories/RefIssues.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StatusOutput/stories/WorktreeIssues.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StatusOutput/stories/WorktreeIssues.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StatusOutput/stories/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/StatusOutput/stories/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/StatusOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StatusOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/stories/Add.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/stories/Add.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/stories/Fetch.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/stories/Fetch.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/stories/Fix.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/stories/Fix.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/stories/GC.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/stories/GC.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/stories/List.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/stories/List.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/stories/Status.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/stories/Status.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/stories/WorktreeNew.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/stories/WorktreeNew.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/stories/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/stories/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/StoreOutput/view.unit.test.tsx": "//packages/@overeng/megarepo:src/cli/renderers/StoreOutput/view.unit.test.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/app.ts": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/app.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/mod.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/schema.ts": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/schema.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/apply/Results.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/apply/Results.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/apply/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/apply/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/fetch/Issues.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/fetch/Issues.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/fetch/LockSync.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/fetch/LockSync.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/fetch/Nested.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/fetch/Nested.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/fetch/Results.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/fetch/Results.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/fetch/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/fetch/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/lock/Results.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/lock/Results.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/lock/_fixtures.ts": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/lock/_fixtures.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/stories/preflight/PreflightFailed.stories.tsx": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/stories/preflight/PreflightFailed.stories.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/ui.ts": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/ui.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/SyncOutput/view.tsx": "//packages/@overeng/megarepo:src/cli/renderers/SyncOutput/view.tsx", - "node_modules/@overeng/megarepo/src/cli/renderers/_story-constants.ts": "//packages/@overeng/megarepo:src/cli/renderers/_story-constants.ts", - "node_modules/@overeng/megarepo/src/cli/renderers/mod.ts": "//packages/@overeng/megarepo:src/cli/renderers/mod.ts", - "node_modules/@overeng/megarepo/src/cli/status.integration.test.ts": "//packages/@overeng/megarepo:src/cli/status.integration.test.ts", - "node_modules/@overeng/megarepo/src/cli/store-gc-cold.integration.test.ts": "//packages/@overeng/megarepo:src/cli/store-gc-cold.integration.test.ts", - "node_modules/@overeng/megarepo/src/cli/store-gc-generated.integration.test.ts": "//packages/@overeng/megarepo:src/cli/store-gc-generated.integration.test.ts", - "node_modules/@overeng/megarepo/src/cli/store-gc-otel.integration.test.ts": "//packages/@overeng/megarepo:src/cli/store-gc-otel.integration.test.ts", - "node_modules/@overeng/megarepo/src/cli/store.integration.test.ts": "//packages/@overeng/megarepo:src/cli/store.integration.test.ts", - "node_modules/@overeng/megarepo/src/cli/sync.integration.test.ts": "//packages/@overeng/megarepo:src/cli/sync.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/acquisition/owned-worktree-acquisition-schema.ts": "//packages/@overeng/megarepo:src/composition/acquisition/owned-worktree-acquisition-schema.ts", - "node_modules/@overeng/megarepo/src/composition/acquisition/owned-worktree-acquisition.integration.test.ts": "//packages/@overeng/megarepo:src/composition/acquisition/owned-worktree-acquisition.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/acquisition/owned-worktree-acquisition.ts": "//packages/@overeng/megarepo:src/composition/acquisition/owned-worktree-acquisition.ts", - "node_modules/@overeng/megarepo/src/composition/apply/composition-apply-schema.ts": "//packages/@overeng/megarepo:src/composition/apply/composition-apply-schema.ts", - "node_modules/@overeng/megarepo/src/composition/apply/composition-apply.integration.test.ts": "//packages/@overeng/megarepo:src/composition/apply/composition-apply.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/apply/composition-apply.ts": "//packages/@overeng/megarepo:src/composition/apply/composition-apply.ts", - "node_modules/@overeng/megarepo/src/composition/apply/composition-apply.unit.test.ts": "//packages/@overeng/megarepo:src/composition/apply/composition-apply.unit.test.ts", - "node_modules/@overeng/megarepo/src/composition/apply/composition-runtime.ts": "//packages/@overeng/megarepo:src/composition/apply/composition-runtime.ts", - "node_modules/@overeng/megarepo/src/composition/apply/workspace-update-lock-schema.ts": "//packages/@overeng/megarepo:src/composition/apply/workspace-update-lock-schema.ts", - "node_modules/@overeng/megarepo/src/composition/apply/workspace-update-lock-schema.unit.test.ts": "//packages/@overeng/megarepo:src/composition/apply/workspace-update-lock-schema.unit.test.ts", - "node_modules/@overeng/megarepo/src/composition/apply/workspace-update-lock.integration.test.ts": "//packages/@overeng/megarepo:src/composition/apply/workspace-update-lock.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/apply/workspace-update-lock.ts": "//packages/@overeng/megarepo:src/composition/apply/workspace-update-lock.ts", - "node_modules/@overeng/megarepo/src/composition/capabilities/composition-capability-resolver-schema.ts": "//packages/@overeng/megarepo:src/composition/capabilities/composition-capability-resolver-schema.ts", - "node_modules/@overeng/megarepo/src/composition/capabilities/composition-capability-resolver.integration.test.ts": "//packages/@overeng/megarepo:src/composition/capabilities/composition-capability-resolver.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/capabilities/composition-capability-resolver.ts": "//packages/@overeng/megarepo:src/composition/capabilities/composition-capability-resolver.ts", - "node_modules/@overeng/megarepo/src/composition/capabilities/owned-capability-projection.integration.test.ts": "//packages/@overeng/megarepo:src/composition/capabilities/owned-capability-projection.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/capabilities/owned-capability-projection.ts": "//packages/@overeng/megarepo:src/composition/capabilities/owned-capability-projection.ts", - "node_modules/@overeng/megarepo/src/composition/mounts/member-mount-cp-a-schema.ts": "//packages/@overeng/megarepo:src/composition/mounts/member-mount-cp-a-schema.ts", - "node_modules/@overeng/megarepo/src/composition/mounts/member-mount-cp-a-schema.unit.test.ts": "//packages/@overeng/megarepo:src/composition/mounts/member-mount-cp-a-schema.unit.test.ts", - "node_modules/@overeng/megarepo/src/composition/mounts/member-mount-cp-a.integration.test.ts": "//packages/@overeng/megarepo:src/composition/mounts/member-mount-cp-a.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/mounts/member-mount-cp-a.ts": "//packages/@overeng/megarepo:src/composition/mounts/member-mount-cp-a.ts", - "node_modules/@overeng/megarepo/src/composition/mounts/member-mount-r6.integration.test.ts": "//packages/@overeng/megarepo:src/composition/mounts/member-mount-r6.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/mounts/member-mount-r6.ts": "//packages/@overeng/megarepo:src/composition/mounts/member-mount-r6.ts", - "node_modules/@overeng/megarepo/src/composition/mounts/member-mount-r6.unit.test.ts": "//packages/@overeng/megarepo:src/composition/mounts/member-mount-r6.unit.test.ts", - "node_modules/@overeng/megarepo/src/composition/mounts/member-mount.ts": "//packages/@overeng/megarepo:src/composition/mounts/member-mount.ts", - "node_modules/@overeng/megarepo/src/composition/overlays/dist-overlay-lifecycle-schema.ts": "//packages/@overeng/megarepo:src/composition/overlays/dist-overlay-lifecycle-schema.ts", - "node_modules/@overeng/megarepo/src/composition/overlays/dist-overlay-lifecycle.integration.test.ts": "//packages/@overeng/megarepo:src/composition/overlays/dist-overlay-lifecycle.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/overlays/dist-overlay-lifecycle.ts": "//packages/@overeng/megarepo:src/composition/overlays/dist-overlay-lifecycle.ts", - "node_modules/@overeng/megarepo/src/composition/overlays/dist-overlay-schema.ts": "//packages/@overeng/megarepo:src/composition/overlays/dist-overlay-schema.ts", - "node_modules/@overeng/megarepo/src/composition/overlays/dist-overlay-schema.unit.test.ts": "//packages/@overeng/megarepo:src/composition/overlays/dist-overlay-schema.unit.test.ts", - "node_modules/@overeng/megarepo/src/composition/root/composition-root-publisher.integration.test.ts": "//packages/@overeng/megarepo:src/composition/root/composition-root-publisher.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/root/composition-root-publisher.ts": "//packages/@overeng/megarepo:src/composition/root/composition-root-publisher.ts", - "node_modules/@overeng/megarepo/src/composition/root/composition-root.integration.test.ts": "//packages/@overeng/megarepo:src/composition/root/composition-root.integration.test.ts", - "node_modules/@overeng/megarepo/src/composition/root/composition-root.ts": "//packages/@overeng/megarepo:src/composition/root/composition-root.ts", - "node_modules/@overeng/megarepo/src/composition/root/composition-root.unit.test.ts": "//packages/@overeng/megarepo:src/composition/root/composition-root.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/config.ts": "//packages/@overeng/megarepo:src/core/config.ts", - "node_modules/@overeng/megarepo/src/core/config.unit.test.ts": "//packages/@overeng/megarepo:src/core/config.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/git-memory.integration.test.ts": "//packages/@overeng/megarepo:src/core/git-memory.integration.test.ts", - "node_modules/@overeng/megarepo/src/core/git-streaming-parsers.integration.test.ts": "//packages/@overeng/megarepo:src/core/git-streaming-parsers.integration.test.ts", - "node_modules/@overeng/megarepo/src/core/git-timeout.integration.test.ts": "//packages/@overeng/megarepo:src/core/git-timeout.integration.test.ts", - "node_modules/@overeng/megarepo/src/core/git.ts": "//packages/@overeng/megarepo:src/core/git.ts", - "node_modules/@overeng/megarepo/src/core/git.unit.test.ts": "//packages/@overeng/megarepo:src/core/git.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/issues.ts": "//packages/@overeng/megarepo:src/core/issues.ts", - "node_modules/@overeng/megarepo/src/core/lock.ts": "//packages/@overeng/megarepo:src/core/lock.ts", - "node_modules/@overeng/megarepo/src/core/lock.unit.test.ts": "//packages/@overeng/megarepo:src/core/lock.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/megarepo-traversal.ts": "//packages/@overeng/megarepo:src/core/megarepo-traversal.ts", - "node_modules/@overeng/megarepo/src/core/megarepo-traversal.unit.test.ts": "//packages/@overeng/megarepo:src/core/megarepo-traversal.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/flake-url.ts": "//packages/@overeng/megarepo:src/core/nix-lock/flake-url.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/flake-url.unit.test.ts": "//packages/@overeng/megarepo:src/core/nix-lock/flake-url.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/input-discovery.ts": "//packages/@overeng/megarepo:src/core/nix-lock/input-discovery.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/input-discovery.unit.test.ts": "//packages/@overeng/megarepo:src/core/nix-lock/input-discovery.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/matcher.ts": "//packages/@overeng/megarepo:src/core/nix-lock/matcher.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/mod.ts": "//packages/@overeng/megarepo:src/core/nix-lock/mod.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/mod.unit.test.ts": "//packages/@overeng/megarepo:src/core/nix-lock/mod.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/schema.ts": "//packages/@overeng/megarepo:src/core/nix-lock/schema.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/schema.unit.test.ts": "//packages/@overeng/megarepo:src/core/nix-lock/schema.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/source-rewriter.ts": "//packages/@overeng/megarepo:src/core/nix-lock/source-rewriter.ts", - "node_modules/@overeng/megarepo/src/core/nix-lock/source-rewriter.unit.test.ts": "//packages/@overeng/megarepo:src/core/nix-lock/source-rewriter.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/observability.ts": "//packages/@overeng/megarepo:src/core/observability.ts", - "node_modules/@overeng/megarepo/src/core/ref.ts": "//packages/@overeng/megarepo:src/core/ref.ts", - "node_modules/@overeng/megarepo/src/core/ref.unit.test.ts": "//packages/@overeng/megarepo:src/core/ref.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/source-policy.ts": "//packages/@overeng/megarepo:src/core/source-policy.ts", - "node_modules/@overeng/megarepo/src/core/source-policy.unit.test.ts": "//packages/@overeng/megarepo:src/core/source-policy.unit.test.ts", - "node_modules/@overeng/megarepo/src/core/version.ts": "//packages/@overeng/megarepo:src/core/version.ts", - "node_modules/@overeng/megarepo/src/generators/generators.unit.test.ts": "//packages/@overeng/megarepo:src/generators/generators.unit.test.ts", - "node_modules/@overeng/megarepo/src/generators/mod.ts": "//packages/@overeng/megarepo:src/generators/mod.ts", - "node_modules/@overeng/megarepo/src/generators/schema.ts": "//packages/@overeng/megarepo:src/generators/schema.ts", - "node_modules/@overeng/megarepo/src/generators/vscode.ts": "//packages/@overeng/megarepo:src/generators/vscode.ts", - "node_modules/@overeng/megarepo/src/git.contract.ts": "//packages/@overeng/megarepo:src/git.contract.ts", - "node_modules/@overeng/megarepo/src/json-wire-baseline.test.ts": "//packages/@overeng/megarepo:src/json-wire-baseline.test.ts", - "node_modules/@overeng/megarepo/src/megarepo.contract.ts": "//packages/@overeng/megarepo:src/megarepo.contract.ts", - "node_modules/@overeng/megarepo/src/mod.ts": "//packages/@overeng/megarepo:src/mod.ts", - "node_modules/@overeng/megarepo/src/nix.contract.ts": "//packages/@overeng/megarepo:src/nix.contract.ts", - "node_modules/@overeng/megarepo/src/store/store-archive.integration.test.ts": "//packages/@overeng/megarepo:src/store/store-archive.integration.test.ts", - "node_modules/@overeng/megarepo/src/store/store-archive.ts": "//packages/@overeng/megarepo:src/store/store-archive.ts", - "node_modules/@overeng/megarepo/src/store/store-deletion-lease.integration.test.ts": "//packages/@overeng/megarepo:src/store/store-deletion-lease.integration.test.ts", - "node_modules/@overeng/megarepo/src/store/store-deletion-lease.ts": "//packages/@overeng/megarepo:src/store/store-deletion-lease.ts", - "node_modules/@overeng/megarepo/src/store/store-fs-atomic.ts": "//packages/@overeng/megarepo:src/store/store-fs-atomic.ts", - "node_modules/@overeng/megarepo/src/store/store-fs-atomic.unit.test.ts": "//packages/@overeng/megarepo:src/store/store-fs-atomic.unit.test.ts", - "node_modules/@overeng/megarepo/src/store/store-gc-config.ts": "//packages/@overeng/megarepo:src/store/store-gc-config.ts", - "node_modules/@overeng/megarepo/src/store/store-gc-config.unit.test.ts": "//packages/@overeng/megarepo:src/store/store-gc-config.unit.test.ts", - "node_modules/@overeng/megarepo/src/store/store-gc-observations.ts": "//packages/@overeng/megarepo:src/store/store-gc-observations.ts", - "node_modules/@overeng/megarepo/src/store/store-gc-observations.unit.test.ts": "//packages/@overeng/megarepo:src/store/store-gc-observations.unit.test.ts", - "node_modules/@overeng/megarepo/src/store/store-gc-plan-order.unit.test.ts": "//packages/@overeng/megarepo:src/store/store-gc-plan-order.unit.test.ts", - "node_modules/@overeng/megarepo/src/store/store-hygiene.ts": "//packages/@overeng/megarepo:src/store/store-hygiene.ts", - "node_modules/@overeng/megarepo/src/store/store-hygiene.unit.test.ts": "//packages/@overeng/megarepo:src/store/store-hygiene.unit.test.ts", - "node_modules/@overeng/megarepo/src/store/store-inuse.integration.test.ts": "//packages/@overeng/megarepo:src/store/store-inuse.integration.test.ts", - "node_modules/@overeng/megarepo/src/store/store-inuse.ts": "//packages/@overeng/megarepo:src/store/store-inuse.ts", - "node_modules/@overeng/megarepo/src/store/store-liveness.integration.test.ts": "//packages/@overeng/megarepo:src/store/store-liveness.integration.test.ts", - "node_modules/@overeng/megarepo/src/store/store-liveness.ts": "//packages/@overeng/megarepo:src/store/store-liveness.ts", - "node_modules/@overeng/megarepo/src/store/store-lock.ts": "//packages/@overeng/megarepo:src/store/store-lock.ts", - "node_modules/@overeng/megarepo/src/store/store-lock.unit.test.ts": "//packages/@overeng/megarepo:src/store/store-lock.unit.test.ts", - "node_modules/@overeng/megarepo/src/store/store-lossless.integration.test.ts": "//packages/@overeng/megarepo:src/store/store-lossless.integration.test.ts", - "node_modules/@overeng/megarepo/src/store/store-lossless.ts": "//packages/@overeng/megarepo:src/store/store-lossless.ts", - "node_modules/@overeng/megarepo/src/store/store-path.ts": "//packages/@overeng/megarepo:src/store/store-path.ts", - "node_modules/@overeng/megarepo/src/store/store-path.unit.test.ts": "//packages/@overeng/megarepo:src/store/store-path.unit.test.ts", - "node_modules/@overeng/megarepo/src/store/store-pr-state.ts": "//packages/@overeng/megarepo:src/store/store-pr-state.ts", - "node_modules/@overeng/megarepo/src/store/store-pr-state.unit.test.ts": "//packages/@overeng/megarepo:src/store/store-pr-state.unit.test.ts", - "node_modules/@overeng/megarepo/src/store/store-symlink.unit.test.ts": "//packages/@overeng/megarepo:src/store/store-symlink.unit.test.ts", - "node_modules/@overeng/megarepo/src/store/store-worktree-policy.ts": "//packages/@overeng/megarepo:src/store/store-worktree-policy.ts", - "node_modules/@overeng/megarepo/src/store/store-worktree-policy.unit.test.ts": "//packages/@overeng/megarepo:src/store/store-worktree-policy.unit.test.ts", - "node_modules/@overeng/megarepo/src/store/store.ts": "//packages/@overeng/megarepo:src/store/store.ts", - "node_modules/@overeng/megarepo/src/sync/member.ts": "//packages/@overeng/megarepo:src/sync/member.ts", - "node_modules/@overeng/megarepo/src/sync/member.unit.test.ts": "//packages/@overeng/megarepo:src/sync/member.unit.test.ts", - "node_modules/@overeng/megarepo/src/sync/mod.ts": "//packages/@overeng/megarepo:src/sync/mod.ts", - "node_modules/@overeng/megarepo/src/sync/schema.ts": "//packages/@overeng/megarepo:src/sync/schema.ts", - "node_modules/@overeng/megarepo/src/sync/types.ts": "//packages/@overeng/megarepo:src/sync/types.ts", - "node_modules/@overeng/megarepo/src/test-utils/consoleCapture.ts": "//packages/@overeng/megarepo:src/test-utils/consoleCapture.ts", - "node_modules/@overeng/megarepo/src/test-utils/coreutils.ts": "//packages/@overeng/megarepo:src/test-utils/coreutils.ts", - "node_modules/@overeng/megarepo/src/test-utils/coreutils.unit.test.ts": "//packages/@overeng/megarepo:src/test-utils/coreutils.unit.test.ts", - "node_modules/@overeng/megarepo/src/test-utils/git-env-setup.ts": "//packages/@overeng/megarepo:src/test-utils/git-env-setup.ts", - "node_modules/@overeng/megarepo/src/test-utils/json.ts": "//packages/@overeng/megarepo:src/test-utils/json.ts", - "node_modules/@overeng/megarepo/src/test-utils/memory-probe.ts": "//packages/@overeng/megarepo:src/test-utils/memory-probe.ts", - "node_modules/@overeng/megarepo/src/test-utils/mod.ts": "//packages/@overeng/megarepo:src/test-utils/mod.ts", - "node_modules/@overeng/megarepo/src/test-utils/setup.ts": "//packages/@overeng/megarepo:src/test-utils/setup.ts", - "node_modules/@overeng/megarepo/src/test-utils/setup.unit.test.ts": "//packages/@overeng/megarepo:src/test-utils/setup.unit.test.ts", - "node_modules/@overeng/megarepo/src/test-utils/store-setup.integration.test.ts": "//packages/@overeng/megarepo:src/test-utils/store-setup.integration.test.ts", - "node_modules/@overeng/megarepo/src/test-utils/store-setup.ts": "//packages/@overeng/megarepo:src/test-utils/store-setup.ts", - "node_modules/@overeng/megarepo/src/test-utils/temp-root.ts": "//packages/@overeng/megarepo:src/test-utils/temp-root.ts", - "node_modules/@overeng/tui-react/dist": "//packages/@overeng/tui-react:dist", - "node_modules/@overeng/tui-react/package.json": "//packages/@overeng/tui-react:package.json", - "node_modules/@overeng/utils-dev/dist": "//packages/@overeng/utils-dev:dist", - "node_modules/@overeng/utils-dev/package.json": "//packages/@overeng/utils-dev:package.json", - "node_modules/@overeng/utils/dist": "//packages/@overeng/utils:dist", - "node_modules/@overeng/utils/package.json": "//packages/@overeng/utils:package.json", - }, - workspace_dependency_views = { - "node_modules/@overeng/megarepo/node_modules": "//packages/@overeng/megarepo:package_tree", - "node_modules/@overeng/tui-react/node_modules": "//packages/@overeng/tui-react:package_tree", - "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", - "node_modules/@overeng/utils/node_modules": "//packages/@overeng/utils:package_tree", - }, + strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -785,6 +210,7 @@ tsgo_emit( package_tree = ":package_tree", declaration_sources = { }, + declaration_entrypoint = "src/mod.d.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/tui-stories/BUCK.genie.ts b/packages/@overeng/tui-stories/BUCK.genie.ts index 166284fc46..444aea1a94 100644 --- a/packages/@overeng/tui-stories/BUCK.genie.ts +++ b/packages/@overeng/tui-stories/BUCK.genie.ts @@ -31,7 +31,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils-dev:dist', }, ], - editorViewConsumer: false, + authorities: [{ declarationEntrypoint: 'src/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/packages/@overeng/tui-stories/package.json b/packages/@overeng/tui-stories/package.json index 43740c5743..b4f911e324 100644 --- a/packages/@overeng/tui-stories/package.json +++ b/packages/@overeng/tui-stories/package.json @@ -22,7 +22,10 @@ "type": "module", "private": true, "exports": { - ".": "./src/mod.ts" + ".": { + "types": "./dist/src/mod.d.ts", + "default": "./src/mod.ts" + } }, "scripts": { "storybook": "storybook dev -p 6013", diff --git a/packages/@overeng/tui-stories/package.json.genie.ts b/packages/@overeng/tui-stories/package.json.genie.ts index b47dca2117..447ddde7ea 100644 --- a/packages/@overeng/tui-stories/package.json.genie.ts +++ b/packages/@overeng/tui-stories/package.json.genie.ts @@ -51,7 +51,10 @@ export default packageJson( 'storybook:build': 'storybook build', }, exports: { - '.': exportEntry('./src/mod.ts', { environment: 'node' }), + '.': exportEntry( + { types: './dist/src/mod.d.ts', default: './src/mod.ts' }, + { environment: 'node' }, + ), }, publishConfig: { access: 'public', diff --git a/packages/@overeng/tui-stories/tsconfig.json b/packages/@overeng/tui-stories/tsconfig.json index 897dcadfb0..62040a1639 100644 --- a/packages/@overeng/tui-stories/tsconfig.json +++ b/packages/@overeng/tui-stories/tsconfig.json @@ -49,17 +49,13 @@ "types": [ "node" ], - "jsx": "react-jsx" + "jsx": "react-jsx", + "noEmit": true }, "include": [ "src/**/*", "test/**/*", "bin/**/*.ts", "bin/**/*.tsx" - ], - "references": [ - { - "path": "../megarepo" - } ] } diff --git a/packages/@overeng/tui-stories/tsconfig.json.genie.ts b/packages/@overeng/tui-stories/tsconfig.json.genie.ts index b5a510ac46..6ad1582658 100644 --- a/packages/@overeng/tui-stories/tsconfig.json.genie.ts +++ b/packages/@overeng/tui-stories/tsconfig.json.genie.ts @@ -12,7 +12,7 @@ export default tsconfigJson({ ...packageTsconfigCompilerOptions, ...nodeTypes, ...reactJsx, + noEmit: true, }, include: ['src/**/*', 'test/**/*', 'bin/**/*.ts', 'bin/**/*.tsx'], - references: [{ path: '../megarepo' }], } satisfies TSConfigArgs) diff --git a/packages/@overeng/utils-dev/BUCK b/packages/@overeng/utils-dev/BUCK index 7436c1a440..e68b9529ed 100644 --- a/packages/@overeng/utils-dev/BUCK +++ b/packages/@overeng/utils-dev/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/utils-dev/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:2e84e8425702196521cd53248923f4f8ebb204bf47645989762aea28aaab43a7 -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils-dev/src/**/*.cts, packages/@overeng/utils-dev/src/**/*.js, packages/@overeng/utils-dev/src/**/*.mts, packages/@overeng/utils-dev/src/**/*.spec.cjs, packages/@overeng/utils-dev/src/**/*.spec.jsx, packages/@overeng/utils-dev/src/**/*.spec.mjs, packages/@overeng/utils-dev/src/**/*.test.cjs, packages/@overeng/utils-dev/src/**/*.test.jsx, packages/@overeng/utils-dev/src/**/*.test.mjs, packages/@overeng/utils-dev/src/**/*.ts, packages/@overeng/utils-dev/src/**/*.tsx, packages/@overeng/utils-dev/src/**/__snapshots__/*.snap, packages/@overeng/utils-dev/tsconfig.json.genie.ts +# Semantic fingerprint: sha256:5f4d97d2f9ce0be5170599d4616ff2df3da6cf0e46a4914ac372c24665cfb742 +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils-dev/src/**/*.cts, packages/@overeng/utils-dev/src/**/*.js, packages/@overeng/utils-dev/src/**/*.mts, packages/@overeng/utils-dev/src/**/*.spec.cjs, packages/@overeng/utils-dev/src/**/*.spec.jsx, packages/@overeng/utils-dev/src/**/*.spec.mjs, packages/@overeng/utils-dev/src/**/*.test.cjs, packages/@overeng/utils-dev/src/**/*.test.jsx, packages/@overeng/utils-dev/src/**/*.test.mjs, packages/@overeng/utils-dev/src/**/*.ts, packages/@overeng/utils-dev/src/**/*.tsx, packages/@overeng/utils-dev/src/**/__snapshots__/*.snap, packages/@overeng/utils-dev/tsconfig.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -49,6 +50,14 @@ export_materialization_inputs([ "src/otelite/vitest-bridge.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/utils-dev", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_utils_dev_8614cc76469c", @@ -99,7 +108,7 @@ package_view( }, workspace_dependency_views = { }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -144,7 +153,7 @@ package_view( workspace_dependency_views = { }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/utils-dev/BUCK.genie.ts b/packages/@overeng/utils-dev/BUCK.genie.ts index 7f5dd64034..d38616ed2a 100644 --- a/packages/@overeng/utils-dev/BUCK.genie.ts +++ b/packages/@overeng/utils-dev/BUCK.genie.ts @@ -7,11 +7,9 @@ export const buck2TypeScriptAdmission = { packagePath: 'packages/@overeng/utils-dev', projectionSource: 'packages/@overeng/utils-dev/BUCK.genie.ts', sourceRoots: ['src'], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/node-vitest/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [ + { declarationEntrypoint: 'src/node-vitest/mod.d.ts', projectFile: 'tsconfig.json' }, + ], tests: [ { name: 'test', diff --git a/packages/@overeng/utils/BUCK b/packages/@overeng/utils/BUCK index 43be0ef779..3bed176519 100644 --- a/packages/@overeng/utils/BUCK +++ b/packages/@overeng/utils/BUCK @@ -2,14 +2,15 @@ # Source: BUCK.genie.ts # Projection source: packages/@overeng/utils/BUCK.genie.ts -# Projection schema version: 8 +# Projection schema version: 11 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:855f6001b40d981725c81c1d4fb2e1b764673ddf5ae8e01720f213ef0975833f -# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/effect-distributed-lock/BUCK.genie.ts, packages/@overeng/effect-distributed-lock/package.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts, packages/@overeng/utils/src/**/*.cts, packages/@overeng/utils/src/**/*.js, packages/@overeng/utils/src/**/*.mts, packages/@overeng/utils/src/**/*.spec.cjs, packages/@overeng/utils/src/**/*.spec.jsx, packages/@overeng/utils/src/**/*.spec.mjs, packages/@overeng/utils/src/**/*.test.cjs, packages/@overeng/utils/src/**/*.test.jsx, packages/@overeng/utils/src/**/*.test.mjs, packages/@overeng/utils/src/**/*.ts, packages/@overeng/utils/src/**/*.tsx, packages/@overeng/utils/src/**/__snapshots__/*.snap, packages/@overeng/utils/tsconfig.json.genie.ts +# Semantic fingerprint: sha256:ca84c8a3e7c8c8fd333888e7a2c73e62191aabfab608e0a33c184b60a3b3b57f +# Semantic inputs: buck2/dependencies/BUCK.genie.ts, buck2/dependencies/pnpm-lock.sha256.json.genie.ts, buck2/static_checks.bzl, genie/buck2/mod.ts, genie/buck2/typescript-package-projection.ts, genie/packages.ts, package.json.genie.ts, packages/@overeng/buck2-tools/src/javascript-runner.ts, packages/@overeng/buck2-tools/src/package-tree.ts, packages/@overeng/buck2-tools/src/real-path.ts, packages/@overeng/buck2-tools/src/typescript-runner.ts, packages/@overeng/effect-distributed-lock/BUCK.genie.ts, packages/@overeng/effect-distributed-lock/package.json.genie.ts, packages/@overeng/otel-contract/BUCK.genie.ts, packages/@overeng/otel-contract/package.json.genie.ts, packages/@overeng/utils-dev/BUCK.genie.ts, packages/@overeng/utils-dev/package.json.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/BUCK.genie.ts, packages/@overeng/utils/package.json.genie.ts, packages/@overeng/utils/src/**/*.cts, packages/@overeng/utils/src/**/*.js, packages/@overeng/utils/src/**/*.mts, packages/@overeng/utils/src/**/*.spec.cjs, packages/@overeng/utils/src/**/*.spec.jsx, packages/@overeng/utils/src/**/*.spec.mjs, packages/@overeng/utils/src/**/*.test.cjs, packages/@overeng/utils/src/**/*.test.jsx, packages/@overeng/utils/src/**/*.test.mjs, packages/@overeng/utils/src/**/*.ts, packages/@overeng/utils/src/**/*.tsx, packages/@overeng/utils/src/**/__snapshots__/*.snap, packages/@overeng/utils/tsconfig.json.genie.ts # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") load("//buck2:editor_view.bzl", "editor_view_inputs") +load("//buck2:static_checks.bzl", "STATIC_SOURCE_EXCLUDES", "STATIC_SOURCE_GLOBS", "static_source_set") load("//buck2:javascript.bzl", "vitest_collect", "vitest_test") load("//buck2:typescript.bzl", "tsgo_emit", "tsgo_typecheck") @@ -129,6 +130,14 @@ export_materialization_inputs([ "src/node/workspace.ts", ]) +static_source_set( + name = "static_sources", + node_modules = ":node_modules", + prefix = "packages/@overeng/utils", + srcs = glob(STATIC_SOURCE_GLOBS, exclude = STATIC_SOURCE_EXCLUDES), + visibility = ["PUBLIC"], +) + alias( name = "node_modules", actual = "//buck2/dependencies:view_packages_overeng_utils_07fe64e7b8ad", @@ -255,20 +264,7 @@ package_view( "src/node/workspace.ts": "src/node/workspace.ts", "tsconfig.json": "tsconfig.json", }, - workspace_dist = { - "node_modules/@overeng/effect-distributed-lock/dist": "//packages/@overeng/effect-distributed-lock:dist", - "node_modules/@overeng/effect-distributed-lock/package.json": "//packages/@overeng/effect-distributed-lock:package.json", - "node_modules/@overeng/otel-contract/dist": "//packages/@overeng/otel-contract:dist", - "node_modules/@overeng/otel-contract/package.json": "//packages/@overeng/otel-contract:package.json", - "node_modules/@overeng/utils-dev/dist": "//packages/@overeng/utils-dev:dist", - "node_modules/@overeng/utils-dev/package.json": "//packages/@overeng/utils-dev:package.json", - }, - workspace_dependency_views = { - "node_modules/@overeng/effect-distributed-lock/node_modules": "//packages/@overeng/effect-distributed-lock:package_tree", - "node_modules/@overeng/otel-contract/node_modules": "//packages/@overeng/otel-contract:package_tree", - "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", - }, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) @@ -388,21 +384,8 @@ package_view( "tsconfig.json": "tsconfig.json", "vitest.config.ts": "vitest.config.ts", }, - workspace_dist = { - "node_modules/@overeng/effect-distributed-lock/dist": "//packages/@overeng/effect-distributed-lock:dist", - "node_modules/@overeng/effect-distributed-lock/package.json": "//packages/@overeng/effect-distributed-lock:package.json", - "node_modules/@overeng/otel-contract/dist": "//packages/@overeng/otel-contract:dist", - "node_modules/@overeng/otel-contract/package.json": "//packages/@overeng/otel-contract:package.json", - "node_modules/@overeng/utils-dev/dist": "//packages/@overeng/utils-dev:dist", - "node_modules/@overeng/utils-dev/package.json": "//packages/@overeng/utils-dev:package.json", - }, - workspace_dependency_views = { - "node_modules/@overeng/effect-distributed-lock/node_modules": "//packages/@overeng/effect-distributed-lock:package_tree", - "node_modules/@overeng/otel-contract/node_modules": "//packages/@overeng/otel-contract:package_tree", - "node_modules/@overeng/utils-dev/node_modules": "//packages/@overeng/utils-dev:package_tree", - }, strip_project_references = True, - runtime = "//:package_tree_runtime", + runtime = "//packages/@overeng/buck2-tools:package_tree_runtime", runtime_entry = "package-tree.ts", visibility = ["PUBLIC"], ) diff --git a/packages/@overeng/utils/BUCK.genie.ts b/packages/@overeng/utils/BUCK.genie.ts index b44aa35ad9..1bba943284 100644 --- a/packages/@overeng/utils/BUCK.genie.ts +++ b/packages/@overeng/utils/BUCK.genie.ts @@ -24,11 +24,7 @@ export const buck2TypeScriptAdmission = { distTarget: '//packages/@overeng/utils-dev:dist', }, ], - editorViewConsumer: false, - authority: { - declarationEntrypoint: 'src/isomorphic/mod.d.ts', - projectFile: 'tsconfig.json', - }, + authorities: [{ declarationEntrypoint: 'src/isomorphic/mod.d.ts', projectFile: 'tsconfig.json' }], tests: [ { name: 'test', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 135482bc09..fe7b6a1620 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -334,6 +334,12 @@ importers: packages/@overeng/effect-rpc-tanstack/examples/basic: dependencies: + '@effect/platform-node': + specifier: 4.0.0-rc.112 + version: 4.0.0-rc.112(effect@4.0.0-rc.112)(redis@6.2.1(@opentelemetry/api@1.9.1)) + '@overeng/effect-rpc-tanstack': + specifier: workspace:^ + version: link:../.. '@tanstack/react-router': specifier: 1.170.33 version: 1.170.33(react-dom@19.2.8(react@19.2.8))(react@19.2.8) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 4994a49549..615e33a2fc 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ -# Repository authority for local Rust tools. Nix builds continue to use +# Repository authority for local Rust tools. Nix stage-zero builds use # pkgs.rustPlatform; Cargo invoked from either external workspace member finds # this file by walking to the repository root. [toolchain] diff --git a/rust/buck2-tools/archive-tool/BUCK b/rust/buck2-tools/archive-tool/BUCK index 21b51f484c..821432af13 100644 --- a/rust/buck2-tools/archive-tool/BUCK +++ b/rust/buck2-tools/archive-tool/BUCK @@ -4,7 +4,7 @@ # Projection source: rust/buck2-tools/archive-tool/BUCK.genie.ts # Projection schema version: 1 # Projection generator: effect-utils/rust/cargo-buck2-package-projection -# Semantic fingerprint: sha256:ae24cc243055d16858f0ce809870f706d15bb514a03d71a5506924b6fd3e50d6 +# Semantic fingerprint: sha256:17efb6e11b48a3db2a82cdc3521464d9c0229a2829e5c2f66062541165220f68 # Semantic inputs: genie/buck2/mod.ts, packages/@overeng/otel-scrape/Cargo.toml, packages/@overeng/otelite/Cargo.toml, rust/Cargo.lock, rust/Cargo.toml, rust/buck2-tools/archive-tool/BUCK.genie.ts, rust/buck2-tools/archive-tool/Cargo.toml, rust/buck2-tools/archive-tool/src/**/*.rs, rust/buck2-tools/archive-tool/tests/**/*.rs, rust/buck2-tools/core/Cargo.toml, rust/buck2-tools/core/cargo-buck2-package-projection.ts, rust/buck2-tools/product/Cargo.toml, rust/reindeer.toml, rust/third-party/BUCK # Regenerate: devenv tasks run genie:run diff --git a/rust/buck2-tools/core/BUCK b/rust/buck2-tools/core/BUCK index 50803ffb14..92f9f09d4b 100644 --- a/rust/buck2-tools/core/BUCK +++ b/rust/buck2-tools/core/BUCK @@ -4,7 +4,7 @@ # Projection source: rust/buck2-tools/core/BUCK.genie.ts # Projection schema version: 1 # Projection generator: effect-utils/rust/cargo-buck2-package-projection -# Semantic fingerprint: sha256:b6a941dfc6a04d1d0db6e332183b08cbe6875cb90a416c9065cf3143e2b0a984 +# Semantic fingerprint: sha256:34df78c7194a3326c1978db143b11883153a6935ec3cd41f1df8015cd6b877ab # Semantic inputs: genie/buck2/mod.ts, packages/@overeng/otel-scrape/Cargo.toml, packages/@overeng/otelite/Cargo.toml, rust/Cargo.lock, rust/Cargo.toml, rust/buck2-tools/archive-tool/Cargo.toml, rust/buck2-tools/core/BUCK.genie.ts, rust/buck2-tools/core/Cargo.toml, rust/buck2-tools/core/cargo-buck2-package-projection.ts, rust/buck2-tools/core/src/**/*.rs, rust/buck2-tools/core/tests/**/*.rs, rust/buck2-tools/product/Cargo.toml, rust/reindeer.toml, rust/third-party/BUCK # Regenerate: devenv tasks run genie:run diff --git a/rust/buck2-tools/core/cargo-buck2-package-projection.ts b/rust/buck2-tools/core/cargo-buck2-package-projection.ts index b3063749d6..8e9428150f 100644 --- a/rust/buck2-tools/core/cargo-buck2-package-projection.ts +++ b/rust/buck2-tools/core/cargo-buck2-package-projection.ts @@ -35,9 +35,11 @@ const repo = defineRepoContext({ name: 'effect-utils', importMetaUrl: import.met */ export const cargoBuck2PackageProjection = ({ buildProduct = false, + cliBuildStamp = false, sourceUrl, }: { readonly buildProduct?: boolean + readonly cliBuildStamp?: boolean readonly sourceUrl: string }): GenieOutput => { const projectionSource = path @@ -217,6 +219,7 @@ export const cargoBuck2PackageProjection = ({ const semanticData = { binaries, compileEnv, + cliBuildStamp, conditionalDevDependencies, conditionalNormalDependencies, devDependencies, @@ -244,6 +247,9 @@ export const cargoBuck2PackageProjection = ({ ...Object.entries(compileEnv).map( ([name, value]) => ` ${starlarkString(name)}: ${starlarkString(value)},`, ), + ...(cliBuildStamp === true + ? [' "CLI_BUILD_STAMP": read_config("build_identity", "cli_build_stamp", ""),'] + : []), ' },', ] const normalConditional = conditionalNormalDependencies diff --git a/rust/buck2-tools/product/BUCK b/rust/buck2-tools/product/BUCK index e2a7f16123..4be173f4f7 100644 --- a/rust/buck2-tools/product/BUCK +++ b/rust/buck2-tools/product/BUCK @@ -4,7 +4,7 @@ # Projection source: rust/buck2-tools/product/BUCK.genie.ts # Projection schema version: 1 # Projection generator: effect-utils/rust/cargo-buck2-package-projection -# Semantic fingerprint: sha256:4a08f2711569a5bd48ff44846f7c4cea2f5a03a140ad3e54f1ca4d698480f984 +# Semantic fingerprint: sha256:f890998a68b6bd30533ba88cfdffa1190a178acebe4e45647f122b452d69186f # Semantic inputs: genie/buck2/mod.ts, packages/@overeng/otel-scrape/Cargo.toml, packages/@overeng/otelite/Cargo.toml, rust/Cargo.lock, rust/Cargo.toml, rust/buck2-tools/archive-tool/Cargo.toml, rust/buck2-tools/core/Cargo.toml, rust/buck2-tools/core/cargo-buck2-package-projection.ts, rust/buck2-tools/product/BUCK.genie.ts, rust/buck2-tools/product/Cargo.toml, rust/buck2-tools/product/src/**/*.rs, rust/buck2-tools/product/tests/**/*.rs, rust/reindeer.toml, rust/third-party/BUCK # Regenerate: devenv tasks run genie:run diff --git a/rust/buck2-tools/product/src/main.rs b/rust/buck2-tools/product/src/main.rs index f31e2a2bb1..948812b67d 100644 --- a/rust/buck2-tools/product/src/main.rs +++ b/rust/buck2-tools/product/src/main.rs @@ -5,7 +5,12 @@ use buck2_tool_core::{ use clap::{Args, Parser, Subcommand}; use serde::Deserialize; use serde_json::{json, Value}; -use std::{collections::BTreeSet, fs, os::unix::fs::PermissionsExt, path::PathBuf}; +use std::{ + collections::{BTreeMap, BTreeSet}, + fs, + os::unix::fs::PermissionsExt, + path::{Path, PathBuf}, +}; use tar::{Builder, EntryType, Header}; #[derive(Parser)] @@ -26,6 +31,8 @@ struct PackageArgs { #[arg(long)] executable: PathBuf, #[arg(long)] + support_tree: Option, + #[arg(long)] entrypoint: String, #[arg(long)] artifact: PathBuf, @@ -131,11 +138,15 @@ struct ProgramHeader { file_size: u64, } -fn elf_runtime(bytes: &[u8], architecture: &str) -> ToolResult { +fn elf_identity( + bytes: &[u8], + architecture: &str, + runtime_contract: &str, +) -> ToolResult<(Endian, &'static str, Vec)> { if bytes.get(..4) != Some(b"\x7fELF") || bytes.get(4) != Some(&2) { return Err(fail( "BUCK2_PRODUCT_ELF", - "elf-dynamic/v1 requires an ELF64 executable", + format!("{runtime_contract} requires an ELF64 executable"), )); } let endian = match bytes.get(5) { @@ -186,6 +197,11 @@ fn elf_runtime(bytes: &[u8], architecture: &str) -> ToolResult { file_size: read_u64(bytes, offset + 32, endian)?, }); } + Ok((endian, machine, headers)) +} + +fn elf_runtime(bytes: &[u8], architecture: &str) -> ToolResult { + let (endian, machine, headers) = elf_identity(bytes, architecture, "elf-dynamic/v1")?; let interpreter_header = headers .iter() .find(|header| header.kind == 3) @@ -325,16 +341,47 @@ fn elf_runtime(bytes: &[u8], architecture: &str) -> ToolResult { })) } +fn elf_static_runtime(bytes: &[u8], architecture: &str) -> ToolResult { + let (_, machine, headers) = elf_identity(bytes, architecture, "elf-static/v1")?; + if !headers.iter().any(|header| header.kind == 1) { + return Err(fail( + "BUCK2_PRODUCT_ELF", + "elf-static/v1 requires a loadable ELF segment", + )); + } + if headers.iter().any(|header| header.kind == 3) { + return Err(fail("BUCK2_PRODUCT_ELF", "elf-static/v1 forbids PT_INTERP")); + } + if headers.iter().any(|header| header.kind == 2) { + return Err(fail( + "BUCK2_PRODUCT_ELF", + "elf-static/v1 forbids PT_DYNAMIC", + )); + } + Ok(json!({ + "elfClass": "ELF64", + "inspectionContract": "elf-static/v1", + "kind": "elf-static", + "machine": machine, + })) +} + fn be_u32(bytes: &[u8], offset: usize) -> ToolResult { read_u32(bytes, offset, Endian::Big) } -fn is_ad_hoc_signature(bytes: &[u8], offset: usize, size: usize) -> ToolResult { +fn mach_o_signing_policy(bytes: &[u8], offset: usize, size: usize) -> ToolResult<&'static str> { + let signature_end = offset + .checked_add(size) + .ok_or_else(|| fail("BUCK2_PRODUCT_MACHO", "invalid Mach-O code signature range"))?; let signature = bytes - .get(offset..offset + size) + .get(offset..signature_end) .ok_or_else(|| fail("BUCK2_PRODUCT_MACHO", "truncated Mach-O code signature"))?; if be_u32(signature, 0)? != 0xfade_0cc0 { - return Ok(false); + return Err(fail( + "BUCK2_PRODUCT_MACHO", + "Mach-O code signature is not a superblob", + )); } let declared_size = usize::try_from(be_u32(signature, 4)?) .map_err(|_| fail("BUCK2_PRODUCT_MACHO", "invalid code signature size"))?; @@ -348,24 +395,71 @@ fn is_ad_hoc_signature(bytes: &[u8], offset: usize, size: usize) -> ToolResult declared_size.saturating_sub(8) { + return Err(fail("BUCK2_PRODUCT_MACHO", "invalid CMS signature offset")); + } + if cms_size.is_some() { + return Err(fail("BUCK2_PRODUCT_MACHO", "duplicate CMS signature blob")); + } + let magic = be_u32(signature, blob_offset)?; + let blob_size = usize::try_from(be_u32(signature, blob_offset + 4)?) + .map_err(|_| fail("BUCK2_PRODUCT_MACHO", "invalid CMS signature size"))?; + if magic != 0xfade_0b01 + || blob_size < 8 + || blob_offset.saturating_add(blob_size) > declared_size + { + return Err(fail("BUCK2_PRODUCT_MACHO", "invalid CMS signature blob")); + } + cms_size = Some(blob_size); } if slot == 0 || (0x1000..=0x1005).contains(&slot) { + if blob_offset > declared_size.saturating_sub(16) { + return Err(fail("BUCK2_PRODUCT_MACHO", "invalid CodeDirectory offset")); + } let magic = be_u32(signature, blob_offset)?; - if !(0xfade_0c02..=0xfade_0c04).contains(&magic) { + let blob_size = usize::try_from(be_u32(signature, blob_offset + 4)?) + .map_err(|_| fail("BUCK2_PRODUCT_MACHO", "invalid CodeDirectory size"))?; + if !(0xfade_0c02..=0xfade_0c04).contains(&magic) + || blob_size < 16 + || blob_offset.saturating_add(blob_size) > declared_size + { return Err(fail("BUCK2_PRODUCT_MACHO", "invalid CodeDirectory blob")); } + code_directory_found = true; ad_hoc_code_directory |= be_u32(signature, blob_offset + 12)? & 0x2 != 0; } } - Ok(ad_hoc_code_directory) + if !code_directory_found { + return Err(fail( + "BUCK2_PRODUCT_MACHO", + "Mach-O CodeDirectory is missing", + )); + } + match (ad_hoc_code_directory, cms_size) { + (true, Some(8)) => Ok("adhoc/v1"), + (false, Some(size)) if size > 8 => Ok("embedded/v1"), + (true, Some(_)) => Err(fail( + "BUCK2_PRODUCT_MACHO", + "ad-hoc Mach-O CodeDirectory has a non-empty CMS signature", + )), + (false, _) => Err(fail( + "BUCK2_PRODUCT_MACHO", + "non-ad-hoc Mach-O CodeDirectory has no embedded CMS signature", + )), + (true, None) => Err(fail( + "BUCK2_PRODUCT_MACHO", + "ad-hoc Mach-O CodeDirectory has no empty CMS wrapper", + )), + } } fn packed_version(value: u32) -> String { @@ -486,12 +580,7 @@ fn mach_o_runtime(bytes: &[u8], architecture: &str) -> ToolResult { let (signature_offset, signature_size) = signature .filter(|(_, size)| *size > 0) .ok_or_else(|| fail("BUCK2_PRODUCT_MACHO", "Mach-O has no code signature"))?; - if !is_ad_hoc_signature(bytes, signature_offset, signature_size)? { - return Err(fail( - "BUCK2_PRODUCT_MACHO", - "Mach-O signature is not ad hoc", - )); - } + let signing_policy = mach_o_signing_policy(bytes, signature_offset, signature_size)?; Ok(json!({ "architecture": observed_architecture, "dylibs": dylibs, @@ -500,7 +589,7 @@ fn mach_o_runtime(bytes: &[u8], architecture: &str) -> ToolResult { "kind": "mach-o-dynamic", "minimumOs": minimum_os.ok_or_else(|| fail("BUCK2_PRODUCT_MACHO", "Mach-O has no LC_BUILD_VERSION"))?, "rpathPolicy": "empty/v1", - "signingPolicy": "adhoc/v1", + "signingPolicy": signing_policy, })) } @@ -525,29 +614,127 @@ fn tar_header(path: &str, size: u64, kind: EntryType, mode: u32) -> ToolResult ToolResult> { +fn collect_support_files( + root: &Path, + directory: &Path, + files: &mut BTreeMap>, +) -> ToolResult<()> { + let mut entries = fs::read_dir(directory) + .map_err(|error| { + fail( + "BUCK2_PRODUCT_INPUT", + format!("could not read support tree: {error}"), + ) + })? + .collect::, _>>() + .map_err(|error| { + fail( + "BUCK2_PRODUCT_INPUT", + format!("could not read support tree: {error}"), + ) + })?; + entries.sort_by_key(std::fs::DirEntry::file_name); + for entry in entries { + let path = entry.path(); + let metadata = fs::symlink_metadata(&path).map_err(|error| { + fail( + "BUCK2_PRODUCT_INPUT", + format!("could not inspect support-tree entry: {error}"), + ) + })?; + if metadata.file_type().is_symlink() { + return Err(fail( + "BUCK2_PRODUCT_INPUT", + "support tree must not contain symlinks", + )); + } + if metadata.is_dir() { + collect_support_files(root, &path, files)?; + } else if metadata.is_file() { + let relative = path + .strip_prefix(root) + .map_err(|error| fail("BUCK2_PRODUCT_INPUT", error.to_string()))? + .to_str() + .ok_or_else(|| fail("BUCK2_PRODUCT_INPUT", "support-tree path is not UTF-8"))?; + let relative = normalized_relative(relative, "support-tree path")?.to_owned(); + let bytes = fs::read(&path).map_err(|error| { + fail( + "BUCK2_PRODUCT_INPUT", + format!("could not read support-tree file: {error}"), + ) + })?; + files.insert(relative, bytes); + } else { + return Err(fail( + "BUCK2_PRODUCT_INPUT", + "support tree must contain only regular files and directories", + )); + } + } + Ok(()) +} + +fn archive( + executable: &[u8], + entrypoint: &str, + support_tree: Option<&Path>, +) -> ToolResult> { + let mut files = BTreeMap::new(); + if let Some(root) = support_tree { + let metadata = fs::symlink_metadata(root).map_err(|error| { + fail( + "BUCK2_PRODUCT_INPUT", + format!("support tree is unavailable: {error}"), + ) + })?; + if !metadata.is_dir() || metadata.file_type().is_symlink() { + return Err(fail( + "BUCK2_PRODUCT_INPUT", + "support tree must be a regular non-symlink directory", + )); + } + collect_support_files(root, root, &mut files)?; + } + if files + .insert(entrypoint.to_owned(), executable.to_vec()) + .is_some() + { + return Err(fail( + "BUCK2_PRODUCT_INPUT", + "support tree collides with the executable entrypoint", + )); + } + + let mut directories = BTreeSet::new(); + for path in files.keys() { + let components = path.split('/').collect::>(); + for end in 1..components.len() { + directories.insert(components[..end].join("/")); + } + } + let mut bytes = Vec::new(); { let mut builder = Builder::new(&mut bytes); - let components = entrypoint.split('/').collect::>(); - for end in 1..components.len() { - let directory = components[..end].join("/"); - let mut header = tar_header(&directory, 0, EntryType::Directory, 0o555)?; + for directory in directories { + let header = tar_header(&directory, 0, EntryType::Directory, 0o555)?; builder .append(&header, std::io::empty()) .map_err(|error| fail("BUCK2_PRODUCT_TAR", error.to_string()))?; - header.set_cksum(); } - let header = tar_header( - entrypoint, - u64::try_from(executable.len()) - .map_err(|_| fail("BUCK2_PRODUCT_TAR", "executable is too large"))?, - EntryType::Regular, - 0o555, - )?; - builder - .append(&header, executable) - .map_err(|error| fail("BUCK2_PRODUCT_TAR", error.to_string()))?; + for (path, contents) in files { + let mode = if path == entrypoint { 0o555 } else { 0o444 }; + let header = tar_header( + &path, + u64::try_from(contents.len()) + .map_err(|_| fail("BUCK2_PRODUCT_TAR", "product file is too large"))?, + EntryType::Regular, + mode, + )?; + builder + .append(&header, contents.as_slice()) + .map_err(|error| fail("BUCK2_PRODUCT_TAR", error.to_string()))?; + } builder .finish() .map_err(|error| fail("BUCK2_PRODUCT_TAR", error.to_string()))?; @@ -610,6 +797,15 @@ fn package(args: PackageArgs) -> ToolResult<()> { } elf_runtime(&executable, &args.platform_architecture)? } + "elf-static/v1" => { + if args.platform_os != "linux" || args.platform_abi != "glibc" { + return Err(fail( + "BUCK2_PRODUCT_PLATFORM", + "elf-static/v1 requires linux/glibc", + )); + } + elf_static_runtime(&executable, &args.platform_architecture)? + } "mach-o-dynamic/v1" => { if args.platform_os != "darwin" || args.platform_abi != "darwin" { return Err(fail( @@ -647,7 +843,7 @@ fn package(args: PackageArgs) -> ToolResult<()> { safe_text(&provenance.recipe, "provenance recipe")?; safe_text(&provenance.toolchain, "provenance toolchain")?; - let artifact = archive(&executable, &entrypoint)?; + let artifact = archive(&executable, &entrypoint, args.support_tree.as_deref())?; let digest = sha256_sri(&sha256_bytes(&artifact))?; let descriptor = json!({ "entrypoints": [entrypoint], @@ -744,11 +940,40 @@ mod tests { fixture } + #[cfg(target_os = "linux")] + fn static_elf_fixture(root: &Path) -> PathBuf { + let mut bytes = fs::read(std::env::current_exe().unwrap()).unwrap(); + let endian = match bytes[5] { + 1 => Endian::Little, + 2 => Endian::Big, + _ => panic!("test executable is not ELF"), + }; + let program_offset = usize_from(read_u64(&bytes, 32, endian).unwrap()).unwrap(); + let entry_size = usize::from(read_u16(&bytes, 54, endian).unwrap()); + let entry_count = usize::from(read_u16(&bytes, 56, endian).unwrap()); + for index in 0..entry_count { + let header = program_offset + index * entry_size; + if !matches!(read_u32(&bytes, header, endian).unwrap(), 2 | 3) { + continue; + } + let replacement = match endian { + Endian::Little => 4u32.to_le_bytes(), + Endian::Big => 4u32.to_be_bytes(), + }; + bytes[header..header + 4].copy_from_slice(&replacement); + } + let fixture = root.join("fixture-static-elf"); + fs::write(&fixture, bytes).unwrap(); + fs::set_permissions(&fixture, fs::Permissions::from_mode(0o555)).unwrap(); + fixture + } + fn args(root: &Path, executable: PathBuf) -> PackageArgs { let provenance = root.join("provenance.json"); fs::write(&provenance, br#"{"schema":"buck-build-provenance/v1","recipe":"effect-utils/v1","toolchain":"rust-test"}"#).unwrap(); PackageArgs { executable, + support_tree: None, entrypoint: "bin/tool".into(), artifact: root.join("artifact.tar"), name: "tool".into(), @@ -796,10 +1021,64 @@ mod tests { assert!(entries.next().is_none()); } + #[cfg(target_os = "linux")] + #[test] + fn packages_a_static_elf_under_the_static_runtime_contract() { + let temporary = tempdir().unwrap(); + let mut arguments = args(temporary.path(), static_elf_fixture(temporary.path())); + arguments.runtime_contract = "elf-static/v1".into(); + package(arguments).unwrap(); + let descriptor: Value = + serde_json::from_slice(&fs::read(temporary.path().join("descriptor.json")).unwrap()) + .unwrap(); + assert_eq!(descriptor["runtime"]["kind"], "elf-static"); + assert_eq!(descriptor["runtime"]["inspectionContract"], "elf-static/v1"); + assert_eq!(descriptor["runtime"]["machine"], std::env::consts::ARCH); + } + + fn signature_with_cms(code_directory_flags: u32, cms_size: u32) -> Vec { + let declared_size = 44 + cms_size; + let mut signature = Vec::new(); + for value in [ + 0xfade_0cc0u32, + declared_size, + 2, + 0, + 28, + 0x1_0000, + 44, + 0xfade_0c02, + 16, + 0, + code_directory_flags, + 0xfade_0b01, + cms_size, + ] { + signature.extend_from_slice(&value.to_be_bytes()); + } + signature.resize(usize::try_from(declared_size).unwrap(), 0); + signature + } + + #[test] + fn distinguishes_ad_hoc_and_embedded_mach_o_signatures() { + let ad_hoc = signature_with_cms(0x2, 8); + assert_eq!( + mach_o_signing_policy(&ad_hoc, 0, ad_hoc.len()).unwrap(), + "adhoc/v1" + ); + + let embedded = signature_with_cms(0, 16); + assert_eq!( + mach_o_signing_policy(&embedded, 0, embedded.len()).unwrap(), + "embedded/v1" + ); + } + #[test] fn archive_bytes_are_deterministic_and_normalized() { - let first = archive(b"executable", "libexec/example/tool").unwrap(); - let second = archive(b"executable", "libexec/example/tool").unwrap(); + let first = archive(b"executable", "libexec/example/tool", None).unwrap(); + let second = archive(b"executable", "libexec/example/tool", None).unwrap(); assert_eq!(first, second); let mut archive = tar::Archive::new(first.as_slice()); let entries = archive @@ -824,6 +1103,42 @@ mod tests { ); } + #[test] + fn archives_support_tree_files_next_to_the_entrypoint() { + let temporary = tempdir().unwrap(); + let support_tree = temporary.path().join("support"); + fs::create_dir_all(support_tree.join("bin")).unwrap(); + fs::write(support_tree.join("bin/lib.d.ts"), b"interface Array {}").unwrap(); + fs::write(support_tree.join("bin/tsc.sig"), b"signature").unwrap(); + let bytes = archive( + b"executable", + "bin/typescript-api-server", + Some(&support_tree), + ) + .unwrap(); + let mut archive = tar::Archive::new(bytes.as_slice()); + let entries = archive + .entries() + .unwrap() + .map(|entry| { + let entry = entry.unwrap(); + ( + entry.path().unwrap().into_owned(), + entry.header().mode().unwrap(), + ) + }) + .collect::>(); + assert_eq!( + entries, + vec![ + (PathBuf::from("bin"), 0o555), + (PathBuf::from("bin/lib.d.ts"), 0o444), + (PathBuf::from("bin/tsc.sig"), 0o444), + (PathBuf::from("bin/typescript-api-server"), 0o555), + ] + ); + } + #[test] fn rejects_unsafe_entrypoints_before_writing_outputs() { let temporary = tempdir().unwrap(); diff --git a/rust/workspace-contract.test.sh b/rust/workspace-contract.test.sh index 7ebaf15b3a..0c808b9834 100644 --- a/rust/workspace-contract.test.sh +++ b/rust/workspace-contract.test.sh @@ -113,45 +113,39 @@ expect_failure \ --format-version 1 export EFFECT_UTILS_RUST_WORKSPACE_REPO="$repo_root" -# `${...}` below is Nix attribute interpolation, not shell expansion. +# Evaluate the same native-product import the flake uses. The import verifies +# every committed descriptor digest, release hash, platform tuple, and Buck +# target before exposing the manifest. # shellcheck disable=SC2016 -source_expr='let +native_products_expr='let repo = builtins.toPath (builtins.getEnv "EFFECT_UTILS_RUST_WORKSPACE_REPO"); flake = builtins.getFlake (toString repo); + pkgs = import flake.inputs.nixpkgs { system = builtins.currentSystem; }; + nativeProducts = import (repo + "/nix/buck2-native-products") { inherit pkgs; }; in { - otelScrape = toString flake.packages.${builtins.currentSystem}.otel-scrape.src; - otelite = toString flake.packages.${builtins.currentSystem}.otelite.src; + inherit (nativeProducts) manifest targets; }' -source_json="$(nix eval --impure --json --expr "$source_expr")" - -check_source() { - local package="$1" - local sibling="$2" - local source_path="$3" - - [ -f "$source_path/rust/Cargo.toml" ] || fail "$package source omitted rust/Cargo.toml" - [ -f "$source_path/rust/Cargo.lock" ] || fail "$package source omitted rust/Cargo.lock" - [ -f "$source_path/rust-toolchain.toml" ] || fail "$package source omitted root rust-toolchain.toml" - [ -f "$source_path/packages/@overeng/otel-scrape/Cargo.toml" ] || - fail "$package source omitted otel-scrape member manifest" - [ -f "$source_path/packages/@overeng/otelite/Cargo.toml" ] || - fail "$package source omitted otelite member manifest" - [ -f "$source_path/packages/@overeng/$package/src/lib.rs" ] || - fail "$package source omitted selected member source" - [ ! -e "$source_path/packages/@overeng/$sibling/src/lib.rs" ] || - fail "$package source captured sibling source" - [ ! -e "$source_path/package.json" ] || fail "$package source captured unrelated repository files" - - cargo metadata \ - --manifest-path "$source_path/rust/Cargo.toml" \ - --locked \ - --no-deps \ - --format-version 1 >/dev/null - echo "rust-workspace-contract: GREEN $package workspace-aware narrow source" -} - -check_source "otel-scrape" "otelite" "$(jq -r '.otelScrape' <<<"$source_json")" -check_source "otelite" "otel-scrape" "$(jq -r '.otelite' <<<"$source_json")" +native_products_json="$(nix eval --impure --json --expr "$native_products_expr")" + +jq -e ' + .targets.products as $targets | + .targets.platforms as $platforms | + (.manifest.schema == "effect-utils/buck2-native-release-products/v1") and + (.targets.schema == "effect-utils/buck2-native-release-targets/v1") and + (($targets | map(.name) | sort) == ["otel-scrape", "otelite"]) and + ((.manifest.products | length) == (($targets | length) * ($platforms | length))) and + all(.manifest.products[]; . as $entry | + ($entry.descriptorSha256 | test("^sha256:[0-9a-f]{64}$")) and + ($entry.descriptor.payload.digest.algorithm == "sha256") and + ($entry.release.hash == $entry.descriptor.payload.digest.sri) and + any($targets[]; + .name == $entry.descriptor.name and + .target == $entry.descriptor.semanticProvenance.target + ) + ) +' <<<"$native_products_json" >/dev/null || + fail "Buck native-product manifest provenance is incomplete or inconsistent" +echo "rust-workspace-contract: GREEN Buck native-product manifest provenance" [ -f "$repo_root/rust-toolchain.toml" ] || fail "repository rust-toolchain.toml is missing" [ ! -e "$repo_root/packages/@overeng/otel-scrape/rust-toolchain.toml" ] || diff --git a/scripts/devenv-task-graph-check.mjs b/scripts/devenv-task-graph-check.mjs index 69a069ec30..909a7abc89 100755 --- a/scripts/devenv-task-graph-check.mjs +++ b/scripts/devenv-task-graph-check.mjs @@ -62,16 +62,19 @@ const dependencies = new Map([...tasks.keys()].map((name) => [name, new Set()])) const ensureTask = (name) => { if (dependencies.has(name) === false) dependencies.set(name, new Set()) } +const missingDependencies = [] for (const [name, task] of tasks) { for (const dependency of task.after ?? []) { const upstream = dependencyName(dependency) if (upstream === undefined) continue ensureTask(upstream) + if (tasks.has(upstream) === false) missingDependencies.push(`${name}.after -> ${upstream}`) dependencies.get(name).add(upstream) } for (const dependency of task.before ?? []) { const downstream = dependencyName(dependency) if (downstream === undefined) continue + if (tasks.has(downstream) === false) missingDependencies.push(`${name}.before -> ${downstream}`) ensureTask(downstream) dependencies.get(downstream).add(name) } @@ -86,6 +89,11 @@ const ok = ({ condition, name, detail = '' }) => { testCount += 1 console.log(`ok ${testCount} - ${name}`) } +ok({ + condition: missingDependencies.length === 0, + name: 'every task dependency resolves to an evaluated task', + detail: missingDependencies.join(', '), +}) const requireTask = (name) => { const task = tasks.get(name) ok({ condition: task !== undefined, name: `evaluated graph contains ${name}` }) @@ -103,20 +111,48 @@ const reaches = ({ start, target }) => { } for (const name of [ - 'ts:check', - 'ts:check:strict', - 'ts:build', - 'ts:build-watch', 'check:quick', 'check:all', + 'nix:check:quick', + 'nix:flake:check', + 'setup:strict', + 'genie:run', + 'genie:check', + 'mr:apply', 'buck2:check', + 'buck2:quick', + 'buck2:all', + 'check:buck2-producer-overlap', 'buck2:typescript:materialize-dist', - 'buck2:tui-core:publish-editor', - 'buck2:tui-core:check-editor', + 'buck2:editor:bootstrap', + 'buck2:editor:materialize', + 'buck2:editor:authority', + 'buck2:editor:publish', + 'buck2:editor:check', 'test:run', 'test:buck2:unit', ]) requireTask(name) +for (const name of [ + 'ts:check', + 'ts:check:strict', + 'ts:build', + 'ts:build-watch', + 'ts:emit', + 'pnpm:install', + 'pnpm:link-native-node-packages', +]) { + ok({ + condition: tasks.has(name) === false, + name: `${name} is absent after its Buck authority cutover`, + }) +} +for (const name of ['nix:build', 'nix:check']) { + ok({ + condition: tasks.has(name) === false, + name: `${name} is absent without repository pnpm FOD producers`, + }) +} const visiting = new Set() const visited = new Set() @@ -136,15 +172,27 @@ try { } const materializer = 'buck2:typescript:materialize-dist' -// Buck owns typecheck and dist for the authoritative packages; the root `tsc` tasks own only -// the residual projects, and those consume Buck-owned declarations through the dist overlays -// the materializer publishes. Every root TypeScript task must therefore run after it. -for (const name of ['ts:check', 'ts:check:strict', 'ts:build', 'ts:build-watch', 'check:quick']) { +for (const [checkTask, aggregateTask] of [ + ['check:quick', 'buck2:quick'], + ['check:all', 'buck2:all'], +]) { + ok({ + condition: reaches({ start: checkTask, target: aggregateTask }), + name: `${checkTask} reaches ${aggregateTask}`, + }) ok({ - condition: reaches({ start: name, target: materializer }), - name: `${name} reaches ${materializer}`, + condition: reaches({ start: checkTask, target: 'check:buck2-producer-overlap' }), + name: `${checkTask} reaches the Buck producer overlap guard`, }) } +ok({ + condition: reaches({ start: 'check:quick', target: 'nix:check:quick' }), + name: 'check:quick retains the empty Nix fingerprint aggregate', +}) +ok({ + condition: reaches({ start: 'check:all', target: 'nix:flake:check' }), + name: 'check:all retains repository-wide Nix flake validation', +}) // `test:run` must schedule the one Buck aggregate and the source-side batches which own // packages absent from the authority plus admitted lanes' exact unbounded complements. Either // edge going missing would silently omit a disjoint side of the test partition. @@ -157,9 +205,10 @@ ok({ condition: testRunDependencies.some((name) => name.startsWith('test:run:batch:') === true), name: 'test:run executes the source-owned complement partition', }) -// `mr apply` both reconciles the workspace and installs the `.buck2/capabilities` -// projection that Buck analysis of `//buck2/toolchains` reads, so it is the single -// ordering barrier for every task that invokes Buck. +// `genie:check` is the source-side stage-zero guard against a graph proving its own stale +// projection. `mr apply` runs only after that proof, then reconciles the workspace and +// installs the `.buck2/capabilities` projection Buck analysis reads. Together they are the +// ordering barriers for every public task that invokes Buck. const buck2TestAuthority = JSON.parse(readFileSync(`${root}/buck2-test-authority.json`, 'utf8')) if (buck2TestAuthority.schemaVersion !== 2 || Array.isArray(buck2TestAuthority.lanes) === false) { throw new Error('buck2-test-authority.json does not match schemaVersion 2') @@ -188,20 +237,52 @@ for (const name of [...buck2UnboundedTaskNames, ...buck2ExternalOwnerTaskNames]) }) } for (const name of [ - materializer, - 'buck2:check', - 'buck2:editor-authority', - 'buck2:tui-core:publish-editor', - 'buck2:tui-core:check-editor', - 'buck2:nix-bridge:check', + 'buck2:editor:authority', + 'buck2:editor:publish', + 'buck2:editor:check', + 'lint:check:asset-import-needs-type-reference', + 'lint:check:format', + 'lint:check:genie:coverage', + 'lint:check:oxlint', + 'workspace:check', 'test:buck2:unit', ...buck2TestLaneTaskNames, ]) { ok({ condition: reaches({ start: name, target: 'mr:apply' }), - name: `${name} waits for workspace reconciliation and the capability projection`, + name: `${name} waits for workspace reconciliation`, + }) + ok({ + condition: reaches({ start: name, target: 'genie:check' }), + name: `${name} waits for source-side generation freshness`, + }) +} +for (const name of ['buck2:check', 'buck2:quick', 'buck2:all', 'buck2:nix-bridge:check']) { + ok({ + condition: reaches({ start: name, target: 'mr:apply' }) === false, + name: `${name} remains standalone`, }) } +ok({ + condition: + reaches({ start: 'buck2:editor:bootstrap', target: 'mr:setup' }) === true && + reaches({ start: 'buck2:editor:bootstrap', target: 'genie:check' }) === false, + name: 'editor bootstrap materializes committed dependencies before freshness without claiming it', +}) + +ok({ + condition: + reaches({ + start: 'buck2:typescript:materialize-dist', + target: 'buck2:editor:materialize', + }) === true && + reaches({ start: 'setup:strict', target: 'buck2:editor:materialize' }) === true, + name: 'mutating setup and dist publication share the ordered editor materialization barrier', +}) +ok({ + condition: reaches({ start: 'genie:check', target: 'genie:run' }) === false, + name: 'standalone generation freshness never invokes the projection producer', +}) const source = readFileSync(`${root}/devenv.nix`, 'utf8') const taskSource = (name) => { @@ -211,6 +292,26 @@ const taskSource = (name) => { return source.slice(start, end === -1 ? source.length : end) } +const editorMaterializeSource = taskSource('buck2:editor:materialize') +const orderedMaterializationSteps = [ + 'devenv tasks run mr:setup', + 'devenv tasks run buck2:editor:bootstrap --mode single', + 'devenv tasks run genie:run --mode single', + 'devenv tasks run genie:check --mode single', + 'devenv tasks run mr:apply --mode single', + 'devenv tasks run buck2:editor:publish --mode single', +] +const orderedMaterializationOffsets = orderedMaterializationSteps.map((step) => + editorMaterializeSource.indexOf(step), +) +ok({ + condition: orderedMaterializationOffsets.every( + (offset, index) => + offset !== -1 && (index === 0 || offset > orderedMaterializationOffsets[index - 1]), + ), + name: 'editor materialization runs bootstrap, generation, freshness, composition, and publication in order', +}) + const materializerSource = taskSource(materializer) const typescriptAuthorityRuntimePath = 'genie/buck2/typescript-authority-runtime.ts' const typescriptAuthorityRuntimeSource = readFileSync( @@ -226,43 +327,62 @@ ok({ }) ok({ condition: - typescriptAuthorityRuntimeSource.includes('authoritativeBuck2TypeScriptAdmissions') === true && + typescriptAuthorityRuntimeSource.includes('authoritativeBuck2TypeScriptDeclarations') === + true && + typescriptAuthorityRuntimeSource.includes('authoritativeBuck2TypeScriptProjects') === true && typescriptAuthorityRuntimeSource.includes('admissions.map(') === true && typescriptAuthorityRuntimeSource.includes('scripts/typescript-materialize-dist.sh') === true && typescriptAuthorityRuntimeSource.includes('packages/@overeng/tui-core') === false && typescriptAuthorityRuntimeSource.includes('packages/@overeng/tui-react') === false, - name: 'TypeScript authority runtime derives materialization from the registry', + name: 'TypeScript authority runtime derives checking and publication from the registry', }) ok({ condition: source.includes('composed_workspace_root()') === true && source.includes('worktree list --porcelain -z') === true && source.includes('backlink=') === true && - materializerSource.includes('TYPESCRIPT_DIST_MODE=publish') === true && - materializerSource.includes('TYPESCRIPT_DIST_MODE=check') === true && - materializerSource.includes('TSGO_BIN=') === true && - materializerSource.includes('DIFF_BIN=') === true, - name: 'materializer publishes from a composition root and checks freshness standalone', + materializerSource.includes('requires a composed megarepo workspace') === true && + materializerSource.includes('WORKSPACE_ROOT=') === true && + materializerSource.includes('TYPESCRIPT_DIST_MODE=') === false && + materializerSource.includes('TSGO_BIN=') === false, + name: 'materializer publishes only from a reciprocal composition root', }) -for (const name of ['buck2:tui-core:publish-editor', 'buck2:tui-core:check-editor']) { - const task = taskSource(name) +const editorViewHelper = source.slice( + source.indexOf(' editorViewExec ='), + source.indexOf('\nin\n{', source.indexOf(' editorViewExec =')), +) +for (const term of ['--isolation-dir', 'buck-out']) { ok({ - condition: task.includes('--isolation-dir') === false, - name: `${name} has no dynamic isolation directory`, + condition: editorViewHelper.includes(term) === false, + name: `whole-workspace editor publisher has no ${term} lifecycle`, }) - ok({ condition: /buck2[^\n]*\bkill\b/.test(task) === false, name: `${name} has no daemon kill` }) - ok({ condition: task.includes('buck-out') === false, name: `${name} has no buck-out cleanup` }) } +ok({ + condition: /\bbuck2[^\n]*\bkill\b/.test(editorViewHelper) === false, + name: 'whole-workspace editor publisher never kills the shared Buck daemon', +}) const buckCheckSource = taskSource('buck2:check') +const buckQuickSource = taskSource('buck2:quick') +const buckAllSource = taskSource('buck2:all') +const producerOverlapSource = taskSource('check:buck2-producer-overlap') +ok({ + condition: + source.includes('buck2AggregateExec =') === true && + buckCheckSource.includes('audit providers') === true && + buckCheckSource.includes('typescript-authority-runtime.ts') === false && + buckQuickSource.includes('buck2AggregateExec "buck2:quick" "//:quick"') === true && + buckAllSource.includes('buck2AggregateExec "buck2:all" "//:all"') === true && + buckQuickSource.includes('--local-only') === false && + buckAllSource.includes('--local-only') === false, + name: 'Buck check tasks separate provider audit from standalone cache-enabled aggregates', +}) ok({ condition: - buckCheckSource.includes('realpath "$root/../.."') === true && - buckCheckSource.includes('$workspace_root/.megarepo/bin/buck2') === true && - buckCheckSource.includes(typescriptAuthorityRuntimePath) === true && - buckCheckSource.includes('build "$buck"') === true, - name: 'buck2:check resolves the composition wrapper and dispatches the authority runtime', + producerOverlapSource.includes('genie/buck2/producer-overlap.ts') === true && + producerOverlapSource.includes('task-config-devenv-config-task-config') === true, + name: 'producer overlap guard reads the evaluated task registry', }) const buckToolchainSource = readFileSync(`${root}/buck2/toolchains/BUCK`, 'utf8') ok({ @@ -271,6 +391,29 @@ ok({ buckToolchainSource.includes('name = "archive_tool"') === true, name: 'Buck toolchains live in the buck2/toolchains package', }) +const configuredToolchainSource = readFileSync( + `${root}/buck2/toolchains/configured.bzl`, + 'utf8', +) +ok({ + condition: + buckToolchainSource.includes('load("@capabilities//:defs.bzl"') === true && + configuredToolchainSource.includes('load("@capabilities//:defs.bzl"') === true, + name: 'capability Starlark loads use external-cell import syntax', +}) +const standaloneBuckConfig = readFileSync(`${root}/.buckconfig`, 'utf8') +const compositionRootSource = readFileSync( + `${root}/packages/@overeng/megarepo/src/composition/root/composition-root.ts`, + 'utf8', +) +ok({ + condition: + standaloneBuckConfig.includes('file_watcher = notify') === true && + standaloneBuckConfig.includes('file_watcher = watchman') === false && + compositionRootSource.includes("lines.push('', '[buck2]', ' file_watcher = watchman')") === + true, + name: 'standalone roots use notify while composed roots retain Watchman', +}) ok({ condition: existsSync(`${root}/toolchains`) === false, name: 'no legacy top-level toolchains directory remains', diff --git a/scripts/editor-view-authority.ts b/scripts/editor-view-authority.ts index 1dd41c7424..009a30fde7 100755 --- a/scripts/editor-view-authority.ts +++ b/scripts/editor-view-authority.ts @@ -1,16 +1,85 @@ #!/usr/bin/env -S bun +import { readFileSync } from 'node:fs' +import { resolve } from 'node:path' import process from 'node:process' -import { editorViewConsumerPackagePaths } from '../genie/buck2/typescript-admissions.ts' +import { pnpmWorkspaceMemberPaths } from '../genie/packages.ts' +import { reconcileBuckViews } from '../packages/@overeng/buck2-tools/src/buck-watch.ts' +import type { BuckWatchPlan } from '../packages/@overeng/buck2-tools/src/buck-watch.ts' import { writeEditorViewAuthority } from '../packages/@overeng/buck2-tools/src/editor-view-authority.ts' +import { defaultEditorViewName } from '../packages/@overeng/buck2-tools/src/editor-view.ts' +/** Complete source-authoritative editor consumer registry, including the repository root. */ +export const editorViewPackagePaths = ['.', ...pnpmWorkspaceMemberPaths].toSorted((left, right) => + left === right ? 0 : left < right ? -1 : 1, +) + +/** Whole-workspace publication plan derived from an explicit package registry. */ +export const editorViewPlan = ({ + cell, + packagePaths = editorViewPackagePaths, +}: { + readonly cell: string + readonly packagePaths?: readonly string[] +}): BuckWatchPlan => ({ + globalPaths: [], + packages: packagePaths + .map((packagePath) => { + const root = packagePath === '.' + const viewName = defaultEditorViewName(packagePath) + const targetPrefix = root === true ? '' : packagePath + return { + packagePath, + sourceRoots: [], + workspaceDependencies: [], + targets: { + packageTree: + root === true + ? `${cell}//:root_editor_package_tree` + : `${cell}//${packagePath}:package_tree`, + }, + editor: { + cell, + consumerCache: `.devenv/vite-cache/${viewName}`, + inputsManifestTarget: `${cell}//${targetPrefix}:editor_view_inputs`, + target: root === true ? '//:editor_inputs' : `//${packagePath}:editor_inputs`, + viewName, + }, + } + }) + .toSorted((left, right) => + left.packagePath === right.packagePath ? 0 : left.packagePath < right.packagePath ? -1 : 1, + ), +}) + +type Command = 'authority' | 'bootstrap' | 'check' | 'publish' const fail = (message: string): never => { throw new Error(`editor view authority: ${message}`) } +const commands = new Set(['authority', 'bootstrap', 'check', 'publish']) + +const bootstrapPackagePaths = (repoRoot: string): readonly string[] => { + const value: unknown = JSON.parse(readFileSync(resolve(repoRoot, 'package.json'), 'utf8')) + if ( + typeof value !== 'object' || + value === null || + !('workspaces' in value) || + Array.isArray(value.workspaces) === false || + value.workspaces.every((entry) => typeof entry === 'string') === false + ) + fail('generated root package.json must declare string workspace paths') + return ['.', ...value.workspaces].toSorted((left, right) => + left === right ? 0 : left < right ? -1 : 1, + ) +} + const parseCli = (args: readonly string[]) => { + const command = args[0] + if (commands.has(command as Command) === false) + fail('expected command: authority, bootstrap, check, or publish') const values = new Map() - for (let index = 0; index < args.length; index += 2) { + for (let index = 1; index < args.length; index += 2) { const flag = args[index] ?? fail('missing option') const value = args[index + 1] ?? fail(`missing value for ${flag}`) if (flag.startsWith('--') === false || values.has(flag) === true) @@ -24,30 +93,87 @@ const parseCli = (args: readonly string[]) => { '--buck2', '--git', '--output', + '--publisher', + '--cp', + '--mv', + '--snapshot-retention', ]) for (const flag of values.keys()) if (allowed.has(flag) === false) fail(`unexpected option: ${flag}`) const get = (flag: string): string => values.get(flag) ?? fail(`missing required option ${flag}`) + const admitting = command !== 'authority' return { + command: command as Command, repoRoot: get('--repo-root'), workspaceRoot: get('--workspace-root'), cell: get('--cell'), buck2: get('--buck2'), git: get('--git'), output: get('--output'), + publisher: admitting === true ? get('--publisher') : '', + cp: admitting === true ? get('--cp') : '', + mv: admitting === true ? get('--mv') : '', + snapshotRetention: admitting === true ? Number(get('--snapshot-retention')) : 3, } } -try { +const main = async (): Promise => { const options = parseCli(process.argv.slice(2)) + if ( + Number.isInteger(options.snapshotRetention) === false || + options.snapshotRetention < 2 || + options.snapshotRetention > 32 + ) + fail('--snapshot-retention must be an integer from 2 through 32') + const packagePaths = + options.command === 'bootstrap' + ? bootstrapPackagePaths(options.repoRoot) + : editorViewPackagePaths const authority = await writeEditorViewAuthority({ ...options, - requiredPackages: editorViewConsumerPackagePaths, + requiredPackages: packagePaths, }) - process.stdout.write( - `wrote editor dependency authority for ${authority.ownedPackages.length} workspace packages\n`, - ) -} catch (error) { - process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`) - process.exitCode = 1 + if (options.command === 'authority') { + process.stdout.write( + `wrote editor dependency authority for ${authority.ownedPackages.length} workspace consumers\n`, + ) + return + } + const plan = editorViewPlan({ cell: options.cell, packagePaths }) + await reconcileBuckViews({ + request: { + packagePaths: plan.packages.map(({ packagePath }) => packagePath), + changedPaths: [], + buildTargets: plan.packages.flatMap(({ editor }) => + editor === undefined ? [] : [editor.inputsManifestTarget], + ), + }, + options: { + plan, + mode: options.command === 'check' ? 'check' : 'publish', + repoRoot: options.repoRoot, + workspaceRoot: options.workspaceRoot, + buck2: options.buck2, + editorViewCommand: [process.execPath, options.publisher], + workspaceAuthority: options.output, + cp: options.cp, + mv: options.mv, + snapshotRetention: options.snapshotRetention, + }, + }) + const action = + options.command === 'bootstrap' + ? 'bootstrapped' + : options.command === 'publish' + ? 'published' + : 'checked' + process.stdout.write(`${action} ${plan.packages.length} editor views\n`) } + +if (import.meta.main === true) + try { + await main() + } catch (error) { + process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`) + process.exitCode = 1 + } diff --git a/scripts/editor-view-authority.unit.test.ts b/scripts/editor-view-authority.unit.test.ts new file mode 100644 index 0000000000..a80c1121e9 --- /dev/null +++ b/scripts/editor-view-authority.unit.test.ts @@ -0,0 +1,25 @@ +import { describe, expect, it } from 'bun:test' + +import { editorViewPackagePaths, editorViewPlan } from './editor-view-authority.ts' + +describe('editor view authority orchestration', () => { + it('derives one deterministic editor publication entry per workspace consumer', () => { + const plan = editorViewPlan({ cell: 'workspace_cell' }) + + expect(plan.packages.map(({ packagePath }) => packagePath)).toEqual(editorViewPackagePaths) + expect(plan.packages).toHaveLength(40) + expect(plan.packages[0]?.editor).toMatchObject({ + cell: 'workspace_cell', + inputsManifestTarget: 'workspace_cell//:editor_view_inputs', + target: '//:editor_inputs', + viewName: 'root', + }) + for (const entry of plan.packages.slice(1)) { + expect(entry.editor?.cell).toBe('workspace_cell') + expect(entry.editor?.inputsManifestTarget).toBe( + `workspace_cell//${entry.packagePath}:editor_view_inputs`, + ) + expect(entry.editor?.target).toBe(`//${entry.packagePath}:editor_inputs`) + } + }) +}) diff --git a/scripts/typescript-materialize-dist.sh b/scripts/typescript-materialize-dist.sh index 5da8995fe4..2e4a5446dd 100755 --- a/scripts/typescript-materialize-dist.sh +++ b/scripts/typescript-materialize-dist.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash set -euo pipefail -if [ "$#" -lt 5 ]; then - echo "usage: $0 REPO_ROOT PACKAGE_PATH BUCK_TARGET DECLARATION_ENTRYPOINT PROJECT [DECLARATION_SOURCE...]" >&2 +if [ "$#" -ne 4 ]; then + echo "usage: $0 REPO_ROOT PACKAGE_PATH BUCK_TARGET DECLARATION_ENTRYPOINT" >&2 exit 2 fi @@ -10,24 +10,13 @@ root="$(cd "$1" && pwd -P)" package_path="$2" target="$3" declaration_entrypoint="$4" -project="$5" -shift 5 -# Registry-declared handwritten declarations: exactly the set the emit action -# copies into the published dist. -declaration_sources=("$@") package_dir="$root/$package_path" dist="$package_dir/dist" -mode="${TYPESCRIPT_DIST_MODE:?TYPESCRIPT_DIST_MODE must be publish or check}" +: "${BUCK2_BIN:?BUCK2_BIN must name the Buck2 executable}" +: "${WORKSPACE_ROOT:?WORKSPACE_ROOT must name the synthesized composition root}" + staging_root="$(mktemp -d "$package_dir/.dist-buck2.XXXXXX")" -# `staging` is mode-specific because the two modes have different depth -# constraints, and both are load-bearing. Buck materializes its output tree into -# a fresh path, so publication stages `/dist` and swaps that whole -# directory into place. The standalone comparison instead compiles, and a -# compiler records declaration-map `sources` relative to the emitting directory: -# staging one level deeper than `dist` would prepend a `../` to every map and -# report the entire map surface as stale. So it emits into the staging root -# itself, which sits exactly where `dist` sits — one directory below the package -# root, the same depth the Buck emit action compiles at inside its own tree. +staging="$staging_root/dist" cleanup_staging() { status=$? trap - EXIT @@ -52,80 +41,11 @@ validate_dist() { fi } -# The emit action copies handwritten declarations verbatim instead of compiling -# them, so the detached comparison has to stage the identical registry-declared -# set. Without this every copied `.d.ts` reads as staleness no compile can fix. -copy_declaration_sources() { - local destination="$1" - local relative - [ "${#declaration_sources[@]}" -gt 0 ] || return 0 - for relative in "${declaration_sources[@]}"; do - if [ ! -f "$package_dir/$relative" ]; then - echo "Declared handwritten declaration source is missing: $package_path/$relative" >&2 - return 1 - fi - mkdir -p "$destination/$(dirname "$relative")" - cp -- "$package_dir/$relative" "$destination/$relative" - done -} - -case "$mode" in - publish) - : "${BUCK2_BIN:?BUCK2_BIN must name the Buck2 executable}" - : "${WORKSPACE_ROOT:?WORKSPACE_ROOT must name the synthesized composition root}" - staging="$staging_root/dist" - ( - cd "$WORKSPACE_ROOT" - "$BUCK2_BIN" build "$target" --out "$staging" - ) - validate_dist "$staging" "Buck target $target" - ;; - check) - : "${TSGO_BIN:?TSGO_BIN must name the tsgo executable}" - : "${DIFF_BIN:?DIFF_BIN must name the diff executable}" - staging="$staging_root" - # A detached checkout cannot run Buck, so this mode only compares against - # declarations a composed workspace already published. State that once, up - # front, instead of spending a full compile to fail inside the comparison. - if [ ! -f "$dist/$declaration_entrypoint" ]; then - echo "Standalone declaration check for $package_path found no published declarations at $package_path/dist/$declaration_entrypoint, so there is nothing to compare against." >&2 - echo "Publish them from a composed workspace root (devenv tasks run mr:apply buck2:typescript:materialize-dist); a detached checkout has no Buck composition and cannot materialize declarations itself." >&2 - exit 1 - fi - # Mirror the emit action exactly: declaration-only, non-composite, - # non-incremental. Emitting JavaScript here would only be excluded from the - # comparison again, which is how extra published files used to hide. - ( - cd "$package_dir" - "$TSGO_BIN" \ - --project "$project" \ - --outDir "$staging" \ - --noEmit false \ - --composite false \ - --incremental false \ - --declaration true \ - --emitDeclarationOnly true \ - --pretty false - ) - validate_dist "$staging" "Standalone declaration check for $package_path" - copy_declaration_sources "$staging" - # Compare the declaration surface exactly, files and maps alike. The one - # exclusion is `tsconfig.tsbuildinfo`: source-owned build metadata rather - # than a published declaration, it embeds absolute paths, and this - # comparison deliberately produces none (`--incremental false`), so a - # published copy would otherwise read as staleness no compile can clear. - if ! "$DIFF_BIN" --no-dereference --recursive --brief \ - --exclude=tsconfig.tsbuildinfo "$staging" "$dist"; then - echo "Published $package_path dist is stale; materialize it from a synthesized composition root" >&2 - exit 1 - fi - exit 0 - ;; - *) - echo "TYPESCRIPT_DIST_MODE must be publish or check, got: $mode" >&2 - exit 2 - ;; -esac +( + cd "$WORKSPACE_ROOT" + "$BUCK2_BIN" build "$target" --out "$staging" +) +validate_dist "$staging" "Buck target $target" had_dist=false if [ -e "$dist" ] || [ -L "$dist" ]; then diff --git a/tsconfig.check.json b/tsconfig.check.json deleted file mode 100644 index 108d305c51..0000000000 --- a/tsconfig.check.json +++ /dev/null @@ -1,40 +0,0 @@ -// Generated file - DO NOT EDIT -// Source: tsconfig.check.json.genie.ts -{ - "files": [], - "references": [ - { - "path": "./context/effect/socket" - }, - { - "path": "./context/opentui" - }, - { - "path": "./packages/@overeng/buck2-tools" - }, - { - "path": "./packages/@overeng/effect-rpc-tanstack/examples/basic" - }, - { - "path": "./packages/@overeng/effect-schema-form-aria" - }, - { - "path": "./packages/@overeng/genie" - }, - { - "path": "./packages/@overeng/gh-ci-utils" - }, - { - "path": "./packages/@overeng/kdl-effect" - }, - { - "path": "./packages/@overeng/megarepo" - }, - { - "path": "./packages/@overeng/react-inspector/tsconfig.strict-consumer.json" - }, - { - "path": "./packages/@overeng/tui-stories" - } - ] -} diff --git a/tsconfig.check.json.genie.ts b/tsconfig.check.json.genie.ts deleted file mode 100644 index 1b4c194ba1..0000000000 --- a/tsconfig.check.json.genie.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { isRootTsconfigCheckProject, rootTsconfigProjects } from './genie/tsconfig-projects.ts' -import type { TSConfigArgs } from './packages/@overeng/genie/src/runtime/mod.ts' -import { tsconfigJson } from './packages/@overeng/genie/src/runtime/mod.ts' - -// This file is meant for convenience to built all TS projects in the workspace at once -export default tsconfigJson({ - files: [], - references: rootTsconfigProjects - .filter(isRootTsconfigCheckProject) - .map((project) => ({ path: `./${project.path}` })) - .toSorted((a, b) => a.path.localeCompare(b.path)), -} satisfies TSConfigArgs) diff --git a/tsconfig.emit.json b/tsconfig.emit.json deleted file mode 100644 index fde9c16cfa..0000000000 --- a/tsconfig.emit.json +++ /dev/null @@ -1,40 +0,0 @@ -// Generated file - DO NOT EDIT -// Source: tsconfig.emit.json.genie.ts -{ - "files": [], - "references": [ - { - "path": "./context/effect/socket" - }, - { - "path": "./context/opentui" - }, - { - "path": "./packages/@overeng/buck2-tools" - }, - { - "path": "./packages/@overeng/effect-rpc-tanstack/examples/basic" - }, - { - "path": "./packages/@overeng/effect-schema-form-aria" - }, - { - "path": "./packages/@overeng/genie" - }, - { - "path": "./packages/@overeng/gh-ci-utils" - }, - { - "path": "./packages/@overeng/kdl-effect" - }, - { - "path": "./packages/@overeng/megarepo" - }, - { - "path": "./packages/@overeng/react-inspector/tsconfig.strict-consumer.json" - }, - { - "path": "./packages/@overeng/tui-stories" - } - ] -} diff --git a/tsconfig.lint.json b/tsconfig.lint.json new file mode 100644 index 0000000000..7dad4c1b04 --- /dev/null +++ b/tsconfig.lint.json @@ -0,0 +1,127 @@ +// Generated file - DO NOT EDIT +// Source: tsconfig.lint.json.genie.ts +{ + "files": [], + "references": [ + { + "path": "./context/effect/socket" + }, + { + "path": "./context/opentui" + }, + { + "path": "./packages/@overeng/agent-session-ingest" + }, + { + "path": "./packages/@overeng/buck2-tools" + }, + { + "path": "./packages/@overeng/ci-tools" + }, + { + "path": "./packages/@overeng/content-address" + }, + { + "path": "./packages/@overeng/effect-ai-claude-cli" + }, + { + "path": "./packages/@overeng/effect-distributed-lock" + }, + { + "path": "./packages/@overeng/effect-path" + }, + { + "path": "./packages/@overeng/effect-react" + }, + { + "path": "./packages/@overeng/effect-rpc-tanstack" + }, + { + "path": "./packages/@overeng/effect-rpc-tanstack/examples/basic" + }, + { + "path": "./packages/@overeng/effect-schema-form" + }, + { + "path": "./packages/@overeng/effect-schema-form-aria" + }, + { + "path": "./packages/@overeng/genie" + }, + { + "path": "./packages/@overeng/gh-ci-utils" + }, + { + "path": "./packages/@overeng/kdl" + }, + { + "path": "./packages/@overeng/kdl-effect" + }, + { + "path": "./packages/@overeng/megarepo" + }, + { + "path": "./packages/@overeng/notion-cli" + }, + { + "path": "./packages/@overeng/notion-core" + }, + { + "path": "./packages/@overeng/notion-datasource-sync" + }, + { + "path": "./packages/@overeng/notion-effect-client" + }, + { + "path": "./packages/@overeng/notion-effect-schema" + }, + { + "path": "./packages/@overeng/notion-md" + }, + { + "path": "./packages/@overeng/notion-property-write" + }, + { + "path": "./packages/@overeng/notion-react" + }, + { + "path": "./packages/@overeng/npm-release" + }, + { + "path": "./packages/@overeng/otel-contract" + }, + { + "path": "./packages/@overeng/oxc-config" + }, + { + "path": "./packages/@overeng/pty-effect" + }, + { + "path": "./packages/@overeng/react-inspector" + }, + { + "path": "./packages/@overeng/react-inspector/tsconfig.strict-consumer.json" + }, + { + "path": "./packages/@overeng/restate-effect" + }, + { + "path": "./packages/@overeng/stylex-tokens" + }, + { + "path": "./packages/@overeng/tui-core" + }, + { + "path": "./packages/@overeng/tui-react" + }, + { + "path": "./packages/@overeng/tui-stories" + }, + { + "path": "./packages/@overeng/utils" + }, + { + "path": "./packages/@overeng/utils-dev" + } + ] +} diff --git a/tsconfig.emit.json.genie.ts b/tsconfig.lint.json.genie.ts similarity index 51% rename from tsconfig.emit.json.genie.ts rename to tsconfig.lint.json.genie.ts index e4aa76a4cf..0b09848090 100644 --- a/tsconfig.emit.json.genie.ts +++ b/tsconfig.lint.json.genie.ts @@ -1,10 +1,10 @@ -import { isRootTsconfigEmitProject, rootTsconfigProjects } from './genie/tsconfig-projects.ts' +import { rootTsconfigProjects } from './genie/tsconfig-projects.ts' import { tsconfigJson, type TSConfigArgs } from './packages/@overeng/genie/src/runtime/mod.ts' +/** Non-producing project graph spanning all Buck-owned projects for oxlint's type-aware rules. */ export default tsconfigJson({ files: [], references: rootTsconfigProjects - .filter(isRootTsconfigEmitProject) .map((project) => ({ path: `./${project.path}` })) - .toSorted((a, b) => a.path.localeCompare(b.path)), + .toSorted((left, right) => left.path.localeCompare(right.path)), } satisfies TSConfigArgs)