diff --git a/.github/workflows/plugin-npm-release.yml b/.github/workflows/plugin-npm-release.yml index e7839c81f0bb..6bd9ee4243c3 100644 --- a/.github/workflows/plugin-npm-release.yml +++ b/.github/workflows/plugin-npm-release.yml @@ -22,6 +22,7 @@ on: - "scripts/lib/plugin-npm-package-manifest.mts" - "scripts/lib/tsx-cli-shim.mjs" - "scripts/lib/local-check-runtime.mts" + - "scripts/tsx.mjs" - "scripts/lib/plugin-npm-release.ts" - "scripts/lib/plugin-publication-candidates.ts" - "scripts/lib/plugin-publication-collector.ts" diff --git a/docs/reference/test.md b/docs/reference/test.md index 7fca57611357..1cffd2ad09ef 100644 --- a/docs/reference/test.md +++ b/docs/reference/test.md @@ -79,6 +79,12 @@ reconcile dependencies before the remote wrapper starts. ## Core commands +Maintained JavaScript tooling wrappers and root package commands use tsx's +in-process transform cache. They skip its shared disk cache before the loader +starts, and child tooling inherits that policy. This does not relocate or clean +temporary directories, Node or Vitest caches, or other global caches. Raw external +`tsx` and `node --import tsx` invocations outside these launchers are unchanged. + Test wrapper runs end with a short `[test] passed|failed|skipped ... in ...` summary; Vitest's own duration line stays the per-shard detail. | Command | What it does | diff --git a/package.json b/package.json index a58a5e0c9094..b57f82078e4b 100644 --- a/package.json +++ b/package.json @@ -1497,16 +1497,16 @@ "./cli-entry": "./openclaw.mjs" }, "scripts": { - "android:assemble": "node --import tsx scripts/run-android-gradle.mts :app:assemblePlayDebug :wear:assembleDebug :wear-shared:assembleDebug", - "android:assemble:third-party": "node --import tsx scripts/run-android-gradle.mts :app:assembleThirdPartyDebug", + "android:assemble": "node --import ./scripts/tsx.mjs scripts/run-android-gradle.mts :app:assemblePlayDebug :wear:assembleDebug :wear-shared:assembleDebug", + "android:assemble:third-party": "node --import ./scripts/tsx.mjs scripts/run-android-gradle.mts :app:assembleThirdPartyDebug", "android:bundle:release": "bash -lc 'source ./scripts/lib/android-fastlane.sh && cd apps/android && run_android_fastlane android play_store_archive'", "android:format": "cd apps/android && ./gradlew :app:ktlintFormat :benchmark:ktlintFormat :wear:ktlintFormat :wear-shared:ktlintFormat", - "android:install": "node --import tsx scripts/run-android-gradle.mts :app:installPlayDebug", - "android:install:third-party": "node --import tsx scripts/run-android-gradle.mts :app:installThirdPartyDebug", + "android:install": "node --import ./scripts/tsx.mjs scripts/run-android-gradle.mts :app:installPlayDebug", + "android:install:third-party": "node --import ./scripts/tsx.mjs scripts/run-android-gradle.mts :app:installThirdPartyDebug", "android:lint": "cd apps/android && ./gradlew :app:ktlintCheck :benchmark:ktlintCheck :wear:ktlintCheck :wear-shared:ktlintCheck", - "android:lint:android": "node --import tsx scripts/run-android-gradle.mts :app:lintPlayDebug :app:lintThirdPartyDebug :wear:lintDebug :wear-shared:lintDebug", - "android:run": "node --import tsx scripts/run-android-gradle.mts :app:runPlayDebug", - "android:run:third-party": "node --import tsx scripts/run-android-gradle.mts :app:runThirdPartyDebug", + "android:lint:android": "node --import ./scripts/tsx.mjs scripts/run-android-gradle.mts :app:lintPlayDebug :app:lintThirdPartyDebug :wear:lintDebug :wear-shared:lintDebug", + "android:run": "node --import ./scripts/tsx.mjs scripts/run-android-gradle.mts :app:runPlayDebug", + "android:run:third-party": "node --import ./scripts/tsx.mjs scripts/run-android-gradle.mts :app:runThirdPartyDebug", "android:release": "bash scripts/android-release.sh", "android:release:archive": "bash -lc 'source ./scripts/lib/android-fastlane.sh && cd apps/android && run_android_fastlane android play_store_archive'", "android:release:auth:check": "bash -lc 'source ./scripts/lib/android-fastlane.sh && cd apps/android && run_android_fastlane android auth_check'", @@ -1518,100 +1518,100 @@ "android:release:signing:sync:push": "bash -lc 'source ./scripts/lib/android-fastlane.sh && cd apps/android && run_android_fastlane android signing_sync_push'", "android:release:upload": "bash scripts/android-release-upload.sh", "android:screenshots": "bash scripts/android-screenshots.sh", - "android:test": "node --import tsx scripts/run-android-gradle.mts :app:testPlayDebugUnitTest :wear:testDebugUnitTest :wear-shared:testDebugUnitTest", - "android:test:integration": "node --import tsx scripts/run-with-env.mts OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_ANDROID_NODE=1 -- node scripts/run-vitest.mjs run --config test/vitest/vitest.live.config.ts src/gateway/android-node.capabilities.live.test.ts", - "android:test:third-party": "node --import tsx scripts/run-android-gradle.mts :app:testThirdPartyDebugUnitTest", - "android:version": "node --import tsx scripts/android-version.ts --json", - "android:version:check": "node --import tsx scripts/android-sync-versioning.ts --check", - "android:version:pin": "node --import tsx scripts/android-pin-version.ts", - "android:version:sync": "node --import tsx scripts/android-sync-versioning.ts --write", - "audit:seams": "node --import tsx scripts/audit-seams.mts", - "build": "node --import tsx scripts/build-all.mts", - "build:ci-artifacts": "node --import tsx scripts/build-all.mts ciArtifacts", - "build:docker": "pnpm plugins:assets:build && node --import tsx scripts/tsdown-build.mts && node --import tsx scripts/check-cli-bootstrap-imports.mts && node scripts/runtime-postbuild.mjs && node --import tsx scripts/build-stamp.mts && node --import tsx scripts/runtime-postbuild-stamp.mts && pnpm plugins:assets:copy && node --import tsx scripts/write-build-info.ts && node --import tsx scripts/write-cli-startup-metadata.ts", - "build:package": "node --import tsx scripts/build-all.mts package", + "android:test": "node --import ./scripts/tsx.mjs scripts/run-android-gradle.mts :app:testPlayDebugUnitTest :wear:testDebugUnitTest :wear-shared:testDebugUnitTest", + "android:test:integration": "node --import ./scripts/tsx.mjs scripts/run-with-env.mts OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_ANDROID_NODE=1 -- node scripts/run-vitest.mjs run --config test/vitest/vitest.live.config.ts src/gateway/android-node.capabilities.live.test.ts", + "android:test:third-party": "node --import ./scripts/tsx.mjs scripts/run-android-gradle.mts :app:testThirdPartyDebugUnitTest", + "android:version": "node --import ./scripts/tsx.mjs scripts/android-version.ts --json", + "android:version:check": "node --import ./scripts/tsx.mjs scripts/android-sync-versioning.ts --check", + "android:version:pin": "node --import ./scripts/tsx.mjs scripts/android-pin-version.ts", + "android:version:sync": "node --import ./scripts/tsx.mjs scripts/android-sync-versioning.ts --write", + "audit:seams": "node --import ./scripts/tsx.mjs scripts/audit-seams.mts", + "build": "node --import ./scripts/tsx.mjs scripts/build-all.mts", + "build:ci-artifacts": "node --import ./scripts/tsx.mjs scripts/build-all.mts ciArtifacts", + "build:docker": "pnpm plugins:assets:build && node --import ./scripts/tsx.mjs scripts/tsdown-build.mts && node --import ./scripts/tsx.mjs scripts/check-cli-bootstrap-imports.mts && node scripts/runtime-postbuild.mjs && node --import ./scripts/tsx.mjs scripts/build-stamp.mts && node --import ./scripts/tsx.mjs scripts/runtime-postbuild-stamp.mts && pnpm plugins:assets:copy && node --import ./scripts/tsx.mjs scripts/write-build-info.ts && node --import ./scripts/tsx.mjs scripts/write-cli-startup-metadata.ts", + "build:package": "node --import ./scripts/tsx.mjs scripts/build-all.mts package", "build:plugin-sdk:dts": "node scripts/run-tsgo.mjs -p tsconfig.plugin-sdk.dts.json --declaration true", - "build:plugin-sdk:strict-smoke": "node --import tsx scripts/tsdown-build.mts && node scripts/runtime-postbuild.mjs && node --import tsx scripts/run-with-env.mts OPENCLAW_PLUGIN_SDK_CANONICAL_DTS=1 -- node --import tsx scripts/write-plugin-sdk-entry-dts.ts && node --import tsx scripts/check-plugin-sdk-exports.mts", - "build:strict-smoke": "pnpm plugins:assets:build && node --import tsx scripts/tsdown-build.mts && node --import tsx scripts/check-cli-bootstrap-imports.mts && node scripts/runtime-postbuild.mjs && node --import tsx scripts/build-stamp.mts && node --import tsx scripts/runtime-postbuild-stamp.mts && node --import tsx scripts/run-with-env.mts OPENCLAW_PLUGIN_SDK_CANONICAL_DTS=1 -- node --import tsx scripts/write-plugin-sdk-entry-dts.ts && node --import tsx scripts/check-plugin-sdk-exports.mts", - "canvas:a2ui:bundle": "node --import tsx scripts/bundle-a2ui.mts", + "build:plugin-sdk:strict-smoke": "node --import ./scripts/tsx.mjs scripts/tsdown-build.mts && node scripts/runtime-postbuild.mjs && node --import ./scripts/tsx.mjs scripts/run-with-env.mts OPENCLAW_PLUGIN_SDK_CANONICAL_DTS=1 -- node --import ./scripts/tsx.mjs scripts/write-plugin-sdk-entry-dts.ts && node --import ./scripts/tsx.mjs scripts/check-plugin-sdk-exports.mts", + "build:strict-smoke": "pnpm plugins:assets:build && node --import ./scripts/tsx.mjs scripts/tsdown-build.mts && node --import ./scripts/tsx.mjs scripts/check-cli-bootstrap-imports.mts && node scripts/runtime-postbuild.mjs && node --import ./scripts/tsx.mjs scripts/build-stamp.mts && node --import ./scripts/tsx.mjs scripts/runtime-postbuild-stamp.mts && node --import ./scripts/tsx.mjs scripts/run-with-env.mts OPENCLAW_PLUGIN_SDK_CANONICAL_DTS=1 -- node --import ./scripts/tsx.mjs scripts/write-plugin-sdk-entry-dts.ts && node --import ./scripts/tsx.mjs scripts/check-plugin-sdk-exports.mts", + "canvas:a2ui:bundle": "node --import ./scripts/tsx.mjs scripts/bundle-a2ui.mts", "channels:catalog:check": "node scripts/write-official-channel-catalog.mjs --check", "channels:catalog:gen": "node scripts/write-official-channel-catalog.mjs --write", "changed:lanes": "node scripts/changed-lanes.mjs", - "check": "node --import tsx scripts/check.mts", + "check": "node --import ./scripts/tsx.mjs scripts/check.mts", "check:architecture": "pnpm check:import-cycles && pnpm check:madge-import-cycles && pnpm check:deprecated-api-usage && pnpm check:wrapper-shadowing && pnpm check:deprecated-jsdoc && pnpm db:kysely:check && pnpm lint:kysely && pnpm check:database-first-legacy-stores", - "check:assertion-safety": "node --import tsx scripts/check-assertion-safety-ratchet.mts", - "check:base-config-schema": "node --import tsx scripts/generate-base-config-schema.ts --check", - "check:bundled-channel-config-metadata": "node --import tsx scripts/generate-bundled-channel-config-metadata.ts --check", + "check:assertion-safety": "node --import ./scripts/tsx.mjs scripts/check-assertion-safety-ratchet.mts", + "check:base-config-schema": "node --import ./scripts/tsx.mjs scripts/generate-base-config-schema.ts --check", + "check:bundled-channel-config-metadata": "node --import ./scripts/tsx.mjs scripts/generate-bundled-channel-config-metadata.ts --check", "check:changed": "node scripts/check-changed.mjs", - "check:changelog-attributions": "node --import tsx scripts/check-changelog-attributions.mts", - "check:coercion-helpers": "node --import tsx scripts/check-coercion-helper-declarations.mts", - "check:database-first-legacy-stores": "node --import tsx scripts/check-database-first-legacy-stores.mts", - "check:deprecated-api-usage": "node --import tsx scripts/check-deprecated-api-usage.mts", - "check:deprecated-jsdoc": "node --import tsx scripts/check-deprecated-jsdoc.mts", - "check:doctor-deprecation-registry": "node --import tsx scripts/check-doctor-deprecation-registry.ts", + "check:changelog-attributions": "node --import ./scripts/tsx.mjs scripts/check-changelog-attributions.mts", + "check:coercion-helpers": "node --import ./scripts/tsx.mjs scripts/check-coercion-helper-declarations.mts", + "check:database-first-legacy-stores": "node --import ./scripts/tsx.mjs scripts/check-database-first-legacy-stores.mts", + "check:deprecated-api-usage": "node --import ./scripts/tsx.mjs scripts/check-deprecated-api-usage.mts", + "check:deprecated-jsdoc": "node --import ./scripts/tsx.mjs scripts/check-deprecated-jsdoc.mts", + "check:doctor-deprecation-registry": "node --import ./scripts/tsx.mjs scripts/check-doctor-deprecation-registry.ts", "check:docs": "pnpm format:docs:check && pnpm lint:docs && pnpm docs:check-mdx && pnpm docs:check-i18n-glossary && pnpm docs:check-links && pnpm docs:check-config-examples", - "check:env-var-count": "node --import tsx scripts/check-env-var-count.mts", - "check:host-env-policy:swift": "node --import tsx scripts/generate-host-env-security-policy-swift.mts --check", - "check:import-cycles": "node --import tsx scripts/check-import-cycles.ts", - "check:max-lines-ratchet": "node --import tsx scripts/check-max-lines-ratchet.mts", - "check:madge-import-cycles": "node --import tsx scripts/check-madge-import-cycles.ts", - "check:media-download-helpers": "node --import tsx scripts/check-media-download-helper-roundtrip.mts", + "check:env-var-count": "node --import ./scripts/tsx.mjs scripts/check-env-var-count.mts", + "check:host-env-policy:swift": "node --import ./scripts/tsx.mjs scripts/generate-host-env-security-policy-swift.mts --check", + "check:import-cycles": "node --import ./scripts/tsx.mjs scripts/check-import-cycles.ts", + "check:max-lines-ratchet": "node --import ./scripts/tsx.mjs scripts/check-max-lines-ratchet.mts", + "check:madge-import-cycles": "node --import ./scripts/tsx.mjs scripts/check-madge-import-cycles.ts", + "check:media-download-helpers": "node --import ./scripts/tsx.mjs scripts/check-media-download-helper-roundtrip.mts", "check:no-conflict-markers": "node scripts/check-no-conflict-markers.mjs", - "check:no-runtime-action-load-config": "node --import tsx scripts/check-no-runtime-action-load-config.mts", + "check:no-runtime-action-load-config": "node --import ./scripts/tsx.mjs scripts/check-no-runtime-action-load-config.mts", "check:opengrep-rule-metadata": "node security/opengrep/check-rule-metadata.mjs", "check:protocol-coverage": "node scripts/check-protocol-event-coverage.mjs", - "check:runtime-sidecar-loaders": "node --import tsx scripts/check-runtime-sidecar-loaders.mts", + "check:runtime-sidecar-loaders": "node --import ./scripts/tsx.mjs scripts/check-runtime-sidecar-loaders.mts", "check:script-erasability": "node --disable-warning=ExperimentalWarning scripts/check-script-erasability.mjs", "check:static-import-sccs": "pnpm check:madge-import-cycles", - "check:temp-path-guardrails": "node --import tsx scripts/check-temp-path-guardrails.ts", - "check:wrapper-shadowing": "node --import tsx scripts/check-wrapper-shadowing.mts", + "check:temp-path-guardrails": "node --import ./scripts/tsx.mjs scripts/check-temp-path-guardrails.ts", + "check:wrapper-shadowing": "node --import ./scripts/tsx.mjs scripts/check-wrapper-shadowing.mts", "check:test-types": "pnpm tsgo:test", - "check:timed": "node --import tsx scripts/check-timed.mts", - "check:timed:all-types": "node --import tsx scripts/check-timed.mts --include-test-types", - "check:timed:architecture": "node --import tsx scripts/check-timed.mts --include-architecture", - "check:workflows": "node --import tsx scripts/check-workflows.mts", + "check:timed": "node --import ./scripts/tsx.mjs scripts/check-timed.mts", + "check:timed:all-types": "node --import ./scripts/tsx.mjs scripts/check-timed.mts --include-test-types", + "check:timed:architecture": "node --import ./scripts/tsx.mjs scripts/check-timed.mts --include-architecture", + "check:workflows": "node --import ./scripts/tsx.mjs scripts/check-workflows.mts", "ci:full-release": "node scripts/full-release-validation-at-sha.mjs", "ci:timings": "node scripts/ci-run-timings.mjs --latest-main", "ci:timings:recent": "node scripts/ci-run-timings.mjs --recent 10", "ci:timings:trend": "node scripts/ci-run-timings.mjs --trend-hours 72 --compare-hours 12", "clean:dist": "node -e \"require('fs').rmSync('dist', {recursive: true, force: true})\"", - "codex-app-server:protocol:check": "node --import tsx scripts/check-codex-app-server-protocol.ts", - "codex-app-server:protocol:sync": "node --import tsx scripts/sync-codex-app-server-protocol.ts", - "codex-supervisor:mcp": "node --import tsx src/mcp/codex-supervision-tools-serve.ts", - "codex:mcp": "node --import tsx src/mcp/codex-supervision-tools-serve.ts", - "config:channels:check": "node --import tsx scripts/generate-bundled-channel-config-metadata.ts --check", - "config:channels:gen": "node --import tsx scripts/generate-bundled-channel-config-metadata.ts --write", - "config:docs:check": "node --import tsx scripts/generate-config-doc-baseline.ts --check", - "config:docs:gen": "node --import tsx scripts/generate-config-doc-baseline.ts --write", - "config:schema:check": "node --import tsx scripts/generate-base-config-schema.ts --check", - "config:schema:gen": "node --import tsx scripts/generate-base-config-schema.ts --write", + "codex-app-server:protocol:check": "node --import ./scripts/tsx.mjs scripts/check-codex-app-server-protocol.ts", + "codex-app-server:protocol:sync": "node --import ./scripts/tsx.mjs scripts/sync-codex-app-server-protocol.ts", + "codex-supervisor:mcp": "node --import ./scripts/tsx.mjs src/mcp/codex-supervision-tools-serve.ts", + "codex:mcp": "node --import ./scripts/tsx.mjs src/mcp/codex-supervision-tools-serve.ts", + "config:channels:check": "node --import ./scripts/tsx.mjs scripts/generate-bundled-channel-config-metadata.ts --check", + "config:channels:gen": "node --import ./scripts/tsx.mjs scripts/generate-bundled-channel-config-metadata.ts --write", + "config:docs:check": "node --import ./scripts/tsx.mjs scripts/generate-config-doc-baseline.ts --check", + "config:docs:gen": "node --import ./scripts/tsx.mjs scripts/generate-config-doc-baseline.ts --write", + "config:schema:check": "node --import ./scripts/tsx.mjs scripts/generate-base-config-schema.ts --check", + "config:schema:gen": "node --import ./scripts/tsx.mjs scripts/generate-base-config-schema.ts --write", "crabbox:hydrate": "node scripts/crabbox-wrapper.mjs actions hydrate", "crabbox:run": "node scripts/crabbox-wrapper.mjs run", "crabbox:stop": "node scripts/crabbox-wrapper.mjs stop", "crabbox:warmup": "node scripts/crabbox-wrapper.mjs warmup", "deadcode:dependencies": "pnpm deadcode:full", - "deadcode:exports": "node --import tsx scripts/check-deadcode-exports.mts", + "deadcode:exports": "node --import ./scripts/tsx.mjs scripts/check-deadcode-exports.mts", "deadcode:full": "pnpm --config.minimum-release-age=0 dlx --package knip@6.32.2 knip --config config/knip.config.ts --production --no-progress --reporter compact --no-config-hints --exclude duplicates && pnpm --config.minimum-release-age=0 dlx --package knip@6.32.2 knip --config config/knip.all-exports.config.ts --no-progress --reporter compact --no-config-hints --exports --exclude duplicates", "deadcode:knip": "pnpm --config.minimum-release-age=0 dlx --package knip@6.32.2 knip --config config/knip.config.ts --production --no-progress --reporter compact --files --dependencies", "deadcode:report": "pnpm deadcode:full && pnpm deadcode:exports", - "deadcode:unused-files": "node --import tsx scripts/check-deadcode-unused-files.mts", - "deps:root-ownership": "node --import tsx scripts/root-dependency-ownership-audit.mts", - "deps:root-ownership:check": "node --import tsx scripts/root-dependency-ownership-audit.mts --check", - "deps:changes:report": "node --import tsx scripts/dependency-changes-report.mts", - "deps:patches:check": "node --import tsx scripts/check-package-patches.mts", - "deps:pins:check": "node --import tsx scripts/check-dependency-pins.mts", + "deadcode:unused-files": "node --import ./scripts/tsx.mjs scripts/check-deadcode-unused-files.mts", + "deps:root-ownership": "node --import ./scripts/tsx.mjs scripts/root-dependency-ownership-audit.mts", + "deps:root-ownership:check": "node --import ./scripts/tsx.mjs scripts/root-dependency-ownership-audit.mts --check", + "deps:changes:report": "node --import ./scripts/tsx.mjs scripts/dependency-changes-report.mts", + "deps:patches:check": "node --import ./scripts/tsx.mjs scripts/check-package-patches.mts", + "deps:pins:check": "node --import ./scripts/tsx.mjs scripts/check-dependency-pins.mts", "deps:npm-lock:check": "node scripts/generate-npm-package-lock.mjs --all", "deps:npm-lock:check:changed": "node scripts/generate-npm-package-lock.mjs --changed", - "deps:ownership-surface:check": "node --import tsx scripts/dependency-ownership-surface-report.mts --check", - "deps:ownership-surface:report": "node --import tsx scripts/dependency-ownership-surface-report.mts", - "deps:transitive-risk:report": "node --import tsx scripts/transitive-manifest-risk-report.mts", - "deps:vuln:gate": "node --import tsx scripts/dependency-vulnerability-gate.mts", - "db:kysely:check": "node --import tsx scripts/generate-kysely-types.mts --verify", - "db:kysely:gen": "node --import tsx scripts/generate-kysely-types.mts", + "deps:ownership-surface:check": "node --import ./scripts/tsx.mjs scripts/dependency-ownership-surface-report.mts --check", + "deps:ownership-surface:report": "node --import ./scripts/tsx.mjs scripts/dependency-ownership-surface-report.mts", + "deps:transitive-risk:report": "node --import ./scripts/tsx.mjs scripts/transitive-manifest-risk-report.mts", + "deps:vuln:gate": "node --import ./scripts/tsx.mjs scripts/dependency-vulnerability-gate.mts", + "db:kysely:check": "node --import ./scripts/tsx.mjs scripts/generate-kysely-types.mts --verify", + "db:kysely:gen": "node --import ./scripts/tsx.mjs scripts/generate-kysely-types.mts", "dev": "node scripts/run-node.mjs", - "dev:ui:mock": "node --import tsx scripts/control-ui-mock-dev.ts", + "dev:ui:mock": "node --import ./scripts/tsx.mjs scripts/control-ui-mock-dev.ts", "docs:check-config-examples": "node scripts/check-docs-config-examples.mjs", - "docs:check-i18n-glossary": "node --import tsx scripts/check-docs-i18n-glossary.mts", + "docs:check-i18n-glossary": "node --import ./scripts/tsx.mjs scripts/check-docs-i18n-glossary.mts", "docs:check-links": "node scripts/docs-link-audit.mjs", "docs:check-links:anchors": "node scripts/docs-link-audit.mjs --anchors", "docs:check-mdx": "node scripts/check-docs-mdx.mjs docs README.md", @@ -1620,8 +1620,8 @@ "docs:map:gen": "node scripts/docs-list.js --headings", "docs:spellcheck": "bash scripts/docs-spellcheck.sh", "docs:spellcheck:fix": "bash scripts/docs-spellcheck.sh --write", - "maturity:check": "node --import tsx scripts/qa/render-maturity-docs.ts --check", - "maturity:render": "node --import tsx scripts/qa/render-maturity-docs.ts", + "maturity:check": "node --import ./scripts/tsx.mjs scripts/qa/render-maturity-docs.ts --check", + "maturity:render": "node --import ./scripts/tsx.mjs scripts/qa/render-maturity-docs.ts", "dup:check": "node scripts/check-duplicates.mjs", "dup:check:coverage": "node scripts/check-duplicates.mjs --coverage", "dup:check:json": "node scripts/check-duplicates.mjs --json", @@ -1629,16 +1629,16 @@ "format:all": "pnpm format && pnpm format:swift", "format:check": "oxfmt --check", "format:diff": "oxfmt --write --threads=1 && git --no-pager diff", - "format:docs": "node --import tsx scripts/format-docs.mts", - "format:docs:check": "node --import tsx scripts/format-docs.mts --check", + "format:docs": "node --import ./scripts/tsx.mjs scripts/format-docs.mts", + "format:docs:check": "node --import ./scripts/tsx.mjs scripts/format-docs.mts --check", "format:fix": "oxfmt --write --threads=1", "format:swift": "./scripts/format-swift.sh", - "gateway:dev": "node --import tsx scripts/run-with-env.mts OPENCLAW_SKIP_CHANNELS=1 -- node scripts/run-node.mjs --dev gateway", - "gateway:dev:reset": "node --import tsx scripts/run-with-env.mts OPENCLAW_SKIP_CHANNELS=1 -- node scripts/run-node.mjs --dev gateway --reset", - "gateway:watch": "node --import tsx scripts/gateway-watch-tmux.mts gateway --force", + "gateway:dev": "node --import ./scripts/tsx.mjs scripts/run-with-env.mts OPENCLAW_SKIP_CHANNELS=1 -- node scripts/run-node.mjs --dev gateway", + "gateway:dev:reset": "node --import ./scripts/tsx.mjs scripts/run-with-env.mts OPENCLAW_SKIP_CHANNELS=1 -- node scripts/run-node.mjs --dev gateway --reset", + "gateway:watch": "node --import ./scripts/tsx.mjs scripts/gateway-watch-tmux.mts gateway --force", "gateway:watch:raw": "node scripts/watch-node.mjs gateway --force", - "gen:host-env-policy:swift": "node --import tsx scripts/generate-host-env-security-policy-swift.mts --write", - "ghsa:patch": "node --import tsx scripts/ghsa-patch.mts", + "gen:host-env-policy:swift": "node --import ./scripts/tsx.mjs scripts/generate-host-env-security-policy-swift.mts --write", + "ghsa:patch": "node --import ./scripts/tsx.mjs scripts/ghsa-patch.mts", "ios:app-review-notes:pdf": "xcrun swift scripts/ios-app-review-notes-pdf.swift apps/ios/APP-REVIEW-NOTES.md apps/ios/build/app-review/APP-REVIEW-NOTES.pdf", "ios:build": "bash -c 'export PATH=\"$PATH:/opt/homebrew/bin:/usr/local/bin\"; ./scripts/ios-configure-signing.sh && ./scripts/ios-write-version-xcconfig.sh && node scripts/ios-write-swift-filelist.mjs && cd apps/ios && xcodegen generate && xcodebuild -project OpenClaw.xcodeproj -scheme OpenClaw -destination \"${IOS_DEST:-generic/platform=iOS Simulator}\" -configuration Debug build'", "ios:filelist:gen": "node scripts/ios-write-swift-filelist.mjs", @@ -1656,155 +1656,155 @@ "ios:release:upload": "bash scripts/ios-release-upload.sh", "ios:run": "bash scripts/ios-run.sh", "ios:screenshots": "bash scripts/ios-screenshots.sh", - "ios:version": "node --import tsx scripts/ios-version.ts --json", - "ios:version:check": "node --import tsx scripts/ios-sync-versioning.ts --check", - "ios:version:sync": "node --import tsx scripts/ios-sync-versioning.ts --write", - "leak:embedded-run": "node --import tsx --expose-gc scripts/embedded-run-abort-leak.ts", - "lint": "node --import tsx scripts/run-lint.mts", - "lint:agent:ingress-owner": "node --import tsx scripts/check-ingress-agent-owner-context.mts", + "ios:version": "node --import ./scripts/tsx.mjs scripts/ios-version.ts --json", + "ios:version:check": "node --import ./scripts/tsx.mjs scripts/ios-sync-versioning.ts --check", + "ios:version:sync": "node --import ./scripts/tsx.mjs scripts/ios-sync-versioning.ts --write", + "leak:embedded-run": "node --import ./scripts/tsx.mjs --expose-gc scripts/embedded-run-abort-leak.ts", + "lint": "node --import ./scripts/tsx.mjs scripts/run-lint.mts", + "lint:agent:ingress-owner": "node --import ./scripts/tsx.mjs scripts/check-ingress-agent-owner-context.mts", "lint:all": "node scripts/run-oxlint.mjs", "lint:apps": "pnpm lint:swift", - "lint:auth:no-pairing-store-group": "node --import tsx scripts/check-no-pairing-store-group-auth.mts", - "lint:auth:pairing-account-scope": "node --import tsx scripts/check-pairing-account-scope.mts", - "lint:core": "node --import tsx scripts/run-oxlint-shards.mts --only=core", - "lint:docker-e2e": "node --import tsx scripts/check-docker-e2e-boundaries.mts", - "lint:kysely": "node --import tsx scripts/check-kysely-guardrails.mts", + "lint:auth:no-pairing-store-group": "node --import ./scripts/tsx.mjs scripts/check-no-pairing-store-group-auth.mts", + "lint:auth:pairing-account-scope": "node --import ./scripts/tsx.mjs scripts/check-pairing-account-scope.mts", + "lint:core": "node --import ./scripts/tsx.mjs scripts/run-oxlint-shards.mts --only=core", + "lint:docker-e2e": "node --import ./scripts/tsx.mjs scripts/check-docker-e2e-boundaries.mts", + "lint:kysely": "node --import ./scripts/tsx.mjs scripts/check-kysely-guardrails.mts", "lint:docs": "pnpm dlx --config.resolution-mode=highest markdownlint-cli2 --config config/markdownlint-cli2.jsonc", "lint:docs:fix": "pnpm dlx --config.resolution-mode=highest markdownlint-cli2 --config config/markdownlint-cli2.jsonc --fix", - "lint:extensions:no-deprecated-channel-access": "node --import tsx scripts/check-no-deprecated-channel-access.ts", - "lint:extensions:telegram-grammy-types": "node --import tsx scripts/check-telegram-grammy-types-imports.mts", + "lint:extensions:no-deprecated-channel-access": "node --import ./scripts/tsx.mjs scripts/check-no-deprecated-channel-access.ts", + "lint:extensions:telegram-grammy-types": "node --import ./scripts/tsx.mjs scripts/check-telegram-grammy-types-imports.mts", "lint:extensions": "node scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.extensions.json extensions", - "lint:extensions:no-guarded-wildcard-reexports": "node --import tsx scripts/check-extension-wildcard-reexports.mts", - "lint:extensions:no-normalization-core-bypass": "node --import tsx scripts/check-extension-plugin-sdk-boundary.mts --mode=normalization-core-bypass", - "lint:extensions:no-plugin-sdk-wildcard-reexports": "node --import tsx scripts/check-plugin-sdk-wildcard-reexports.mts", - "lint:extensions:no-relative-outside-package": "node --import tsx scripts/check-extension-plugin-sdk-boundary.mts --mode=relative-outside-package", - "lint:extensions:no-src-outside-plugin-sdk": "node --import tsx scripts/check-extension-plugin-sdk-boundary.mts --mode=src-outside-plugin-sdk", + "lint:extensions:no-guarded-wildcard-reexports": "node --import ./scripts/tsx.mjs scripts/check-extension-wildcard-reexports.mts", + "lint:extensions:no-normalization-core-bypass": "node --import ./scripts/tsx.mjs scripts/check-extension-plugin-sdk-boundary.mts --mode=normalization-core-bypass", + "lint:extensions:no-plugin-sdk-wildcard-reexports": "node --import ./scripts/tsx.mjs scripts/check-plugin-sdk-wildcard-reexports.mts", + "lint:extensions:no-relative-outside-package": "node --import ./scripts/tsx.mjs scripts/check-extension-plugin-sdk-boundary.mts --mode=relative-outside-package", + "lint:extensions:no-src-outside-plugin-sdk": "node --import ./scripts/tsx.mjs scripts/check-extension-plugin-sdk-boundary.mts --mode=src-outside-plugin-sdk", "lint:fix": "node scripts/run-oxlint.mjs --fix && pnpm format", - "lint:plugins:no-extension-imports": "node --import tsx scripts/check-plugin-extension-import-boundary.mts", - "lint:plugins:no-extension-src-imports": "node --import tsx scripts/check-no-extension-src-imports.ts", - "lint:plugins:no-extension-test-core-imports": "node --import tsx scripts/check-no-extension-test-core-imports.ts", - "lint:plugins:no-monolithic-plugin-sdk-entry-imports": "node --import tsx scripts/check-no-monolithic-plugin-sdk-entry-imports.ts", + "lint:plugins:no-extension-imports": "node --import ./scripts/tsx.mjs scripts/check-plugin-extension-import-boundary.mts", + "lint:plugins:no-extension-src-imports": "node --import ./scripts/tsx.mjs scripts/check-no-extension-src-imports.ts", + "lint:plugins:no-extension-test-core-imports": "node --import ./scripts/tsx.mjs scripts/check-no-extension-test-core-imports.ts", + "lint:plugins:no-monolithic-plugin-sdk-entry-imports": "node --import ./scripts/tsx.mjs scripts/check-no-monolithic-plugin-sdk-entry-imports.ts", "lint:plugins:no-register-http-handler": "node scripts/run-oxlint.mjs --openclaw-focused-config --config config/oxlint/boundary-guards.json src extensions", - "lint:plugins:plugin-sdk-subpaths-exported": "node --import tsx scripts/check-plugin-sdk-subpath-exports.mts", + "lint:plugins:plugin-sdk-subpaths-exported": "node --import ./scripts/tsx.mjs scripts/check-plugin-sdk-subpath-exports.mts", "lint:no-chained-type-assertions": "node scripts/run-oxlint.mjs --openclaw-focused-config --config config/oxlint/boundary-guards.json src extensions packages ui/src", "lint:no-widen-then-assert": "node scripts/run-oxlint.mjs --openclaw-focused-config --config config/oxlint/boundary-guards.json src extensions packages ui/src", "lint:scripts": "pnpm lint:docker-e2e && pnpm lint:tmp:no-raw-http2-imports && node scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.scripts.json scripts", "lint:swift": "./scripts/lint-swift.sh", - "lint:tmp:channel-agnostic-boundaries": "node --import tsx scripts/check-channel-agnostic-boundaries.mts", - "lint:tmp:dynamic-import-warts": "node --import tsx scripts/check-dynamic-import-warts.mts", - "lint:tmp:export-name-collisions": "node --import tsx scripts/check-export-name-collisions.mts", - "lint:tmp:no-random-messaging": "node --import tsx scripts/check-no-random-messaging-tmp.mts", - "lint:tmp:no-raw-channel-fetch": "node --import tsx scripts/check-no-raw-channel-fetch.mts", - "lint:tmp:no-raw-http2-imports": "node --import tsx scripts/check-no-raw-http2-imports.mts", - "lint:tmp:session-accessor-boundary": "node --import tsx scripts/check-session-accessor-boundary.mts", - "lint:tmp:session-accessor-boundary:gen": "node --import tsx scripts/check-session-accessor-boundary.mts --update-debt-baseline", - "lint:tmp:session-transcript-reader-boundary": "node --import tsx scripts/check-session-transcript-reader-boundary.mts", - "lint:tmp:sqlite-transaction-boundary": "node --import tsx scripts/check-sqlite-transaction-boundary.mts", - "lint:tmp:tsgo-core-boundary": "node --import tsx scripts/check-tsgo-core-boundary.mts", + "lint:tmp:channel-agnostic-boundaries": "node --import ./scripts/tsx.mjs scripts/check-channel-agnostic-boundaries.mts", + "lint:tmp:dynamic-import-warts": "node --import ./scripts/tsx.mjs scripts/check-dynamic-import-warts.mts", + "lint:tmp:export-name-collisions": "node --import ./scripts/tsx.mjs scripts/check-export-name-collisions.mts", + "lint:tmp:no-random-messaging": "node --import ./scripts/tsx.mjs scripts/check-no-random-messaging-tmp.mts", + "lint:tmp:no-raw-channel-fetch": "node --import ./scripts/tsx.mjs scripts/check-no-raw-channel-fetch.mts", + "lint:tmp:no-raw-http2-imports": "node --import ./scripts/tsx.mjs scripts/check-no-raw-http2-imports.mts", + "lint:tmp:session-accessor-boundary": "node --import ./scripts/tsx.mjs scripts/check-session-accessor-boundary.mts", + "lint:tmp:session-accessor-boundary:gen": "node --import ./scripts/tsx.mjs scripts/check-session-accessor-boundary.mts --update-debt-baseline", + "lint:tmp:session-transcript-reader-boundary": "node --import ./scripts/tsx.mjs scripts/check-session-transcript-reader-boundary.mts", + "lint:tmp:sqlite-transaction-boundary": "node --import ./scripts/tsx.mjs scripts/check-sqlite-transaction-boundary.mts", + "lint:tmp:tsgo-core-boundary": "node --import ./scripts/tsx.mjs scripts/check-tsgo-core-boundary.mts", "lint:ui:i18n": "pnpm ui:i18n:verify", "lint:ui:lit": "lit-analyzer \"ui/src/**/*.ts\" --quiet", "lint:ui:no-raw-window-open": "node scripts/run-oxlint.mjs --openclaw-focused-config --config config/oxlint/boundary-guards.json ui/src", "lint:ui:styles": "stylelint --config config/stylelint.config.mjs \"ui/src/**/*.css\" \"ui/src/**/*.ts\" \"ui/public/themes/*.css\"", - "lint:web-fetch-provider-boundaries": "node --import tsx scripts/check-web-fetch-provider-boundaries.mts", - "lint:webhook:no-low-level-body-read": "node --import tsx scripts/check-webhook-auth-body-order.mts", + "lint:web-fetch-provider-boundaries": "node --import ./scripts/tsx.mjs scripts/check-web-fetch-provider-boundaries.mts", + "lint:webhook:no-low-level-body-read": "node --import ./scripts/tsx.mjs scripts/check-webhook-auth-body-order.mts", "mac:open": "open dist/OpenClaw.app", "mac:package": "bash scripts/package-mac-app.sh", "mac:restart": "bash scripts/restart-mac.sh", - "mobile:release:preflight": "node --import tsx scripts/mobile-release-ref.ts preflight", - "mobile:release:record": "node --import tsx scripts/mobile-release-ref.ts record", - "mobile:release:resolve": "node --import tsx scripts/mobile-release-ref.ts resolve", + "mobile:release:preflight": "node --import ./scripts/tsx.mjs scripts/mobile-release-ref.ts preflight", + "mobile:release:record": "node --import ./scripts/tsx.mjs scripts/mobile-release-ref.ts record", + "mobile:release:resolve": "node --import ./scripts/tsx.mjs scripts/mobile-release-ref.ts resolve", "openclaw": "node scripts/run-node.mjs", "openclaw:rpc": "node scripts/run-node.mjs agent --mode rpc --json", - "perf:web-fetch": "node --import tsx scripts/bench-web-fetch.ts", - "perf:kova:summary": "node --import tsx scripts/kova-ci-summary.mts", - "perf:source:summary": "node --import tsx scripts/openclaw-performance-source-summary.mts", - "plugin-sdk:api:diff": "node --max-old-space-size=8192 --import tsx scripts/plugin-sdk-api-diff.mts", - "plugin-sdk:check-exports": "node --import tsx scripts/sync-plugin-sdk-exports.mts --check", - "plugin-sdk:surface": "node --max-old-space-size=8192 --import tsx scripts/plugin-sdk-surface-report.mts", - "plugin-sdk:surface:check": "node --max-old-space-size=8192 --import tsx scripts/plugin-sdk-surface-report.mts --check", - "plugin-sdk:sync-exports": "node --import tsx scripts/sync-plugin-sdk-exports.mts", - "plugin-sdk:usage": "node --max-old-space-size=8192 --import tsx scripts/analyze-plugin-sdk-usage.ts", - "policy:config-coverage": "node --import tsx scripts/check-policy-config-coverage.ts", - "plugins:boundary-report": "node --import tsx scripts/plugin-boundary-report.ts", - "plugins:boundary-report:ci": "node --import tsx scripts/plugin-boundary-report.ts --summary --fail-on-eligible-compat", - "plugins:boundary-report:json": "node --import tsx scripts/plugin-boundary-report.ts --json", - "plugins:boundary-report:summary": "node --import tsx scripts/plugin-boundary-report.ts --summary", - "plugins:assets:build": "node --import tsx scripts/bundled-plugin-assets.mts --phase build", - "plugins:assets:check": "node --import tsx scripts/bundled-plugin-assets.mts --phase build --check", - "plugins:assets:copy": "node --import tsx scripts/bundled-plugin-assets.mts --phase copy", - "plugins:inventory:check": "node --import tsx scripts/generate-plugin-inventory-doc.mts --check", - "plugins:inventory:gen": "node --import tsx scripts/generate-plugin-inventory-doc.mts --write", - "plugins:sync": "node --import tsx scripts/sync-plugin-versions.ts", - "plugins:sync:check": "node --import tsx scripts/sync-plugin-versions.ts --check", + "perf:web-fetch": "node --import ./scripts/tsx.mjs scripts/bench-web-fetch.ts", + "perf:kova:summary": "node --import ./scripts/tsx.mjs scripts/kova-ci-summary.mts", + "perf:source:summary": "node --import ./scripts/tsx.mjs scripts/openclaw-performance-source-summary.mts", + "plugin-sdk:api:diff": "node --max-old-space-size=8192 --import ./scripts/tsx.mjs scripts/plugin-sdk-api-diff.mts", + "plugin-sdk:check-exports": "node --import ./scripts/tsx.mjs scripts/sync-plugin-sdk-exports.mts --check", + "plugin-sdk:surface": "node --max-old-space-size=8192 --import ./scripts/tsx.mjs scripts/plugin-sdk-surface-report.mts", + "plugin-sdk:surface:check": "node --max-old-space-size=8192 --import ./scripts/tsx.mjs scripts/plugin-sdk-surface-report.mts --check", + "plugin-sdk:sync-exports": "node --import ./scripts/tsx.mjs scripts/sync-plugin-sdk-exports.mts", + "plugin-sdk:usage": "node --max-old-space-size=8192 --import ./scripts/tsx.mjs scripts/analyze-plugin-sdk-usage.ts", + "policy:config-coverage": "node --import ./scripts/tsx.mjs scripts/check-policy-config-coverage.ts", + "plugins:boundary-report": "node --import ./scripts/tsx.mjs scripts/plugin-boundary-report.ts", + "plugins:boundary-report:ci": "node --import ./scripts/tsx.mjs scripts/plugin-boundary-report.ts --summary --fail-on-eligible-compat", + "plugins:boundary-report:json": "node --import ./scripts/tsx.mjs scripts/plugin-boundary-report.ts --json", + "plugins:boundary-report:summary": "node --import ./scripts/tsx.mjs scripts/plugin-boundary-report.ts --summary", + "plugins:assets:build": "node --import ./scripts/tsx.mjs scripts/bundled-plugin-assets.mts --phase build", + "plugins:assets:check": "node --import ./scripts/tsx.mjs scripts/bundled-plugin-assets.mts --phase build --check", + "plugins:assets:copy": "node --import ./scripts/tsx.mjs scripts/bundled-plugin-assets.mts --phase copy", + "plugins:inventory:check": "node --import ./scripts/tsx.mjs scripts/generate-plugin-inventory-doc.mts --check", + "plugins:inventory:gen": "node --import ./scripts/tsx.mjs scripts/generate-plugin-inventory-doc.mts --write", + "plugins:sync": "node --import ./scripts/tsx.mjs scripts/sync-plugin-versions.ts", + "plugins:sync:check": "node --import ./scripts/tsx.mjs scripts/sync-plugin-versions.ts --check", "postinstall": "node scripts/postinstall-bundled-plugins.mjs", "postpack": "node scripts/openclaw-postpack.mjs", "preinstall": "node scripts/preinstall-package-manager-warning.mjs", - "prepack": "node --import tsx scripts/openclaw-prepack.ts", + "prepack": "node --import ./scripts/tsx.mjs scripts/openclaw-prepack.ts", "prepare": "node scripts/prepare-git-hooks.mjs", "prepush:ci": "bash scripts/prepush-ci.sh", - "probe:anthropic:prompt": "node --import tsx scripts/anthropic-prompt-probe.ts", - "prompt:snapshots:check": "node --import tsx scripts/generate-prompt-snapshots.ts --check", - "prompt:snapshots:gen": "node --import tsx scripts/generate-prompt-snapshots.ts --write", - "prompt:snapshots:sync-codex-model": "node --import tsx scripts/sync-codex-model-prompt-fixture.ts", - "protocol:check": "pnpm protocol-registry:check && pnpm protocol:gen && pnpm protocol:check:swift && pnpm protocol:gen:kotlin && node --import tsx scripts/check-protocol-since.mts && git diff --exit-code -- dist/protocol.schema.json apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewayProtocol.kt apps/android/app/src/main/java/ai/openclaw/app/protocol/OpenClawProtocolConstants.kt", + "probe:anthropic:prompt": "node --import ./scripts/tsx.mjs scripts/anthropic-prompt-probe.ts", + "prompt:snapshots:check": "node --import ./scripts/tsx.mjs scripts/generate-prompt-snapshots.ts --check", + "prompt:snapshots:gen": "node --import ./scripts/tsx.mjs scripts/generate-prompt-snapshots.ts --write", + "prompt:snapshots:sync-codex-model": "node --import ./scripts/tsx.mjs scripts/sync-codex-model-prompt-fixture.ts", + "protocol:check": "pnpm protocol-registry:check && pnpm protocol:gen && pnpm protocol:check:swift && pnpm protocol:gen:kotlin && node --import ./scripts/tsx.mjs scripts/check-protocol-since.mts && git diff --exit-code -- dist/protocol.schema.json apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewayProtocol.kt apps/android/app/src/main/java/ai/openclaw/app/protocol/OpenClawProtocolConstants.kt", "protocol:check:kotlin": "pnpm protocol:gen:kotlin && git diff --exit-code -- apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewayProtocol.kt apps/android/app/src/main/java/ai/openclaw/app/protocol/OpenClawProtocolConstants.kt", - "protocol:check:swift": "node --import tsx scripts/protocol-gen-swift.ts --check", - "protocol:gen": "node --import tsx scripts/protocol-gen.ts", - "protocol:gen:kotlin": "node --import tsx scripts/protocol-gen-kotlin.ts", - "protocol:gen:swift": "node --import tsx scripts/protocol-gen-swift.ts", - "protocol-registry:check": "node --import tsx scripts/check-protocol-registry.mts", + "protocol:check:swift": "node --import ./scripts/tsx.mjs scripts/protocol-gen-swift.ts --check", + "protocol:gen": "node --import ./scripts/tsx.mjs scripts/protocol-gen.ts", + "protocol:gen:kotlin": "node --import ./scripts/tsx.mjs scripts/protocol-gen-kotlin.ts", + "protocol:gen:swift": "node --import ./scripts/tsx.mjs scripts/protocol-gen-swift.ts", + "protocol-registry:check": "node --import ./scripts/tsx.mjs scripts/check-protocol-registry.mts", "proxy:coverage": "node scripts/run-node.mjs proxy coverage", "proxy:gateway": "node scripts/run-node.mjs proxy run -- node scripts/run-node.mjs gateway", - "proxy:install-ca": "node --import tsx scripts/proxy-install-ca.mts", + "proxy:install-ca": "node --import ./scripts/tsx.mjs scripts/proxy-install-ca.mts", "proxy:run": "node scripts/run-node.mjs proxy run", "proxy:start": "node scripts/run-node.mjs proxy start", - "qa:e2e": "node --import tsx scripts/qa-e2e.ts", - "qa:telegram-desktop-recorder": "node --import tsx scripts/e2e/telegram-desktop-recorder.ts", + "qa:e2e": "node --import ./scripts/tsx.mjs scripts/qa-e2e.ts", + "qa:telegram-desktop-recorder": "node --import ./scripts/tsx.mjs scripts/e2e/telegram-desktop-recorder.ts", "qa:lab:build": "vite build --config extensions/qa-lab/web/vite.config.ts", "qa:lab:ui": "pnpm openclaw qa ui", - "qa:lab:up": "node --import tsx scripts/qa-lab-up.ts", - "qa:lab:up:fast": "node --import tsx scripts/qa-lab-up.ts --use-prebuilt-image --bind-ui-dist --skip-ui-build", + "qa:lab:up": "node --import ./scripts/tsx.mjs scripts/qa-lab-up.ts", + "qa:lab:up:fast": "node --import ./scripts/tsx.mjs scripts/qa-lab-up.ts --use-prebuilt-image --bind-ui-dist --skip-ui-build", "qa:lab:watch": "vite build --watch --config extensions/qa-lab/web/vite.config.ts", "qa:observability:collector-smoke": "pnpm qa:otel:collector-smoke && pnpm qa:prometheus:smoke", "qa:observability:smoke": "pnpm qa:otel:smoke && pnpm qa:prometheus:smoke", - "qa:otel:collector-smoke": "node --import tsx test/e2e/qa-lab/runtime/qa-otel-smoke-runtime.ts --collector docker", - "qa:otel:smoke": "node --import tsx test/e2e/qa-lab/runtime/qa-otel-smoke-runtime.ts", - "qa:code-mode-models": "node --import tsx scripts/code-mode-model-matrix.ts", + "qa:otel:collector-smoke": "node --import ./scripts/tsx.mjs test/e2e/qa-lab/runtime/qa-otel-smoke-runtime.ts --collector docker", + "qa:otel:smoke": "node --import ./scripts/tsx.mjs test/e2e/qa-lab/runtime/qa-otel-smoke-runtime.ts", + "qa:code-mode-models": "node --import ./scripts/tsx.mjs scripts/code-mode-model-matrix.ts", "qa:prometheus:smoke": "node scripts/run-node.mjs qa suite --provider-mode mock-openai --scenario docker-prometheus-smoke --concurrency 1 --fast", - "release-metadata:check": "node --import tsx scripts/check-release-metadata-only.mts", - "release:beta": "node --import tsx scripts/release-candidate-checklist.mts", - "release:beta-smoke": "node --import tsx scripts/release-beta-smoke.ts", - "release:candidate": "node --import tsx scripts/release-candidate-checklist.mts", - "release:check": "pnpm build:package && pnpm release:generated:check && node --import tsx scripts/release-check.ts", + "release-metadata:check": "node --import ./scripts/tsx.mjs scripts/check-release-metadata-only.mts", + "release:beta": "node --import ./scripts/tsx.mjs scripts/release-candidate-checklist.mts", + "release:beta-smoke": "node --import ./scripts/tsx.mjs scripts/release-beta-smoke.ts", + "release:candidate": "node --import ./scripts/tsx.mjs scripts/release-candidate-checklist.mts", + "release:check": "pnpm build:package && pnpm release:generated:check && node --import ./scripts/tsx.mjs scripts/release-check.ts", "release:fast-pretag-check": "bash scripts/release-fast-pretag-check.sh", "release:generated:check": "node scripts/release-preflight.mjs --check", - "release:openclaw:npm:check": "node --import tsx scripts/openclaw-npm-release-check.ts", - "release:openclaw:npm:verify-published": "node --import tsx scripts/openclaw-npm-postpublish-verify.ts", - "release:prepare": "node --import tsx scripts/release-prepare.ts", - "release:plugins:clawhub:check": "node --import tsx scripts/plugin-clawhub-release-check.ts", - "release:plugins:clawhub:plan": "node --import tsx scripts/plugin-clawhub-release-plan.ts", - "release:plugins:npm:check": "node --import tsx scripts/plugin-npm-release-check.ts", - "release:plugins:npm:plan": "node --import tsx scripts/plugin-npm-release-plan.ts", - "release:verify-beta": "node --import tsx scripts/release-verify-beta.ts", + "release:openclaw:npm:check": "node --import ./scripts/tsx.mjs scripts/openclaw-npm-release-check.ts", + "release:openclaw:npm:verify-published": "node --import ./scripts/tsx.mjs scripts/openclaw-npm-postpublish-verify.ts", + "release:prepare": "node --import ./scripts/tsx.mjs scripts/release-prepare.ts", + "release:plugins:clawhub:check": "node --import ./scripts/tsx.mjs scripts/plugin-clawhub-release-check.ts", + "release:plugins:clawhub:plan": "node --import ./scripts/tsx.mjs scripts/plugin-clawhub-release-plan.ts", + "release:plugins:npm:check": "node --import ./scripts/tsx.mjs scripts/plugin-npm-release-check.ts", + "release:plugins:npm:plan": "node --import ./scripts/tsx.mjs scripts/plugin-npm-release-plan.ts", + "release:verify-beta": "node --import ./scripts/tsx.mjs scripts/release-verify-beta.ts", "release:prep": "node scripts/release-preflight.mjs --fix", "release:prep:version": "node scripts/release-preflight.mjs --fix --scope version", - "release:version": "node --import tsx scripts/release-version.ts", - "runtime-sidecars:check": "node --import tsx scripts/generate-runtime-sidecar-paths-baseline.ts --check", - "runtime-sidecars:gen": "node --import tsx scripts/generate-runtime-sidecar-paths-baseline.ts --write", - "sqlite:sessions-schema:check": "node --import tsx scripts/generate-sqlite-session-schema-baseline.ts --check", - "sqlite:sessions-schema:gen": "node --import tsx scripts/generate-sqlite-session-schema-baseline.ts --write", + "release:version": "node --import ./scripts/tsx.mjs scripts/release-version.ts", + "runtime-sidecars:check": "node --import ./scripts/tsx.mjs scripts/generate-runtime-sidecar-paths-baseline.ts --check", + "runtime-sidecars:gen": "node --import ./scripts/tsx.mjs scripts/generate-runtime-sidecar-paths-baseline.ts --write", + "sqlite:sessions-schema:check": "node --import ./scripts/tsx.mjs scripts/generate-sqlite-session-schema-baseline.ts --check", + "sqlite:sessions-schema:gen": "node --import ./scripts/tsx.mjs scripts/generate-sqlite-session-schema-baseline.ts --write", "start": "node openclaw.mjs", - "test": "node --import tsx scripts/test-projects.mts", + "test": "node --import ./scripts/tsx.mjs scripts/test-projects.mts", "test:all": "pnpm lint && pnpm build && pnpm test && pnpm test:e2e && pnpm test:live && pnpm test:docker:all", "test:auth:compat": "node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway.config.ts src/gateway/server.auth.compat-baseline.test.ts src/gateway/client.test.ts src/gateway/reconnect-gating.test.ts && node scripts/run-vitest.mjs run packages/gateway-protocol/src/connect-error-details.test.ts", - "test:build:singleton": "node --import tsx scripts/test-built-plugin-singleton.mts", - "test:build:status-message-runtime": "node --import tsx scripts/test-built-status-message-runtime.mts", + "test:build:singleton": "node --import ./scripts/tsx.mjs scripts/test-built-plugin-singleton.mts", + "test:build:status-message-runtime": "node --import ./scripts/tsx.mjs scripts/test-built-status-message-runtime.mts", "test:bundled": "node scripts/run-vitest.mjs run --config test/vitest/vitest.bundled.config.ts", - "test:changed": "node --import tsx scripts/test-projects.mts --changed origin/main", - "test:changed:max": "node --import tsx scripts/test-projects-max.mts --changed origin/main", + "test:changed": "node --import ./scripts/tsx.mjs scripts/test-projects.mts --changed origin/main", + "test:changed:max": "node --import ./scripts/tsx.mjs scripts/test-projects-max.mts --changed origin/main", "test:channels": "node scripts/run-vitest.mjs run --config test/vitest/vitest.channels.config.ts", "test:contracts": "pnpm test:contracts:channels && pnpm test:contracts:plugins", - "test:contracts:channels": "node --import tsx scripts/test-projects.mts --maxWorkers=1 test/vitest/vitest.contracts-channel-surface.config.ts test/vitest/vitest.contracts-channel-config.config.ts test/vitest/vitest.contracts-channel-registry.config.ts test/vitest/vitest.contracts-channel-session.config.ts", + "test:contracts:channels": "node --import ./scripts/tsx.mjs scripts/test-projects.mts --maxWorkers=1 test/vitest/vitest.contracts-channel-surface.config.ts test/vitest/vitest.contracts-channel-config.config.ts test/vitest/vitest.contracts-channel-registry.config.ts test/vitest/vitest.contracts-channel-session.config.ts", "test:contracts:plugins": "node scripts/run-vitest.mjs run --config test/vitest/vitest.contracts-plugin.config.ts --maxWorkers=1", "test:coverage": "node scripts/run-vitest.mjs run --config test/vitest/vitest.unit.config.ts --coverage", "test:coverage:changed": "node scripts/run-vitest.mjs run --config test/vitest/vitest.unit.config.ts --coverage --changed origin/main", @@ -1856,8 +1856,8 @@ "test:docker:live-models": "bash scripts/test-live-models-docker.sh", "test:docker:live-models:claude": "OPENCLAW_LIVE_PROVIDERS=claude-cli OPENCLAW_LIVE_MODELS=claude-cli/claude-sonnet-4-6 bash scripts/test-live-models-docker.sh", "test:docker:live-models:gemini": "OPENCLAW_LIVE_PROVIDERS=google-gemini-cli OPENCLAW_LIVE_MODELS=google-gemini-cli/gemini-3.1-pro-preview bash scripts/test-live-models-docker.sh", - "test:docker:live:all": "node --import tsx scripts/run-with-env.mts OPENCLAW_DOCKER_ALL_LIVE_MODE=only -- node scripts/test-docker-all.mjs", - "test:docker:local:all": "node --import tsx scripts/run-with-env.mts OPENCLAW_DOCKER_ALL_LIVE_MODE=skip -- node scripts/test-docker-all.mjs", + "test:docker:live:all": "node --import ./scripts/tsx.mjs scripts/run-with-env.mts OPENCLAW_DOCKER_ALL_LIVE_MODE=only -- node scripts/test-docker-all.mjs", + "test:docker:local:all": "node --import ./scripts/tsx.mjs scripts/run-with-env.mts OPENCLAW_DOCKER_ALL_LIVE_MODE=skip -- node scripts/test-docker-all.mjs", "test:docker:cli-installer-distribution": "bash scripts/e2e/cli-installer-distribution-docker.sh", "test:docker:mcp-channels": "bash scripts/e2e/mcp-channels-docker.sh", "test:docker:mcp-code-mode-gateway": "bash scripts/e2e/mcp-code-mode-gateway-docker.sh", @@ -1882,109 +1882,109 @@ "test:docker:plugin-lifecycle-matrix": "bash scripts/e2e/plugin-lifecycle-matrix-docker.sh", "test:docker:plugin-update": "bash scripts/e2e/plugin-update-unchanged-docker.sh", "test:docker:plugins": "bash scripts/e2e/plugins-docker.sh", - "test:docker:published-upgrade-survivor": "node --import tsx scripts/run-with-env.mts OPENCLAW_DOCKER_ALL_LANES=published-upgrade-survivor -- node scripts/test-docker-all.mjs", + "test:docker:published-upgrade-survivor": "node --import ./scripts/tsx.mjs scripts/run-with-env.mts OPENCLAW_DOCKER_ALL_LANES=published-upgrade-survivor -- node scripts/test-docker-all.mjs", "test:docker:qr": "bash scripts/e2e/qr-import-docker.sh", - "test:docker:rerun": "node --import tsx scripts/docker-e2e-rerun.mts", + "test:docker:rerun": "node --import ./scripts/tsx.mjs scripts/docker-e2e-rerun.mts", "test:docker:root-managed-vps-upgrade": "env OPENCLAW_UPGRADE_SURVIVOR_PUBLISHED_BASELINE=1 OPENCLAW_UPGRADE_SURVIVOR_ROOT_MANAGED_VPS=1 OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC=${OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC:-openclaw@2026.5.7} OPENCLAW_UPGRADE_SURVIVOR_DOCKER_RUN_TIMEOUT=${OPENCLAW_UPGRADE_SURVIVOR_DOCKER_RUN_TIMEOUT:-1500s} bash scripts/e2e/upgrade-survivor-docker.sh", "test:docker:selected-plugins": "bash scripts/e2e/docker-selected-plugins.sh", "test:docker:session-runtime-context": "bash scripts/e2e/session-runtime-context-docker.sh", "test:docker:skill-install": "bash scripts/e2e/skill-install-docker.sh", - "test:docker:timings": "node --import tsx scripts/docker-e2e-timings.mts", + "test:docker:timings": "node --import ./scripts/tsx.mjs scripts/docker-e2e-timings.mts", "test:docker:update-channel-switch": "bash scripts/e2e/update-channel-switch-docker.sh", "test:docker:update-corrupt-plugin": "bash scripts/e2e/update-corrupt-plugin-docker.sh", "test:docker:update-migration": "env OPENCLAW_UPGRADE_SURVIVOR_PUBLISHED_BASELINE=1 OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC=${OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC:-openclaw@2026.4.23} OPENCLAW_UPGRADE_SURVIVOR_SCENARIO=${OPENCLAW_UPGRADE_SURVIVOR_SCENARIO:-plugin-deps-cleanup} bash scripts/e2e/upgrade-survivor-docker.sh", "test:docker:update-restart-auth": "env OPENCLAW_UPGRADE_SURVIVOR_UPDATE_RESTART_MODE=auto-auth OPENCLAW_UPGRADE_SURVIVOR_DOCKER_RUN_TIMEOUT=${OPENCLAW_UPGRADE_SURVIVOR_DOCKER_RUN_TIMEOUT:-1500s} bash scripts/e2e/upgrade-survivor-docker.sh", "test:docker:update-run-package-self-upgrade": "bash scripts/e2e/update-run-package-self-upgrade-docker.sh", "test:docker:upgrade-survivor": "bash scripts/e2e/upgrade-survivor-docker.sh", - "test:env-mutations:report": "node --import tsx scripts/test-env-mutation-report.ts", - "test:skip-inventory:report": "node --import tsx scripts/test-skip-inventory.ts", - "test:type-suppression-inventory:report": "node --import tsx scripts/type-suppression-inventory.ts", + "test:env-mutations:report": "node --import ./scripts/tsx.mjs scripts/test-env-mutation-report.ts", + "test:skip-inventory:report": "node --import ./scripts/tsx.mjs scripts/test-skip-inventory.ts", + "test:type-suppression-inventory:report": "node --import ./scripts/tsx.mjs scripts/type-suppression-inventory.ts", "test:e2e": "pnpm test:e2e:gateway && pnpm test:e2e:agent-plugin-gateway && pnpm test:ui:e2e", - "test:e2e:agent-plugin-gateway": "node --import tsx scripts/agent-plugin-gateway-e2e.ts", - "test:e2e:browser-extension": "node --import tsx scripts/run-with-env.mts PLAYWRIGHT_BROWSERS_PATH=.artifacts/playwright-browsers -- node --import tsx scripts/ensure-playwright-chromium.mts --require-playwright-chromium && node --import tsx scripts/run-with-env.mts PLAYWRIGHT_BROWSERS_PATH=.artifacts/playwright-browsers OPENCLAW_BROWSER_EXTENSION_E2E=1 OPENCLAW_E2E_WORKERS=1 -- node scripts/run-vitest.mjs extensions/browser/chrome-extension/bootstrap.chromium.test.ts", + "test:e2e:agent-plugin-gateway": "node --import ./scripts/tsx.mjs scripts/agent-plugin-gateway-e2e.ts", + "test:e2e:browser-extension": "node --import ./scripts/tsx.mjs scripts/run-with-env.mts PLAYWRIGHT_BROWSERS_PATH=.artifacts/playwright-browsers -- node --import ./scripts/tsx.mjs scripts/ensure-playwright-chromium.mts --require-playwright-chromium && node --import ./scripts/tsx.mjs scripts/run-with-env.mts PLAYWRIGHT_BROWSERS_PATH=.artifacts/playwright-browsers OPENCLAW_BROWSER_EXTENSION_E2E=1 OPENCLAW_E2E_WORKERS=1 -- node scripts/run-vitest.mjs extensions/browser/chrome-extension/bootstrap.chromium.test.ts", "test:e2e:gateway": "node scripts/run-vitest.mjs run --config test/vitest/vitest.e2e.config.ts", - "test:e2e:openshell": "node --import tsx scripts/run-with-env.mts OPENCLAW_E2E_OPENSHELL=1 -- node scripts/run-vitest.mjs run --config test/vitest/vitest.e2e.config.ts extensions/openshell/src/backend.e2e.test.ts", + "test:e2e:openshell": "node --import ./scripts/tsx.mjs scripts/run-with-env.mts OPENCLAW_E2E_OPENSHELL=1 -- node scripts/run-vitest.mjs run --config test/vitest/vitest.e2e.config.ts extensions/openshell/src/backend.e2e.test.ts", "test:e2e:status-corrupt-plugin-deps": "bash scripts/e2e/status-corrupt-plugin-deps.sh", - "test:extension": "node --import tsx scripts/test-extension.mts", - "test:extensions": "node --import tsx scripts/test-projects.mts extensions", - "test:extensions:batch": "node --import tsx scripts/test-extension-batch.mts", - "test:extensions:memory": "node --import tsx scripts/profile-extension-memory.mts", - "test:extensions:package-boundary": "node --import tsx scripts/check-extension-package-tsc-boundary.mts", - "test:extensions:package-boundary:canary": "node --import tsx scripts/check-extension-package-tsc-boundary.mts --mode=canary", - "test:extensions:package-boundary:compile": "node --import tsx scripts/check-extension-package-tsc-boundary.mts --mode=compile", + "test:extension": "node --import ./scripts/tsx.mjs scripts/test-extension.mts", + "test:extensions": "node --import ./scripts/tsx.mjs scripts/test-projects.mts extensions", + "test:extensions:batch": "node --import ./scripts/tsx.mjs scripts/test-extension-batch.mts", + "test:extensions:memory": "node --import ./scripts/tsx.mjs scripts/profile-extension-memory.mts", + "test:extensions:package-boundary": "node --import ./scripts/tsx.mjs scripts/check-extension-package-tsc-boundary.mts", + "test:extensions:package-boundary:canary": "node --import ./scripts/tsx.mjs scripts/check-extension-package-tsc-boundary.mts --mode=canary", + "test:extensions:package-boundary:compile": "node --import ./scripts/tsx.mjs scripts/check-extension-package-tsc-boundary.mts --mode=compile", "test:fast": "node scripts/run-vitest.mjs run --config test/vitest/vitest.unit.config.ts", - "test:force": "node --import tsx scripts/test-force.ts", - "test:gateway": "node --import tsx scripts/run-with-env.mts OPENCLAW_GATEWAY_PROJECT_SHARDS=1 -- node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway.config.ts", - "test:gateway:cpu-scenarios": "node --import tsx scripts/check-gateway-cpu-scenarios.mts", + "test:force": "node --import ./scripts/tsx.mjs scripts/test-force.ts", + "test:gateway": "node --import ./scripts/tsx.mjs scripts/run-with-env.mts OPENCLAW_GATEWAY_PROJECT_SHARDS=1 -- node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway.config.ts", + "test:gateway:cpu-scenarios": "node --import ./scripts/tsx.mjs scripts/check-gateway-cpu-scenarios.mts", "test:gateway:concurrency": "node scripts/bench-gateway-concurrency.ts", - "test:gateway:memory-fd-repro": "node --import tsx scripts/check-memory-fd-repro.mts", - "test:gateway:watch-regression": "node --import tsx scripts/check-gateway-watch-regression.mts", + "test:gateway:memory-fd-repro": "node --import ./scripts/tsx.mjs scripts/check-memory-fd-repro.mts", + "test:gateway:watch-regression": "node --import ./scripts/tsx.mjs scripts/check-gateway-watch-regression.mts", "test:install:e2e": "bash scripts/test-install-sh-e2e-docker.sh", "test:install:e2e:anthropic": "OPENCLAW_E2E_MODELS=anthropic bash scripts/test-install-sh-e2e-docker.sh", "test:install:e2e:openai": "OPENCLAW_E2E_MODELS=openai bash scripts/test-install-sh-e2e-docker.sh", "test:install:smoke": "bash scripts/test-install-sh-docker.sh", - "test:live": "node --import tsx scripts/test-live.mts", - "test:live:cache": "node --import tsx scripts/run-with-env.mts OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_CACHE_TEST=1 -- node --import tsx scripts/check-live-cache.ts", - "test:live:codex-harness": "node --import tsx scripts/test-live.mts --codex-harness -- src/gateway/gateway-codex-harness.live.test.ts", - "test:live:system-agent-rescue-channel": "node --import tsx scripts/run-with-env.mts OPENCLAW_LIVE_SYSTEM_AGENT_RESCUE_CHANNEL=1 -- node --import tsx scripts/test-live.mts -- src/system-agent/rescue-channel.live.test.ts", - "test:live:gateway-profiles": "node --import tsx scripts/test-live.mts -- src/gateway/gateway-models.profiles.live.test.ts", - "test:live:media": "node --import tsx test/e2e/qa-lab/media/hosted-media-provider-live.ts", - "test:live:media:image": "node --import tsx test/e2e/qa-lab/media/hosted-media-provider-live.ts image", - "test:live:media:music": "node --import tsx test/e2e/qa-lab/media/hosted-media-provider-live.ts music", - "test:live:media:video": "node --import tsx test/e2e/qa-lab/media/hosted-media-provider-live.ts video", - "test:live:models-profiles": "node --import tsx scripts/test-live.mts -- src/agents/models.profiles.live.test.ts", - "test:macos:ci": "node --import tsx scripts/test-projects.mts src/daemon/launchd.test.ts src/daemon/runtime-paths.test.ts src/daemon/runtime-binary.test.ts src/gateway/worker-environments/workspace-rsync-path.test.ts src/infra/brew.test.ts src/infra/stable-node-path.test.ts src/process/supervisor/adapters/child.service-lifecycle.test.ts test/scripts/vitest-process-group.test.ts test/scripts/package-mac-app.test.ts test/scripts/package-mac-dist.test.ts test/scripts/create-dmg.test.ts test/scripts/codesign-mac-app.test.ts test/scripts/notarize-mac-artifact.test.ts test/scripts/mac-elevation-host.test.ts", - "test:max": "node --import tsx scripts/test-projects-max.mts", + "test:live": "node --import ./scripts/tsx.mjs scripts/test-live.mts", + "test:live:cache": "node --import ./scripts/tsx.mjs scripts/run-with-env.mts OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_CACHE_TEST=1 -- node --import ./scripts/tsx.mjs scripts/check-live-cache.ts", + "test:live:codex-harness": "node --import ./scripts/tsx.mjs scripts/test-live.mts --codex-harness -- src/gateway/gateway-codex-harness.live.test.ts", + "test:live:system-agent-rescue-channel": "node --import ./scripts/tsx.mjs scripts/run-with-env.mts OPENCLAW_LIVE_SYSTEM_AGENT_RESCUE_CHANNEL=1 -- node --import ./scripts/tsx.mjs scripts/test-live.mts -- src/system-agent/rescue-channel.live.test.ts", + "test:live:gateway-profiles": "node --import ./scripts/tsx.mjs scripts/test-live.mts -- src/gateway/gateway-models.profiles.live.test.ts", + "test:live:media": "node --import ./scripts/tsx.mjs test/e2e/qa-lab/media/hosted-media-provider-live.ts", + "test:live:media:image": "node --import ./scripts/tsx.mjs test/e2e/qa-lab/media/hosted-media-provider-live.ts image", + "test:live:media:music": "node --import ./scripts/tsx.mjs test/e2e/qa-lab/media/hosted-media-provider-live.ts music", + "test:live:media:video": "node --import ./scripts/tsx.mjs test/e2e/qa-lab/media/hosted-media-provider-live.ts video", + "test:live:models-profiles": "node --import ./scripts/tsx.mjs scripts/test-live.mts -- src/agents/models.profiles.live.test.ts", + "test:macos:ci": "node --import ./scripts/tsx.mjs scripts/test-projects.mts src/daemon/launchd.test.ts src/daemon/runtime-paths.test.ts src/daemon/runtime-binary.test.ts src/gateway/worker-environments/workspace-rsync-path.test.ts src/infra/brew.test.ts src/infra/stable-node-path.test.ts src/process/supervisor/adapters/child.service-lifecycle.test.ts test/scripts/vitest-process-group.test.ts test/scripts/package-mac-app.test.ts test/scripts/package-mac-dist.test.ts test/scripts/create-dmg.test.ts test/scripts/codesign-mac-app.test.ts test/scripts/notarize-mac-artifact.test.ts test/scripts/mac-elevation-host.test.ts", + "test:max": "node --import ./scripts/tsx.mjs scripts/test-projects-max.mts", "test:parallels:linux": "bash scripts/e2e/parallels-linux-smoke.sh", "test:parallels:macos": "bash scripts/e2e/parallels-macos-smoke.sh", "test:parallels:npm-update": "bash scripts/e2e/parallels-npm-update-smoke.sh", "test:parallels:windows:prepare": "bash scripts/e2e/parallels-windows-prepare.sh", "test:parallels:windows": "bash scripts/e2e/parallels-windows-smoke.sh", - "test:agents:concurrency": "node --import tsx scripts/bench-agent-concurrency.ts", - "test:tasks:sqlite-churn": "node --import tsx scripts/bench-task-registry-sqlite.ts", - "test:perf:budget": "node --import tsx scripts/test-perf-budget.mts", - "test:perf:changed:bench": "node --import tsx scripts/bench-test-changed.mts", - "test:perf:groups": "node --import tsx scripts/test-group-report.mts", - "test:perf:groups:compare": "node --import tsx scripts/test-group-report.mts --compare", - "test:perf:hotspots": "node --import tsx scripts/test-hotspots.mts", - "test:perf:imports": "node --import tsx scripts/test-projects-imports.mts", - "test:perf:imports:changed": "node --import tsx scripts/test-projects-imports.mts --changed origin/main", - "test:perf:profile:main": "node --import tsx scripts/run-vitest-profile.mts main", - "test:perf:profile:runner": "node --import tsx scripts/run-vitest-profile.mts runner", - "test:sqlite:perf": "node --import tsx scripts/bench-sqlite-state.ts --profile default --output .artifacts/sqlite-perf/default.json", - "test:sqlite:perf:large": "node --import tsx scripts/bench-sqlite-state.ts --profile large --output .artifacts/sqlite-perf/large.json", - "test:sqlite:perf:smoke": "node --import tsx scripts/bench-sqlite-state.ts --profile smoke --output .artifacts/sqlite-perf/smoke.json", - "test:plugins:gateway-gauntlet": "node --import tsx scripts/check-plugin-gateway-gauntlet.mts", - "test:plugins:init-provider-scaffold": "node --import tsx scripts/validate-plugin-init-provider-scaffold.ts", + "test:agents:concurrency": "node --import ./scripts/tsx.mjs scripts/bench-agent-concurrency.ts", + "test:tasks:sqlite-churn": "node --import ./scripts/tsx.mjs scripts/bench-task-registry-sqlite.ts", + "test:perf:budget": "node --import ./scripts/tsx.mjs scripts/test-perf-budget.mts", + "test:perf:changed:bench": "node --import ./scripts/tsx.mjs scripts/bench-test-changed.mts", + "test:perf:groups": "node --import ./scripts/tsx.mjs scripts/test-group-report.mts", + "test:perf:groups:compare": "node --import ./scripts/tsx.mjs scripts/test-group-report.mts --compare", + "test:perf:hotspots": "node --import ./scripts/tsx.mjs scripts/test-hotspots.mts", + "test:perf:imports": "node --import ./scripts/tsx.mjs scripts/test-projects-imports.mts", + "test:perf:imports:changed": "node --import ./scripts/tsx.mjs scripts/test-projects-imports.mts --changed origin/main", + "test:perf:profile:main": "node --import ./scripts/tsx.mjs scripts/run-vitest-profile.mts main", + "test:perf:profile:runner": "node --import ./scripts/tsx.mjs scripts/run-vitest-profile.mts runner", + "test:sqlite:perf": "node --import ./scripts/tsx.mjs scripts/bench-sqlite-state.ts --profile default --output .artifacts/sqlite-perf/default.json", + "test:sqlite:perf:large": "node --import ./scripts/tsx.mjs scripts/bench-sqlite-state.ts --profile large --output .artifacts/sqlite-perf/large.json", + "test:sqlite:perf:smoke": "node --import ./scripts/tsx.mjs scripts/bench-sqlite-state.ts --profile smoke --output .artifacts/sqlite-perf/smoke.json", + "test:plugins:gateway-gauntlet": "node --import ./scripts/tsx.mjs scripts/check-plugin-gateway-gauntlet.mts", + "test:plugins:init-provider-scaffold": "node --import ./scripts/tsx.mjs scripts/validate-plugin-init-provider-scaffold.ts", "test:plugins:kitchen-sink-live": "bash -lc 'if [ -x \"$HOME/.local/bin/openclaw-testbox-env\" ]; then exec \"$HOME/.local/bin/openclaw-testbox-env\" pnpm openclaw qa suite --provider-mode live-frontier --scenario kitchen-sink-live-openai; fi; exec pnpm openclaw qa suite --provider-mode live-frontier --scenario kitchen-sink-live-openai'", - "test:plugins:kitchen-sink-rpc": "node --import tsx scripts/e2e/kitchen-sink-rpc-walk.mts", - "test:sectriage": "node --import tsx scripts/run-with-env.mts OPENCLAW_GATEWAY_PROJECT_SHARDS=1 -- node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway.config.ts && node scripts/run-vitest.mjs run --config test/vitest/vitest.unit.config.ts --exclude src/process/exec.test.ts", - "test:serial": "node --import tsx scripts/test-projects-serial.mts", - "test:stability:gateway": "node --import tsx scripts/run-with-env.mts OPENCLAW_VITEST_MAX_WORKERS=1 -- node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway.config.ts src/gateway/gateway-stability.test.ts && node --import tsx scripts/run-with-env.mts OPENCLAW_VITEST_MAX_WORKERS=1 -- node scripts/run-vitest.mjs run --config test/vitest/vitest.logging.config.ts src/logging/diagnostic-stability-bundle.test.ts && node --import tsx scripts/run-with-env.mts OPENCLAW_VITEST_MAX_WORKERS=1 -- node scripts/run-vitest.mjs run --config test/vitest/vitest.infra.config.ts src/infra/fatal-error-hooks.test.ts", - "test:cli-response:contract": "node --import tsx scripts/build-all.mts cliStartup && node --import tsx scripts/test-cli-startup-bench-budget.mts --preset response --runs 1 --warmup 0 --timeout-ms 10000 --skip-baseline", - "test:startup:bench": "node --import tsx scripts/bench-cli-startup.ts", - "test:startup:bench:check": "node --import tsx scripts/test-cli-startup-bench-budget.mts", - "test:startup:bench:save": "node --import tsx scripts/bench-cli-startup.ts --preset all --runs 5 --warmup 1 --output .artifacts/cli-startup-bench-all.json", - "test:startup:bench:smoke": "node --import tsx scripts/ensure-cli-startup-build.mts && node --import tsx scripts/bench-cli-startup.ts --preset real --case gatewayStatusJson --runs 1 --warmup 0 --output .artifacts/cli-startup-bench-smoke.json", - "test:startup:bench:update": "node --import tsx scripts/test-update-cli-startup-bench.mts", - "test:startup:gateway": "node --import tsx scripts/bench-gateway-startup.ts", - "test:restart:gateway": "node --import tsx scripts/bench-gateway-restart.ts", - "test:sessions:hydration-memory": "node --import tsx scripts/bench-session-manager-hydration-memory.ts", - "test:startup:memory": "node --import tsx scripts/ensure-cli-startup-build.mts && node scripts/check-cli-startup-memory.mjs", - "test:ui": "pnpm lint:ui:no-raw-window-open && node --import tsx scripts/ensure-playwright-chromium.mts && pnpm --dir ui test", - "test:ui:e2e": "node --import tsx scripts/ensure-playwright-chromium.mts && node scripts/run-vitest.mjs run --config test/vitest/vitest.ui-e2e.config.ts --configLoader runner", + "test:plugins:kitchen-sink-rpc": "node --import ./scripts/tsx.mjs scripts/e2e/kitchen-sink-rpc-walk.mts", + "test:sectriage": "node --import ./scripts/tsx.mjs scripts/run-with-env.mts OPENCLAW_GATEWAY_PROJECT_SHARDS=1 -- node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway.config.ts && node scripts/run-vitest.mjs run --config test/vitest/vitest.unit.config.ts --exclude src/process/exec.test.ts", + "test:serial": "node --import ./scripts/tsx.mjs scripts/test-projects-serial.mts", + "test:stability:gateway": "node --import ./scripts/tsx.mjs scripts/run-with-env.mts OPENCLAW_VITEST_MAX_WORKERS=1 -- node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway.config.ts src/gateway/gateway-stability.test.ts && node --import ./scripts/tsx.mjs scripts/run-with-env.mts OPENCLAW_VITEST_MAX_WORKERS=1 -- node scripts/run-vitest.mjs run --config test/vitest/vitest.logging.config.ts src/logging/diagnostic-stability-bundle.test.ts && node --import ./scripts/tsx.mjs scripts/run-with-env.mts OPENCLAW_VITEST_MAX_WORKERS=1 -- node scripts/run-vitest.mjs run --config test/vitest/vitest.infra.config.ts src/infra/fatal-error-hooks.test.ts", + "test:cli-response:contract": "node --import ./scripts/tsx.mjs scripts/build-all.mts cliStartup && node --import ./scripts/tsx.mjs scripts/test-cli-startup-bench-budget.mts --preset response --runs 1 --warmup 0 --timeout-ms 10000 --skip-baseline", + "test:startup:bench": "node --import ./scripts/tsx.mjs scripts/bench-cli-startup.ts", + "test:startup:bench:check": "node --import ./scripts/tsx.mjs scripts/test-cli-startup-bench-budget.mts", + "test:startup:bench:save": "node --import ./scripts/tsx.mjs scripts/bench-cli-startup.ts --preset all --runs 5 --warmup 1 --output .artifacts/cli-startup-bench-all.json", + "test:startup:bench:smoke": "node --import ./scripts/tsx.mjs scripts/ensure-cli-startup-build.mts && node --import ./scripts/tsx.mjs scripts/bench-cli-startup.ts --preset real --case gatewayStatusJson --runs 1 --warmup 0 --output .artifacts/cli-startup-bench-smoke.json", + "test:startup:bench:update": "node --import ./scripts/tsx.mjs scripts/test-update-cli-startup-bench.mts", + "test:startup:gateway": "node --import ./scripts/tsx.mjs scripts/bench-gateway-startup.ts", + "test:restart:gateway": "node --import ./scripts/tsx.mjs scripts/bench-gateway-restart.ts", + "test:sessions:hydration-memory": "node --import ./scripts/tsx.mjs scripts/bench-session-manager-hydration-memory.ts", + "test:startup:memory": "node --import ./scripts/tsx.mjs scripts/ensure-cli-startup-build.mts && node scripts/check-cli-startup-memory.mjs", + "test:ui": "pnpm lint:ui:no-raw-window-open && node --import ./scripts/tsx.mjs scripts/ensure-playwright-chromium.mts && pnpm --dir ui test", + "test:ui:e2e": "node --import ./scripts/tsx.mjs scripts/ensure-playwright-chromium.mts && node scripts/run-vitest.mjs run --config test/vitest/vitest.ui-e2e.config.ts --configLoader runner", "test:unit": "pnpm test:unit:fast && node scripts/run-vitest.mjs run --config test/vitest/vitest.unit.config.ts", "test:unit:fast": "node scripts/run-vitest.mjs run --config test/vitest/vitest.unit-fast.config.ts", - "test:unit:fast:audit": "node --import tsx scripts/test-unit-fast-audit.mts", - "test:voicecall:closedloop": "node --import tsx scripts/test-voicecall-closedloop.mts", - "test:watch": "node --import tsx scripts/test-projects.mts --watch", + "test:unit:fast:audit": "node --import ./scripts/tsx.mjs scripts/test-unit-fast-audit.mts", + "test:voicecall:closedloop": "node --import ./scripts/tsx.mjs scripts/test-voicecall-closedloop.mts", + "test:watch": "node --import ./scripts/tsx.mjs scripts/test-projects.mts --watch", "test:windows:ci": "pnpm test:windows:ci:1 && pnpm test:windows:ci:2", - "test:windows:ci:1": "node --import tsx scripts/test-projects.mts src/state/openclaw-state-ownership.test.ts src/snapshot/local-repository.windows.test.ts src/state/openclaw-database-paths.windows.test.ts src/node-host/invoke-system-run-allowlist.test.ts src/node-host/node-worker-transfer-client.test.ts packages/terminal-core/src/display-string.test.ts src/config/sessions/session-accessor.sqlite-archive.worker.test.ts src/commands/doctor-gateway-auth-token.windows.test.ts src/infra/state-migrations.audit-logs.windows.test.ts src/commands/backup-verify.test.ts src/commands/agents.commands.list.test.ts src/shared/runtime-import.test.ts src/shared/worker-bundle-archive.test.ts src/node-host/node-worker-bundle-installer.test.ts test/scripts/direct-run-entrypoints.test.ts test/scripts/format-generated-module.test.ts test/scripts/openclaw-cross-os-installer.windows.test.ts test/scripts/openclaw-cross-os-release-workflow.test.ts test/scripts/pnpm-runner.test.ts test/scripts/run-with-env.test.ts test/scripts/ui.test.ts test/scripts/vitest-process-group.test.ts src/agents/tools/media-tool-file-url.windows.test.ts extensions/memory-core/src/memory-extra-file-path.windows.test.ts src/daemon/schtasks.startup-fallback.test.ts src/plugin-sdk/node-host.test.ts test/e2e/qa-lab/runtime/package-openclaw-for-docker.e2e.test.ts extensions/lobster/src/lobster-runner.test.ts src/gateway/worker-environments/workspace-quiescence.windows.test.ts", - "test:windows:ci:2": "node --import tsx scripts/test-projects.mts src/infra/sqlite-snapshot.test.ts src/infra/ports.test.ts src/infra/advertised-lan-host.windows.test.ts src/infra/update-managed-service-handoff-command.test.ts src/infra/update-managed-service-handoff-lifecycle.test.ts src/infra/executable-path.test.ts src/infra/fs-safe-remove.test.ts src/infra/state-migrations.legacy-session-store.test.ts src/infra/windows-install-roots.test.ts src/infra/ssh-client.windows.test.ts src/infra/exec-allowlist-pattern.test.ts src/infra/process-env.test.ts src/agents/sessions/windows-git-bash-path.test.ts test/scripts/npm-runner.test.ts test/scripts/ts-topology.test.ts src/test-utils/openclaw-test-state.test.ts src/utils.test.ts src/media/local-media-path.windows.test.ts src/media/web-media.file-url.windows.test.ts src/process/exec.windows.test.ts src/process/exec.windows.integration.test.ts src/agents/sessions/exec.real.test.ts src/process/windows-command.test.ts src/process/terminal-pty.test.ts src/process/supervisor/supervisor.anchored-shell.real.test.ts src/tui/tui.resolve-codex-bin.test.ts src/media-understanding/attachments.file-url.windows.test.ts src/cli/daemon-cli/status.print.test.ts src/cli/mcp-cli.path-case.windows.test.ts src/auto-reply/usage-bar/template.windows.test.ts src/auto-reply/reply.triggers.trigger-handling.stages-inbound-media-into-sandbox-workspace.test.ts src/agents/provider-local-service.env-case.test.ts src/agents/bash-tools.exec.script-preflight.test.ts src/agents/agent-tools.read.windows.test.ts src/agents/agent-tools.read.host-operations.test.ts src/agents/sandbox/fs-paths.test.ts src/agents/sessions/tools/render-utils.test.ts src/agents/sessions/tools/path-utils.test.ts extensions/msteams/src/media-helpers.test.ts extensions/msteams/src/messenger.test.ts extensions/mxc/test/mxc-backend.test.ts extensions/mxc/test/sandbox-policy-loader.test.ts", - "test:windows:schtasks:integration": "node --import tsx scripts/run-with-env.mts CI_WINDOWS_SCHTASKS_INTEGRATION=1 OPENCLAW_E2E_SKIP_BUILD=1 OPENCLAW_E2E_VERBOSE=1 OPENCLAW_VITEST_MAX_WORKERS=1 -- node scripts/run-vitest.mjs src/daemon/schtasks.integration.e2e.test.ts", - "tool-display:check": "node --import tsx scripts/tool-display.ts --check", - "tool-display:write": "node --import tsx scripts/tool-display.ts --write", - "ts-topology": "node --import tsx scripts/ts-topology.ts", + "test:windows:ci:1": "node --import ./scripts/tsx.mjs scripts/test-projects.mts src/state/openclaw-state-ownership.test.ts src/snapshot/local-repository.windows.test.ts src/state/openclaw-database-paths.windows.test.ts src/node-host/invoke-system-run-allowlist.test.ts src/node-host/node-worker-transfer-client.test.ts packages/terminal-core/src/display-string.test.ts src/config/sessions/session-accessor.sqlite-archive.worker.test.ts src/commands/doctor-gateway-auth-token.windows.test.ts src/infra/state-migrations.audit-logs.windows.test.ts src/commands/backup-verify.test.ts src/commands/agents.commands.list.test.ts src/shared/runtime-import.test.ts src/shared/worker-bundle-archive.test.ts src/node-host/node-worker-bundle-installer.test.ts test/scripts/direct-run-entrypoints.test.ts test/scripts/format-generated-module.test.ts test/scripts/openclaw-cross-os-installer.windows.test.ts test/scripts/openclaw-cross-os-release-workflow.test.ts test/scripts/pnpm-runner.test.ts test/scripts/run-with-env.test.ts test/scripts/ui.test.ts test/scripts/vitest-process-group.test.ts src/agents/tools/media-tool-file-url.windows.test.ts extensions/memory-core/src/memory-extra-file-path.windows.test.ts src/daemon/schtasks.startup-fallback.test.ts src/plugin-sdk/node-host.test.ts test/e2e/qa-lab/runtime/package-openclaw-for-docker.e2e.test.ts extensions/lobster/src/lobster-runner.test.ts src/gateway/worker-environments/workspace-quiescence.windows.test.ts", + "test:windows:ci:2": "node --import ./scripts/tsx.mjs scripts/test-projects.mts src/infra/sqlite-snapshot.test.ts src/infra/ports.test.ts src/infra/advertised-lan-host.windows.test.ts src/infra/update-managed-service-handoff-command.test.ts src/infra/update-managed-service-handoff-lifecycle.test.ts src/infra/executable-path.test.ts src/infra/fs-safe-remove.test.ts src/infra/state-migrations.legacy-session-store.test.ts src/infra/windows-install-roots.test.ts src/infra/ssh-client.windows.test.ts src/infra/exec-allowlist-pattern.test.ts src/infra/process-env.test.ts src/agents/sessions/windows-git-bash-path.test.ts test/scripts/npm-runner.test.ts test/scripts/ts-topology.test.ts src/test-utils/openclaw-test-state.test.ts src/utils.test.ts src/media/local-media-path.windows.test.ts src/media/web-media.file-url.windows.test.ts src/process/exec.windows.test.ts src/process/exec.windows.integration.test.ts src/agents/sessions/exec.real.test.ts src/process/windows-command.test.ts src/process/terminal-pty.test.ts src/process/supervisor/supervisor.anchored-shell.real.test.ts src/tui/tui.resolve-codex-bin.test.ts src/media-understanding/attachments.file-url.windows.test.ts src/cli/daemon-cli/status.print.test.ts src/cli/mcp-cli.path-case.windows.test.ts src/auto-reply/usage-bar/template.windows.test.ts src/auto-reply/reply.triggers.trigger-handling.stages-inbound-media-into-sandbox-workspace.test.ts src/agents/provider-local-service.env-case.test.ts src/agents/bash-tools.exec.script-preflight.test.ts src/agents/agent-tools.read.windows.test.ts src/agents/agent-tools.read.host-operations.test.ts src/agents/sandbox/fs-paths.test.ts src/agents/sessions/tools/render-utils.test.ts src/agents/sessions/tools/path-utils.test.ts extensions/msteams/src/media-helpers.test.ts extensions/msteams/src/messenger.test.ts extensions/mxc/test/mxc-backend.test.ts extensions/mxc/test/sandbox-policy-loader.test.ts", + "test:windows:schtasks:integration": "node --import ./scripts/tsx.mjs scripts/run-with-env.mts CI_WINDOWS_SCHTASKS_INTEGRATION=1 OPENCLAW_E2E_SKIP_BUILD=1 OPENCLAW_E2E_VERBOSE=1 OPENCLAW_VITEST_MAX_WORKERS=1 -- node scripts/run-vitest.mjs src/daemon/schtasks.integration.e2e.test.ts", + "tool-display:check": "node --import ./scripts/tsx.mjs scripts/tool-display.ts --check", + "tool-display:write": "node --import ./scripts/tsx.mjs scripts/tool-display.ts --write", + "ts-topology": "node --import ./scripts/tsx.mjs scripts/ts-topology.ts", "tsgo": "pnpm tsgo:core", "tsgo:all": "pnpm tsgo:core:all && pnpm tsgo:extensions:all && pnpm tsgo:scripts && pnpm tsgo:test:root", "tsgo:core": "node scripts/run-tsgo.mjs -p tsconfig.core.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core.tsbuildinfo", @@ -1994,7 +1994,7 @@ "tsgo:extensions:all": "node scripts/run-tsgo.mjs -b tsconfig.extensions.projects.json", "tsgo:extensions:test": "node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.extensions.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions-test.tsbuildinfo", "tsgo:prod": "pnpm tsgo:core && pnpm tsgo:ui && pnpm tsgo:extensions", - "tsgo:profile": "node --import tsx scripts/profile-tsgo.mts", + "tsgo:profile": "node --import ./scripts/tsx.mjs scripts/profile-tsgo.mts", "tsgo:scripts": "node scripts/run-tsgo.mjs -p tsconfig.scripts.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/scripts.tsbuildinfo", "tsgo:test": "pnpm tsgo:core:test && pnpm tsgo:extensions:test && pnpm tsgo:test:root", "tsgo:test:extensions": "pnpm tsgo:extensions:test", @@ -2004,32 +2004,32 @@ "tsgo:test:ui": "node scripts/run-tsgo-core-test-shards.mjs ui", "tsgo:ui": "node scripts/run-tsgo.mjs -p tsconfig.ui.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/ui.tsbuildinfo", "tui": "node scripts/run-node.mjs tui", - "tui:dev": "node --import tsx scripts/run-with-env.mts OPENCLAW_PROFILE=dev -- node scripts/run-node.mjs --dev tui", - "tui:pty:test:watch": "node --import tsx scripts/dev/tui-pty-test-watch.ts", - "tui:pty:test:watch:all": "node --import tsx scripts/dev/tui-pty-test-watch.ts --mode all", - "tui:pty:test:watch:fake": "node --import tsx scripts/dev/tui-pty-test-watch.ts --mode fake", - "tui:pty:test:watch:local": "node --import tsx scripts/dev/tui-pty-test-watch.ts --mode local", - "ui:boot-manifest:gen": "node --import tsx scripts/control-ui-boot-manifest.mts", + "tui:dev": "node --import ./scripts/tsx.mjs scripts/run-with-env.mts OPENCLAW_PROFILE=dev -- node scripts/run-node.mjs --dev tui", + "tui:pty:test:watch": "node --import ./scripts/tsx.mjs scripts/dev/tui-pty-test-watch.ts", + "tui:pty:test:watch:all": "node --import ./scripts/tsx.mjs scripts/dev/tui-pty-test-watch.ts --mode all", + "tui:pty:test:watch:fake": "node --import ./scripts/tsx.mjs scripts/dev/tui-pty-test-watch.ts --mode fake", + "tui:pty:test:watch:local": "node --import ./scripts/tsx.mjs scripts/dev/tui-pty-test-watch.ts --mode local", + "ui:boot-manifest:gen": "node --import ./scripts/tsx.mjs scripts/control-ui-boot-manifest.mts", "ui:build": "node scripts/ui.js build", "ui:dev": "node scripts/ui.js dev", - "ui:i18n:baseline": "node --import tsx scripts/control-ui-i18n-verify.ts baseline", - "ui:i18n:check": "node --import tsx scripts/control-ui-i18n.ts check", - "ui:i18n:report": "node --import tsx scripts/control-ui-i18n-report.ts", - "ui:i18n:sync": "node --import tsx scripts/control-ui-i18n.ts sync --write", - "ui:i18n:verify": "node --import tsx scripts/control-ui-i18n-verify.ts verify", - "ui:proof:composer-mic-hover": "node --import tsx scripts/capture-composer-mic-hover-proof.mts", - "ui:proof:injected-turn-notice": "node --import tsx scripts/capture-injected-turn-notice-proof.mts", - "ui:proof:model-picker": "node --import tsx scripts/capture-model-picker-proof.mts", - "ui:proof:session-toolbar": "node --import tsx scripts/capture-session-toolbar-proof.mts", - "ui:proof:workboard": "node --import tsx scripts/capture-workboard-ui-proof.mts", - "native:i18n:baseline": "node --import tsx scripts/native-app-i18n.ts baseline --write", - "native:i18n:check": "node --import tsx scripts/native-app-i18n.ts check", - "native:i18n:sync": "node --import tsx scripts/native-app-i18n.ts sync --write", - "native:i18n:verify": "node --import tsx scripts/native-app-i18n.ts verify", - "android:i18n:check": "node --import tsx scripts/android-app-i18n.ts check", - "apple:i18n:check": "node --import tsx scripts/apple-app-i18n.ts check", + "ui:i18n:baseline": "node --import ./scripts/tsx.mjs scripts/control-ui-i18n-verify.ts baseline", + "ui:i18n:check": "node --import ./scripts/tsx.mjs scripts/control-ui-i18n.ts check", + "ui:i18n:report": "node --import ./scripts/tsx.mjs scripts/control-ui-i18n-report.ts", + "ui:i18n:sync": "node --import ./scripts/tsx.mjs scripts/control-ui-i18n.ts sync --write", + "ui:i18n:verify": "node --import ./scripts/tsx.mjs scripts/control-ui-i18n-verify.ts verify", + "ui:proof:composer-mic-hover": "node --import ./scripts/tsx.mjs scripts/capture-composer-mic-hover-proof.mts", + "ui:proof:injected-turn-notice": "node --import ./scripts/tsx.mjs scripts/capture-injected-turn-notice-proof.mts", + "ui:proof:model-picker": "node --import ./scripts/tsx.mjs scripts/capture-model-picker-proof.mts", + "ui:proof:session-toolbar": "node --import ./scripts/tsx.mjs scripts/capture-session-toolbar-proof.mts", + "ui:proof:workboard": "node --import ./scripts/tsx.mjs scripts/capture-workboard-ui-proof.mts", + "native:i18n:baseline": "node --import ./scripts/tsx.mjs scripts/native-app-i18n.ts baseline --write", + "native:i18n:check": "node --import ./scripts/tsx.mjs scripts/native-app-i18n.ts check", + "native:i18n:sync": "node --import ./scripts/tsx.mjs scripts/native-app-i18n.ts sync --write", + "native:i18n:verify": "node --import ./scripts/tsx.mjs scripts/native-app-i18n.ts verify", + "android:i18n:check": "node --import ./scripts/tsx.mjs scripts/android-app-i18n.ts check", + "apple:i18n:check": "node --import ./scripts/tsx.mjs scripts/apple-app-i18n.ts check", "ui:install": "node scripts/ui.js install", - "verify": "node --import tsx scripts/verify.mts" + "verify": "node --import ./scripts/tsx.mjs scripts/verify.mts" }, "dependencies": { "@agentclientprotocol/sdk": "1.3.0", diff --git a/scripts/ci-changed-scope.mjs b/scripts/ci-changed-scope.mjs index 9fdbebab8876..f8dd637d34c1 100644 --- a/scripts/ci-changed-scope.mjs +++ b/scripts/ci-changed-scope.mjs @@ -62,7 +62,7 @@ const WINDOWS_SQLITE_SCOPE_RE = /^src\/(?:state\/|.*sqlite.*\.ts$)/; const WINDOWS_FILE_URL_SCOPE_RE = /^(?:src\/agents\/tools\/(?:media-tool-file-url\.windows\.test|media-tool-shared(?:\.test)?|pdf-tool(?:\.test)?)|src\/auto-reply\/(?:reply\/stage-sandbox-media|reply\.triggers\.trigger-handling\.stages-inbound-media-into-sandbox-workspace\.test)|src\/media\/(?:local-media-path(?:\.windows\.test)?|local-roots(?:\.test)?|web-media(?:\.file-url\.windows\.test)?)|src\/channels\/inbound-event\/media(?:\.test)?|src\/gateway\/managed-image-attachments(?:\.test)?|extensions\/msteams\/src\/(?:media-helpers|messenger)(?:\.test)?)\.ts$/; const WINDOWS_SCOPE_RE = - /^(extensions\/mxc\/|src\/agents\/(?:bash-tools\.exec-script-(?:preflight|target)|bash-tools\.exec\.script-preflight\.test)\.ts$|src\/config\/sessions\/(?:session-accessor\.sqlite-archive(?:\.worker(?:\.test)?)?|store\.session-lifecycle-mutation\.test)\.ts$|src\/process\/|src\/infra\/(?:(?:advertised-lan-host|exec-allowlist-pattern|fs-safe-remove)(?:\.windows)?(?:\.test)?|ports(?:-inspect|\.test)|ssh-client(?:\.windows\.test)?|update-managed-service-handoff(?:-(?:command|lifecycle)\.test)?|windows-install-roots)\.ts$|src\/shared\/(?:import-specifier|runtime-import)(?:\.test)?\.ts$|src\/test-utils\/openclaw-test-state(?:\.test)?\.ts$|scripts\/(?:android-(?:app-i18n|pin-version)\.ts|ci-run-timings\.mjs|e2e\/lib\/package-compat\.mjs|generate-bundled-channel-config-metadata\.ts|install\.ps1|openclaw-cross-os-release-checks\.ts|plan-release-workflow-matrix\.mjs|run-additional-boundary-checks\.mts|verify-docker-attestations\.mjs|github\/run-openclaw-cross-os-release-checks\.sh|(?:npm-runner|pnpm-runner|ui|vitest-process-group)\.(?:mjs|mts|js)|lib\/(?:direct-run\.(?:mjs|mts)|format-generated-module\.mts|tsx-cli-shim\.mjs|cross-os-release-checks\/[^/]+\.ts))$|test\/scripts\/(?:direct-run-entrypoints|format-generated-module|install-ps1|npm-runner|openclaw-cross-os-release-workflow|pnpm-runner|ui|vitest-process-group)\.test\.ts$|package\.json$|pnpm-lock\.yaml$|pnpm-workspace\.yaml$|\.github\/workflows\/(?:ci|openclaw-cross-os-release-checks-reusable)\.yml$|\.github\/actions\/setup-node-env\/action\.yml$|\.github\/actions\/setup-pnpm-store-cache\/action\.yml$)/; + /^(extensions\/mxc\/|src\/agents\/(?:bash-tools\.exec-script-(?:preflight|target)|bash-tools\.exec\.script-preflight\.test)\.ts$|src\/config\/sessions\/(?:session-accessor\.sqlite-archive(?:\.worker(?:\.test)?)?|store\.session-lifecycle-mutation\.test)\.ts$|src\/process\/|src\/infra\/(?:(?:advertised-lan-host|exec-allowlist-pattern|fs-safe-remove)(?:\.windows)?(?:\.test)?|ports(?:-inspect|\.test)|ssh-client(?:\.windows\.test)?|update-managed-service-handoff(?:-(?:command|lifecycle)\.test)?|windows-install-roots)\.ts$|src\/shared\/(?:import-specifier|runtime-import)(?:\.test)?\.ts$|src\/test-utils\/openclaw-test-state(?:\.test)?\.ts$|scripts\/(?:android-(?:app-i18n|pin-version)\.ts|ci-run-timings\.mjs|e2e\/lib\/package-compat\.mjs|generate-bundled-channel-config-metadata\.ts|install\.ps1|openclaw-cross-os-release-checks\.ts|plan-release-workflow-matrix\.mjs|run-additional-boundary-checks\.mts|verify-docker-attestations\.mjs|github\/run-openclaw-cross-os-release-checks\.sh|tsx\.mjs|(?:npm-runner|pnpm-runner|ui|vitest-process-group)\.(?:mjs|mts|js)|lib\/(?:direct-run\.(?:mjs|mts)|format-generated-module\.mts|tsx-cli-shim\.mjs|cross-os-release-checks\/[^/]+\.ts))$|test\/scripts\/(?:direct-run-entrypoints|format-generated-module|install-ps1|npm-runner|openclaw-cross-os-release-workflow|pnpm-runner|ui|vitest-process-group)\.test\.ts$|package\.json$|pnpm-lock\.yaml$|pnpm-workspace\.yaml$|\.github\/workflows\/(?:ci|openclaw-cross-os-release-checks-reusable)\.yml$|\.github\/actions\/setup-node-env\/action\.yml$|\.github\/actions\/setup-pnpm-store-cache\/action\.yml$)/; const WINDOWS_TEST_SCOPE_RE = /^(extensions\/mxc\/test\/(?:mxc-backend|sandbox-policy-loader)\.test\.ts$|src\/agents\/bash-tools\.exec\.script-preflight\.test\.ts$|src\/config\/sessions\/(?:session-accessor\.sqlite-archive\.worker|store\.session-lifecycle-mutation)\.test\.ts$|src\/process\/(?:exec\.windows|supervisor\/supervisor\.anchored-shell\.real|terminal-pty|windows-command)\.test\.ts$|src\/infra\/(?:advertised-lan-host(?:\.windows)?|exec-allowlist-pattern|fs-safe-remove|ports|ssh-client\.windows|update-managed-service-handoff-(?:command|lifecycle)|windows-install-roots)\.test\.ts$|src\/shared\/runtime-import\.test\.ts$|src\/state\/openclaw-database-paths\.windows\.test\.ts$|src\/test-utils\/openclaw-test-state\.test\.ts$|test\/scripts\/(?:direct-run-entrypoints|format-generated-module|npm-runner|openclaw-cross-os-release-workflow|pnpm-runner|ui|vitest-process-group)\.test\.ts$)/; const WINDOWS_SECRETREF_SCOPE_RE = diff --git a/scripts/docs-sync-publish.mjs b/scripts/docs-sync-publish.mjs index 896677bbea3c..28bf93a79ef1 100644 --- a/scripts/docs-sync-publish.mjs +++ b/scripts/docs-sync-publish.mjs @@ -37,6 +37,10 @@ const SYNC_SUPPORT_FILES = [ source: path.join(ROOT, "scripts", "lib", "local-check-runtime.mts"), target: path.join(".openclaw-sync", "lib", "local-check-runtime.mts"), }, + { + source: path.join(ROOT, "scripts", "tsx.mjs"), + target: path.join(".openclaw-sync", "tsx.mjs"), + }, { source: path.join(ROOT, "scripts", "lib", "mintlify-accordion.mjs"), target: path.join(".openclaw-sync", "lib", "mintlify-accordion.mjs"), diff --git a/scripts/lib/plugin-publication-candidates.ts b/scripts/lib/plugin-publication-candidates.ts index 7c6bc462f6ea..4c1bfbace6e9 100644 --- a/scripts/lib/plugin-publication-candidates.ts +++ b/scripts/lib/plugin-publication-candidates.ts @@ -31,6 +31,7 @@ export const PLUGIN_NPM_RELEASE_AUTHORITY_PATHS = [ "scripts/lib/plugin-npm-package-manifest.mts", "scripts/lib/plugin-npm-release.ts", "scripts/lib/tsx-cli-shim.mjs", + "scripts/tsx.mjs", "scripts/plugin-npm-publish.sh", "scripts/plugin-npm-release-check.ts", "scripts/plugin-npm-release-plan.ts", diff --git a/scripts/lib/tsx-cli-shim.mjs b/scripts/lib/tsx-cli-shim.mjs index c1a9a5fc5ef0..59456a5cab51 100644 --- a/scripts/lib/tsx-cli-shim.mjs +++ b/scripts/lib/tsx-cli-shim.mjs @@ -55,6 +55,14 @@ function resolveTsxImport(checkoutRoot) { throw resolutionError; } +export async function registerToolingTsx() { + // tsx indexes the entire shared disk cache before expiration, coupling startup + // to other checkouts' cache size. This flag retains its in-process Map and + // reaches descendant tooling before their loaders initialize. + process.env.TSX_DISABLE_CACHE = "1"; + await import(resolveTsxImport(SHIM_CHECKOUT_ROOT)); +} + function signalExitCode(signal) { const signalNumber = osConstants.signals[signal]; return typeof signalNumber === "number" ? 128 + signalNumber : 1; @@ -118,7 +126,7 @@ async function runTsxCliShimInner(moduleUrl, options) { try { const implementationUrl = new URL(options.implementation, moduleUrl); const implementationPath = fileURLToPath(implementationUrl); - const tsxImport = resolveTsxImport(SHIM_CHECKOUT_ROOT); + const tsxImport = new URL("../tsx.mjs", import.meta.url).href; const nodeExecutable = process.versions.bun ? "node" : process.execPath; child = spawn( nodeExecutable, diff --git a/scripts/pr b/scripts/pr index ac3076f3c8fd..e1aed87afec0 100755 --- a/scripts/pr +++ b/scripts/pr @@ -52,6 +52,7 @@ pr_wrapper_components=( scripts/lib/direct-run.mjs scripts/lib/tsx-cli-shim.mjs scripts/lib/local-check-runtime.mts + scripts/tsx.mjs scripts/verify-pr-hosted-gates.mjs scripts/verify-pr-hosted-gates.mts scripts/watch-pr-ci.mjs diff --git a/scripts/test-projects.test-support.mts b/scripts/test-projects.test-support.mts index dbfde136680f..a8edcc920571 100644 --- a/scripts/test-projects.test-support.mts +++ b/scripts/test-projects.test-support.mts @@ -2362,7 +2362,7 @@ const SEMANTIC_TOOLING_TARGET_PATTERNS: Array<[RegExp, string[]]> = [ [/^scripts\/ci-changed-scope\.mjs$/u, [...changedScopeTests, "control-ui-i18n"]], [/^scripts\/check-changed\.(?:mjs|mts)$/u, ["changed-lanes"]], [/^scripts\/changed-lanes\.(?:mjs|mts)$/u, ["changed-lanes"]], - [/^scripts\/lib\/tsx-cli-shim\.mjs$/u, ["direct-run-entrypoints"]], + [/^scripts\/(?:lib\/tsx-cli-shim|tsx)\.mjs$/u, ["direct-run-entrypoints"]], [ new RegExp( [ diff --git a/scripts/tsx.mjs b/scripts/tsx.mjs new file mode 100644 index 000000000000..5a77d5f15a20 --- /dev/null +++ b/scripts/tsx.mjs @@ -0,0 +1,14 @@ +import { registerToolingTsx } from "./lib/tsx-cli-shim.mjs"; + +// fork() inherits execArgv but can change cwd. Keep our root-script preload +// resolvable there without rewriting unrelated flags or other preloads. +const preload = "./scripts/tsx.mjs"; +for (const [index, arg] of process.execArgv.entries()) { + if (arg === preload && process.execArgv[index - 1] === "--import") { + process.execArgv[index] = import.meta.url; + } else if (arg === `--import=${preload}`) { + process.execArgv[index] = `--import=${import.meta.url}`; + } +} + +await registerToolingTsx(); diff --git a/src/infra/vitest-config.test.ts b/src/infra/vitest-config.test.ts index 8a96f2c28415..9e001c7548a9 100644 --- a/src/infra/vitest-config.test.ts +++ b/src/infra/vitest-config.test.ts @@ -253,16 +253,20 @@ describe("test scripts", () => { scripts?: Record; }; - expect(pkg.scripts?.["test:serial"]).toBe("node --import tsx scripts/test-projects-serial.mts"); - expect(pkg.scripts?.["test:max"]).toBe("node --import tsx scripts/test-projects-max.mts"); + expect(pkg.scripts?.["test:serial"]).toBe( + "node --import ./scripts/tsx.mjs scripts/test-projects-serial.mts", + ); + expect(pkg.scripts?.["test:max"]).toBe( + "node --import ./scripts/tsx.mjs scripts/test-projects-max.mts", + ); expect(pkg.scripts?.["test:changed:max"]).toBe( - "node --import tsx scripts/test-projects-max.mts --changed origin/main", + "node --import ./scripts/tsx.mjs scripts/test-projects-max.mts --changed origin/main", ); expect(pkg.scripts?.["test:perf:imports"]).toBe( - "node --import tsx scripts/test-projects-imports.mts", + "node --import ./scripts/tsx.mjs scripts/test-projects-imports.mts", ); expect(pkg.scripts?.["test:perf:imports:changed"]).toBe( - "node --import tsx scripts/test-projects-imports.mts --changed origin/main", + "node --import ./scripts/tsx.mjs scripts/test-projects-imports.mts --changed origin/main", ); expect(pkg.scripts?.["test:fast"]).toBe( "node scripts/run-vitest.mjs run --config test/vitest/vitest.unit.config.ts", @@ -274,12 +278,14 @@ describe("test scripts", () => { "node scripts/run-vitest.mjs run --config test/vitest/vitest.unit-fast.config.ts", ); expect(pkg.scripts?.["test:unit:fast:audit"]).toBe( - "node --import tsx scripts/test-unit-fast-audit.mts", + "node --import ./scripts/tsx.mjs scripts/test-unit-fast-audit.mts", + ); + expect(pkg.scripts?.["test"]).toBe("node --import ./scripts/tsx.mjs scripts/test-projects.mts"); + expect(pkg.scripts?.["test:force"]).toBe( + "node --import ./scripts/tsx.mjs scripts/test-force.ts", ); - expect(pkg.scripts?.["test"]).toBe("node --import tsx scripts/test-projects.mts"); - expect(pkg.scripts?.["test:force"]).toBe("node --import tsx scripts/test-force.ts"); expect(pkg.scripts?.["test:gateway"]).toBe( - "node --import tsx scripts/run-with-env.mts OPENCLAW_GATEWAY_PROJECT_SHARDS=1 -- node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway.config.ts", + "node --import ./scripts/tsx.mjs scripts/run-with-env.mts OPENCLAW_GATEWAY_PROJECT_SHARDS=1 -- node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway.config.ts", ); expect(pkg.scripts?.["test:single"]).toBeUndefined(); }); diff --git a/test/package-scripts.test.ts b/test/package-scripts.test.ts index 326c05338334..10a3ed41a0ac 100644 --- a/test/package-scripts.test.ts +++ b/test/package-scripts.test.ts @@ -98,7 +98,7 @@ describe("package scripts", () => { it("finds node script targets after env assignments and valued node options", () => { expect( extractNodeScriptTargets( - "FOO=1 node --import tsx scripts/release-check.ts && node --max-old-space-size=8192 --import tsx scripts/plugin-sdk-surface-report.mts && env BAR=1 node -r tsx scripts/check.ts", + "FOO=1 node --import ./scripts/tsx.mjs scripts/release-check.ts && node --max-old-space-size=8192 --import ./scripts/tsx.mjs scripts/plugin-sdk-surface-report.mts && env BAR=1 node -r ./preload.cjs scripts/check.ts", ), ).toEqual([ "scripts/release-check.ts", @@ -142,31 +142,36 @@ describe("package scripts", () => { { scriptName: "build:docker", expectedCount: 2 }, { scriptName: "build:plugin-sdk:strict-smoke", expectedCount: 1 }, { scriptName: "build:strict-smoke", expectedCount: 1 }, - ])("runs TypeScript steps in $scriptName through tsx", ({ scriptName, expectedCount }) => { - const script = expectDefined( - readPackageJson().scripts[scriptName], - `package script ${scriptName}`, - ); + ])( + "runs TypeScript steps in $scriptName through the tooling bootstrap", + ({ scriptName, expectedCount }) => { + const script = expectDefined( + readPackageJson().scripts[scriptName], + `package script ${scriptName}`, + ); - expect(script).not.toContain("--experimental-strip-types"); - expect(script.match(/node --import tsx scripts\/[^\s]+\.ts/gu)).toHaveLength(expectedCount); - }); + expect(script).not.toContain("--experimental-strip-types"); + expect( + script.match(/node --import \.\/scripts\/tsx\.mjs scripts\/[^\s]+\.ts(?=\s|$)/gu), + ).toHaveLength(expectedCount); + }, + ); it("enables live cache validation in the package script", () => { expect(readPackageJson().scripts["test:live:cache"]).toBe( - "node --import tsx scripts/run-with-env.mts OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_CACHE_TEST=1 -- node --import tsx scripts/check-live-cache.ts", + "node --import ./scripts/tsx.mjs scripts/run-with-env.mts OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_CACHE_TEST=1 -- node --import ./scripts/tsx.mjs scripts/check-live-cache.ts", ); }); it("runs browser extension bootstrap E2E against real Chromium", () => { expect(readPackageJson().scripts["test:e2e:browser-extension"]).toBe( - "node --import tsx scripts/run-with-env.mts PLAYWRIGHT_BROWSERS_PATH=.artifacts/playwright-browsers -- node --import tsx scripts/ensure-playwright-chromium.mts --require-playwright-chromium && node --import tsx scripts/run-with-env.mts PLAYWRIGHT_BROWSERS_PATH=.artifacts/playwright-browsers OPENCLAW_BROWSER_EXTENSION_E2E=1 OPENCLAW_E2E_WORKERS=1 -- node scripts/run-vitest.mjs extensions/browser/chrome-extension/bootstrap.chromium.test.ts", + "node --import ./scripts/tsx.mjs scripts/run-with-env.mts PLAYWRIGHT_BROWSERS_PATH=.artifacts/playwright-browsers -- node --import ./scripts/tsx.mjs scripts/ensure-playwright-chromium.mts --require-playwright-chromium && node --import ./scripts/tsx.mjs scripts/run-with-env.mts PLAYWRIGHT_BROWSERS_PATH=.artifacts/playwright-browsers OPENCLAW_BROWSER_EXTENSION_E2E=1 OPENCLAW_E2E_WORKERS=1 -- node scripts/run-vitest.mjs extensions/browser/chrome-extension/bootstrap.chromium.test.ts", ); }); it("gives the plugin SDK usage scan enough heap for repository-wide analysis", () => { expect(readPackageJson().scripts["plugin-sdk:usage"]).toBe( - "node --max-old-space-size=8192 --import tsx scripts/analyze-plugin-sdk-usage.ts", + "node --max-old-space-size=8192 --import ./scripts/tsx.mjs scripts/analyze-plugin-sdk-usage.ts", ); }); @@ -178,7 +183,7 @@ describe("package scripts", () => { it("runs runtime postbuild before plugin SDK strict export checks", () => { expect(readPackageJson().scripts["build:plugin-sdk:strict-smoke"]).toBe( - "node --import tsx scripts/tsdown-build.mts && node scripts/runtime-postbuild.mjs && node --import tsx scripts/run-with-env.mts OPENCLAW_PLUGIN_SDK_CANONICAL_DTS=1 -- node --import tsx scripts/write-plugin-sdk-entry-dts.ts && node --import tsx scripts/check-plugin-sdk-exports.mts", + "node --import ./scripts/tsx.mjs scripts/tsdown-build.mts && node scripts/runtime-postbuild.mjs && node --import ./scripts/tsx.mjs scripts/run-with-env.mts OPENCLAW_PLUGIN_SDK_CANONICAL_DTS=1 -- node --import ./scripts/tsx.mjs scripts/write-plugin-sdk-entry-dts.ts && node --import ./scripts/tsx.mjs scripts/check-plugin-sdk-exports.mts", ); }); @@ -196,9 +201,11 @@ describe("package scripts", () => { it("cleans package builds before validating release contents", () => { const scripts = readPackageJson().scripts; - expect(scripts["build:package"]).toBe("node --import tsx scripts/build-all.mts package"); + expect(scripts["build:package"]).toBe( + "node --import ./scripts/tsx.mjs scripts/build-all.mts package", + ); expect(scripts["release:check"]).toBe( - "pnpm build:package && pnpm release:generated:check && node --import tsx scripts/release-check.ts", + "pnpm build:package && pnpm release:generated:check && node --import ./scripts/tsx.mjs scripts/release-check.ts", ); }); diff --git a/test/plugin-npm-release.test.ts b/test/plugin-npm-release.test.ts index f3887082299c..4c9798e715be 100644 --- a/test/plugin-npm-release.test.ts +++ b/test/plugin-npm-release.test.ts @@ -833,6 +833,8 @@ describe("collectPluginNpmGitRangeSelection", () => { "packages/plugin-package-contract/src/schema.ts", "scripts/lib/plugin-publication-candidates.ts", "scripts/lib/plugin-publication-collector.ts", + "scripts/lib/tsx-cli-shim.mjs", + "scripts/tsx.mjs", "scripts/plugin-npm-release-plan.ts", ])("selects all publishable plugins for an authority-only %s change", (changedPath) => { const repoDir = makeTempRepoRoot(tempDirs, "openclaw-plugin-npm-range-"); diff --git a/test/scripts/direct-run-entrypoints.test.ts b/test/scripts/direct-run-entrypoints.test.ts index 63f00bd1fc74..9f562bb1e8b9 100644 --- a/test/scripts/direct-run-entrypoints.test.ts +++ b/test/scripts/direct-run-entrypoints.test.ts @@ -1,15 +1,19 @@ import { spawnSync } from "node:child_process"; import { copyFileSync, + existsSync, mkdirSync, mkdtempSync, readFileSync, + readdirSync, realpathSync, rmSync, writeFileSync, } from "node:fs"; -import { tmpdir } from "node:os"; +import { createRequire } from "node:module"; +import { tmpdir, userInfo } from "node:os"; import path from "node:path"; +import { pathToFileURL } from "node:url"; import { describe, expect, it } from "vitest"; import { detectChangedScope } from "../../scripts/ci-changed-scope.mjs"; import { isDirectRunPath } from "../../scripts/lib/direct-run.mjs"; @@ -109,12 +113,14 @@ function writeTsxFixture(modulesDir: string, marker: string) { writeFileSync(path.join(dependencyDir, "index.js"), 'export const value = "loaded";\n'); } -function runShimFixture( +function withShimFixture( wrapper: (typeof TSX_SHIM_WRAPPERS)[number], - configureModules: (paths: { + run: (paths: { checkoutRoot: string; fixtureRoot: string; - }) => ModulesEnv = () => ({}), + implementationPath: string; + wrapperPath: string; + }) => T, ) { const fixtureRoot = realpathSync(mkdtempSync(path.join(tmpdir(), "openclaw-tsx-cli-shim-"))); const checkoutRoot = path.join(fixtureRoot, "checkout"); @@ -124,6 +130,7 @@ function runShimFixture( mkdirSync(path.dirname(wrapperPath), { recursive: true }); mkdirSync(path.join(checkoutRoot, "scripts", "lib"), { recursive: true }); copyFileSync(wrapper, wrapperPath); + copyFileSync("scripts/tsx.mjs", path.join(checkoutRoot, "scripts", "tsx.mjs")); copyFileSync( "scripts/lib/tsx-cli-shim.mjs", path.join(checkoutRoot, "scripts", "lib", "tsx-cli-shim.mjs"), @@ -133,30 +140,45 @@ function runShimFixture( path.join(checkoutRoot, "scripts", "lib", "local-check-runtime.mts"), ); writeFileSync(path.join(checkoutRoot, "pnpm-lock.yaml"), "lockfileVersion: '9.0'\n"); - writeFileSync( - implementationPath, - 'import { value } from "shim-dependency";\nprocess.stdout.write(JSON.stringify({ loader: process.env.OPENCLAW_TSX_FIXTURE_LOADER, dependency: value, args: process.argv.slice(2) }));\n', - ); - writeTsxFixture(path.join(checkoutRoot, "node_modules"), "checkout"); - const modulesEnv = configureModules({ checkoutRoot, fixtureRoot }); - - const env = { ...process.env }; - delete env.NODE_OPTIONS; - delete env.NODE_PATH; - delete env.PNPM_CONFIG_MODULES_DIR; - delete env.npm_config_modules_dir; - Object.assign(env, modulesEnv); - return spawnSync(process.execPath, [wrapperPath, "--hydrated-proof"], { - cwd: fixtureRoot, - encoding: "utf8", - env, - timeout: 10_000, - }); + return run({ checkoutRoot, fixtureRoot, implementationPath, wrapperPath }); } finally { rmSync(fixtureRoot, { recursive: true, force: true }); } } +function runShimFixture( + wrapper: (typeof TSX_SHIM_WRAPPERS)[number], + configureModules: (paths: { + checkoutRoot: string; + fixtureRoot: string; + }) => ModulesEnv = () => ({}), +) { + return withShimFixture( + wrapper, + ({ checkoutRoot, fixtureRoot, implementationPath, wrapperPath }) => { + writeFileSync( + implementationPath, + 'import { value } from "shim-dependency";\nprocess.stdout.write(JSON.stringify({ loader: process.env.OPENCLAW_TSX_FIXTURE_LOADER, dependency: value, args: process.argv.slice(2) }));\n', + ); + writeTsxFixture(path.join(checkoutRoot, "node_modules"), "checkout"); + const modulesEnv = configureModules({ checkoutRoot, fixtureRoot }); + + const env = { ...process.env }; + delete env.NODE_OPTIONS; + delete env.NODE_PATH; + delete env.PNPM_CONFIG_MODULES_DIR; + delete env.npm_config_modules_dir; + Object.assign(env, modulesEnv); + return spawnSync(process.execPath, [wrapperPath, "--hydrated-proof"], { + cwd: fixtureRoot, + encoding: "utf8", + env, + timeout: 10_000, + }); + }, + ); +} + function expectShimLoader(result: ReturnType, loader: string) { expect(result.error).toBeUndefined(); expect(result.status, result.stderr).toBe(0); @@ -168,6 +190,217 @@ function expectShimLoader(result: ReturnType, loader: str } describe("script direct-run entrypoints", () => { + it.each([false, true])( + "preserves preloads when forking into another cwd (equals=%s)", + (equals) => { + withShimFixture(TSX_SHIM_WRAPPERS[0], ({ checkoutRoot, fixtureRoot, implementationPath }) => { + const forkCwd = path.join(fixtureRoot, "child cwd"); + mkdirSync(forkCwd); + const childPath = path.join(fixtureRoot, "fork-child.mts"); + const extraPreloadPath = path.join(fixtureRoot, "extra-preload.mjs"); + writeFileSync(extraPreloadPath, 'globalThis.fixturePreload = "preserved";\n'); + const snapshotSource = ` +enum Transformed { Value = "transformed" } +console.log(JSON.stringify({ transformed: Transformed.Value, preload: globalThis.fixturePreload, + args: process.argv.slice(2), cwd: process.cwd(), execArgv: process.execArgv })); +`; + writeFileSync(childPath, `${snapshotSource}\nprocess.exitCode = 17;\n`); + writeFileSync( + implementationPath, + `${snapshotSource} +import { fork } from "node:child_process"; +const child = fork(${JSON.stringify(childPath)}, process.argv.slice(2), { + cwd: ${JSON.stringify(forkCwd)}, stdio: "inherit", +}); +process.exitCode = await new Promise((resolve, reject) => { + child.once("error", reject); + child.once("exit", code => resolve(code ?? 1)); +}); +`, + ); + const nodeFlags = ["--no-warnings", "--import", pathToFileURL(extraPreloadPath).href]; + const trailingFlags = ["--title", "./scripts/tsx.mjs", "--import=node:fs"]; + const preload = equals ? ["--import=./scripts/tsx.mjs"] : ["--import", "./scripts/tsx.mjs"]; + const bootstrapUrl = pathToFileURL(path.join(checkoutRoot, "scripts/tsx.mjs")).href; + const expectedPreload = equals ? [`--import=${bootstrapUrl}`] : ["--import", bootstrapUrl]; + const env: NodeJS.ProcessEnv = { + ...process.env, + TMPDIR: fixtureRoot, + TMP: fixtureRoot, + TEMP: fixtureRoot, + PNPM_CONFIG_MODULES_DIR: path.dirname( + path.dirname(createRequire(import.meta.url).resolve("tsx/package.json")), + ), + }; + delete env.TSX_DISABLE_CACHE; + delete env.NODE_OPTIONS; + const result = spawnSync( + process.execPath, + [ + ...nodeFlags, + ...preload, + ...trailingFlags, + implementationPath, + "argument with spaces", + "--fork-proof", + ], + { + cwd: checkoutRoot, + encoding: "utf8", + env, + timeout: 10_000, + }, + ); + expect(result.error).toBeUndefined(); + expect(result.status, result.stderr).toBe(17); + expect( + result.stdout + .trim() + .split("\n") + .map((line) => JSON.parse(line)), + ).toEqual( + [checkoutRoot, forkCwd].map((cwd) => ({ + transformed: "transformed", + preload: "preserved", + args: ["argument with spaces", "--fork-proof"], + cwd, + execArgv: [...nodeFlags, ...expectedPreload, ...trailingFlags], + })), + ); + }); + }, + ); + + it.each(["wrapper", "root package preloads"])( + "keeps %s and raw tsx children off disk caches without changing other cache settings", + (entrypoint) => { + withShimFixture(TSX_SHIM_WRAPPERS[0], ({ fixtureRoot, implementationPath, wrapperPath }) => { + const require = createRequire(import.meta.url); + const modulesDir = path.dirname(path.dirname(require.resolve("tsx/package.json"))); + const tempRoot = path.join(fixtureRoot, "temp"); + const cacheRoots = ["tsx", `tsx-${process.geteuid?.() ?? userInfo().username}`].map( + (name) => path.join(tempRoot, name), + ); + for (const cacheRoot of cacheRoots) { + mkdirSync(cacheRoot, { recursive: true }); + writeFileSync(path.join(cacheRoot, "0-sentinel"), "keep"); + } + const accessLog = path.join(fixtureRoot, "cache-access.log"); + const guard = path.join(fixtureRoot, "cache-guard.cjs"); + writeFileSync( + guard, + ` +const fs = require("node:fs"); +const path = require("node:path"); +const readdirSync = fs.readdirSync; +fs.readdirSync = function (directory, ...args) { + if (/^tsx(?:-|$)/.test(path.basename(String(directory)))) { + fs.appendFileSync(${JSON.stringify(accessLog)}, "cache scan\\n"); + throw new Error("Unexpected tsx disk cache access"); + } + return readdirSync.call(this, directory, ...args); +}; +`, + ); + const preservedEnv = Object.fromEntries( + [ + "TMPDIR", + "TMP", + "TEMP", + "XDG_CACHE_HOME", + "NODE_COMPILE_CACHE", + "OPENCLAW_VITEST_FS_MODULE_CACHE_PATH", + ].map((key) => [ + key, + key === "TMPDIR" || key === "TEMP" ? tempRoot : path.join(fixtureRoot, key), + ]), + ); + const childPath = path.join(fixtureRoot, "child.mts"); + const snapshotSource = ` +enum Transformed { Value = "transformed" } +console.log(JSON.stringify({ + transformed: Transformed.Value, + args: process.argv.slice(2), + cwd: process.cwd(), + env: Object.fromEntries(${JSON.stringify(Object.keys(preservedEnv))}.map(key => [key, process.env[key]])), +})); +`; + writeFileSync(childPath, `${snapshotSource}\nprocess.exitCode = 17;\n`); + writeFileSync( + implementationPath, + `${snapshotSource} +import { spawnSync } from "node:child_process"; +const child = spawnSync(process.execPath, ["--import", "tsx", ${JSON.stringify(childPath)}, ...process.argv.slice(2)], { stdio: "inherit" }); +if (child.error) throw child.error; +process.exitCode = child.status ?? 1; +`, + ); + const { scripts } = JSON.parse(readFileSync("package.json", "utf8")) as { + scripts: Record; + }; + const preloads = [ + ...new Set( + Object.values(scripts).flatMap((command) => + [...command.matchAll(/--import(?:=|\s+)(\S+)/gu)].map((match) => match[1]!), + ), + ), + ]; + expect(preloads.length).toBeGreaterThan(0); + const launches = + entrypoint === "wrapper" + ? [[wrapperPath]] + : preloads.map((preload) => ["--import", preload, implementationPath]); + for (const cacheFlag of [undefined, ""]) { + const env: NodeJS.ProcessEnv = { + ...process.env, + ...preservedEnv, + PNPM_CONFIG_MODULES_DIR: modulesDir, + NODE_OPTIONS: `--require ${JSON.stringify(guard)}`, + }; + delete env.TSX_DISABLE_CACHE; + if (cacheFlag !== undefined) { + env.TSX_DISABLE_CACHE = cacheFlag; + } + for (const launch of launches) { + const result = spawnSync( + process.execPath, + [...launch, "argument with spaces", "--proof"], + { + cwd: process.cwd(), + encoding: "utf8", + env, + timeout: 10_000, + }, + ); + expect(result.error).toBeUndefined(); + expect(result.status, result.stderr).toBe(17); + expect( + result.stdout + .trim() + .split("\n") + .map((line) => JSON.parse(line)), + ).toEqual( + Array.from({ length: 2 }, () => ({ + transformed: "transformed", + args: ["argument with spaces", "--proof"], + cwd: process.cwd(), + env: preservedEnv, + })), + ); + if (entrypoint === "wrapper") { + expect(result.stderr.trim().split("\n").at(-1)).toBe("[test] FAILED (exit 17)"); + } + } + } + expect(existsSync(accessLog)).toBe(false); + for (const cacheRoot of cacheRoots) { + expect(readdirSync(cacheRoot)).toEqual(["0-sentinel"]); + expect(readFileSync(path.join(cacheRoot, "0-sentinel"), "utf8")).toBe("keep"); + } + }); + }, + ); + it.each(EXECUTABLE_ENTRYPOINTS)("runs $script through its guarded CLI", (entrypoint) => { const result = runEntrypoint(entrypoint); const output = `${result.stdout}${result.stderr}`; @@ -257,6 +490,7 @@ describe("script direct-run entrypoints", () => { "scripts/lib/direct-run.mjs", "scripts/lib/tsx-cli-shim.mjs", "test/scripts/direct-run-entrypoints.test.ts", + "scripts/tsx.mjs", ])("routes %s through Windows CI", (changedPath) => { expect(detectChangedScope([changedPath]).runWindows).toBe(true); }); diff --git a/test/scripts/docker-all-scheduler.test.ts b/test/scripts/docker-all-scheduler.test.ts index 7d184d85ca55..d1164d766b21 100644 --- a/test/scripts/docker-all-scheduler.test.ts +++ b/test/scripts/docker-all-scheduler.test.ts @@ -616,6 +616,7 @@ describe("scripts/test-docker-all scheduler", () => { copyFileSync("scripts/test-docker-all.mjs", path.join(scriptsDir, "test-docker-all.mjs")); copyFileSync("scripts/test-docker-all.mts", path.join(scriptsDir, "test-docker-all.mts")); copyFileSync("scripts/lib/tsx-cli-shim.mjs", path.join(libDir, "tsx-cli-shim.mjs")); + copyFileSync("scripts/tsx.mjs", path.join(scriptsDir, "tsx.mjs")); copyFileSync( "scripts/prepublish-plugin-registry-artifact.mjs", path.join(scriptsDir, "prepublish-plugin-registry-artifact.mjs"), diff --git a/test/scripts/package-acceptance-workflow.test.ts b/test/scripts/package-acceptance-workflow.test.ts index 16df52af1a70..788c26cfdcbe 100644 --- a/test/scripts/package-acceptance-workflow.test.ts +++ b/test/scripts/package-acceptance-workflow.test.ts @@ -7258,9 +7258,10 @@ describe("package artifact reuse", () => { const postpublishEvidence = workflowStep(releasePublishJob, "Upload postpublish evidence"); expect(packageJson.scripts).toMatchObject({ - "release:verify-beta": "node --import tsx scripts/release-verify-beta.ts", - "release:candidate": "node --import tsx scripts/release-candidate-checklist.mts", - "release:beta": "node --import tsx scripts/release-candidate-checklist.mts", + "release:verify-beta": "node --import ./scripts/tsx.mjs scripts/release-verify-beta.ts", + "release:candidate": + "node --import ./scripts/tsx.mjs scripts/release-candidate-checklist.mts", + "release:beta": "node --import ./scripts/tsx.mjs scripts/release-candidate-checklist.mts", "release:fast-pretag-check": "bash scripts/release-fast-pretag-check.sh", }); expect(workflowStep(releasePublishJob, "Setup Node environment").with).toMatchObject({ diff --git a/test/scripts/pr-operation-lock.test.ts b/test/scripts/pr-operation-lock.test.ts index 9e12cd250f78..358d300c184a 100644 --- a/test/scripts/pr-operation-lock.test.ts +++ b/test/scripts/pr-operation-lock.test.ts @@ -214,6 +214,7 @@ function installPrCliFixture(repoDir: string) { "scripts/lib/direct-run.mjs", "scripts/lib/tsx-cli-shim.mjs", "scripts/lib/local-check-runtime.mts", + "scripts/tsx.mjs", "scripts/pr-lib/worktree.sh", "scripts/pr-lib/operation-lock.sh", "scripts/pr-lib/process-group-runner.mjs", diff --git a/test/scripts/pr-wrappers.test.ts b/test/scripts/pr-wrappers.test.ts index 800d422a6e46..0fa64a89fd75 100644 --- a/test/scripts/pr-wrappers.test.ts +++ b/test/scripts/pr-wrappers.test.ts @@ -91,6 +91,7 @@ function makeMismatchedWrapperRepo() { "scripts/lib/local-check-runtime.mts", join(canonical, "scripts", "lib", "local-check-runtime.mts"), ); + cpSync("scripts/tsx.mjs", join(canonical, "scripts", "tsx.mjs")); writeFileSync( join(canonical, "scripts", "lib", "plain-gh.sh"), "resolve_plain_gh_bin() { printf '/usr/bin/true\\n'; }\ngh_plain() { :; }\n", @@ -205,6 +206,7 @@ describe("scripts/pr wrappers", () => { expect(script).toContain("scripts/verify-pr-hosted-gates.mjs"); expect(script).toContain("scripts/verify-pr-hosted-gates.mts"); expect(script).toContain("scripts/lib/tsx-cli-shim.mjs"); + expect(script).toContain("scripts/tsx.mjs"); expect(script).toContain("scripts/lib/plain-gh.mjs"); expect(script).toContain("scripts/lib/direct-run.mjs"); expect(script).toContain("scripts/pr review-init "); @@ -443,6 +445,7 @@ describe("scripts/pr wrappers", () => { writeFileSync(join(repo, "scripts", "lib", "direct-run.mjs"), "// canonical\n"); writeFileSync(join(repo, "scripts", "lib", "tsx-cli-shim.mjs"), "// canonical\n"); writeFileSync(join(repo, "scripts", "lib", "local-check-runtime.mts"), "// canonical\n"); + writeFileSync(join(repo, "scripts", "tsx.mjs"), "// canonical\n"); writeFileSync(join(repo, "scripts", "watch-pr-ci.mjs"), "// canonical\n"); writeFileSync(join(repo, "scripts", "watch-pr-ci.mts"), "// canonical\n"); writeFileSync(join(repo, "scripts", "verify-pr-hosted-gates.mjs"), "// canonical\n"); @@ -477,6 +480,17 @@ describe("scripts/pr wrappers", () => { expect(git(linked, ["restore", component]).status).toBe(0); } + writeFileSync(join(linked, "scripts", "tsx.mjs"), "// dirty preloader\n"); + const dirtyPreloaderResult = spawnSync(join(linked, "scripts", "pr"), ["ls"], { + cwd: linked, + encoding: "utf8", + }); + expect(dirtyPreloaderResult.status).toBe(1); + expect(dirtyPreloaderResult.stderr).toContain( + "scripts/pr wrapper files have uncommitted changes", + ); + expect(git(linked, ["restore", "scripts/tsx.mjs"]).status).toBe(0); + // A dirty canonical checkout no longer blocks a linked worktree whose // committed wrapper matches the origin/main trust anchor; without that // anchor it must still refuse. @@ -520,6 +534,7 @@ describe("scripts/pr wrappers", () => { writeFileSync(join(repo, "scripts", "lib", "direct-run.mjs"), "// canonical\n"); writeFileSync(join(repo, "scripts", "lib", "tsx-cli-shim.mjs"), "// canonical\n"); writeFileSync(join(repo, "scripts", "lib", "local-check-runtime.mts"), "// canonical\n"); + writeFileSync(join(repo, "scripts", "tsx.mjs"), "// canonical\n"); writeFileSync(join(repo, "scripts", "watch-pr-ci.mjs"), "// canonical\n"); writeFileSync(join(repo, "scripts", "watch-pr-ci.mts"), "// canonical\n"); writeFileSync(join(repo, "scripts", "verify-pr-hosted-gates.mjs"), "// canonical\n"); diff --git a/test/scripts/release-preflight.test.ts b/test/scripts/release-preflight.test.ts index 37015d654669..b2ec29896166 100644 --- a/test/scripts/release-preflight.test.ts +++ b/test/scripts/release-preflight.test.ts @@ -129,6 +129,7 @@ function makeIsolatedPreflightFixture(params: Parameters { ); }); - it("uses bounded parallelism for independent checks", () => { + it.each([1, 2, 3])("uses bounded parallelism for independent checks with jobs=%i", (jobs) => { const fakePnpm = makeFakePnpm(); const root = makeReleaseFixture(); - const env = { OPENCLAW_RELEASE_PREFLIGHT_DELAY_MS: "120" }; + const commands = [ + "pnpm config:schema:check", + "pnpm config:channels:check", + "pnpm config:docs:check", + ]; + const observerPath = join(root, "observe-concurrency.cjs"); + const resultPath = join(root, "concurrency.json"); + writeFileSync( + observerPath, + `const childProcess = require("node:child_process"); +const { writeFileSync } = require("node:fs"); +const { syncBuiltinESMExports } = require("node:module"); +const commands = ${JSON.stringify(commands)}; +const originalSpawn = childProcess.spawn; +let active = 0; +let maxActive = 0; +let total = 0; +childProcess.spawn = function (...args) { + const child = originalSpawn.apply(this, args); + if (commands.includes([args[0], ...(args[1] ?? [])].join(" "))) { + active += 1; + total += 1; + maxActive = Math.max(maxActive, active); + child.once("close", () => { active -= 1; }); + } + return child; +}; +syncBuiltinESMExports(); +process.once("exit", () => { + if (total > 0) { + writeFileSync(${JSON.stringify(resultPath)}, JSON.stringify({ maxActive, total, active })); + } +}); +`, + ); - const serialStartedAt = performance.now(); - const serial = runPreflight(["--scope", "config", "--jobs", "1"], fakePnpm, env, root); - const serialMs = performance.now() - serialStartedAt; + // Count real managed commands from synchronous admission through close, excluding + // loader startup time. Inherited observers with no matching commands write nothing. + const result = runPreflight( + ["--scope", "config", "--jobs", String(jobs)], + fakePnpm, + { + NODE_OPTIONS: `${process.env.NODE_OPTIONS ?? ""} --require ${JSON.stringify(observerPath)}`, + }, + root, + ); - const parallelStartedAt = performance.now(); - const parallel = runPreflight(["--scope", "config", "--jobs", "3"], fakePnpm, env, root); - const parallelMs = performance.now() - parallelStartedAt; - - expect(serial.status).toBe(0); - expect(parallel.status).toBe(0); - expect(parallelMs).toBeLessThan(serialMs * 0.75); + expect(result.status, result.stderr).toBe(0); + expect(JSON.parse(readFileSync(resultPath, "utf8"))).toEqual({ + maxActive: Math.min(jobs, commands.length), + total: commands.length, + active: 0, + }); + expect(readPnpmLog(fakePnpm.logPath).toSorted()).toEqual(commands.toSorted()); }); it("accepts base macOS metadata for a beta package version", () => { diff --git a/test/scripts/run-oxlint.test.ts b/test/scripts/run-oxlint.test.ts index 7a8cc56e4330..60e42e0dd94b 100644 --- a/test/scripts/run-oxlint.test.ts +++ b/test/scripts/run-oxlint.test.ts @@ -239,13 +239,13 @@ describe("run-oxlint", () => { }; const shardedLintRunner = readFileSync("scripts/run-oxlint-shards.mts", "utf8"); - expect(packageJson.scripts.check).toBe("node --import tsx scripts/check.mts"); - expect(packageJson.scripts.lint).toBe("node --import tsx scripts/run-lint.mts"); + expect(packageJson.scripts.check).toBe("node --import ./scripts/tsx.mjs scripts/check.mts"); + expect(packageJson.scripts.lint).toBe("node --import ./scripts/tsx.mjs scripts/run-lint.mts"); expect(packageJson.scripts["lint:core"]).toBe( - "node --import tsx scripts/run-oxlint-shards.mts --only=core", + "node --import ./scripts/tsx.mjs scripts/run-oxlint-shards.mts --only=core", ); expect(packageJson.scripts.check).not.toContain( - "node --import tsx scripts/prepare-extension-package-boundary-artifacts.mts", + "node --import ./scripts/tsx.mjs scripts/prepare-extension-package-boundary-artifacts.mts", ); expect(shardedLintRunner).toContain("prepare-extension-package-boundary-artifacts.mts"); expect(shardedLintRunner).toContain('OPENCLAW_OXLINT_SKIP_PREPARE: "1"'); @@ -257,7 +257,7 @@ describe("run-oxlint", () => { }; const lintRunner = readFileSync("scripts/run-lint.mts", "utf8"); - expect(packageJson.scripts.lint).toBe("node --import tsx scripts/run-lint.mts"); + expect(packageJson.scripts.lint).toBe("node --import ./scripts/tsx.mjs scripts/run-lint.mts"); expect(lintRunner.indexOf("ensureRepoToolNodeModulesLink(")).toBeGreaterThan(-1); expect( lintRunner.indexOf('path.resolve("scripts", "control-ui-i18n-verify.ts")'), diff --git a/test/scripts/test-projects.test.ts b/test/scripts/test-projects.test.ts index 2d9a2076d6f6..46caef269104 100644 --- a/test/scripts/test-projects.test.ts +++ b/test/scripts/test-projects.test.ts @@ -232,12 +232,12 @@ describe("scripts/test-projects changed-target routing", () => { } }); - it("routes shared TypeScript CLI shim changes through wrapper tests", () => { - expectChangedTargets( - ["scripts/lib/tsx-cli-shim.mjs"], - ["test/scripts/direct-run-entrypoints.test.ts"], - ); - }); + it.each(["scripts/lib/tsx-cli-shim.mjs", "scripts/tsx.mjs"])( + "routes shared TypeScript tooling changes through wrapper tests for %s", + (scriptPath) => { + expectChangedTargets([scriptPath], ["test/scripts/direct-run-entrypoints.test.ts"]); + }, + ); it("routes Docker pull retry helper changes through its regression test", () => { expectChangedTargets(