From 3fa9c47f8e347f057c39b8884f877fe621444df7 Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Tue, 7 Jul 2026 16:34:29 -0700 Subject: [PATCH] refactor(tests): relocate runtime integration tests into packages/runtime-core; add test-standardization spec --- .../registry-test-standardization.md | 194 ++++++++++++++ package.json | 1 + .../integration}/bridge-child-process.test.ts | 4 +- .../cross-runtime-network.test.ts | 4 +- .../integration}/cross-runtime-pipes.test.ts | 4 +- .../cross-runtime-terminal.test.ts | 4 +- .../ctrl-c-shell-behavior.test.ts | 4 +- .../integration}/dispose-behavior.test.ts | 6 +- .../dynamic-module-integration.test.ts | 8 +- .../integration}/e2e-concurrently.test.ts | 2 +- .../integration}/e2e-nextjs-build.test.ts | 2 +- .../integration}/e2e-npm-install.test.ts | 2 +- .../integration}/e2e-npm-lifecycle.test.ts | 2 +- .../integration}/e2e-npm-scripts.test.ts | 2 +- .../tests/integration}/e2e-npm-suite.test.ts | 2 +- .../integration}/e2e-npm-version-init.test.ts | 2 +- .../integration}/e2e-npx-and-pipes.test.ts | 2 +- .../integration}/e2e-project-matrix.test.ts | 2 +- .../tests/integration}/envsubst.test.ts | 8 +- .../integration}/error-propagation.test.ts | 4 +- .../integration}/exec-integration.test.ts | 4 +- .../tests/integration}/fd-inheritance.test.ts | 4 +- .../integration}/module-resolution.test.ts | 4 +- .../tests/integration}/net-server.test.ts | 6 +- .../tests/integration}/net-udp.test.ts | 6 +- .../tests/integration}/net-unix.test.ts | 6 +- .../integration}/node-binary-behavior.test.ts | 4 +- .../projects/astro-pass/astro.config.mjs | 0 .../projects/astro-pass/fixture.json | 0 .../projects/astro-pass/package.json | 0 .../astro-pass/src/components/Counter.jsx | 0 .../projects/astro-pass/src/index.js | 0 .../projects/astro-pass/src/pages/index.astro | 0 .../projects/axios-pass/fixture.json | 0 .../projects/axios-pass/package.json | 0 .../projects/axios-pass/src/index.js | 0 .../projects/bcryptjs-pass/fixture.json | 0 .../projects/bcryptjs-pass/package.json | 0 .../projects/bcryptjs-pass/pnpm-lock.yaml | 0 .../projects/bcryptjs-pass/src/index.js | 0 .../projects/bun-layout-pass/bun.lock | 0 .../projects/bun-layout-pass/fixture.json | 0 .../projects/bun-layout-pass/package.json | 0 .../projects/bun-layout-pass/src/index.js | 0 .../projects/chalk-pass/fixture.json | 0 .../projects/chalk-pass/package.json | 0 .../projects/chalk-pass/src/index.js | 0 .../conditional-exports-pass/fixture.json | 0 .../package-lock.json | 0 .../conditional-exports-pass/package.json | 0 .../cond-exports-lib/lib/feature-cjs.js | 0 .../cond-exports-lib/lib/feature-default.js | 0 .../packages/cond-exports-lib/lib/main-cjs.js | 0 .../cond-exports-lib/lib/main-default.js | 0 .../packages/cond-exports-lib/package.json | 0 .../conditional-exports-pass/src/index.js | 0 .../projects/crypto-random-pass/fixture.json | 0 .../projects/crypto-random-pass/package.json | 0 .../projects/crypto-random-pass/src/index.js | 0 .../integration}/projects/dotenv-pass/.env | 0 .../projects/dotenv-pass/fixture.json | 0 .../projects/dotenv-pass/package.json | 0 .../projects/dotenv-pass/src/index.js | 0 .../projects/drizzle-pass/fixture.json | 0 .../projects/drizzle-pass/package.json | 0 .../projects/drizzle-pass/src/index.js | 0 .../projects/esm-import-pass/fixture.json | 0 .../projects/esm-import-pass/package.json | 0 .../projects/esm-import-pass/src/index.js | 0 .../projects/express-pass/fixture.json | 0 .../projects/express-pass/package.json | 0 .../projects/express-pass/pnpm-lock.yaml | 0 .../projects/express-pass/src/index.js | 0 .../projects/fastify-pass/fixture.json | 0 .../projects/fastify-pass/package.json | 0 .../projects/fastify-pass/pnpm-lock.yaml | 0 .../projects/fastify-pass/src/index.js | 0 .../fs-metadata-rename-pass/fixture.json | 0 .../fs-metadata-rename-pass/package.json | 0 .../fs-metadata-rename-pass/src/index.js | 0 .../projects/ioredis-pass/fixture.json | 0 .../projects/ioredis-pass/package.json | 0 .../projects/ioredis-pass/pnpm-lock.yaml | 0 .../projects/ioredis-pass/src/index.js | 0 .../projects/jsonwebtoken-pass/fixture.json | 0 .../projects/jsonwebtoken-pass/package.json | 0 .../projects/jsonwebtoken-pass/src/index.js | 0 .../projects/lodash-es-pass/fixture.json | 0 .../projects/lodash-es-pass/package.json | 0 .../projects/lodash-es-pass/pnpm-lock.yaml | 0 .../projects/lodash-es-pass/src/index.js | 0 .../projects/module-access-pass/fixture.json | 0 .../projects/module-access-pass/package.json | 0 .../projects/module-access-pass/src/index.js | 0 .../vendor/entry-lib/index.js | 0 .../vendor/entry-lib/package.json | 0 .../vendor/transitive-lib/index.js | 0 .../vendor/transitive-lib/package.json | 0 .../projects/mysql2-pass/fixture.json | 0 .../projects/mysql2-pass/package.json | 0 .../projects/mysql2-pass/src/index.js | 0 .../net-create-server-pass/fixture.json | 0 .../net-create-server-pass/package.json | 0 .../net-create-server-pass/src/index.js | 0 .../projects/nextjs-pass/.babelrc | 0 .../projects/nextjs-pass/fixture.json | 0 .../projects/nextjs-pass/next-wasm-shim.cjs | 0 .../projects/nextjs-pass/next.config.js | 0 .../projects/nextjs-pass/package.json | 0 .../projects/nextjs-pass/pages/api/hello.js | 0 .../projects/nextjs-pass/pages/index.js | 0 .../projects/nextjs-pass/run-next-build.cjs | 0 .../projects/nextjs-pass/src/index.js | 0 .../projects/node-fetch-pass/fixture.json | 0 .../projects/node-fetch-pass/package.json | 0 .../projects/node-fetch-pass/src/index.js | 0 .../projects/npm-layout-pass/fixture.json | 0 .../npm-layout-pass/package-lock.json | 0 .../projects/npm-layout-pass/package.json | 0 .../projects/npm-layout-pass/src/index.js | 0 .../projects/optional-deps-pass/fixture.json | 0 .../optional-deps-pass/package-lock.json | 0 .../projects/optional-deps-pass/package.json | 0 .../projects/optional-deps-pass/src/index.js | 0 .../projects/peer-deps-pass/fixture.json | 0 .../projects/peer-deps-pass/package-lock.json | 0 .../projects/peer-deps-pass/package.json | 0 .../peer-deps-pass/packages/host/index.js | 0 .../peer-deps-pass/packages/host/package.json | 0 .../peer-deps-pass/packages/plugin/index.js | 0 .../packages/plugin/package.json | 0 .../projects/peer-deps-pass/src/index.js | 0 .../projects/pg-pass/fixture.json | 0 .../projects/pg-pass/package.json | 0 .../projects/pg-pass/pnpm-lock.yaml | 0 .../projects/pg-pass/src/index.js | 0 .../projects/pino-pass/fixture.json | 0 .../projects/pino-pass/package.json | 0 .../projects/pino-pass/pnpm-lock.yaml | 0 .../projects/pino-pass/src/index.js | 0 .../projects/pnpm-layout-pass/fixture.json | 0 .../projects/pnpm-layout-pass/package.json | 0 .../projects/pnpm-layout-pass/pnpm-lock.yaml | 0 .../projects/pnpm-layout-pass/src/index.js | 0 .../projects/rivetkit/fixture.json | 0 .../projects/rivetkit/package.json | 0 .../projects/rivetkit/src/index.js | 0 .../rivetkit/vendor/rivetkit/package.json | 0 .../projects/semver-pass/fixture.json | 0 .../projects/semver-pass/package.json | 0 .../projects/semver-pass/src/index.js | 0 .../projects/sse-streaming-pass/fixture.json | 0 .../projects/sse-streaming-pass/package.json | 0 .../projects/sse-streaming-pass/src/index.js | 0 .../projects/ssh2-pass/fixture.json | 0 .../projects/ssh2-pass/package.json | 0 .../projects/ssh2-pass/src/index.js | 0 .../ssh2-sftp-client-pass/fixture.json | 0 .../ssh2-sftp-client-pass/package.json | 0 .../ssh2-sftp-client-pass/src/index.js | 0 .../transitive-deps-pass/fixture.json | 0 .../transitive-deps-pass/package-lock.json | 0 .../transitive-deps-pass/package.json | 0 .../packages/level-a/index.js | 0 .../packages/level-a/package.json | 0 .../packages/level-b/index.js | 0 .../packages/level-b/package.json | 0 .../packages/level-c/index.js | 0 .../packages/level-c/package.json | 0 .../transitive-deps-pass/src/index.js | 0 .../projects/uuid-pass/fixture.json | 0 .../projects/uuid-pass/package.json | 0 .../projects/uuid-pass/src/index.js | 0 .../projects/vite-pass/app/main.jsx | 0 .../projects/vite-pass/fixture.json | 0 .../projects/vite-pass/index.html | 0 .../projects/vite-pass/package.json | 0 .../projects/vite-pass/src/index.js | 0 .../projects/vite-pass/vite.config.mjs | 0 .../workspace-layout-pass/fixture.json | 0 .../workspace-layout-pass/package.json | 0 .../packages/app/package.json | 0 .../packages/app/src/index.js | 0 .../packages/lib/package.json | 0 .../packages/lib/src/index.js | 0 .../projects/ws-pass/fixture.json | 0 .../projects/ws-pass/package-lock.json | 0 .../projects/ws-pass/package.json | 0 .../projects/ws-pass/src/index.js | 0 .../projects/yaml-pass/fixture.json | 0 .../projects/yaml-pass/package.json | 0 .../projects/yaml-pass/src/index.js | 0 .../yarn-berry-layout-pass/.yarnrc.yml | 0 .../yarn-berry-layout-pass/fixture.json | 0 .../yarn-berry-layout-pass/package.json | 0 .../yarn-berry-layout-pass/src/index.js | 0 .../projects/yarn-berry-layout-pass/yarn.lock | 0 .../yarn-classic-layout-pass/fixture.json | 0 .../yarn-classic-layout-pass/package.json | 0 .../yarn-classic-layout-pass/src/index.js | 0 .../yarn-classic-layout-pass/yarn.lock | 0 .../projects/zod-pass/fixture.json | 0 .../projects/zod-pass/package.json | 0 .../projects/zod-pass/pnpm-lock.yaml | 0 .../projects/zod-pass/src/index.js | 0 .../tests/integration}/repro-npm-install.ts | 2 +- .../tests/integration}/shim-streaming.test.ts | 4 +- .../integration}/signal-forwarding.test.ts | 4 +- .../tests/integration}/signal-handler.test.ts | 6 +- .../integration}/vfs-consistency.test.ts | 4 +- .../tests/integration}/wasi-http.test.ts | 6 +- .../tests/integration}/wasi-spawn.test.ts | 6 +- packages/vm-test-harness/package.json | 27 ++ packages/vm-test-harness/src/index.ts | 168 ++++++++++++ .../vm-test-harness/src}/terminal-harness.ts | 6 +- packages/vm-test-harness/tsconfig.json | 10 + pnpm-lock.yaml | 46 ++++ pnpm-workspace.yaml | 2 + .../wasmvm => native/tests}/c-parity.test.ts | 6 +- .../tests}/ci-artifact-availability.test.ts | 2 +- .../ci-wasm-artifact-availability.test.ts | 2 +- .../tests}/libc-test-conformance.test.ts | 6 +- .../tests}/libc-test-exclusions.json | 0 .../tests}/os-test-conformance.test.ts | 6 +- .../tests}/os-test-exclusions.json | 0 registry/package.json | 4 +- registry/scripts/check-test-coverage.mjs | 52 ++++ registry/scripts/test-status.mjs | 133 ++++++++++ .../codex-cli/test}/codex-exec.test.ts | 12 +- .../codex-cli/test}/codex-tui.test.ts | 19 +- .../coreutils/test}/shell-redirect.test.ts | 2 +- .../coreutils/test}/shell-terminal.test.ts | 8 +- .../curl/test}/curl.test.ts | 6 +- .../duckdb/test}/duckdb.test.ts | 6 +- .../fd/test/fd.test.ts} | 6 +- .../software/findutils/test/findutils.test.ts | 73 +++++ .../wasmvm => software/git/test}/git.test.ts | 8 +- .../sqlite3/test}/sqlite3.test.ts | 6 +- .../tree/test}/tree-test.test.ts | 4 +- registry/software/unzip/test/unzip.test.ts | 219 +++++++++++++++ .../wget/test}/wget.test.ts | 8 +- registry/software/zip/test/zip.test.ts | 56 ++++ registry/test-status.json | 247 +++++++++++++++++ registry/tests/helpers.ts | 120 --------- registry/tests/kernel/helpers.ts | 103 -------- registry/tests/wasmvm/terminal-harness.ts | 172 ------------ registry/tests/wasmvm/zip-unzip.test.ts | 249 ------------------ turbo.json | 9 +- 248 files changed, 1363 insertions(+), 765 deletions(-) create mode 100644 docs-internal/registry-test-standardization.md rename {registry/tests/kernel => packages/runtime-core/tests/integration}/bridge-child-process.test.ts (99%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/cross-runtime-network.test.ts (99%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/cross-runtime-pipes.test.ts (95%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/cross-runtime-terminal.test.ts (98%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/ctrl-c-shell-behavior.test.ts (95%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/dispose-behavior.test.ts (92%) rename {registry/tests/wasmvm => packages/runtime-core/tests/integration}/dynamic-module-integration.test.ts (98%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/e2e-concurrently.test.ts (99%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/e2e-nextjs-build.test.ts (98%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/e2e-npm-install.test.ts (98%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/e2e-npm-lifecycle.test.ts (99%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/e2e-npm-scripts.test.ts (96%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/e2e-npm-suite.test.ts (99%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/e2e-npm-version-init.test.ts (95%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/e2e-npx-and-pipes.test.ts (98%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/e2e-project-matrix.test.ts (99%) rename {registry/tests/wasmvm => packages/runtime-core/tests/integration}/envsubst.test.ts (95%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/error-propagation.test.ts (95%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/exec-integration.test.ts (97%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/fd-inheritance.test.ts (95%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/module-resolution.test.ts (96%) rename {registry/tests/wasmvm => packages/runtime-core/tests/integration}/net-server.test.ts (97%) rename {registry/tests/wasmvm => packages/runtime-core/tests/integration}/net-udp.test.ts (97%) rename {registry/tests/wasmvm => packages/runtime-core/tests/integration}/net-unix.test.ts (97%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/node-binary-behavior.test.ts (99%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/astro-pass/astro.config.mjs (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/astro-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/astro-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/astro-pass/src/components/Counter.jsx (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/astro-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/astro-pass/src/pages/index.astro (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/axios-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/axios-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/axios-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/bcryptjs-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/bcryptjs-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/bcryptjs-pass/pnpm-lock.yaml (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/bcryptjs-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/bun-layout-pass/bun.lock (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/bun-layout-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/bun-layout-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/bun-layout-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/chalk-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/chalk-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/chalk-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/conditional-exports-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/conditional-exports-pass/package-lock.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/conditional-exports-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/conditional-exports-pass/packages/cond-exports-lib/lib/feature-cjs.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/conditional-exports-pass/packages/cond-exports-lib/lib/feature-default.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/conditional-exports-pass/packages/cond-exports-lib/lib/main-cjs.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/conditional-exports-pass/packages/cond-exports-lib/lib/main-default.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/conditional-exports-pass/packages/cond-exports-lib/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/conditional-exports-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/crypto-random-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/crypto-random-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/crypto-random-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/dotenv-pass/.env (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/dotenv-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/dotenv-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/dotenv-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/drizzle-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/drizzle-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/drizzle-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/esm-import-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/esm-import-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/esm-import-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/express-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/express-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/express-pass/pnpm-lock.yaml (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/express-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/fastify-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/fastify-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/fastify-pass/pnpm-lock.yaml (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/fastify-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/fs-metadata-rename-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/fs-metadata-rename-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/fs-metadata-rename-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/ioredis-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/ioredis-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/ioredis-pass/pnpm-lock.yaml (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/ioredis-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/jsonwebtoken-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/jsonwebtoken-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/jsonwebtoken-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/lodash-es-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/lodash-es-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/lodash-es-pass/pnpm-lock.yaml (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/lodash-es-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/module-access-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/module-access-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/module-access-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/module-access-pass/vendor/entry-lib/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/module-access-pass/vendor/entry-lib/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/module-access-pass/vendor/transitive-lib/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/module-access-pass/vendor/transitive-lib/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/mysql2-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/mysql2-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/mysql2-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/net-create-server-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/net-create-server-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/net-create-server-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/nextjs-pass/.babelrc (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/nextjs-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/nextjs-pass/next-wasm-shim.cjs (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/nextjs-pass/next.config.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/nextjs-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/nextjs-pass/pages/api/hello.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/nextjs-pass/pages/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/nextjs-pass/run-next-build.cjs (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/nextjs-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/node-fetch-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/node-fetch-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/node-fetch-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/npm-layout-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/npm-layout-pass/package-lock.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/npm-layout-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/npm-layout-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/optional-deps-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/optional-deps-pass/package-lock.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/optional-deps-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/optional-deps-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/peer-deps-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/peer-deps-pass/package-lock.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/peer-deps-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/peer-deps-pass/packages/host/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/peer-deps-pass/packages/host/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/peer-deps-pass/packages/plugin/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/peer-deps-pass/packages/plugin/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/peer-deps-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/pg-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/pg-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/pg-pass/pnpm-lock.yaml (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/pg-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/pino-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/pino-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/pino-pass/pnpm-lock.yaml (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/pino-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/pnpm-layout-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/pnpm-layout-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/pnpm-layout-pass/pnpm-lock.yaml (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/pnpm-layout-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/rivetkit/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/rivetkit/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/rivetkit/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/rivetkit/vendor/rivetkit/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/semver-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/semver-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/semver-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/sse-streaming-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/sse-streaming-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/sse-streaming-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/ssh2-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/ssh2-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/ssh2-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/ssh2-sftp-client-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/ssh2-sftp-client-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/ssh2-sftp-client-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/transitive-deps-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/transitive-deps-pass/package-lock.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/transitive-deps-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/transitive-deps-pass/packages/level-a/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/transitive-deps-pass/packages/level-a/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/transitive-deps-pass/packages/level-b/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/transitive-deps-pass/packages/level-b/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/transitive-deps-pass/packages/level-c/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/transitive-deps-pass/packages/level-c/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/transitive-deps-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/uuid-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/uuid-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/uuid-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/vite-pass/app/main.jsx (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/vite-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/vite-pass/index.html (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/vite-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/vite-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/vite-pass/vite.config.mjs (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/workspace-layout-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/workspace-layout-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/workspace-layout-pass/packages/app/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/workspace-layout-pass/packages/app/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/workspace-layout-pass/packages/lib/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/workspace-layout-pass/packages/lib/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/ws-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/ws-pass/package-lock.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/ws-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/ws-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/yaml-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/yaml-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/yaml-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/yarn-berry-layout-pass/.yarnrc.yml (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/yarn-berry-layout-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/yarn-berry-layout-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/yarn-berry-layout-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/yarn-berry-layout-pass/yarn.lock (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/yarn-classic-layout-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/yarn-classic-layout-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/yarn-classic-layout-pass/src/index.js (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/yarn-classic-layout-pass/yarn.lock (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/zod-pass/fixture.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/zod-pass/package.json (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/zod-pass/pnpm-lock.yaml (100%) rename {registry/tests => packages/runtime-core/tests/integration}/projects/zod-pass/src/index.js (100%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/repro-npm-install.ts (93%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/shim-streaming.test.ts (86%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/signal-forwarding.test.ts (96%) rename {registry/tests/wasmvm => packages/runtime-core/tests/integration}/signal-handler.test.ts (96%) rename {registry/tests/kernel => packages/runtime-core/tests/integration}/vfs-consistency.test.ts (96%) rename {registry/tests/wasmvm => packages/runtime-core/tests/integration}/wasi-http.test.ts (98%) rename {registry/tests/wasmvm => packages/runtime-core/tests/integration}/wasi-spawn.test.ts (96%) create mode 100644 packages/vm-test-harness/package.json create mode 100644 packages/vm-test-harness/src/index.ts rename {registry/tests => packages/vm-test-harness/src}/terminal-harness.ts (96%) create mode 100644 packages/vm-test-harness/tsconfig.json rename registry/{tests/wasmvm => native/tests}/c-parity.test.ts (99%) rename registry/{tests/wasmvm => native/tests}/ci-artifact-availability.test.ts (95%) rename registry/{tests/kernel => native/tests}/ci-wasm-artifact-availability.test.ts (94%) rename registry/{tests/wasmvm => native/tests}/libc-test-conformance.test.ts (98%) rename registry/{tests/wasmvm => native/tests}/libc-test-exclusions.json (100%) rename registry/{tests/wasmvm => native/tests}/os-test-conformance.test.ts (99%) rename registry/{tests/wasmvm => native/tests}/os-test-exclusions.json (100%) create mode 100644 registry/scripts/check-test-coverage.mjs create mode 100644 registry/scripts/test-status.mjs rename registry/{tests/wasmvm => software/codex-cli/test}/codex-exec.test.ts (95%) rename registry/{tests/wasmvm => software/codex-cli/test}/codex-tui.test.ts (93%) rename registry/{tests/wasmvm => software/coreutils/test}/shell-redirect.test.ts (95%) rename registry/{tests/wasmvm => software/coreutils/test}/shell-terminal.test.ts (98%) rename registry/{tests/wasmvm => software/curl/test}/curl.test.ts (99%) rename registry/{tests/wasmvm => software/duckdb/test}/duckdb.test.ts (98%) rename registry/{tests/wasmvm/fd-find.test.ts => software/fd/test/fd.test.ts} (98%) create mode 100644 registry/software/findutils/test/findutils.test.ts rename registry/{tests/wasmvm => software/git/test}/git.test.ts (99%) rename registry/{tests/wasmvm => software/sqlite3/test}/sqlite3.test.ts (98%) rename registry/{tests/kernel => software/tree/test}/tree-test.test.ts (97%) create mode 100644 registry/software/unzip/test/unzip.test.ts rename registry/{tests/wasmvm => software/wget/test}/wget.test.ts (96%) create mode 100644 registry/software/zip/test/zip.test.ts create mode 100644 registry/test-status.json delete mode 100644 registry/tests/helpers.ts delete mode 100644 registry/tests/kernel/helpers.ts delete mode 100644 registry/tests/wasmvm/terminal-harness.ts delete mode 100644 registry/tests/wasmvm/zip-unzip.test.ts diff --git a/docs-internal/registry-test-standardization.md b/docs-internal/registry-test-standardization.md new file mode 100644 index 0000000000..f193795672 --- /dev/null +++ b/docs-internal/registry-test-standardization.md @@ -0,0 +1,194 @@ +# Spec: Registry Test Standardization + +Status: proposal · Owner: registry · Last updated: 2026-07-07 + +## Problem + +Every registry integration test lives under `registry/tests/`, organized by +**where the WASM binaries are built (`registry/native/`), not by what is being +tested.** The harness (`registry/tests/helpers.ts`) resolves command binaries at +`registry/tests/../native/...`, so anything needing a real WASM command was +parked next to the native build — including tests that have nothing to do with +registry packages (npm e2e, VFS, sockets, libc conformance). + +That layout coupling is already obsolete: + +- `packages/runtime-core/scripts/copy-wasm-commands.mjs` vendors the binaries + into `packages/runtime-core/commands/`, and CI stages them there. +- The harness already supports an env seam: + `AGENTOS_WASM_COMMANDS_DIR` / `AGENTOS_C_WASM_COMMANDS_DIR`. +- `packages/runtime-core/` already has its own `tests/` + `vitest.config.ts`. + +Consequences today: the `agentos-registry` test package is **not a pnpm +workspace member**, so root `pnpm test` (turbo, member-filtered) never runs it; +`@xterm/headless` doesn't resolve without a manual symlink; and there is no way +to answer "which packages have no test?" mechanically. + +## Goals + +1. Organize tests by **subject under test**, not by binary location. +2. Make "does package X have a test?" answerable by `ls` + a coverage gate. +3. Re-attach the suites to CI (turbo) so they actually run. +4. **Report test status; never silently fix or hide failures.** Migration must + not touch package behavior. A package whose test fails moves as-is and is + recorded as `failing` — see [Non-goals](#non-goals). + +## Non-goals + +- **Do not fix failing packages.** Moving a test must not change the command's + behavior to make a red test green. If a test fails after moving, its status is + `failing` and it is tracked in the manifest, not patched. +- No new test coverage is *required* by the migration itself. Writing the + missing tests (the `no-test` rows) is follow-up work, tracked but separate. + +## Target layout + +| Home | Contains | Rationale | +|---|---|---| +| `registry/software//test/` | Tests exercising **one package's command** | The package owns its behavior | +| `packages/runtime-core/tests/integration/` | Tests of the **VM/kernel** using commands as generic fixtures | runtime-core already vendors the binaries and has a test setup | +| `registry/native/tests/` | **libc/sysroot conformance** — validates the C toolchain | Lives next to the artifact it validates | +| `packages/vm-test-harness/` (new, workspace member) | `helpers.ts` + `terminal-harness.ts` shared harness | One import surface; fixes `@xterm/headless` resolution and turbo wiring | + +Binaries are injected via `AGENTOS_WASM_COMMANDS_DIR` pointing at +`packages/runtime-core/commands` — no relative-path coupling to `registry/native`. + +## The rule (enforced) + +> Every `*.test.ts` is either **owned by exactly one package** +> (`software//test/`) **or** lives in a runtime/toolchain home with a +> one-line reason header. No loose files. No test organized by binary location. + +CI coverage gate (`registry/scripts/check-test-coverage.mjs`): +- Fail if any `software/*` has neither a `test/` dir nor an entry in the + **known-gap allowlist**. +- Allowlist (no direct test expected): meta bundles `common`, + `build-essential`, `everything`; external wrappers `browserbase`, `vix`. + +## Status reporter (`registry/scripts/test-status.mjs`) + +A report-only tool. It **does not fix anything** and its default exit code does +not fail on known-tracked failures. + +Behavior: +1. Enumerate `software/*` + `agent/*`. +2. For each, resolve its test dir (post-migration) and run it via vitest with + binaries from `runtime-core/commands`. +3. Classify each package into one status (below) and print a table + write + `registry/test-status.json`. +4. Reconcile against the **expected-status manifest** in this spec: + - A package whose result matches its recorded status → OK. + - A `failing`/`not-compiling` package that is still failing → **reported, not + an error** (exit 0). This is the "don't fix broken packages" contract. + - A package that **regressed** (recorded `working`, now failing) → exit + non-zero. Only *new* breakage fails CI. + +Status values: + +| Status | Meaning | +|---|---| +| `working` | Live test, all (or all-but-hardening) pass | +| `failing` | Live test, real functional failures — tracked, not fixed | +| `disabled` | Test file exists but is `describe.skip` | +| `no-test` | Compiles, no test exists | +| `not-compiling` | Build fails | +| `not-buildable` | Needs an external artifact absent from this checkout | +| `meta` | Aggregate bundle — no direct test | + +## Migration & coverage manifest + +Statuses below are from the 2026-07-07 audit (full run: +8 failed / 6 passed / 9 skipped files; 34 failed / 84 passed / 59 skipped tests). +The reporter regenerates them; they are the baseline the reporter reconciles +against. + +### Software packages (29) + +| Package | Command(s) | Current test | Action | Target | Status | +|---|---|---|---|---|---| +| coreutils | `sh` +80 | `shell-terminal`, `shell-redirect` | move | `software/coreutils/test/` | `working` | +| fd | `fd` | `fd-find` (shared) | **split** + move | `software/fd/test/` | `working` | +| findutils | `find`,`xargs` | `fd-find` (shared) | **split** + move | `software/findutils/test/` | `working` | +| tree | `tree` | `kernel/tree-test` (**misfiled**) | move | `software/tree/test/` | `working` | +| sqlite3 | `sqlite3` | `sqlite3` | move | `software/sqlite3/test/` | `failing` (1/16: VFS `pwrite`) | +| zip | `zip` | `zip-unzip` (shared) | **split** + move | `software/zip/test/` | `failing` (3/8 hardening) | +| unzip | `unzip` | `zip-unzip` (shared) | **split** + move | `software/unzip/test/` | `failing` (3/8 hardening) | +| curl | `curl` | `curl` | move | `software/curl/test/` | `failing` (24/30; exits 1 incl. `--version`) | +| git | `git` | `git` (`describe.skip`) | move + unskip via `describeIf` | `software/git/test/` | `disabled` (compiles) | +| duckdb | `duckdb` | `duckdb` (`describe.skip`) | move + `describeIf` | `software/duckdb/test/` | `disabled` (compiles) | +| wget | `wget` | `wget` (`describe.skip`) | move + `describeIf` | `software/wget/test/` | `not-compiling` (dup `getpeername`) | +| codex-cli | `codex`,`codex-exec` | `codex-exec`,`codex-tui` (`describe.skip`) | move + `describeIf` | `software/codex-cli/test/` | `not-buildable` (needs codex-rs fork) | +| gawk | `awk` | — | **write new** | `software/gawk/test/` | `no-test` | +| sed | `sed` | — | **write new** | `software/sed/test/` | `no-test` | +| grep | `grep` | — (only a vehicle in `dynamic-module`) | **write new** | `software/grep/test/` | `no-test` | +| tar | `tar` | — | **write new** | `software/tar/test/` | `no-test` | +| gzip | `gzip` | — | **write new** | `software/gzip/test/` | `no-test` | +| jq | `jq` | — | **write new** | `software/jq/test/` | `no-test` | +| ripgrep | `rg` | — | **write new** | `software/ripgrep/test/` | `no-test` | +| yq | `yq` | — | **write new** | `software/yq/test/` | `no-test` | +| diffutils | `diff` | — | **write new** | `software/diffutils/test/` | `no-test` | +| file | `file` | — | **write new** | `software/file/test/` | `no-test` | +| http-get | `http_get` | — | **write new** | `software/http-get/test/` | `no-test` | +| vim | `vim` | — | **write new** | `software/vim/test/` | `no-test` (compile unverified; heavy `make cmd/vim`) | +| vix | `vix` | — | allowlist | — | `not-buildable` (external, no source) | +| browserbase | (`browse`) | — | allowlist | — | `no-test` (external CLI wrapper) | +| common | (bundle) | — | allowlist | — | `meta` | +| build-essential | (bundle) | — | allowlist | — | `meta` | +| everything | (bundle) | — | allowlist | — | `meta` | + +### Agent packages (5) + +All are JS ACP adapters with **no integration test**. Decision needed: adapter +smoke tests, or explicitly out of scope (allowlist). + +| Package | Action | Status | +|---|---|---| +| claude | write new / allowlist | `no-test` | +| codex | write new / allowlist | `no-test` | +| opencode | write new / allowlist | `no-test` | +| pi | write new / allowlist | `no-test` | +| pi-cli | write new / allowlist | `no-test` | + +### Not-a-package tests → relocate out of `registry/tests/` + +**→ `packages/runtime-core/tests/integration/`** (VM/kernel): +- from `wasmvm/`: `net-server`, `net-udp`, `net-unix`, `signal-handler`, + `wasi-http`, `wasi-spawn`, `dynamic-module-integration` +- **all of `kernel/`** except `tree-test`: `e2e-npm-*`, `e2e-nextjs-build`, + `e2e-concurrently`, `e2e-npx-and-pipes`, `e2e-project-matrix`, + `cross-runtime-*`, `bridge-child-process`, `ctrl-c-shell-behavior`, + `dispose-behavior`, `error-propagation`, `exec-integration`, + `fd-inheritance`, `module-resolution`, `node-binary-behavior`, + `shim-streaming`, `signal-forwarding`, `vfs-consistency` +- `registry/tests/projects/` (~45 npm fixtures) — move with the kernel e2e + +**→ `registry/native/tests/`** (toolchain/libc conformance): +- `os-test-conformance`, `libc-test-conformance`, `c-parity`, + `ci-artifact-availability`, `kernel/ci-wasm-artifact-availability` + +**Decision:** `envsubst` — command has **no owning package**. Either give it one +(coreutils?) or move `envsubst.test.ts` to runtime. Currently `working` (6/6). + +## Migration phases + +1. **Foundation** — extract `packages/vm-test-harness`; make it a workspace + member; point it at `runtime-core/commands` via env. Wire turbo `test`. + (Fixes xterm + CI-orphan bugs; moves nothing yet.) +2. **Relocate runtime + toolchain tests** out of `registry/tests/` per the lists + above. Pure `git mv`, no behavior change. +3. **Co-locate package tests** into `software//test/`; split the two shared + files (`fd-find`, `zip-unzip`); move misfiled `tree-test`; swap + `describe.skip` → `describeIf(binaryPresent)`. +4. **Gate** — add `check-test-coverage.mjs` + `test-status.mjs`; commit the + baseline `test-status.json`; fail CI only on regressions. +5. **Backfill** — write the `no-test` suites (12 software + 5 agents). Separate + PRs, tracked by the manifest. + +## Open decisions + +- Runtime tests home: **`runtime-core/tests/`** (recommended, binaries already + there) vs. a new `packages/vm-integration-tests`. +- `envsubst` owner. +- Agent adapter tests: in scope or allowlist. +- `describe.skip` → `describeIf`: gate on binary presence, or also on + network/env (git remote clone, codex `OPENAI_API_KEY`). diff --git a/package.json b/package.json index 4e38e9c42d..fea75752db 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@agentos-software/claude-code": "workspace:*", "@agentos-software/codex": "workspace:*", "@agentos-software/common": "workspace:*", + "@rivet-dev/agentos-vm-test-harness": "workspace:*", "@rivet-dev/agentos-runtime-core": "workspace:*", "@agentos-software/pi": "workspace:*", "@types/node": "^22.19.15", diff --git a/registry/tests/kernel/bridge-child-process.test.ts b/packages/runtime-core/tests/integration/bridge-child-process.test.ts similarity index 99% rename from registry/tests/kernel/bridge-child-process.test.ts rename to packages/runtime-core/tests/integration/bridge-child-process.test.ts index 7cf5032c62..e1298a2cc5 100644 --- a/registry/tests/kernel/bridge-child-process.test.ts +++ b/packages/runtime-core/tests/integration/bridge-child-process.test.ts @@ -21,8 +21,8 @@ import { describeIf, createIntegrationKernel, NodeFileSystem, -} from './helpers.ts'; -import type { IntegrationKernelResult } from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { IntegrationKernelResult } from '@rivet-dev/agentos-vm-test-harness'; const __dirname = dirname(fileURLToPath(import.meta.url)); const PACKAGED_COREUTILS_COMMANDS_DIR = resolve( diff --git a/registry/tests/kernel/cross-runtime-network.test.ts b/packages/runtime-core/tests/integration/cross-runtime-network.test.ts similarity index 99% rename from registry/tests/kernel/cross-runtime-network.test.ts rename to packages/runtime-core/tests/integration/cross-runtime-network.test.ts index 98519e2b24..5167ea3bad 100644 --- a/registry/tests/kernel/cross-runtime-network.test.ts +++ b/packages/runtime-core/tests/integration/cross-runtime-network.test.ts @@ -16,8 +16,8 @@ import { createIntegrationKernel, itIf, skipUnlessWasmBuilt, -} from './helpers.ts'; -import type { IntegrationKernelResult, Kernel } from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { IntegrationKernelResult, Kernel } from '@rivet-dev/agentos-vm-test-harness'; const WASM_HTTP_GET = resolve(C_BUILD_DIR, 'http_get'); const WASM_HTTP_SERVER = resolve(C_BUILD_DIR, 'http_server'); diff --git a/registry/tests/kernel/cross-runtime-pipes.test.ts b/packages/runtime-core/tests/integration/cross-runtime-pipes.test.ts similarity index 95% rename from registry/tests/kernel/cross-runtime-pipes.test.ts rename to packages/runtime-core/tests/integration/cross-runtime-pipes.test.ts index 4db8328b22..8c19d7e198 100644 --- a/registry/tests/kernel/cross-runtime-pipes.test.ts +++ b/packages/runtime-core/tests/integration/cross-runtime-pipes.test.ts @@ -17,8 +17,8 @@ import { describeIf, createIntegrationKernel, skipUnlessWasmBuilt, -} from './helpers.ts'; -import type { Kernel } from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { Kernel } from '@rivet-dev/agentos-vm-test-harness'; // --------------------------------------------------------------------------- // Integration tests with real WasmVM + Node (skipped if WASM not built) diff --git a/registry/tests/kernel/cross-runtime-terminal.test.ts b/packages/runtime-core/tests/integration/cross-runtime-terminal.test.ts similarity index 98% rename from registry/tests/kernel/cross-runtime-terminal.test.ts rename to packages/runtime-core/tests/integration/cross-runtime-terminal.test.ts index 5a4f14b749..3fd5039d1f 100644 --- a/registry/tests/kernel/cross-runtime-terminal.test.ts +++ b/packages/runtime-core/tests/integration/cross-runtime-terminal.test.ts @@ -15,8 +15,8 @@ import { createIntegrationKernel, skipUnlessWasmBuilt, TerminalHarness, -} from './helpers.ts'; -import type { IntegrationKernelResult } from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { IntegrationKernelResult } from '@rivet-dev/agentos-vm-test-harness'; /** brush-shell interactive prompt. */ const PROMPT = 'sh-0.4$ '; diff --git a/registry/tests/kernel/ctrl-c-shell-behavior.test.ts b/packages/runtime-core/tests/integration/ctrl-c-shell-behavior.test.ts similarity index 95% rename from registry/tests/kernel/ctrl-c-shell-behavior.test.ts rename to packages/runtime-core/tests/integration/ctrl-c-shell-behavior.test.ts index 08af122ec2..3788f6fc1c 100644 --- a/registry/tests/kernel/ctrl-c-shell-behavior.test.ts +++ b/packages/runtime-core/tests/integration/ctrl-c-shell-behavior.test.ts @@ -16,8 +16,8 @@ import { createIntegrationKernel, skipUnlessWasmBuilt, TerminalHarness, -} from './helpers.ts'; -import type { IntegrationKernelResult } from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { IntegrationKernelResult } from '@rivet-dev/agentos-vm-test-harness'; const PROMPT = 'sh-0.4$ '; const wasmSkip = skipUnlessWasmBuilt(); diff --git a/registry/tests/kernel/dispose-behavior.test.ts b/packages/runtime-core/tests/integration/dispose-behavior.test.ts similarity index 92% rename from registry/tests/kernel/dispose-behavior.test.ts rename to packages/runtime-core/tests/integration/dispose-behavior.test.ts index 299b08e3fc..d77a5cbcd5 100644 --- a/registry/tests/kernel/dispose-behavior.test.ts +++ b/packages/runtime-core/tests/integration/dispose-behavior.test.ts @@ -17,9 +17,9 @@ import { createIntegrationKernel, skipUnlessWasmBuilt, createInMemoryFileSystem, -} from './helpers.ts'; -import type { Kernel } from './helpers.ts'; -import type { IntegrationKernelResult } from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { Kernel } from '@rivet-dev/agentos-vm-test-harness'; +import type { IntegrationKernelResult } from '@rivet-dev/agentos-vm-test-harness'; const skipReason = skipUnlessWasmBuilt(); diff --git a/registry/tests/wasmvm/dynamic-module-integration.test.ts b/packages/runtime-core/tests/integration/dynamic-module-integration.test.ts similarity index 98% rename from registry/tests/wasmvm/dynamic-module-integration.test.ts rename to packages/runtime-core/tests/integration/dynamic-module-integration.test.ts index a884adee9c..afc8bd00e9 100644 --- a/registry/tests/wasmvm/dynamic-module-integration.test.ts +++ b/packages/runtime-core/tests/integration/dynamic-module-integration.test.ts @@ -10,16 +10,16 @@ */ import { describe, it, expect, afterEach, vi } from 'vitest'; -import { createWasmVmRuntime, WASMVM_COMMANDS } from '../helpers.js'; -import type { WasmVmRuntimeOptions } from '../helpers.js'; -import { COMMANDS_DIR, createKernel, describeIf, hasWasmBinaries } from '../helpers.js'; +import { createWasmVmRuntime, WASMVM_COMMANDS } from '@rivet-dev/agentos-vm-test-harness'; +import type { WasmVmRuntimeOptions } from '@rivet-dev/agentos-vm-test-harness'; +import { COMMANDS_DIR, createKernel, describeIf, hasWasmBinaries } from '@rivet-dev/agentos-vm-test-harness'; import type { DriverProcess, Kernel, KernelInterface, KernelRuntimeDriver as RuntimeDriver, ProcessContext, -} from '../helpers.js'; +} from '@rivet-dev/agentos-vm-test-harness'; import { writeFile, mkdir, rm, symlink } from 'node:fs/promises'; import { existsSync } from 'node:fs'; import { join } from 'node:path'; diff --git a/registry/tests/kernel/e2e-concurrently.test.ts b/packages/runtime-core/tests/integration/e2e-concurrently.test.ts similarity index 99% rename from registry/tests/kernel/e2e-concurrently.test.ts rename to packages/runtime-core/tests/integration/e2e-concurrently.test.ts index 95ef7cf24d..bdc77ed515 100644 --- a/registry/tests/kernel/e2e-concurrently.test.ts +++ b/packages/runtime-core/tests/integration/e2e-concurrently.test.ts @@ -25,7 +25,7 @@ import { createWasmVmRuntime, createNodeRuntime, skipUnlessWasmBuilt, -} from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; const wasmSkip = skipUnlessWasmBuilt(); diff --git a/registry/tests/kernel/e2e-nextjs-build.test.ts b/packages/runtime-core/tests/integration/e2e-nextjs-build.test.ts similarity index 98% rename from registry/tests/kernel/e2e-nextjs-build.test.ts rename to packages/runtime-core/tests/integration/e2e-nextjs-build.test.ts index f5ade032a4..3ebf9e7192 100644 --- a/registry/tests/kernel/e2e-nextjs-build.test.ts +++ b/packages/runtime-core/tests/integration/e2e-nextjs-build.test.ts @@ -29,7 +29,7 @@ import { createWasmVmRuntime, createNodeRuntime, skipUnlessWasmBuilt, -} from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; const wasmSkip = skipUnlessWasmBuilt(); const __dirname = path.dirname(fileURLToPath(import.meta.url)); diff --git a/registry/tests/kernel/e2e-npm-install.test.ts b/packages/runtime-core/tests/integration/e2e-npm-install.test.ts similarity index 98% rename from registry/tests/kernel/e2e-npm-install.test.ts rename to packages/runtime-core/tests/integration/e2e-npm-install.test.ts index 42c508be53..d7cd270212 100644 --- a/registry/tests/kernel/e2e-npm-install.test.ts +++ b/packages/runtime-core/tests/integration/e2e-npm-install.test.ts @@ -22,7 +22,7 @@ import { createWasmVmRuntime, createNodeRuntime, skipUnlessWasmBuilt, -} from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; const wasmSkip = skipUnlessWasmBuilt(); diff --git a/registry/tests/kernel/e2e-npm-lifecycle.test.ts b/packages/runtime-core/tests/integration/e2e-npm-lifecycle.test.ts similarity index 99% rename from registry/tests/kernel/e2e-npm-lifecycle.test.ts rename to packages/runtime-core/tests/integration/e2e-npm-lifecycle.test.ts index 69f3f46e12..cf1b7b3ff0 100644 --- a/registry/tests/kernel/e2e-npm-lifecycle.test.ts +++ b/packages/runtime-core/tests/integration/e2e-npm-lifecycle.test.ts @@ -24,7 +24,7 @@ import { createWasmVmRuntime, createNodeRuntime, skipUnlessWasmBuilt, -} from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; const wasmSkip = skipUnlessWasmBuilt(); diff --git a/registry/tests/kernel/e2e-npm-scripts.test.ts b/packages/runtime-core/tests/integration/e2e-npm-scripts.test.ts similarity index 96% rename from registry/tests/kernel/e2e-npm-scripts.test.ts rename to packages/runtime-core/tests/integration/e2e-npm-scripts.test.ts index ff16dc5c0b..3950bf97a6 100644 --- a/registry/tests/kernel/e2e-npm-scripts.test.ts +++ b/packages/runtime-core/tests/integration/e2e-npm-scripts.test.ts @@ -9,7 +9,7 @@ */ import { describe, expect, it } from 'vitest'; -import { createIntegrationKernel, skipUnlessWasmBuilt } from './helpers.ts'; +import { createIntegrationKernel, skipUnlessWasmBuilt } from '@rivet-dev/agentos-vm-test-harness'; const skipReason = skipUnlessWasmBuilt(); void skipReason; diff --git a/registry/tests/kernel/e2e-npm-suite.test.ts b/packages/runtime-core/tests/integration/e2e-npm-suite.test.ts similarity index 99% rename from registry/tests/kernel/e2e-npm-suite.test.ts rename to packages/runtime-core/tests/integration/e2e-npm-suite.test.ts index 6d5faffe2a..276ce773a7 100644 --- a/registry/tests/kernel/e2e-npm-suite.test.ts +++ b/packages/runtime-core/tests/integration/e2e-npm-suite.test.ts @@ -26,7 +26,7 @@ import { createIntegrationKernel, NodeFileSystem, skipUnlessWasmBuilt, -} from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; const wasmSkip = skipUnlessWasmBuilt(); diff --git a/registry/tests/kernel/e2e-npm-version-init.test.ts b/packages/runtime-core/tests/integration/e2e-npm-version-init.test.ts similarity index 95% rename from registry/tests/kernel/e2e-npm-version-init.test.ts rename to packages/runtime-core/tests/integration/e2e-npm-version-init.test.ts index 3f529ae057..9debd4d285 100644 --- a/registry/tests/kernel/e2e-npm-version-init.test.ts +++ b/packages/runtime-core/tests/integration/e2e-npm-version-init.test.ts @@ -13,7 +13,7 @@ */ import { describe, expect, it } from 'vitest'; -import { createIntegrationKernel, skipUnlessWasmBuilt } from './helpers.ts'; +import { createIntegrationKernel, skipUnlessWasmBuilt } from '@rivet-dev/agentos-vm-test-harness'; const skipReason = skipUnlessWasmBuilt(); void skipReason; diff --git a/registry/tests/kernel/e2e-npx-and-pipes.test.ts b/packages/runtime-core/tests/integration/e2e-npx-and-pipes.test.ts similarity index 98% rename from registry/tests/kernel/e2e-npx-and-pipes.test.ts rename to packages/runtime-core/tests/integration/e2e-npx-and-pipes.test.ts index a4d49092ee..c6c3ba84ab 100644 --- a/registry/tests/kernel/e2e-npx-and-pipes.test.ts +++ b/packages/runtime-core/tests/integration/e2e-npx-and-pipes.test.ts @@ -11,7 +11,7 @@ import { createIntegrationKernel, itIf, skipUnlessWasmBuilt, -} from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; const skipReason = skipUnlessWasmBuilt(); void skipReason; diff --git a/registry/tests/kernel/e2e-project-matrix.test.ts b/packages/runtime-core/tests/integration/e2e-project-matrix.test.ts similarity index 99% rename from registry/tests/kernel/e2e-project-matrix.test.ts rename to packages/runtime-core/tests/integration/e2e-project-matrix.test.ts index cc9eaabb78..27f5297a20 100644 --- a/registry/tests/kernel/e2e-project-matrix.test.ts +++ b/packages/runtime-core/tests/integration/e2e-project-matrix.test.ts @@ -26,7 +26,7 @@ import { createWasmVmRuntime, createNodeRuntime, skipUnlessWasmBuilt, -} from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; const execFileAsync = promisify(execFile); const TEST_TIMEOUT_MS = 55_000; diff --git a/registry/tests/wasmvm/envsubst.test.ts b/packages/runtime-core/tests/integration/envsubst.test.ts similarity index 95% rename from registry/tests/wasmvm/envsubst.test.ts rename to packages/runtime-core/tests/integration/envsubst.test.ts index 3415284a6d..6f2b75136b 100644 --- a/registry/tests/wasmvm/envsubst.test.ts +++ b/packages/runtime-core/tests/integration/envsubst.test.ts @@ -10,9 +10,9 @@ */ import { describe, it, expect, afterEach } from 'vitest'; -import { createWasmVmRuntime } from '../helpers.js'; -import { C_BUILD_DIR, COMMANDS_DIR, createKernel } from '../helpers.js'; -import type { Kernel } from '../helpers.js'; +import { createWasmVmRuntime } from '@rivet-dev/agentos-vm-test-harness'; +import { C_BUILD_DIR, COMMANDS_DIR, createKernel, describeIf, hasCWasmBinaries } from '@rivet-dev/agentos-vm-test-harness'; +import type { Kernel } from '@rivet-dev/agentos-vm-test-harness'; // Minimal in-memory VFS for kernel tests class SimpleVFS { @@ -102,7 +102,7 @@ class SimpleVFS { } } -describe('envsubst command', () => { +describeIf(hasCWasmBinaries('envsubst'), 'envsubst command', () => { let kernel: Kernel; afterEach(async () => { diff --git a/registry/tests/kernel/error-propagation.test.ts b/packages/runtime-core/tests/integration/error-propagation.test.ts similarity index 95% rename from registry/tests/kernel/error-propagation.test.ts rename to packages/runtime-core/tests/integration/error-propagation.test.ts index c71c3c580d..cdb233c52d 100644 --- a/registry/tests/kernel/error-propagation.test.ts +++ b/packages/runtime-core/tests/integration/error-propagation.test.ts @@ -13,8 +13,8 @@ import { describeIf, createIntegrationKernel, skipUnlessWasmBuilt, -} from './helpers.ts'; -import type { IntegrationKernelResult } from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { IntegrationKernelResult } from '@rivet-dev/agentos-vm-test-harness'; const skipReason = skipUnlessWasmBuilt(); diff --git a/registry/tests/kernel/exec-integration.test.ts b/packages/runtime-core/tests/integration/exec-integration.test.ts similarity index 97% rename from registry/tests/kernel/exec-integration.test.ts rename to packages/runtime-core/tests/integration/exec-integration.test.ts index a02216d71b..9cd0184869 100644 --- a/registry/tests/kernel/exec-integration.test.ts +++ b/packages/runtime-core/tests/integration/exec-integration.test.ts @@ -13,8 +13,8 @@ import { describeIf, createIntegrationKernel, skipUnlessWasmBuilt, -} from './helpers.ts'; -import type { IntegrationKernelResult } from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { IntegrationKernelResult } from '@rivet-dev/agentos-vm-test-harness'; const skipReason = skipUnlessWasmBuilt(); diff --git a/registry/tests/kernel/fd-inheritance.test.ts b/packages/runtime-core/tests/integration/fd-inheritance.test.ts similarity index 95% rename from registry/tests/kernel/fd-inheritance.test.ts rename to packages/runtime-core/tests/integration/fd-inheritance.test.ts index b99412009d..7892e5e75a 100644 --- a/registry/tests/kernel/fd-inheritance.test.ts +++ b/packages/runtime-core/tests/integration/fd-inheritance.test.ts @@ -12,8 +12,8 @@ import { describeIf, createIntegrationKernel, skipUnlessWasmBuilt, -} from './helpers.ts'; -import type { IntegrationKernelResult } from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { IntegrationKernelResult } from '@rivet-dev/agentos-vm-test-harness'; const skipReason = skipUnlessWasmBuilt(); diff --git a/registry/tests/kernel/module-resolution.test.ts b/packages/runtime-core/tests/integration/module-resolution.test.ts similarity index 96% rename from registry/tests/kernel/module-resolution.test.ts rename to packages/runtime-core/tests/integration/module-resolution.test.ts index 829f757144..424bbb5a69 100644 --- a/registry/tests/kernel/module-resolution.test.ts +++ b/packages/runtime-core/tests/integration/module-resolution.test.ts @@ -12,8 +12,8 @@ import { describeIf, createIntegrationKernel, skipUnlessWasmBuilt, -} from './helpers.ts'; -import type { IntegrationKernelResult } from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { IntegrationKernelResult } from '@rivet-dev/agentos-vm-test-harness'; const skipReason = skipUnlessWasmBuilt(); diff --git a/registry/tests/wasmvm/net-server.test.ts b/packages/runtime-core/tests/integration/net-server.test.ts similarity index 97% rename from registry/tests/wasmvm/net-server.test.ts rename to packages/runtime-core/tests/integration/net-server.test.ts index c943363629..8c29929c48 100644 --- a/registry/tests/wasmvm/net-server.test.ts +++ b/packages/runtime-core/tests/integration/net-server.test.ts @@ -7,7 +7,7 @@ */ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; -import { createWasmVmRuntime } from '../helpers.js'; +import { createWasmVmRuntime } from '@rivet-dev/agentos-vm-test-harness'; import { AF_INET, COMMANDS_DIR, @@ -16,8 +16,8 @@ import { describeIf, hasWasmBinaries, SOCK_STREAM, -} from '../helpers.js'; -import type { Kernel } from '../helpers.js'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { Kernel } from '@rivet-dev/agentos-vm-test-harness'; import { existsSync } from 'node:fs'; import { join } from 'node:path'; diff --git a/registry/tests/wasmvm/net-udp.test.ts b/packages/runtime-core/tests/integration/net-udp.test.ts similarity index 97% rename from registry/tests/wasmvm/net-udp.test.ts rename to packages/runtime-core/tests/integration/net-udp.test.ts index 98e6b93696..dcf9bdaa46 100644 --- a/registry/tests/wasmvm/net-udp.test.ts +++ b/packages/runtime-core/tests/integration/net-udp.test.ts @@ -7,7 +7,7 @@ */ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; -import { createWasmVmRuntime } from '../helpers.js'; +import { createWasmVmRuntime } from '@rivet-dev/agentos-vm-test-harness'; import { AF_INET, COMMANDS_DIR, @@ -16,8 +16,8 @@ import { describeIf, hasWasmBinaries, SOCK_DGRAM, -} from '../helpers.js'; -import type { Kernel } from '../helpers.js'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { Kernel } from '@rivet-dev/agentos-vm-test-harness'; import { existsSync } from 'node:fs'; import { join } from 'node:path'; diff --git a/registry/tests/wasmvm/net-unix.test.ts b/packages/runtime-core/tests/integration/net-unix.test.ts similarity index 97% rename from registry/tests/wasmvm/net-unix.test.ts rename to packages/runtime-core/tests/integration/net-unix.test.ts index b4bac046ba..848dcd0792 100644 --- a/registry/tests/wasmvm/net-unix.test.ts +++ b/packages/runtime-core/tests/integration/net-unix.test.ts @@ -7,7 +7,7 @@ */ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; -import { createWasmVmRuntime } from '../helpers.js'; +import { createWasmVmRuntime } from '@rivet-dev/agentos-vm-test-harness'; import { AF_UNIX, COMMANDS_DIR, @@ -16,8 +16,8 @@ import { describeIf, hasWasmBinaries, SOCK_STREAM, -} from '../helpers.js'; -import type { Kernel } from '../helpers.js'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { Kernel } from '@rivet-dev/agentos-vm-test-harness'; import { existsSync } from 'node:fs'; import { join } from 'node:path'; diff --git a/registry/tests/kernel/node-binary-behavior.test.ts b/packages/runtime-core/tests/integration/node-binary-behavior.test.ts similarity index 99% rename from registry/tests/kernel/node-binary-behavior.test.ts rename to packages/runtime-core/tests/integration/node-binary-behavior.test.ts index 0f71bd648b..6464eb3f44 100644 --- a/registry/tests/kernel/node-binary-behavior.test.ts +++ b/packages/runtime-core/tests/integration/node-binary-behavior.test.ts @@ -26,8 +26,8 @@ import { createWasmVmRuntime, NodeFileSystem, COMMANDS_DIR, -} from './helpers.ts'; -import type { IntegrationKernelResult } from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { IntegrationKernelResult } from '@rivet-dev/agentos-vm-test-harness'; const skipReason = skipUnlessWasmBuilt(); diff --git a/registry/tests/projects/astro-pass/astro.config.mjs b/packages/runtime-core/tests/integration/projects/astro-pass/astro.config.mjs similarity index 100% rename from registry/tests/projects/astro-pass/astro.config.mjs rename to packages/runtime-core/tests/integration/projects/astro-pass/astro.config.mjs diff --git a/registry/tests/projects/astro-pass/fixture.json b/packages/runtime-core/tests/integration/projects/astro-pass/fixture.json similarity index 100% rename from registry/tests/projects/astro-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/astro-pass/fixture.json diff --git a/registry/tests/projects/astro-pass/package.json b/packages/runtime-core/tests/integration/projects/astro-pass/package.json similarity index 100% rename from registry/tests/projects/astro-pass/package.json rename to packages/runtime-core/tests/integration/projects/astro-pass/package.json diff --git a/registry/tests/projects/astro-pass/src/components/Counter.jsx b/packages/runtime-core/tests/integration/projects/astro-pass/src/components/Counter.jsx similarity index 100% rename from registry/tests/projects/astro-pass/src/components/Counter.jsx rename to packages/runtime-core/tests/integration/projects/astro-pass/src/components/Counter.jsx diff --git a/registry/tests/projects/astro-pass/src/index.js b/packages/runtime-core/tests/integration/projects/astro-pass/src/index.js similarity index 100% rename from registry/tests/projects/astro-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/astro-pass/src/index.js diff --git a/registry/tests/projects/astro-pass/src/pages/index.astro b/packages/runtime-core/tests/integration/projects/astro-pass/src/pages/index.astro similarity index 100% rename from registry/tests/projects/astro-pass/src/pages/index.astro rename to packages/runtime-core/tests/integration/projects/astro-pass/src/pages/index.astro diff --git a/registry/tests/projects/axios-pass/fixture.json b/packages/runtime-core/tests/integration/projects/axios-pass/fixture.json similarity index 100% rename from registry/tests/projects/axios-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/axios-pass/fixture.json diff --git a/registry/tests/projects/axios-pass/package.json b/packages/runtime-core/tests/integration/projects/axios-pass/package.json similarity index 100% rename from registry/tests/projects/axios-pass/package.json rename to packages/runtime-core/tests/integration/projects/axios-pass/package.json diff --git a/registry/tests/projects/axios-pass/src/index.js b/packages/runtime-core/tests/integration/projects/axios-pass/src/index.js similarity index 100% rename from registry/tests/projects/axios-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/axios-pass/src/index.js diff --git a/registry/tests/projects/bcryptjs-pass/fixture.json b/packages/runtime-core/tests/integration/projects/bcryptjs-pass/fixture.json similarity index 100% rename from registry/tests/projects/bcryptjs-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/bcryptjs-pass/fixture.json diff --git a/registry/tests/projects/bcryptjs-pass/package.json b/packages/runtime-core/tests/integration/projects/bcryptjs-pass/package.json similarity index 100% rename from registry/tests/projects/bcryptjs-pass/package.json rename to packages/runtime-core/tests/integration/projects/bcryptjs-pass/package.json diff --git a/registry/tests/projects/bcryptjs-pass/pnpm-lock.yaml b/packages/runtime-core/tests/integration/projects/bcryptjs-pass/pnpm-lock.yaml similarity index 100% rename from registry/tests/projects/bcryptjs-pass/pnpm-lock.yaml rename to packages/runtime-core/tests/integration/projects/bcryptjs-pass/pnpm-lock.yaml diff --git a/registry/tests/projects/bcryptjs-pass/src/index.js b/packages/runtime-core/tests/integration/projects/bcryptjs-pass/src/index.js similarity index 100% rename from registry/tests/projects/bcryptjs-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/bcryptjs-pass/src/index.js diff --git a/registry/tests/projects/bun-layout-pass/bun.lock b/packages/runtime-core/tests/integration/projects/bun-layout-pass/bun.lock similarity index 100% rename from registry/tests/projects/bun-layout-pass/bun.lock rename to packages/runtime-core/tests/integration/projects/bun-layout-pass/bun.lock diff --git a/registry/tests/projects/bun-layout-pass/fixture.json b/packages/runtime-core/tests/integration/projects/bun-layout-pass/fixture.json similarity index 100% rename from registry/tests/projects/bun-layout-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/bun-layout-pass/fixture.json diff --git a/registry/tests/projects/bun-layout-pass/package.json b/packages/runtime-core/tests/integration/projects/bun-layout-pass/package.json similarity index 100% rename from registry/tests/projects/bun-layout-pass/package.json rename to packages/runtime-core/tests/integration/projects/bun-layout-pass/package.json diff --git a/registry/tests/projects/bun-layout-pass/src/index.js b/packages/runtime-core/tests/integration/projects/bun-layout-pass/src/index.js similarity index 100% rename from registry/tests/projects/bun-layout-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/bun-layout-pass/src/index.js diff --git a/registry/tests/projects/chalk-pass/fixture.json b/packages/runtime-core/tests/integration/projects/chalk-pass/fixture.json similarity index 100% rename from registry/tests/projects/chalk-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/chalk-pass/fixture.json diff --git a/registry/tests/projects/chalk-pass/package.json b/packages/runtime-core/tests/integration/projects/chalk-pass/package.json similarity index 100% rename from registry/tests/projects/chalk-pass/package.json rename to packages/runtime-core/tests/integration/projects/chalk-pass/package.json diff --git a/registry/tests/projects/chalk-pass/src/index.js b/packages/runtime-core/tests/integration/projects/chalk-pass/src/index.js similarity index 100% rename from registry/tests/projects/chalk-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/chalk-pass/src/index.js diff --git a/registry/tests/projects/conditional-exports-pass/fixture.json b/packages/runtime-core/tests/integration/projects/conditional-exports-pass/fixture.json similarity index 100% rename from registry/tests/projects/conditional-exports-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/conditional-exports-pass/fixture.json diff --git a/registry/tests/projects/conditional-exports-pass/package-lock.json b/packages/runtime-core/tests/integration/projects/conditional-exports-pass/package-lock.json similarity index 100% rename from registry/tests/projects/conditional-exports-pass/package-lock.json rename to packages/runtime-core/tests/integration/projects/conditional-exports-pass/package-lock.json diff --git a/registry/tests/projects/conditional-exports-pass/package.json b/packages/runtime-core/tests/integration/projects/conditional-exports-pass/package.json similarity index 100% rename from registry/tests/projects/conditional-exports-pass/package.json rename to packages/runtime-core/tests/integration/projects/conditional-exports-pass/package.json diff --git a/registry/tests/projects/conditional-exports-pass/packages/cond-exports-lib/lib/feature-cjs.js b/packages/runtime-core/tests/integration/projects/conditional-exports-pass/packages/cond-exports-lib/lib/feature-cjs.js similarity index 100% rename from registry/tests/projects/conditional-exports-pass/packages/cond-exports-lib/lib/feature-cjs.js rename to packages/runtime-core/tests/integration/projects/conditional-exports-pass/packages/cond-exports-lib/lib/feature-cjs.js diff --git a/registry/tests/projects/conditional-exports-pass/packages/cond-exports-lib/lib/feature-default.js b/packages/runtime-core/tests/integration/projects/conditional-exports-pass/packages/cond-exports-lib/lib/feature-default.js similarity index 100% rename from registry/tests/projects/conditional-exports-pass/packages/cond-exports-lib/lib/feature-default.js rename to packages/runtime-core/tests/integration/projects/conditional-exports-pass/packages/cond-exports-lib/lib/feature-default.js diff --git a/registry/tests/projects/conditional-exports-pass/packages/cond-exports-lib/lib/main-cjs.js b/packages/runtime-core/tests/integration/projects/conditional-exports-pass/packages/cond-exports-lib/lib/main-cjs.js similarity index 100% rename from registry/tests/projects/conditional-exports-pass/packages/cond-exports-lib/lib/main-cjs.js rename to packages/runtime-core/tests/integration/projects/conditional-exports-pass/packages/cond-exports-lib/lib/main-cjs.js diff --git a/registry/tests/projects/conditional-exports-pass/packages/cond-exports-lib/lib/main-default.js b/packages/runtime-core/tests/integration/projects/conditional-exports-pass/packages/cond-exports-lib/lib/main-default.js similarity index 100% rename from registry/tests/projects/conditional-exports-pass/packages/cond-exports-lib/lib/main-default.js rename to packages/runtime-core/tests/integration/projects/conditional-exports-pass/packages/cond-exports-lib/lib/main-default.js diff --git a/registry/tests/projects/conditional-exports-pass/packages/cond-exports-lib/package.json b/packages/runtime-core/tests/integration/projects/conditional-exports-pass/packages/cond-exports-lib/package.json similarity index 100% rename from registry/tests/projects/conditional-exports-pass/packages/cond-exports-lib/package.json rename to packages/runtime-core/tests/integration/projects/conditional-exports-pass/packages/cond-exports-lib/package.json diff --git a/registry/tests/projects/conditional-exports-pass/src/index.js b/packages/runtime-core/tests/integration/projects/conditional-exports-pass/src/index.js similarity index 100% rename from registry/tests/projects/conditional-exports-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/conditional-exports-pass/src/index.js diff --git a/registry/tests/projects/crypto-random-pass/fixture.json b/packages/runtime-core/tests/integration/projects/crypto-random-pass/fixture.json similarity index 100% rename from registry/tests/projects/crypto-random-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/crypto-random-pass/fixture.json diff --git a/registry/tests/projects/crypto-random-pass/package.json b/packages/runtime-core/tests/integration/projects/crypto-random-pass/package.json similarity index 100% rename from registry/tests/projects/crypto-random-pass/package.json rename to packages/runtime-core/tests/integration/projects/crypto-random-pass/package.json diff --git a/registry/tests/projects/crypto-random-pass/src/index.js b/packages/runtime-core/tests/integration/projects/crypto-random-pass/src/index.js similarity index 100% rename from registry/tests/projects/crypto-random-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/crypto-random-pass/src/index.js diff --git a/registry/tests/projects/dotenv-pass/.env b/packages/runtime-core/tests/integration/projects/dotenv-pass/.env similarity index 100% rename from registry/tests/projects/dotenv-pass/.env rename to packages/runtime-core/tests/integration/projects/dotenv-pass/.env diff --git a/registry/tests/projects/dotenv-pass/fixture.json b/packages/runtime-core/tests/integration/projects/dotenv-pass/fixture.json similarity index 100% rename from registry/tests/projects/dotenv-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/dotenv-pass/fixture.json diff --git a/registry/tests/projects/dotenv-pass/package.json b/packages/runtime-core/tests/integration/projects/dotenv-pass/package.json similarity index 100% rename from registry/tests/projects/dotenv-pass/package.json rename to packages/runtime-core/tests/integration/projects/dotenv-pass/package.json diff --git a/registry/tests/projects/dotenv-pass/src/index.js b/packages/runtime-core/tests/integration/projects/dotenv-pass/src/index.js similarity index 100% rename from registry/tests/projects/dotenv-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/dotenv-pass/src/index.js diff --git a/registry/tests/projects/drizzle-pass/fixture.json b/packages/runtime-core/tests/integration/projects/drizzle-pass/fixture.json similarity index 100% rename from registry/tests/projects/drizzle-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/drizzle-pass/fixture.json diff --git a/registry/tests/projects/drizzle-pass/package.json b/packages/runtime-core/tests/integration/projects/drizzle-pass/package.json similarity index 100% rename from registry/tests/projects/drizzle-pass/package.json rename to packages/runtime-core/tests/integration/projects/drizzle-pass/package.json diff --git a/registry/tests/projects/drizzle-pass/src/index.js b/packages/runtime-core/tests/integration/projects/drizzle-pass/src/index.js similarity index 100% rename from registry/tests/projects/drizzle-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/drizzle-pass/src/index.js diff --git a/registry/tests/projects/esm-import-pass/fixture.json b/packages/runtime-core/tests/integration/projects/esm-import-pass/fixture.json similarity index 100% rename from registry/tests/projects/esm-import-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/esm-import-pass/fixture.json diff --git a/registry/tests/projects/esm-import-pass/package.json b/packages/runtime-core/tests/integration/projects/esm-import-pass/package.json similarity index 100% rename from registry/tests/projects/esm-import-pass/package.json rename to packages/runtime-core/tests/integration/projects/esm-import-pass/package.json diff --git a/registry/tests/projects/esm-import-pass/src/index.js b/packages/runtime-core/tests/integration/projects/esm-import-pass/src/index.js similarity index 100% rename from registry/tests/projects/esm-import-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/esm-import-pass/src/index.js diff --git a/registry/tests/projects/express-pass/fixture.json b/packages/runtime-core/tests/integration/projects/express-pass/fixture.json similarity index 100% rename from registry/tests/projects/express-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/express-pass/fixture.json diff --git a/registry/tests/projects/express-pass/package.json b/packages/runtime-core/tests/integration/projects/express-pass/package.json similarity index 100% rename from registry/tests/projects/express-pass/package.json rename to packages/runtime-core/tests/integration/projects/express-pass/package.json diff --git a/registry/tests/projects/express-pass/pnpm-lock.yaml b/packages/runtime-core/tests/integration/projects/express-pass/pnpm-lock.yaml similarity index 100% rename from registry/tests/projects/express-pass/pnpm-lock.yaml rename to packages/runtime-core/tests/integration/projects/express-pass/pnpm-lock.yaml diff --git a/registry/tests/projects/express-pass/src/index.js b/packages/runtime-core/tests/integration/projects/express-pass/src/index.js similarity index 100% rename from registry/tests/projects/express-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/express-pass/src/index.js diff --git a/registry/tests/projects/fastify-pass/fixture.json b/packages/runtime-core/tests/integration/projects/fastify-pass/fixture.json similarity index 100% rename from registry/tests/projects/fastify-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/fastify-pass/fixture.json diff --git a/registry/tests/projects/fastify-pass/package.json b/packages/runtime-core/tests/integration/projects/fastify-pass/package.json similarity index 100% rename from registry/tests/projects/fastify-pass/package.json rename to packages/runtime-core/tests/integration/projects/fastify-pass/package.json diff --git a/registry/tests/projects/fastify-pass/pnpm-lock.yaml b/packages/runtime-core/tests/integration/projects/fastify-pass/pnpm-lock.yaml similarity index 100% rename from registry/tests/projects/fastify-pass/pnpm-lock.yaml rename to packages/runtime-core/tests/integration/projects/fastify-pass/pnpm-lock.yaml diff --git a/registry/tests/projects/fastify-pass/src/index.js b/packages/runtime-core/tests/integration/projects/fastify-pass/src/index.js similarity index 100% rename from registry/tests/projects/fastify-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/fastify-pass/src/index.js diff --git a/registry/tests/projects/fs-metadata-rename-pass/fixture.json b/packages/runtime-core/tests/integration/projects/fs-metadata-rename-pass/fixture.json similarity index 100% rename from registry/tests/projects/fs-metadata-rename-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/fs-metadata-rename-pass/fixture.json diff --git a/registry/tests/projects/fs-metadata-rename-pass/package.json b/packages/runtime-core/tests/integration/projects/fs-metadata-rename-pass/package.json similarity index 100% rename from registry/tests/projects/fs-metadata-rename-pass/package.json rename to packages/runtime-core/tests/integration/projects/fs-metadata-rename-pass/package.json diff --git a/registry/tests/projects/fs-metadata-rename-pass/src/index.js b/packages/runtime-core/tests/integration/projects/fs-metadata-rename-pass/src/index.js similarity index 100% rename from registry/tests/projects/fs-metadata-rename-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/fs-metadata-rename-pass/src/index.js diff --git a/registry/tests/projects/ioredis-pass/fixture.json b/packages/runtime-core/tests/integration/projects/ioredis-pass/fixture.json similarity index 100% rename from registry/tests/projects/ioredis-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/ioredis-pass/fixture.json diff --git a/registry/tests/projects/ioredis-pass/package.json b/packages/runtime-core/tests/integration/projects/ioredis-pass/package.json similarity index 100% rename from registry/tests/projects/ioredis-pass/package.json rename to packages/runtime-core/tests/integration/projects/ioredis-pass/package.json diff --git a/registry/tests/projects/ioredis-pass/pnpm-lock.yaml b/packages/runtime-core/tests/integration/projects/ioredis-pass/pnpm-lock.yaml similarity index 100% rename from registry/tests/projects/ioredis-pass/pnpm-lock.yaml rename to packages/runtime-core/tests/integration/projects/ioredis-pass/pnpm-lock.yaml diff --git a/registry/tests/projects/ioredis-pass/src/index.js b/packages/runtime-core/tests/integration/projects/ioredis-pass/src/index.js similarity index 100% rename from registry/tests/projects/ioredis-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/ioredis-pass/src/index.js diff --git a/registry/tests/projects/jsonwebtoken-pass/fixture.json b/packages/runtime-core/tests/integration/projects/jsonwebtoken-pass/fixture.json similarity index 100% rename from registry/tests/projects/jsonwebtoken-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/jsonwebtoken-pass/fixture.json diff --git a/registry/tests/projects/jsonwebtoken-pass/package.json b/packages/runtime-core/tests/integration/projects/jsonwebtoken-pass/package.json similarity index 100% rename from registry/tests/projects/jsonwebtoken-pass/package.json rename to packages/runtime-core/tests/integration/projects/jsonwebtoken-pass/package.json diff --git a/registry/tests/projects/jsonwebtoken-pass/src/index.js b/packages/runtime-core/tests/integration/projects/jsonwebtoken-pass/src/index.js similarity index 100% rename from registry/tests/projects/jsonwebtoken-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/jsonwebtoken-pass/src/index.js diff --git a/registry/tests/projects/lodash-es-pass/fixture.json b/packages/runtime-core/tests/integration/projects/lodash-es-pass/fixture.json similarity index 100% rename from registry/tests/projects/lodash-es-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/lodash-es-pass/fixture.json diff --git a/registry/tests/projects/lodash-es-pass/package.json b/packages/runtime-core/tests/integration/projects/lodash-es-pass/package.json similarity index 100% rename from registry/tests/projects/lodash-es-pass/package.json rename to packages/runtime-core/tests/integration/projects/lodash-es-pass/package.json diff --git a/registry/tests/projects/lodash-es-pass/pnpm-lock.yaml b/packages/runtime-core/tests/integration/projects/lodash-es-pass/pnpm-lock.yaml similarity index 100% rename from registry/tests/projects/lodash-es-pass/pnpm-lock.yaml rename to packages/runtime-core/tests/integration/projects/lodash-es-pass/pnpm-lock.yaml diff --git a/registry/tests/projects/lodash-es-pass/src/index.js b/packages/runtime-core/tests/integration/projects/lodash-es-pass/src/index.js similarity index 100% rename from registry/tests/projects/lodash-es-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/lodash-es-pass/src/index.js diff --git a/registry/tests/projects/module-access-pass/fixture.json b/packages/runtime-core/tests/integration/projects/module-access-pass/fixture.json similarity index 100% rename from registry/tests/projects/module-access-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/module-access-pass/fixture.json diff --git a/registry/tests/projects/module-access-pass/package.json b/packages/runtime-core/tests/integration/projects/module-access-pass/package.json similarity index 100% rename from registry/tests/projects/module-access-pass/package.json rename to packages/runtime-core/tests/integration/projects/module-access-pass/package.json diff --git a/registry/tests/projects/module-access-pass/src/index.js b/packages/runtime-core/tests/integration/projects/module-access-pass/src/index.js similarity index 100% rename from registry/tests/projects/module-access-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/module-access-pass/src/index.js diff --git a/registry/tests/projects/module-access-pass/vendor/entry-lib/index.js b/packages/runtime-core/tests/integration/projects/module-access-pass/vendor/entry-lib/index.js similarity index 100% rename from registry/tests/projects/module-access-pass/vendor/entry-lib/index.js rename to packages/runtime-core/tests/integration/projects/module-access-pass/vendor/entry-lib/index.js diff --git a/registry/tests/projects/module-access-pass/vendor/entry-lib/package.json b/packages/runtime-core/tests/integration/projects/module-access-pass/vendor/entry-lib/package.json similarity index 100% rename from registry/tests/projects/module-access-pass/vendor/entry-lib/package.json rename to packages/runtime-core/tests/integration/projects/module-access-pass/vendor/entry-lib/package.json diff --git a/registry/tests/projects/module-access-pass/vendor/transitive-lib/index.js b/packages/runtime-core/tests/integration/projects/module-access-pass/vendor/transitive-lib/index.js similarity index 100% rename from registry/tests/projects/module-access-pass/vendor/transitive-lib/index.js rename to packages/runtime-core/tests/integration/projects/module-access-pass/vendor/transitive-lib/index.js diff --git a/registry/tests/projects/module-access-pass/vendor/transitive-lib/package.json b/packages/runtime-core/tests/integration/projects/module-access-pass/vendor/transitive-lib/package.json similarity index 100% rename from registry/tests/projects/module-access-pass/vendor/transitive-lib/package.json rename to packages/runtime-core/tests/integration/projects/module-access-pass/vendor/transitive-lib/package.json diff --git a/registry/tests/projects/mysql2-pass/fixture.json b/packages/runtime-core/tests/integration/projects/mysql2-pass/fixture.json similarity index 100% rename from registry/tests/projects/mysql2-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/mysql2-pass/fixture.json diff --git a/registry/tests/projects/mysql2-pass/package.json b/packages/runtime-core/tests/integration/projects/mysql2-pass/package.json similarity index 100% rename from registry/tests/projects/mysql2-pass/package.json rename to packages/runtime-core/tests/integration/projects/mysql2-pass/package.json diff --git a/registry/tests/projects/mysql2-pass/src/index.js b/packages/runtime-core/tests/integration/projects/mysql2-pass/src/index.js similarity index 100% rename from registry/tests/projects/mysql2-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/mysql2-pass/src/index.js diff --git a/registry/tests/projects/net-create-server-pass/fixture.json b/packages/runtime-core/tests/integration/projects/net-create-server-pass/fixture.json similarity index 100% rename from registry/tests/projects/net-create-server-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/net-create-server-pass/fixture.json diff --git a/registry/tests/projects/net-create-server-pass/package.json b/packages/runtime-core/tests/integration/projects/net-create-server-pass/package.json similarity index 100% rename from registry/tests/projects/net-create-server-pass/package.json rename to packages/runtime-core/tests/integration/projects/net-create-server-pass/package.json diff --git a/registry/tests/projects/net-create-server-pass/src/index.js b/packages/runtime-core/tests/integration/projects/net-create-server-pass/src/index.js similarity index 100% rename from registry/tests/projects/net-create-server-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/net-create-server-pass/src/index.js diff --git a/registry/tests/projects/nextjs-pass/.babelrc b/packages/runtime-core/tests/integration/projects/nextjs-pass/.babelrc similarity index 100% rename from registry/tests/projects/nextjs-pass/.babelrc rename to packages/runtime-core/tests/integration/projects/nextjs-pass/.babelrc diff --git a/registry/tests/projects/nextjs-pass/fixture.json b/packages/runtime-core/tests/integration/projects/nextjs-pass/fixture.json similarity index 100% rename from registry/tests/projects/nextjs-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/nextjs-pass/fixture.json diff --git a/registry/tests/projects/nextjs-pass/next-wasm-shim.cjs b/packages/runtime-core/tests/integration/projects/nextjs-pass/next-wasm-shim.cjs similarity index 100% rename from registry/tests/projects/nextjs-pass/next-wasm-shim.cjs rename to packages/runtime-core/tests/integration/projects/nextjs-pass/next-wasm-shim.cjs diff --git a/registry/tests/projects/nextjs-pass/next.config.js b/packages/runtime-core/tests/integration/projects/nextjs-pass/next.config.js similarity index 100% rename from registry/tests/projects/nextjs-pass/next.config.js rename to packages/runtime-core/tests/integration/projects/nextjs-pass/next.config.js diff --git a/registry/tests/projects/nextjs-pass/package.json b/packages/runtime-core/tests/integration/projects/nextjs-pass/package.json similarity index 100% rename from registry/tests/projects/nextjs-pass/package.json rename to packages/runtime-core/tests/integration/projects/nextjs-pass/package.json diff --git a/registry/tests/projects/nextjs-pass/pages/api/hello.js b/packages/runtime-core/tests/integration/projects/nextjs-pass/pages/api/hello.js similarity index 100% rename from registry/tests/projects/nextjs-pass/pages/api/hello.js rename to packages/runtime-core/tests/integration/projects/nextjs-pass/pages/api/hello.js diff --git a/registry/tests/projects/nextjs-pass/pages/index.js b/packages/runtime-core/tests/integration/projects/nextjs-pass/pages/index.js similarity index 100% rename from registry/tests/projects/nextjs-pass/pages/index.js rename to packages/runtime-core/tests/integration/projects/nextjs-pass/pages/index.js diff --git a/registry/tests/projects/nextjs-pass/run-next-build.cjs b/packages/runtime-core/tests/integration/projects/nextjs-pass/run-next-build.cjs similarity index 100% rename from registry/tests/projects/nextjs-pass/run-next-build.cjs rename to packages/runtime-core/tests/integration/projects/nextjs-pass/run-next-build.cjs diff --git a/registry/tests/projects/nextjs-pass/src/index.js b/packages/runtime-core/tests/integration/projects/nextjs-pass/src/index.js similarity index 100% rename from registry/tests/projects/nextjs-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/nextjs-pass/src/index.js diff --git a/registry/tests/projects/node-fetch-pass/fixture.json b/packages/runtime-core/tests/integration/projects/node-fetch-pass/fixture.json similarity index 100% rename from registry/tests/projects/node-fetch-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/node-fetch-pass/fixture.json diff --git a/registry/tests/projects/node-fetch-pass/package.json b/packages/runtime-core/tests/integration/projects/node-fetch-pass/package.json similarity index 100% rename from registry/tests/projects/node-fetch-pass/package.json rename to packages/runtime-core/tests/integration/projects/node-fetch-pass/package.json diff --git a/registry/tests/projects/node-fetch-pass/src/index.js b/packages/runtime-core/tests/integration/projects/node-fetch-pass/src/index.js similarity index 100% rename from registry/tests/projects/node-fetch-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/node-fetch-pass/src/index.js diff --git a/registry/tests/projects/npm-layout-pass/fixture.json b/packages/runtime-core/tests/integration/projects/npm-layout-pass/fixture.json similarity index 100% rename from registry/tests/projects/npm-layout-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/npm-layout-pass/fixture.json diff --git a/registry/tests/projects/npm-layout-pass/package-lock.json b/packages/runtime-core/tests/integration/projects/npm-layout-pass/package-lock.json similarity index 100% rename from registry/tests/projects/npm-layout-pass/package-lock.json rename to packages/runtime-core/tests/integration/projects/npm-layout-pass/package-lock.json diff --git a/registry/tests/projects/npm-layout-pass/package.json b/packages/runtime-core/tests/integration/projects/npm-layout-pass/package.json similarity index 100% rename from registry/tests/projects/npm-layout-pass/package.json rename to packages/runtime-core/tests/integration/projects/npm-layout-pass/package.json diff --git a/registry/tests/projects/npm-layout-pass/src/index.js b/packages/runtime-core/tests/integration/projects/npm-layout-pass/src/index.js similarity index 100% rename from registry/tests/projects/npm-layout-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/npm-layout-pass/src/index.js diff --git a/registry/tests/projects/optional-deps-pass/fixture.json b/packages/runtime-core/tests/integration/projects/optional-deps-pass/fixture.json similarity index 100% rename from registry/tests/projects/optional-deps-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/optional-deps-pass/fixture.json diff --git a/registry/tests/projects/optional-deps-pass/package-lock.json b/packages/runtime-core/tests/integration/projects/optional-deps-pass/package-lock.json similarity index 100% rename from registry/tests/projects/optional-deps-pass/package-lock.json rename to packages/runtime-core/tests/integration/projects/optional-deps-pass/package-lock.json diff --git a/registry/tests/projects/optional-deps-pass/package.json b/packages/runtime-core/tests/integration/projects/optional-deps-pass/package.json similarity index 100% rename from registry/tests/projects/optional-deps-pass/package.json rename to packages/runtime-core/tests/integration/projects/optional-deps-pass/package.json diff --git a/registry/tests/projects/optional-deps-pass/src/index.js b/packages/runtime-core/tests/integration/projects/optional-deps-pass/src/index.js similarity index 100% rename from registry/tests/projects/optional-deps-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/optional-deps-pass/src/index.js diff --git a/registry/tests/projects/peer-deps-pass/fixture.json b/packages/runtime-core/tests/integration/projects/peer-deps-pass/fixture.json similarity index 100% rename from registry/tests/projects/peer-deps-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/peer-deps-pass/fixture.json diff --git a/registry/tests/projects/peer-deps-pass/package-lock.json b/packages/runtime-core/tests/integration/projects/peer-deps-pass/package-lock.json similarity index 100% rename from registry/tests/projects/peer-deps-pass/package-lock.json rename to packages/runtime-core/tests/integration/projects/peer-deps-pass/package-lock.json diff --git a/registry/tests/projects/peer-deps-pass/package.json b/packages/runtime-core/tests/integration/projects/peer-deps-pass/package.json similarity index 100% rename from registry/tests/projects/peer-deps-pass/package.json rename to packages/runtime-core/tests/integration/projects/peer-deps-pass/package.json diff --git a/registry/tests/projects/peer-deps-pass/packages/host/index.js b/packages/runtime-core/tests/integration/projects/peer-deps-pass/packages/host/index.js similarity index 100% rename from registry/tests/projects/peer-deps-pass/packages/host/index.js rename to packages/runtime-core/tests/integration/projects/peer-deps-pass/packages/host/index.js diff --git a/registry/tests/projects/peer-deps-pass/packages/host/package.json b/packages/runtime-core/tests/integration/projects/peer-deps-pass/packages/host/package.json similarity index 100% rename from registry/tests/projects/peer-deps-pass/packages/host/package.json rename to packages/runtime-core/tests/integration/projects/peer-deps-pass/packages/host/package.json diff --git a/registry/tests/projects/peer-deps-pass/packages/plugin/index.js b/packages/runtime-core/tests/integration/projects/peer-deps-pass/packages/plugin/index.js similarity index 100% rename from registry/tests/projects/peer-deps-pass/packages/plugin/index.js rename to packages/runtime-core/tests/integration/projects/peer-deps-pass/packages/plugin/index.js diff --git a/registry/tests/projects/peer-deps-pass/packages/plugin/package.json b/packages/runtime-core/tests/integration/projects/peer-deps-pass/packages/plugin/package.json similarity index 100% rename from registry/tests/projects/peer-deps-pass/packages/plugin/package.json rename to packages/runtime-core/tests/integration/projects/peer-deps-pass/packages/plugin/package.json diff --git a/registry/tests/projects/peer-deps-pass/src/index.js b/packages/runtime-core/tests/integration/projects/peer-deps-pass/src/index.js similarity index 100% rename from registry/tests/projects/peer-deps-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/peer-deps-pass/src/index.js diff --git a/registry/tests/projects/pg-pass/fixture.json b/packages/runtime-core/tests/integration/projects/pg-pass/fixture.json similarity index 100% rename from registry/tests/projects/pg-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/pg-pass/fixture.json diff --git a/registry/tests/projects/pg-pass/package.json b/packages/runtime-core/tests/integration/projects/pg-pass/package.json similarity index 100% rename from registry/tests/projects/pg-pass/package.json rename to packages/runtime-core/tests/integration/projects/pg-pass/package.json diff --git a/registry/tests/projects/pg-pass/pnpm-lock.yaml b/packages/runtime-core/tests/integration/projects/pg-pass/pnpm-lock.yaml similarity index 100% rename from registry/tests/projects/pg-pass/pnpm-lock.yaml rename to packages/runtime-core/tests/integration/projects/pg-pass/pnpm-lock.yaml diff --git a/registry/tests/projects/pg-pass/src/index.js b/packages/runtime-core/tests/integration/projects/pg-pass/src/index.js similarity index 100% rename from registry/tests/projects/pg-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/pg-pass/src/index.js diff --git a/registry/tests/projects/pino-pass/fixture.json b/packages/runtime-core/tests/integration/projects/pino-pass/fixture.json similarity index 100% rename from registry/tests/projects/pino-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/pino-pass/fixture.json diff --git a/registry/tests/projects/pino-pass/package.json b/packages/runtime-core/tests/integration/projects/pino-pass/package.json similarity index 100% rename from registry/tests/projects/pino-pass/package.json rename to packages/runtime-core/tests/integration/projects/pino-pass/package.json diff --git a/registry/tests/projects/pino-pass/pnpm-lock.yaml b/packages/runtime-core/tests/integration/projects/pino-pass/pnpm-lock.yaml similarity index 100% rename from registry/tests/projects/pino-pass/pnpm-lock.yaml rename to packages/runtime-core/tests/integration/projects/pino-pass/pnpm-lock.yaml diff --git a/registry/tests/projects/pino-pass/src/index.js b/packages/runtime-core/tests/integration/projects/pino-pass/src/index.js similarity index 100% rename from registry/tests/projects/pino-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/pino-pass/src/index.js diff --git a/registry/tests/projects/pnpm-layout-pass/fixture.json b/packages/runtime-core/tests/integration/projects/pnpm-layout-pass/fixture.json similarity index 100% rename from registry/tests/projects/pnpm-layout-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/pnpm-layout-pass/fixture.json diff --git a/registry/tests/projects/pnpm-layout-pass/package.json b/packages/runtime-core/tests/integration/projects/pnpm-layout-pass/package.json similarity index 100% rename from registry/tests/projects/pnpm-layout-pass/package.json rename to packages/runtime-core/tests/integration/projects/pnpm-layout-pass/package.json diff --git a/registry/tests/projects/pnpm-layout-pass/pnpm-lock.yaml b/packages/runtime-core/tests/integration/projects/pnpm-layout-pass/pnpm-lock.yaml similarity index 100% rename from registry/tests/projects/pnpm-layout-pass/pnpm-lock.yaml rename to packages/runtime-core/tests/integration/projects/pnpm-layout-pass/pnpm-lock.yaml diff --git a/registry/tests/projects/pnpm-layout-pass/src/index.js b/packages/runtime-core/tests/integration/projects/pnpm-layout-pass/src/index.js similarity index 100% rename from registry/tests/projects/pnpm-layout-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/pnpm-layout-pass/src/index.js diff --git a/registry/tests/projects/rivetkit/fixture.json b/packages/runtime-core/tests/integration/projects/rivetkit/fixture.json similarity index 100% rename from registry/tests/projects/rivetkit/fixture.json rename to packages/runtime-core/tests/integration/projects/rivetkit/fixture.json diff --git a/registry/tests/projects/rivetkit/package.json b/packages/runtime-core/tests/integration/projects/rivetkit/package.json similarity index 100% rename from registry/tests/projects/rivetkit/package.json rename to packages/runtime-core/tests/integration/projects/rivetkit/package.json diff --git a/registry/tests/projects/rivetkit/src/index.js b/packages/runtime-core/tests/integration/projects/rivetkit/src/index.js similarity index 100% rename from registry/tests/projects/rivetkit/src/index.js rename to packages/runtime-core/tests/integration/projects/rivetkit/src/index.js diff --git a/registry/tests/projects/rivetkit/vendor/rivetkit/package.json b/packages/runtime-core/tests/integration/projects/rivetkit/vendor/rivetkit/package.json similarity index 100% rename from registry/tests/projects/rivetkit/vendor/rivetkit/package.json rename to packages/runtime-core/tests/integration/projects/rivetkit/vendor/rivetkit/package.json diff --git a/registry/tests/projects/semver-pass/fixture.json b/packages/runtime-core/tests/integration/projects/semver-pass/fixture.json similarity index 100% rename from registry/tests/projects/semver-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/semver-pass/fixture.json diff --git a/registry/tests/projects/semver-pass/package.json b/packages/runtime-core/tests/integration/projects/semver-pass/package.json similarity index 100% rename from registry/tests/projects/semver-pass/package.json rename to packages/runtime-core/tests/integration/projects/semver-pass/package.json diff --git a/registry/tests/projects/semver-pass/src/index.js b/packages/runtime-core/tests/integration/projects/semver-pass/src/index.js similarity index 100% rename from registry/tests/projects/semver-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/semver-pass/src/index.js diff --git a/registry/tests/projects/sse-streaming-pass/fixture.json b/packages/runtime-core/tests/integration/projects/sse-streaming-pass/fixture.json similarity index 100% rename from registry/tests/projects/sse-streaming-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/sse-streaming-pass/fixture.json diff --git a/registry/tests/projects/sse-streaming-pass/package.json b/packages/runtime-core/tests/integration/projects/sse-streaming-pass/package.json similarity index 100% rename from registry/tests/projects/sse-streaming-pass/package.json rename to packages/runtime-core/tests/integration/projects/sse-streaming-pass/package.json diff --git a/registry/tests/projects/sse-streaming-pass/src/index.js b/packages/runtime-core/tests/integration/projects/sse-streaming-pass/src/index.js similarity index 100% rename from registry/tests/projects/sse-streaming-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/sse-streaming-pass/src/index.js diff --git a/registry/tests/projects/ssh2-pass/fixture.json b/packages/runtime-core/tests/integration/projects/ssh2-pass/fixture.json similarity index 100% rename from registry/tests/projects/ssh2-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/ssh2-pass/fixture.json diff --git a/registry/tests/projects/ssh2-pass/package.json b/packages/runtime-core/tests/integration/projects/ssh2-pass/package.json similarity index 100% rename from registry/tests/projects/ssh2-pass/package.json rename to packages/runtime-core/tests/integration/projects/ssh2-pass/package.json diff --git a/registry/tests/projects/ssh2-pass/src/index.js b/packages/runtime-core/tests/integration/projects/ssh2-pass/src/index.js similarity index 100% rename from registry/tests/projects/ssh2-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/ssh2-pass/src/index.js diff --git a/registry/tests/projects/ssh2-sftp-client-pass/fixture.json b/packages/runtime-core/tests/integration/projects/ssh2-sftp-client-pass/fixture.json similarity index 100% rename from registry/tests/projects/ssh2-sftp-client-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/ssh2-sftp-client-pass/fixture.json diff --git a/registry/tests/projects/ssh2-sftp-client-pass/package.json b/packages/runtime-core/tests/integration/projects/ssh2-sftp-client-pass/package.json similarity index 100% rename from registry/tests/projects/ssh2-sftp-client-pass/package.json rename to packages/runtime-core/tests/integration/projects/ssh2-sftp-client-pass/package.json diff --git a/registry/tests/projects/ssh2-sftp-client-pass/src/index.js b/packages/runtime-core/tests/integration/projects/ssh2-sftp-client-pass/src/index.js similarity index 100% rename from registry/tests/projects/ssh2-sftp-client-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/ssh2-sftp-client-pass/src/index.js diff --git a/registry/tests/projects/transitive-deps-pass/fixture.json b/packages/runtime-core/tests/integration/projects/transitive-deps-pass/fixture.json similarity index 100% rename from registry/tests/projects/transitive-deps-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/transitive-deps-pass/fixture.json diff --git a/registry/tests/projects/transitive-deps-pass/package-lock.json b/packages/runtime-core/tests/integration/projects/transitive-deps-pass/package-lock.json similarity index 100% rename from registry/tests/projects/transitive-deps-pass/package-lock.json rename to packages/runtime-core/tests/integration/projects/transitive-deps-pass/package-lock.json diff --git a/registry/tests/projects/transitive-deps-pass/package.json b/packages/runtime-core/tests/integration/projects/transitive-deps-pass/package.json similarity index 100% rename from registry/tests/projects/transitive-deps-pass/package.json rename to packages/runtime-core/tests/integration/projects/transitive-deps-pass/package.json diff --git a/registry/tests/projects/transitive-deps-pass/packages/level-a/index.js b/packages/runtime-core/tests/integration/projects/transitive-deps-pass/packages/level-a/index.js similarity index 100% rename from registry/tests/projects/transitive-deps-pass/packages/level-a/index.js rename to packages/runtime-core/tests/integration/projects/transitive-deps-pass/packages/level-a/index.js diff --git a/registry/tests/projects/transitive-deps-pass/packages/level-a/package.json b/packages/runtime-core/tests/integration/projects/transitive-deps-pass/packages/level-a/package.json similarity index 100% rename from registry/tests/projects/transitive-deps-pass/packages/level-a/package.json rename to packages/runtime-core/tests/integration/projects/transitive-deps-pass/packages/level-a/package.json diff --git a/registry/tests/projects/transitive-deps-pass/packages/level-b/index.js b/packages/runtime-core/tests/integration/projects/transitive-deps-pass/packages/level-b/index.js similarity index 100% rename from registry/tests/projects/transitive-deps-pass/packages/level-b/index.js rename to packages/runtime-core/tests/integration/projects/transitive-deps-pass/packages/level-b/index.js diff --git a/registry/tests/projects/transitive-deps-pass/packages/level-b/package.json b/packages/runtime-core/tests/integration/projects/transitive-deps-pass/packages/level-b/package.json similarity index 100% rename from registry/tests/projects/transitive-deps-pass/packages/level-b/package.json rename to packages/runtime-core/tests/integration/projects/transitive-deps-pass/packages/level-b/package.json diff --git a/registry/tests/projects/transitive-deps-pass/packages/level-c/index.js b/packages/runtime-core/tests/integration/projects/transitive-deps-pass/packages/level-c/index.js similarity index 100% rename from registry/tests/projects/transitive-deps-pass/packages/level-c/index.js rename to packages/runtime-core/tests/integration/projects/transitive-deps-pass/packages/level-c/index.js diff --git a/registry/tests/projects/transitive-deps-pass/packages/level-c/package.json b/packages/runtime-core/tests/integration/projects/transitive-deps-pass/packages/level-c/package.json similarity index 100% rename from registry/tests/projects/transitive-deps-pass/packages/level-c/package.json rename to packages/runtime-core/tests/integration/projects/transitive-deps-pass/packages/level-c/package.json diff --git a/registry/tests/projects/transitive-deps-pass/src/index.js b/packages/runtime-core/tests/integration/projects/transitive-deps-pass/src/index.js similarity index 100% rename from registry/tests/projects/transitive-deps-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/transitive-deps-pass/src/index.js diff --git a/registry/tests/projects/uuid-pass/fixture.json b/packages/runtime-core/tests/integration/projects/uuid-pass/fixture.json similarity index 100% rename from registry/tests/projects/uuid-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/uuid-pass/fixture.json diff --git a/registry/tests/projects/uuid-pass/package.json b/packages/runtime-core/tests/integration/projects/uuid-pass/package.json similarity index 100% rename from registry/tests/projects/uuid-pass/package.json rename to packages/runtime-core/tests/integration/projects/uuid-pass/package.json diff --git a/registry/tests/projects/uuid-pass/src/index.js b/packages/runtime-core/tests/integration/projects/uuid-pass/src/index.js similarity index 100% rename from registry/tests/projects/uuid-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/uuid-pass/src/index.js diff --git a/registry/tests/projects/vite-pass/app/main.jsx b/packages/runtime-core/tests/integration/projects/vite-pass/app/main.jsx similarity index 100% rename from registry/tests/projects/vite-pass/app/main.jsx rename to packages/runtime-core/tests/integration/projects/vite-pass/app/main.jsx diff --git a/registry/tests/projects/vite-pass/fixture.json b/packages/runtime-core/tests/integration/projects/vite-pass/fixture.json similarity index 100% rename from registry/tests/projects/vite-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/vite-pass/fixture.json diff --git a/registry/tests/projects/vite-pass/index.html b/packages/runtime-core/tests/integration/projects/vite-pass/index.html similarity index 100% rename from registry/tests/projects/vite-pass/index.html rename to packages/runtime-core/tests/integration/projects/vite-pass/index.html diff --git a/registry/tests/projects/vite-pass/package.json b/packages/runtime-core/tests/integration/projects/vite-pass/package.json similarity index 100% rename from registry/tests/projects/vite-pass/package.json rename to packages/runtime-core/tests/integration/projects/vite-pass/package.json diff --git a/registry/tests/projects/vite-pass/src/index.js b/packages/runtime-core/tests/integration/projects/vite-pass/src/index.js similarity index 100% rename from registry/tests/projects/vite-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/vite-pass/src/index.js diff --git a/registry/tests/projects/vite-pass/vite.config.mjs b/packages/runtime-core/tests/integration/projects/vite-pass/vite.config.mjs similarity index 100% rename from registry/tests/projects/vite-pass/vite.config.mjs rename to packages/runtime-core/tests/integration/projects/vite-pass/vite.config.mjs diff --git a/registry/tests/projects/workspace-layout-pass/fixture.json b/packages/runtime-core/tests/integration/projects/workspace-layout-pass/fixture.json similarity index 100% rename from registry/tests/projects/workspace-layout-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/workspace-layout-pass/fixture.json diff --git a/registry/tests/projects/workspace-layout-pass/package.json b/packages/runtime-core/tests/integration/projects/workspace-layout-pass/package.json similarity index 100% rename from registry/tests/projects/workspace-layout-pass/package.json rename to packages/runtime-core/tests/integration/projects/workspace-layout-pass/package.json diff --git a/registry/tests/projects/workspace-layout-pass/packages/app/package.json b/packages/runtime-core/tests/integration/projects/workspace-layout-pass/packages/app/package.json similarity index 100% rename from registry/tests/projects/workspace-layout-pass/packages/app/package.json rename to packages/runtime-core/tests/integration/projects/workspace-layout-pass/packages/app/package.json diff --git a/registry/tests/projects/workspace-layout-pass/packages/app/src/index.js b/packages/runtime-core/tests/integration/projects/workspace-layout-pass/packages/app/src/index.js similarity index 100% rename from registry/tests/projects/workspace-layout-pass/packages/app/src/index.js rename to packages/runtime-core/tests/integration/projects/workspace-layout-pass/packages/app/src/index.js diff --git a/registry/tests/projects/workspace-layout-pass/packages/lib/package.json b/packages/runtime-core/tests/integration/projects/workspace-layout-pass/packages/lib/package.json similarity index 100% rename from registry/tests/projects/workspace-layout-pass/packages/lib/package.json rename to packages/runtime-core/tests/integration/projects/workspace-layout-pass/packages/lib/package.json diff --git a/registry/tests/projects/workspace-layout-pass/packages/lib/src/index.js b/packages/runtime-core/tests/integration/projects/workspace-layout-pass/packages/lib/src/index.js similarity index 100% rename from registry/tests/projects/workspace-layout-pass/packages/lib/src/index.js rename to packages/runtime-core/tests/integration/projects/workspace-layout-pass/packages/lib/src/index.js diff --git a/registry/tests/projects/ws-pass/fixture.json b/packages/runtime-core/tests/integration/projects/ws-pass/fixture.json similarity index 100% rename from registry/tests/projects/ws-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/ws-pass/fixture.json diff --git a/registry/tests/projects/ws-pass/package-lock.json b/packages/runtime-core/tests/integration/projects/ws-pass/package-lock.json similarity index 100% rename from registry/tests/projects/ws-pass/package-lock.json rename to packages/runtime-core/tests/integration/projects/ws-pass/package-lock.json diff --git a/registry/tests/projects/ws-pass/package.json b/packages/runtime-core/tests/integration/projects/ws-pass/package.json similarity index 100% rename from registry/tests/projects/ws-pass/package.json rename to packages/runtime-core/tests/integration/projects/ws-pass/package.json diff --git a/registry/tests/projects/ws-pass/src/index.js b/packages/runtime-core/tests/integration/projects/ws-pass/src/index.js similarity index 100% rename from registry/tests/projects/ws-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/ws-pass/src/index.js diff --git a/registry/tests/projects/yaml-pass/fixture.json b/packages/runtime-core/tests/integration/projects/yaml-pass/fixture.json similarity index 100% rename from registry/tests/projects/yaml-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/yaml-pass/fixture.json diff --git a/registry/tests/projects/yaml-pass/package.json b/packages/runtime-core/tests/integration/projects/yaml-pass/package.json similarity index 100% rename from registry/tests/projects/yaml-pass/package.json rename to packages/runtime-core/tests/integration/projects/yaml-pass/package.json diff --git a/registry/tests/projects/yaml-pass/src/index.js b/packages/runtime-core/tests/integration/projects/yaml-pass/src/index.js similarity index 100% rename from registry/tests/projects/yaml-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/yaml-pass/src/index.js diff --git a/registry/tests/projects/yarn-berry-layout-pass/.yarnrc.yml b/packages/runtime-core/tests/integration/projects/yarn-berry-layout-pass/.yarnrc.yml similarity index 100% rename from registry/tests/projects/yarn-berry-layout-pass/.yarnrc.yml rename to packages/runtime-core/tests/integration/projects/yarn-berry-layout-pass/.yarnrc.yml diff --git a/registry/tests/projects/yarn-berry-layout-pass/fixture.json b/packages/runtime-core/tests/integration/projects/yarn-berry-layout-pass/fixture.json similarity index 100% rename from registry/tests/projects/yarn-berry-layout-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/yarn-berry-layout-pass/fixture.json diff --git a/registry/tests/projects/yarn-berry-layout-pass/package.json b/packages/runtime-core/tests/integration/projects/yarn-berry-layout-pass/package.json similarity index 100% rename from registry/tests/projects/yarn-berry-layout-pass/package.json rename to packages/runtime-core/tests/integration/projects/yarn-berry-layout-pass/package.json diff --git a/registry/tests/projects/yarn-berry-layout-pass/src/index.js b/packages/runtime-core/tests/integration/projects/yarn-berry-layout-pass/src/index.js similarity index 100% rename from registry/tests/projects/yarn-berry-layout-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/yarn-berry-layout-pass/src/index.js diff --git a/registry/tests/projects/yarn-berry-layout-pass/yarn.lock b/packages/runtime-core/tests/integration/projects/yarn-berry-layout-pass/yarn.lock similarity index 100% rename from registry/tests/projects/yarn-berry-layout-pass/yarn.lock rename to packages/runtime-core/tests/integration/projects/yarn-berry-layout-pass/yarn.lock diff --git a/registry/tests/projects/yarn-classic-layout-pass/fixture.json b/packages/runtime-core/tests/integration/projects/yarn-classic-layout-pass/fixture.json similarity index 100% rename from registry/tests/projects/yarn-classic-layout-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/yarn-classic-layout-pass/fixture.json diff --git a/registry/tests/projects/yarn-classic-layout-pass/package.json b/packages/runtime-core/tests/integration/projects/yarn-classic-layout-pass/package.json similarity index 100% rename from registry/tests/projects/yarn-classic-layout-pass/package.json rename to packages/runtime-core/tests/integration/projects/yarn-classic-layout-pass/package.json diff --git a/registry/tests/projects/yarn-classic-layout-pass/src/index.js b/packages/runtime-core/tests/integration/projects/yarn-classic-layout-pass/src/index.js similarity index 100% rename from registry/tests/projects/yarn-classic-layout-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/yarn-classic-layout-pass/src/index.js diff --git a/registry/tests/projects/yarn-classic-layout-pass/yarn.lock b/packages/runtime-core/tests/integration/projects/yarn-classic-layout-pass/yarn.lock similarity index 100% rename from registry/tests/projects/yarn-classic-layout-pass/yarn.lock rename to packages/runtime-core/tests/integration/projects/yarn-classic-layout-pass/yarn.lock diff --git a/registry/tests/projects/zod-pass/fixture.json b/packages/runtime-core/tests/integration/projects/zod-pass/fixture.json similarity index 100% rename from registry/tests/projects/zod-pass/fixture.json rename to packages/runtime-core/tests/integration/projects/zod-pass/fixture.json diff --git a/registry/tests/projects/zod-pass/package.json b/packages/runtime-core/tests/integration/projects/zod-pass/package.json similarity index 100% rename from registry/tests/projects/zod-pass/package.json rename to packages/runtime-core/tests/integration/projects/zod-pass/package.json diff --git a/registry/tests/projects/zod-pass/pnpm-lock.yaml b/packages/runtime-core/tests/integration/projects/zod-pass/pnpm-lock.yaml similarity index 100% rename from registry/tests/projects/zod-pass/pnpm-lock.yaml rename to packages/runtime-core/tests/integration/projects/zod-pass/pnpm-lock.yaml diff --git a/registry/tests/projects/zod-pass/src/index.js b/packages/runtime-core/tests/integration/projects/zod-pass/src/index.js similarity index 100% rename from registry/tests/projects/zod-pass/src/index.js rename to packages/runtime-core/tests/integration/projects/zod-pass/src/index.js diff --git a/registry/tests/kernel/repro-npm-install.ts b/packages/runtime-core/tests/integration/repro-npm-install.ts similarity index 93% rename from registry/tests/kernel/repro-npm-install.ts rename to packages/runtime-core/tests/integration/repro-npm-install.ts index 03358f9204..7e24de262e 100644 --- a/registry/tests/kernel/repro-npm-install.ts +++ b/packages/runtime-core/tests/integration/repro-npm-install.ts @@ -1,7 +1,7 @@ import { mkdtemp, rm, writeFile } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import path from 'node:path'; -import { COMMANDS_DIR, createKernel, NodeFileSystem, createWasmVmRuntime, createNodeRuntime } from '../helpers.ts'; +import { COMMANDS_DIR, createKernel, NodeFileSystem, createWasmVmRuntime, createNodeRuntime } from '@rivet-dev/agentos-vm-test-harness'; const tempDir = await mkdtemp(path.join(tmpdir(), 'kernel-npm-install-repro-')); console.log('tempDir', tempDir); diff --git a/registry/tests/kernel/shim-streaming.test.ts b/packages/runtime-core/tests/integration/shim-streaming.test.ts similarity index 86% rename from registry/tests/kernel/shim-streaming.test.ts rename to packages/runtime-core/tests/integration/shim-streaming.test.ts index aad4e4de59..634f9729c7 100644 --- a/registry/tests/kernel/shim-streaming.test.ts +++ b/packages/runtime-core/tests/integration/shim-streaming.test.ts @@ -3,8 +3,8 @@ import { createIntegrationKernel, describeIf, skipUnlessWasmBuilt, -} from './helpers.ts'; -import type { IntegrationKernelResult } from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { IntegrationKernelResult } from '@rivet-dev/agentos-vm-test-harness'; const skipReason = skipUnlessWasmBuilt(); diff --git a/registry/tests/kernel/signal-forwarding.test.ts b/packages/runtime-core/tests/integration/signal-forwarding.test.ts similarity index 96% rename from registry/tests/kernel/signal-forwarding.test.ts rename to packages/runtime-core/tests/integration/signal-forwarding.test.ts index 117b079dab..ac085e0818 100644 --- a/registry/tests/kernel/signal-forwarding.test.ts +++ b/packages/runtime-core/tests/integration/signal-forwarding.test.ts @@ -11,8 +11,8 @@ import { describeIf, createIntegrationKernel, skipUnlessWasmBuilt, -} from './helpers.ts'; -import type { IntegrationKernelResult } from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { IntegrationKernelResult } from '@rivet-dev/agentos-vm-test-harness'; const skipReason = skipUnlessWasmBuilt(); diff --git a/registry/tests/wasmvm/signal-handler.test.ts b/packages/runtime-core/tests/integration/signal-handler.test.ts similarity index 96% rename from registry/tests/wasmvm/signal-handler.test.ts rename to packages/runtime-core/tests/integration/signal-handler.test.ts index 9feeed21c8..1365ad9596 100644 --- a/registry/tests/wasmvm/signal-handler.test.ts +++ b/packages/runtime-core/tests/integration/signal-handler.test.ts @@ -7,7 +7,7 @@ */ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; -import { createWasmVmRuntime } from '../helpers.js'; +import { createWasmVmRuntime } from '@rivet-dev/agentos-vm-test-harness'; import { COMMANDS_DIR, C_BUILD_DIR, @@ -15,8 +15,8 @@ import { describeIf, hasWasmBinaries, SIGTERM, -} from '../helpers.js'; -import type { Kernel } from '../helpers.js'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { Kernel } from '@rivet-dev/agentos-vm-test-harness'; import { existsSync } from 'node:fs'; import { join } from 'node:path'; diff --git a/registry/tests/kernel/vfs-consistency.test.ts b/packages/runtime-core/tests/integration/vfs-consistency.test.ts similarity index 96% rename from registry/tests/kernel/vfs-consistency.test.ts rename to packages/runtime-core/tests/integration/vfs-consistency.test.ts index c4a1fa04a6..19939a6ff8 100644 --- a/registry/tests/kernel/vfs-consistency.test.ts +++ b/packages/runtime-core/tests/integration/vfs-consistency.test.ts @@ -12,8 +12,8 @@ import { describeIf, createIntegrationKernel, skipUnlessWasmBuilt, -} from './helpers.ts'; -import type { IntegrationKernelResult } from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { IntegrationKernelResult } from '@rivet-dev/agentos-vm-test-harness'; const skipReason = skipUnlessWasmBuilt(); diff --git a/registry/tests/wasmvm/wasi-http.test.ts b/packages/runtime-core/tests/integration/wasi-http.test.ts similarity index 98% rename from registry/tests/wasmvm/wasi-http.test.ts rename to packages/runtime-core/tests/integration/wasi-http.test.ts index 06f6cec3cf..1ae71fc27b 100644 --- a/registry/tests/wasmvm/wasi-http.test.ts +++ b/packages/runtime-core/tests/integration/wasi-http.test.ts @@ -12,9 +12,9 @@ */ import { describe, it, expect, afterEach, beforeAll, afterAll } from 'vitest'; -import { createWasmVmRuntime } from '../helpers.js'; -import { COMMANDS_DIR, createKernel, describeIf, hasWasmBinaries } from '../helpers.js'; -import type { Kernel } from '../helpers.js'; +import { createWasmVmRuntime } from '@rivet-dev/agentos-vm-test-harness'; +import { COMMANDS_DIR, createKernel, describeIf, hasWasmBinaries } from '@rivet-dev/agentos-vm-test-harness'; +import type { Kernel } from '@rivet-dev/agentos-vm-test-harness'; import { createServer as createHttpServer, type Server, type IncomingMessage, type ServerResponse } from 'node:http'; import { createServer as createHttpsServer, type Server as HttpsServer } from 'node:https'; import { execSync } from 'node:child_process'; diff --git a/registry/tests/wasmvm/wasi-spawn.test.ts b/packages/runtime-core/tests/integration/wasi-spawn.test.ts similarity index 96% rename from registry/tests/wasmvm/wasi-spawn.test.ts rename to packages/runtime-core/tests/integration/wasi-spawn.test.ts index 5f74ef1eae..910364314b 100644 --- a/registry/tests/wasmvm/wasi-spawn.test.ts +++ b/packages/runtime-core/tests/integration/wasi-spawn.test.ts @@ -9,9 +9,9 @@ */ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; -import { createWasmVmRuntime } from '../helpers.js'; -import { COMMANDS_DIR, createKernel, describeIf, hasWasmBinaries } from '../helpers.js'; -import type { Kernel } from '../helpers.js'; +import { createWasmVmRuntime } from '@rivet-dev/agentos-vm-test-harness'; +import { COMMANDS_DIR, createKernel, describeIf, hasWasmBinaries } from '@rivet-dev/agentos-vm-test-harness'; +import type { Kernel } from '@rivet-dev/agentos-vm-test-harness'; import { existsSync } from 'node:fs'; import { resolve } from 'node:path'; diff --git a/packages/vm-test-harness/package.json b/packages/vm-test-harness/package.json new file mode 100644 index 0000000000..ae0cd7b34a --- /dev/null +++ b/packages/vm-test-harness/package.json @@ -0,0 +1,27 @@ +{ + "name": "@rivet-dev/agentos-vm-test-harness", + "version": "0.0.1", + "private": true, + "type": "module", + "license": "Apache-2.0", + "exports": { + ".": { + "types": "./src/index.ts", + "import": "./src/index.ts" + } + }, + "scripts": { + "check-types": "tsc --noEmit", + "build": "tsc --noEmit", + "test": "node -e \"process.exit(0)\"" + }, + "dependencies": { + "@rivet-dev/agentos-runtime-core": "workspace:*", + "@xterm/headless": "^6.0.0" + }, + "devDependencies": { + "@types/node": "^22.10.2", + "typescript": "^5.9.2", + "vitest": "^2.1.9" + } +} diff --git a/packages/vm-test-harness/src/index.ts b/packages/vm-test-harness/src/index.ts new file mode 100644 index 0000000000..6af7afdaca --- /dev/null +++ b/packages/vm-test-harness/src/index.ts @@ -0,0 +1,168 @@ +import { existsSync } from "node:fs"; +import { resolve } from "node:path"; +import { describe, it } from "vitest"; + +/** Directory containing WASM command binaries built from Rust. */ +export const COMMANDS_DIR = resolve( + process.env.AGENTOS_WASM_COMMANDS_DIR ?? + resolve(import.meta.dirname, "../../runtime-core/commands"), +); + +/** Directory containing C-compiled WASM binaries. */ +export const C_BUILD_DIR = resolve( + process.env.AGENTOS_C_WASM_COMMANDS_DIR ?? + resolve(import.meta.dirname, "../../../registry/native/c/build"), +); + +/** Whether the main WASM command binaries are available (includes 'sh'). */ +export const hasWasmBinaries = + existsSync(COMMANDS_DIR) && existsSync(resolve(COMMANDS_DIR, "sh")); + +/** + * Check whether specific C WASM binaries are present. + * @param names - Binary names to check for inside C_BUILD_DIR. + * @returns true if all requested binaries exist. + */ +export function hasCWasmBinaries(...names: string[]): boolean { + if (!existsSync(C_BUILD_DIR)) return false; + return names.every((name) => existsSync(resolve(C_BUILD_DIR, name))); +} + +/** + * Returns a skip-reason string if WASM binaries are missing, or false if + * they are available and tests should run. + */ +export function skipReason(): string | false { + if (!hasWasmBinaries) { + return `WASM binaries not found at ${COMMANDS_DIR} - build registry/native first`; + } + return false; +} + +export function describeIf( + condition: unknown, + ...args: Parameters +): void { + if (condition) { + describe(...args); + return; + } + const [name] = args; + describe.skip(`${String(name)} [environment prerequisites not met]`, () => {}); +} + +export function itIf(condition: unknown, ...args: Parameters): void { + if (condition) { + it(...args); + return; + } + const [name] = args; + it.skip(`${String(name)} [environment prerequisites not met]`, () => {}); +} + +export { + AF_INET, + AF_UNIX, + allowAll, + createInMemoryFileSystem, + SIGTERM, + SOCK_DGRAM, + SOCK_STREAM, +} from "../../runtime-core/src/test-runtime.js"; +import { + allowAll, + createInMemoryFileSystem, + createKernel as createKernelBase, + createNodeRuntime, + createWasmVmRuntime, +} from "../../runtime-core/src/test-runtime.js"; +export type { + DriverProcess, + Kernel, + KernelInterface, + KernelRuntimeDriver, + Permissions, + ProcessContext, + VirtualFileSystem, +} from "../../runtime-core/src/test-runtime.js"; +export { + createWasmVmRuntime, + DEFAULT_FIRST_PARTY_TIERS, + WASMVM_COMMANDS, + type PermissionTier, + type WasmVmRuntimeOptions, +} from "../../runtime-core/src/test-runtime.js"; +export { + createNodeHostNetworkAdapter, + createNodeRuntime, + NodeFileSystem, +} from "../../runtime-core/src/test-runtime.js"; +export { TerminalHarness } from "./terminal-harness.js"; + +/** + * Registry integration tests assume they can bootstrap runtimes and /bin stubs + * unless they explicitly opt into a stricter permission policy. + */ +export function createKernel( + options: Parameters[0], +): ReturnType { + return createKernelBase({ + ...options, + permissions: options.permissions ?? allowAll, + }); +} + +export interface IntegrationKernelResult { + kernel: ReturnType; + vfs: ReturnType; + dispose: () => Promise; +} + +export interface IntegrationKernelOptions { + runtimes?: ("wasmvm" | "node")[]; + loopbackExemptPorts?: number[]; + commandDirs?: string[]; + permissions?: Parameters[0]["permissions"]; +} + +/** + * Create a kernel with the in-scope runtime drivers for integration testing. + * + * Mount order matters. Last-mounted driver wins for overlapping commands: + * 1. WasmVM first: provides sh/bash/coreutils (90+ commands) + * 2. Node second: overrides WasmVM's 'node' stub with real V8 + */ +export async function createIntegrationKernel( + options?: IntegrationKernelOptions, +): Promise { + const runtimes = options?.runtimes ?? ["wasmvm"]; + const vfs = createInMemoryFileSystem(); + const kernel = createKernel({ + filesystem: vfs, + loopbackExemptPorts: options?.loopbackExemptPorts, + permissions: options?.permissions, + }); + + if (runtimes.includes("wasmvm")) { + await kernel.mount( + createWasmVmRuntime({ commandDirs: options?.commandDirs ?? [COMMANDS_DIR] }), + ); + } + if (runtimes.includes("node")) { + await kernel.mount(createNodeRuntime()); + } + + return { + kernel, + vfs, + dispose: () => kernel.dispose(), + }; +} + +/** + * Skip helper: returns a reason string if the WASM binaries are not built, + * or false if the commands directory exists and tests can run. + */ +export function skipUnlessWasmBuilt(): string | false { + return skipReason(); +} diff --git a/registry/tests/terminal-harness.ts b/packages/vm-test-harness/src/terminal-harness.ts similarity index 96% rename from registry/tests/terminal-harness.ts rename to packages/vm-test-harness/src/terminal-harness.ts index b01ad66a9e..3ec00c1caa 100644 --- a/registry/tests/terminal-harness.ts +++ b/packages/vm-test-harness/src/terminal-harness.ts @@ -1,10 +1,10 @@ /** - * TerminalHarness wires openShell() to a headless xterm Terminal so registry - * tests can assert against deterministic terminal screen state. + * TerminalHarness wires openShell() to a headless xterm Terminal so tests can + * assert against deterministic terminal screen state. */ import { Terminal } from "@xterm/headless"; -import type { Kernel } from "./helpers.js"; +import type { Kernel } from "./index.js"; type ShellHandle = ReturnType; diff --git a/packages/vm-test-harness/tsconfig.json b/packages/vm-test-harness/tsconfig.json new file mode 100644 index 0000000000..639c948caf --- /dev/null +++ b/packages/vm-test-harness/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "noEmit": true + }, + "include": ["src/**/*"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f159cc531e..1740b41e83 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,6 +50,9 @@ importers: '@rivet-dev/agentos-runtime-core': specifier: workspace:* version: link:packages/runtime-core + '@rivet-dev/agentos-vm-test-harness': + specifier: workspace:* + version: link:packages/vm-test-harness '@types/node': specifier: ^22.19.15 version: 22.19.15 @@ -2924,6 +2927,49 @@ importers: specifier: ^2.1.8 version: 2.1.9(@types/node@22.19.15) + packages/vm-test-harness: + dependencies: + '@rivet-dev/agentos-runtime-core': + specifier: workspace:* + version: link:../runtime-core + '@xterm/headless': + specifier: ^6.0.0 + version: 6.0.0 + devDependencies: + '@types/node': + specifier: ^22.10.2 + version: 22.19.15 + typescript: + specifier: ^5.9.2 + version: 5.9.3 + vitest: + specifier: ^2.1.9 + version: 2.1.9(@types/node@22.19.15) + + registry: + devDependencies: + '@agentos-software/common': + specifier: workspace:* + version: link:software/common + '@agentos-software/curl': + specifier: workspace:* + version: link:software/curl + '@rivet-dev/agentos-runtime-core': + specifier: workspace:* + version: link:../packages/runtime-core + '@rivet-dev/agentos-vm-test-harness': + specifier: workspace:* + version: link:../packages/vm-test-harness + '@types/node': + specifier: ^22.10.2 + version: 22.19.15 + typescript: + specifier: ^5.9.2 + version: 5.9.3 + vitest: + specifier: ^2.1.9 + version: 2.1.9(@types/node@22.19.15) + registry/agent/claude: dependencies: '@agentclientprotocol/sdk': diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index abbcff2e92..cd84490eb8 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -15,11 +15,13 @@ packages: - packages/runtime-core - packages/runtime-sidecar - packages/runtime-sidecar/npm/* + - packages/vm-test-harness - packages/secure-exec - packages/secure-exec-example-ai-agent-type-check - packages/typescript - packages/shell - packages/sidecar-binary + - registry - registry/agent/* - registry/software/* - registry/tool/* diff --git a/registry/tests/wasmvm/c-parity.test.ts b/registry/native/tests/c-parity.test.ts similarity index 99% rename from registry/tests/wasmvm/c-parity.test.ts rename to registry/native/tests/c-parity.test.ts index 84daa0a463..b71f8b907d 100644 --- a/registry/tests/wasmvm/c-parity.test.ts +++ b/registry/native/tests/c-parity.test.ts @@ -8,7 +8,7 @@ */ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; -import { createWasmVmRuntime } from '../helpers.js'; +import { createWasmVmRuntime } from '@rivet-dev/agentos-vm-test-harness'; import { COMMANDS_DIR, C_BUILD_DIR, @@ -16,8 +16,8 @@ import { describeIf, hasWasmBinaries, itIf, -} from '../helpers.js'; -import type { Kernel } from '../helpers.js'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { Kernel } from '@rivet-dev/agentos-vm-test-harness'; import { existsSync } from 'node:fs'; import { writeFile as fsWriteFile, readFile as fsReadFile, mkdtemp, rm, mkdir as fsMkdir } from 'node:fs/promises'; import { spawn } from 'node:child_process'; diff --git a/registry/tests/wasmvm/ci-artifact-availability.test.ts b/registry/native/tests/ci-artifact-availability.test.ts similarity index 95% rename from registry/tests/wasmvm/ci-artifact-availability.test.ts rename to registry/native/tests/ci-artifact-availability.test.ts index 5f86752143..eed6275c5c 100644 --- a/registry/tests/wasmvm/ci-artifact-availability.test.ts +++ b/registry/native/tests/ci-artifact-availability.test.ts @@ -7,7 +7,7 @@ */ import { describe, it, expect } from 'vitest'; -import { COMMANDS_DIR, C_BUILD_DIR, itIf } from '../helpers.js'; +import { COMMANDS_DIR, C_BUILD_DIR, itIf } from '@rivet-dev/agentos-vm-test-harness'; import { existsSync } from 'node:fs'; import { join } from 'node:path'; diff --git a/registry/tests/kernel/ci-wasm-artifact-availability.test.ts b/registry/native/tests/ci-wasm-artifact-availability.test.ts similarity index 94% rename from registry/tests/kernel/ci-wasm-artifact-availability.test.ts rename to registry/native/tests/ci-wasm-artifact-availability.test.ts index 5f4c420669..c7f395e1b9 100644 --- a/registry/tests/kernel/ci-wasm-artifact-availability.test.ts +++ b/registry/native/tests/ci-wasm-artifact-availability.test.ts @@ -9,7 +9,7 @@ import { describe, it, expect } from 'vitest'; import { existsSync } from 'node:fs'; import { join } from 'node:path'; -import { COMMANDS_DIR, itIf } from './helpers.ts'; +import { COMMANDS_DIR, itIf } from '@rivet-dev/agentos-vm-test-harness'; const REQUIRED_ARTIFACTS = [ { diff --git a/registry/tests/wasmvm/libc-test-conformance.test.ts b/registry/native/tests/libc-test-conformance.test.ts similarity index 98% rename from registry/tests/wasmvm/libc-test-conformance.test.ts rename to registry/native/tests/libc-test-conformance.test.ts index 5211783d91..47eb5bc5f8 100644 --- a/registry/tests/wasmvm/libc-test-conformance.test.ts +++ b/registry/native/tests/libc-test-conformance.test.ts @@ -13,7 +13,7 @@ */ import { describe, it, expect, beforeAll, afterAll } from 'vitest'; -import { createWasmVmRuntime } from '../helpers.js'; +import { createWasmVmRuntime } from '@rivet-dev/agentos-vm-test-harness'; import { COMMANDS_DIR, C_BUILD_DIR, @@ -21,8 +21,8 @@ import { createKernel, describeIf, hasWasmBinaries, -} from '../helpers.js'; -import type { Kernel } from '../helpers.js'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { Kernel } from '@rivet-dev/agentos-vm-test-harness'; import { existsSync, readdirSync, diff --git a/registry/tests/wasmvm/libc-test-exclusions.json b/registry/native/tests/libc-test-exclusions.json similarity index 100% rename from registry/tests/wasmvm/libc-test-exclusions.json rename to registry/native/tests/libc-test-exclusions.json diff --git a/registry/tests/wasmvm/os-test-conformance.test.ts b/registry/native/tests/os-test-conformance.test.ts similarity index 99% rename from registry/tests/wasmvm/os-test-conformance.test.ts rename to registry/native/tests/os-test-conformance.test.ts index d85cb14e97..c06748cc16 100644 --- a/registry/tests/wasmvm/os-test-conformance.test.ts +++ b/registry/native/tests/os-test-conformance.test.ts @@ -9,7 +9,7 @@ */ import { describe, it, expect, beforeAll, afterAll } from 'vitest'; -import { createWasmVmRuntime } from '../helpers.js'; +import { createWasmVmRuntime } from '@rivet-dev/agentos-vm-test-harness'; import { COMMANDS_DIR, C_BUILD_DIR, @@ -17,8 +17,8 @@ import { createKernel, describeIf, hasWasmBinaries, -} from '../helpers.js'; -import type { Kernel } from '../helpers.js'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { Kernel } from '@rivet-dev/agentos-vm-test-harness'; import { existsSync, readdirSync, diff --git a/registry/tests/wasmvm/os-test-exclusions.json b/registry/native/tests/os-test-exclusions.json similarity index 100% rename from registry/tests/wasmvm/os-test-exclusions.json rename to registry/native/tests/os-test-exclusions.json diff --git a/registry/package.json b/registry/package.json index 5a19029fcb..d46a33250b 100644 --- a/registry/package.json +++ b/registry/package.json @@ -10,14 +10,14 @@ }, "scripts": { "check-types": "node -e \"process.exit(0)\"", - "test": "node ./scripts/run-vitest.mjs" + "test": "node ./scripts/check-test-coverage.mjs && node ./scripts/test-status.mjs --check && node ./scripts/run-vitest.mjs native/tests" }, "devDependencies": { "@agentos-software/common": "workspace:*", "@rivet-dev/agentos-runtime-core": "workspace:*", + "@rivet-dev/agentos-vm-test-harness": "workspace:*", "@agentos-software/curl": "workspace:*", "@types/node": "^22.10.2", - "@xterm/headless": "^6.0.0", "typescript": "^5.9.2", "vitest": "^2.1.9" } diff --git a/registry/scripts/check-test-coverage.mjs b/registry/scripts/check-test-coverage.mjs new file mode 100644 index 0000000000..351add6062 --- /dev/null +++ b/registry/scripts/check-test-coverage.mjs @@ -0,0 +1,52 @@ +import { existsSync, readFileSync, readdirSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +const registryRoot = dirname(fileURLToPath(new URL("../package.json", import.meta.url))); +const baselinePath = join(registryRoot, "test-status.json"); +const baseline = JSON.parse(readFileSync(baselinePath, "utf8")); + +const trackedGapStatuses = new Set(["no-test", "not-buildable", "meta"]); +const packages = baseline.packages ?? {}; + +function packageDirs(scope) { + const root = join(registryRoot, scope); + return readdirSync(root, { withFileTypes: true }) + .filter((entry) => entry.isDirectory()) + .map((entry) => entry.name) + .sort(); +} + +const failures = []; + +for (const name of packageDirs("software")) { + const key = `software/${name}`; + const testDir = join(registryRoot, "software", name, "test"); + const entry = packages[key]; + + if (existsSync(testDir)) continue; + if (entry && trackedGapStatuses.has(entry.baselineStatus)) continue; + + failures.push(`${key} has no test/ directory and no tracked gap entry`); +} + +for (const name of packageDirs("agent")) { + const key = `agent/${name}`; + const testDir = join(registryRoot, "agent", name, "test"); + const entry = packages[key]; + + if (existsSync(testDir)) continue; + if (entry?.baselineStatus === "no-test") continue; + + failures.push(`${key} has no test/ directory and no tracked gap entry`); +} + +if (failures.length > 0) { + console.error("Registry test coverage gate failed:"); + for (const failure of failures) { + console.error(`- ${failure}`); + } + process.exit(1); +} + +console.log("Registry test coverage gate passed."); diff --git a/registry/scripts/test-status.mjs b/registry/scripts/test-status.mjs new file mode 100644 index 0000000000..1e12379dab --- /dev/null +++ b/registry/scripts/test-status.mjs @@ -0,0 +1,133 @@ +import { spawnSync } from "node:child_process"; +import { + existsSync, + readFileSync, + readdirSync, + writeFileSync, +} from "node:fs"; +import { dirname, join, relative, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +const registryRoot = dirname(fileURLToPath(new URL("../package.json", import.meta.url))); +const repoRoot = resolve(registryRoot, ".."); +const baselinePath = join(registryRoot, "test-status.json"); +const runVitest = join(registryRoot, "scripts", "run-vitest.mjs"); +const checkMode = process.argv.includes("--check"); + +const baseline = JSON.parse(readFileSync(baselinePath, "utf8")); +const baselinePackages = baseline.packages ?? {}; + +function listPackageDirs(scope) { + const root = join(registryRoot, scope); + return readdirSync(root, { withFileTypes: true }) + .filter((entry) => entry.isDirectory()) + .map((entry) => entry.name) + .sort(); +} + +function classifyVitest(result) { + const output = `${result.stdout ?? ""}\n${result.stderr ?? ""}`; + if (result.status === 0) { + if (/\bskipped\b/i.test(output) && !/\bpassed\b/i.test(output)) { + return "disabled"; + } + return "working"; + } + + if ( + /Transform failed|Failed to load|Cannot find module|SyntaxError|TSError|TypeError: Unknown file extension/i.test( + output, + ) + ) { + return "not-compiling"; + } + + return "failing"; +} + +function runPackageTests(testDir) { + const relTestDir = relative(registryRoot, testDir); + return spawnSync(process.execPath, [runVitest, relTestDir], { + cwd: registryRoot, + encoding: "utf8", + env: { + ...process.env, + AGENTOS_WASM_COMMANDS_DIR: join(repoRoot, "packages/runtime-core/commands"), + AGENTOS_C_WASM_COMMANDS_DIR: join(registryRoot, "native/c/build"), + }, + }); +} + +function currentStatus(scope, name, baselineEntry) { + const testDir = join(registryRoot, scope, name, "test"); + if (!existsSync(testDir)) { + return baselineEntry?.baselineStatus ?? "no-test"; + } + + const result = runPackageTests(testDir); + return classifyVitest(result); +} + +const rows = []; + +for (const scope of ["software", "agent"]) { + for (const name of listPackageDirs(scope)) { + const key = `${scope}/${name}`; + const baselineEntry = baselinePackages[key] ?? {}; + const status = currentStatus(scope, name, baselineEntry); + rows.push({ + key, + baselineStatus: baselineEntry.baselineStatus ?? "no-test", + status, + commands: baselineEntry.commands ?? [], + notes: baselineEntry.notes, + }); + } +} + +const regressions = rows.filter((row) => { + if (row.baselineStatus === "working") return row.status !== "working"; + return false; +}); + +const updated = { + schemaVersion: 1, + generatedAt: new Date().toISOString(), + packages: Object.fromEntries( + rows.map((row) => [ + row.key, + { + baselineStatus: row.baselineStatus, + status: row.status, + commands: row.commands, + ...(row.notes ? { notes: row.notes } : {}), + }, + ]), + ), +}; + +writeFileSync(baselinePath, `${JSON.stringify(updated, null, 2)}\n`); + +const keyWidth = Math.max("package".length, ...rows.map((row) => row.key.length)); +const baselineWidth = "baseline".length; +console.log( + `${"package".padEnd(keyWidth)} ${"baseline".padEnd(baselineWidth)} status`, +); +console.log(`${"-".repeat(keyWidth)} ${"-".repeat(baselineWidth)} ------`); +for (const row of rows) { + console.log( + `${row.key.padEnd(keyWidth)} ${row.baselineStatus.padEnd(baselineWidth)} ${row.status}`, + ); +} + +if (regressions.length > 0) { + console.error("\nRegistry test regressions:"); + for (const row of regressions) { + console.error(`- ${row.key}: baseline working, now ${row.status}`); + } + process.exit(1); +} + +if (checkMode) { + console.log("\nNo registry package test regressions detected."); +} diff --git a/registry/tests/wasmvm/codex-exec.test.ts b/registry/software/codex-cli/test/codex-exec.test.ts similarity index 95% rename from registry/tests/wasmvm/codex-exec.test.ts rename to registry/software/codex-cli/test/codex-exec.test.ts index 1d3da03c42..de6f7002b1 100644 --- a/registry/tests/wasmvm/codex-exec.test.ts +++ b/registry/software/codex-cli/test/codex-exec.test.ts @@ -14,9 +14,13 @@ */ import { describe, it, expect, afterEach } from 'vitest'; -import { createWasmVmRuntime } from '../helpers.js'; -import { COMMANDS_DIR, createKernel, describeIf, hasWasmBinaries } from '../helpers.js'; -import type { Kernel } from '../helpers.js'; +import { existsSync } from 'node:fs'; +import { resolve } from 'node:path'; +import { createWasmVmRuntime } from '@rivet-dev/agentos-vm-test-harness'; +import { COMMANDS_DIR, createKernel, describeIf, hasWasmBinaries } from '@rivet-dev/agentos-vm-test-harness'; +import type { Kernel } from '@rivet-dev/agentos-vm-test-harness'; + +const hasCodexExec = hasWasmBinaries && existsSync(resolve(COMMANDS_DIR, 'codex-exec')); // Minimal in-memory VFS for kernel tests class SimpleVFS { @@ -115,7 +119,7 @@ async function createTestKernel(): Promise<{ kernel: Kernel; vfs: SimpleVFS }> { } // TODO(P6): requires codex-exec WASM artifact from an external fork build, intentionally excluded from the fast registry-build gate. -describe.skip('codex-exec command (WasmVM)', { timeout: 30_000 }, () => { +describeIf(hasCodexExec, 'codex-exec command (WasmVM)', { timeout: 30_000 }, () => { let kernel: Kernel; afterEach(async () => { diff --git a/registry/tests/wasmvm/codex-tui.test.ts b/registry/software/codex-cli/test/codex-tui.test.ts similarity index 93% rename from registry/tests/wasmvm/codex-tui.test.ts rename to registry/software/codex-cli/test/codex-tui.test.ts index ea004eb986..306bb14598 100644 --- a/registry/tests/wasmvm/codex-tui.test.ts +++ b/registry/software/codex-cli/test/codex-tui.test.ts @@ -14,11 +14,14 @@ */ import { describe, it, expect, afterEach } from 'vitest'; -import { TerminalHarness } from './terminal-harness.js'; -import { createWasmVmRuntime } from '../helpers.js'; -import { COMMANDS_DIR, createKernel, describeIf, hasWasmBinaries } from '../helpers.js'; -import type { Kernel } from '../helpers.js'; - +import { existsSync } from 'node:fs'; +import { resolve } from 'node:path'; +import { TerminalHarness } from '@rivet-dev/agentos-vm-test-harness'; +import { createWasmVmRuntime } from '@rivet-dev/agentos-vm-test-harness'; +import { COMMANDS_DIR, createKernel, describeIf, hasWasmBinaries } from '@rivet-dev/agentos-vm-test-harness'; +import type { Kernel } from '@rivet-dev/agentos-vm-test-harness'; + +const hasCodex = hasWasmBinaries && existsSync(resolve(COMMANDS_DIR, 'codex')); const hasApiKey = !!process.env.OPENAI_API_KEY; /** brush-shell interactive prompt. */ @@ -125,7 +128,7 @@ async function createTestKernel(): Promise<{ kernel: Kernel; vfs: SimpleVFS }> { // --------------------------------------------------------------------------- // TODO(P6): requires codex WASM artifact from an external fork build, intentionally excluded from the fast registry-build gate. -describe.skip('codex TUI (WasmVM) - non-interactive', { timeout: 30_000 }, () => { +describeIf(hasCodex, 'codex TUI (WasmVM) - non-interactive', { timeout: 30_000 }, () => { let kernel: Kernel; afterEach(async () => { @@ -156,7 +159,7 @@ describe.skip('codex TUI (WasmVM) - non-interactive', { timeout: 30_000 }, () => // --------------------------------------------------------------------------- // TODO(P6): requires codex WASM artifact from an external fork build, intentionally excluded from the fast registry-build gate. -describe.skip('codex TUI (WasmVM) - interactive', { timeout: 30_000 }, () => { +describeIf(hasCodex, 'codex TUI (WasmVM) - interactive', { timeout: 30_000 }, () => { let kernel: Kernel; let harness: TerminalHarness; @@ -262,7 +265,7 @@ describe.skip('codex TUI (WasmVM) - interactive', { timeout: 30_000 }, () => { // --------------------------------------------------------------------------- // TODO(P6): requires codex WASM artifact from an external fork build, intentionally excluded from the fast registry-build gate. -describe.skip('codex TUI API integration (requires OPENAI_API_KEY)', { timeout: 60_000 }, () => { +describeIf(hasCodex && hasApiKey, 'codex TUI API integration (requires OPENAI_API_KEY)', { timeout: 60_000 }, () => { let kernel: Kernel; let harness: TerminalHarness; diff --git a/registry/tests/wasmvm/shell-redirect.test.ts b/registry/software/coreutils/test/shell-redirect.test.ts similarity index 95% rename from registry/tests/wasmvm/shell-redirect.test.ts rename to registry/software/coreutils/test/shell-redirect.test.ts index ccee94a39b..19889a8643 100644 --- a/registry/tests/wasmvm/shell-redirect.test.ts +++ b/registry/software/coreutils/test/shell-redirect.test.ts @@ -7,7 +7,7 @@ import { describeIf, hasWasmBinaries, type Kernel, -} from "../helpers.js"; +} from '@rivet-dev/agentos-vm-test-harness'; describeIf(hasWasmBinaries, "wasmvm shell redirects", () => { let kernel: Kernel | undefined; diff --git a/registry/tests/wasmvm/shell-terminal.test.ts b/registry/software/coreutils/test/shell-terminal.test.ts similarity index 98% rename from registry/tests/wasmvm/shell-terminal.test.ts rename to registry/software/coreutils/test/shell-terminal.test.ts index 7efaffbb69..b7bf356017 100644 --- a/registry/tests/wasmvm/shell-terminal.test.ts +++ b/registry/software/coreutils/test/shell-terminal.test.ts @@ -7,10 +7,10 @@ */ import { describe, it, expect, afterEach } from "vitest"; -import { TerminalHarness } from './terminal-harness.js'; -import { createWasmVmRuntime } from '../helpers.js'; -import { COMMANDS_DIR, createKernel, describeIf, hasWasmBinaries } from '../helpers.js'; -import type { Kernel } from "../helpers.js"; +import { TerminalHarness } from '@rivet-dev/agentos-vm-test-harness'; +import { createWasmVmRuntime } from '@rivet-dev/agentos-vm-test-harness'; +import { COMMANDS_DIR, createKernel, describeIf, hasWasmBinaries } from '@rivet-dev/agentos-vm-test-harness'; +import type { Kernel } from '@rivet-dev/agentos-vm-test-harness'; /** brush-shell interactive prompt (captured empirically). */ const PROMPT = "sh-0.4$ "; diff --git a/registry/tests/wasmvm/curl.test.ts b/registry/software/curl/test/curl.test.ts similarity index 99% rename from registry/tests/wasmvm/curl.test.ts rename to registry/software/curl/test/curl.test.ts index da9c1b5600..0d72e13057 100644 --- a/registry/tests/wasmvm/curl.test.ts +++ b/registry/software/curl/test/curl.test.ts @@ -12,7 +12,7 @@ */ import { describe, it, expect, afterEach, beforeAll, afterAll } from 'vitest'; -import { createWasmVmRuntime } from '../helpers.js'; +import { createWasmVmRuntime } from '@rivet-dev/agentos-vm-test-harness'; import { allowAll, C_BUILD_DIR, @@ -23,8 +23,8 @@ import { hasCWasmBinaries, hasWasmBinaries, itIf, -} from '../helpers.js'; -import type { Kernel } from '../helpers.js'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { Kernel } from '@rivet-dev/agentos-vm-test-harness'; import { createServer as createHttpServer, type IncomingMessage, diff --git a/registry/tests/wasmvm/duckdb.test.ts b/registry/software/duckdb/test/duckdb.test.ts similarity index 98% rename from registry/tests/wasmvm/duckdb.test.ts rename to registry/software/duckdb/test/duckdb.test.ts index f1dddc9d46..1d4ce161a7 100644 --- a/registry/tests/wasmvm/duckdb.test.ts +++ b/registry/software/duckdb/test/duckdb.test.ts @@ -23,8 +23,8 @@ import { createWasmVmRuntime, describeIf, itIf, -} from '../helpers.js'; -import type { Kernel } from '../helpers.js'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { Kernel } from '@rivet-dev/agentos-vm-test-harness'; import { createServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http'; import { existsSync } from 'node:fs'; import { resolve } from 'node:path'; @@ -83,7 +83,7 @@ async function waitForFilesystemPath( } // TODO(P6): requires duckdb WASM artifact, intentionally excluded from the fast registry-build gate. -describe.skip('duckdb command', { timeout: 120_000 }, () => { +describeIf(hasWasmDuckDB, 'duckdb command', { timeout: 120_000 }, () => { let kernel: Kernel | undefined; afterEach(async () => { diff --git a/registry/tests/wasmvm/fd-find.test.ts b/registry/software/fd/test/fd.test.ts similarity index 98% rename from registry/tests/wasmvm/fd-find.test.ts rename to registry/software/fd/test/fd.test.ts index dfb5faf21d..1faa9cb5e7 100644 --- a/registry/tests/wasmvm/fd-find.test.ts +++ b/registry/software/fd/test/fd.test.ts @@ -11,9 +11,9 @@ */ import { describe, it, expect, afterEach } from 'vitest'; -import { createWasmVmRuntime } from '../helpers.js'; -import { COMMANDS_DIR, createKernel, describeIf, hasWasmBinaries } from '../helpers.js'; -import type { Kernel } from '../helpers.js'; +import { createWasmVmRuntime } from '@rivet-dev/agentos-vm-test-harness'; +import { COMMANDS_DIR, createKernel, describeIf, hasWasmBinaries } from '@rivet-dev/agentos-vm-test-harness'; +import type { Kernel } from '@rivet-dev/agentos-vm-test-harness'; // Minimal in-memory VFS for kernel tests class SimpleVFS { diff --git a/registry/software/findutils/test/findutils.test.ts b/registry/software/findutils/test/findutils.test.ts new file mode 100644 index 0000000000..ddbc597adf --- /dev/null +++ b/registry/software/findutils/test/findutils.test.ts @@ -0,0 +1,73 @@ +/** + * Package-owned integration tests for GNU findutils commands. + */ + +import { afterEach, expect, it } from "vitest"; +import { + COMMANDS_DIR, + createInMemoryFileSystem, + createKernel, + createWasmVmRuntime, + describeIf, + hasWasmBinaries, + type Kernel, +} from "@rivet-dev/agentos-vm-test-harness"; + +function parseLines(stdout: string): string[] { + return stdout + .split("\n") + .map((line) => line.trim()) + .filter(Boolean) + .sort(); +} + +describeIf(hasWasmBinaries, "findutils commands", { timeout: 10_000 }, () => { + let kernel: Kernel; + + afterEach(async () => { + await kernel?.dispose(); + }); + + it("find matches files by name", async () => { + const vfs = createInMemoryFileSystem(); + await vfs.mkdir("/project/src", { recursive: true }); + await vfs.mkdir("/project/docs", { recursive: true }); + await vfs.writeFile("/project/src/main.js", "console.log('main')\n"); + await vfs.writeFile("/project/src/helper.ts", "export {}\n"); + await vfs.writeFile("/project/docs/readme.md", "# Readme\n"); + + kernel = createKernel({ filesystem: vfs }); + await kernel.mount(createWasmVmRuntime({ commandDirs: [COMMANDS_DIR] })); + + const result = await kernel.exec("find /project -name '*.js'"); + expect(parseLines(result.stdout)).toEqual(["/project/src/main.js"]); + }); + + it("find filters directories", async () => { + const vfs = createInMemoryFileSystem(); + await vfs.mkdir("/project/src", { recursive: true }); + await vfs.mkdir("/project/docs", { recursive: true }); + await vfs.writeFile("/project/src/main.js", "console.log('main')\n"); + + kernel = createKernel({ filesystem: vfs }); + await kernel.mount(createWasmVmRuntime({ commandDirs: [COMMANDS_DIR] })); + + const result = await kernel.exec("find /project -type d"); + expect(parseLines(result.stdout)).toEqual([ + "/project", + "/project/docs", + "/project/src", + ]); + }); + + it("xargs passes stdin arguments to a command", async () => { + const vfs = createInMemoryFileSystem(); + await vfs.writeFile("/args.txt", "alpha\nbeta\n"); + + kernel = createKernel({ filesystem: vfs }); + await kernel.mount(createWasmVmRuntime({ commandDirs: [COMMANDS_DIR] })); + + const result = await kernel.exec("xargs echo < /args.txt"); + expect(result.stdout.trim()).toBe("alpha beta"); + }); +}); diff --git a/registry/tests/wasmvm/git.test.ts b/registry/software/git/test/git.test.ts similarity index 99% rename from registry/tests/wasmvm/git.test.ts rename to registry/software/git/test/git.test.ts index 93264c08ea..0e3da18537 100644 --- a/registry/tests/wasmvm/git.test.ts +++ b/registry/software/git/test/git.test.ts @@ -11,7 +11,7 @@ import { resolve, join } from 'node:path'; import { tmpdir } from 'node:os'; import { createServer, type Server as HttpServer } from 'node:http'; import { spawn, spawnSync } from 'node:child_process'; -import { createWasmVmRuntime } from '../helpers.js'; +import { createWasmVmRuntime } from '@rivet-dev/agentos-vm-test-harness'; import { allowAll, COMMANDS_DIR, @@ -19,8 +19,8 @@ import { createKernel, describeIf, hasWasmBinaries, -} from '../helpers.js'; -import type { Kernel } from '../helpers.js'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { Kernel } from '@rivet-dev/agentos-vm-test-harness'; vi.setConfig({ testTimeout: 30_000 }); @@ -77,7 +77,7 @@ async function run(kernel: Kernel, cmd: string): Promise<{ stdout: string; stder } // TODO(P6): requires git WASM artifact, intentionally excluded from the fast registry-build gate. -describe.skip('git command', () => { +describeIf(hasGit, 'git command', () => { let kernel: Kernel; let vfs: any; let dispose: () => Promise; diff --git a/registry/tests/wasmvm/sqlite3.test.ts b/registry/software/sqlite3/test/sqlite3.test.ts similarity index 98% rename from registry/tests/wasmvm/sqlite3.test.ts rename to registry/software/sqlite3/test/sqlite3.test.ts index 2457ce3e1a..a371be05a5 100644 --- a/registry/tests/wasmvm/sqlite3.test.ts +++ b/registry/software/sqlite3/test/sqlite3.test.ts @@ -15,15 +15,15 @@ */ import { describe, it, expect, afterEach } from 'vitest'; -import { createWasmVmRuntime } from '../helpers.js'; +import { createWasmVmRuntime } from '@rivet-dev/agentos-vm-test-harness'; import { C_BUILD_DIR, COMMANDS_DIR, createKernel, describeIf, hasCWasmBinaries, -} from '../helpers.js'; -import type { Kernel } from '../helpers.js'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { Kernel } from '@rivet-dev/agentos-vm-test-harness'; // Minimal in-memory VFS for kernel tests class SimpleVFS { diff --git a/registry/tests/kernel/tree-test.test.ts b/registry/software/tree/test/tree-test.test.ts similarity index 97% rename from registry/tests/kernel/tree-test.test.ts rename to registry/software/tree/test/tree-test.test.ts index 850b5e371a..16fb9ee0aa 100644 --- a/registry/tests/kernel/tree-test.test.ts +++ b/registry/software/tree/test/tree-test.test.ts @@ -10,8 +10,8 @@ import { describeIf, createIntegrationKernel, skipUnlessWasmBuilt, -} from './helpers.ts'; -import type { IntegrationKernelResult } from './helpers.ts'; +} from '@rivet-dev/agentos-vm-test-harness'; +import type { IntegrationKernelResult } from '@rivet-dev/agentos-vm-test-harness'; const wasmSkip = skipUnlessWasmBuilt(); const TREE_COMMAND_TIMEOUT_MS = 20_000; diff --git a/registry/software/unzip/test/unzip.test.ts b/registry/software/unzip/test/unzip.test.ts new file mode 100644 index 0000000000..8cc82c431f --- /dev/null +++ b/registry/software/unzip/test/unzip.test.ts @@ -0,0 +1,219 @@ +/** + * Package-owned integration tests for the unzip command. + */ + +import { afterEach, expect, it } from "vitest"; +import { + C_BUILD_DIR, + COMMANDS_DIR, + createInMemoryFileSystem, + createKernel, + createWasmVmRuntime, + describeIf, + hasCWasmBinaries, + type Kernel, +} from "@rivet-dev/agentos-vm-test-harness"; + +interface HostileEntry { + name: string; + method: number; + compressedSize: number; + uncompressedSize: number; + localOffset: number; +} + +/** Builds a ZIP whose EOCD cd-size field is corrupt so unzip's raw central-directory fallback parser is exercised. */ +function buildFallbackArchive( + prefix: Uint8Array, + entries: HostileEntry[], +): Uint8Array { + const enc = new TextEncoder(); + const cdParts: Uint8Array[] = []; + for (const entry of entries) { + const nameBytes = enc.encode(entry.name); + const cd = new Uint8Array(46 + nameBytes.length); + const dv = new DataView(cd.buffer); + dv.setUint32(0, 0x02014b50, true); + dv.setUint16(4, 20, true); + dv.setUint16(6, 20, true); + dv.setUint16(10, entry.method, true); + dv.setUint32(20, entry.compressedSize, true); + dv.setUint32(24, entry.uncompressedSize, true); + dv.setUint16(28, nameBytes.length, true); + dv.setUint32(42, entry.localOffset, true); + cd.set(nameBytes, 46); + cdParts.push(cd); + } + const cdOffset = prefix.length; + const cdLen = cdParts.reduce((n, part) => n + part.length, 0); + const eocd = new Uint8Array(22); + const dv = new DataView(eocd.buffer); + dv.setUint32(0, 0x06054b50, true); + dv.setUint16(8, entries.length, true); + dv.setUint16(10, entries.length, true); + dv.setUint32(12, 0xffffffff, true); + dv.setUint32(16, cdOffset, true); + const out = new Uint8Array(prefix.length + cdLen + 22); + out.set(prefix, 0); + let offset = cdOffset; + for (const part of cdParts) { + out.set(part, offset); + offset += part.length; + } + out.set(eocd, offset); + return out; +} + +describeIf( + hasCWasmBinaries("zip", "unzip"), + "unzip command", + { timeout: 10_000 }, + () => { + let kernel: Kernel; + + afterEach(async () => { + await kernel?.dispose(); + }); + + it("extracts a zip archive into a target directory", async () => { + const vfs = createInMemoryFileSystem(); + await vfs.writeFile("/hello.txt", "Hello, World!\n"); + + kernel = createKernel({ filesystem: vfs }); + await kernel.mount( + createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }), + ); + + const zipResult = await kernel.exec("zip /archive.zip /hello.txt"); + expect(zipResult.exitCode, zipResult.stderr).toBe(0); + + const unzipResult = await kernel.exec("unzip -d /extracted /archive.zip"); + expect(unzipResult.exitCode, unzipResult.stderr).toBe(0); + expect(await vfs.readTextFile("/extracted/hello.txt")).toBe( + "Hello, World!\n", + ); + }); + + it("lists archive contents with sizes", async () => { + const vfs = createInMemoryFileSystem(); + await vfs.writeFile("/data.txt", "some data content\n"); + + kernel = createKernel({ filesystem: vfs }); + await kernel.mount( + createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }), + ); + + const zipResult = await kernel.exec("zip /list-test.zip /data.txt"); + expect(zipResult.exitCode, zipResult.stderr).toBe(0); + + const listResult = await kernel.exec("unzip -l /list-test.zip"); + expect(listResult.exitCode, listResult.stderr).toBe(0); + expect(listResult.stdout).toContain("data.txt"); + expect(listResult.stdout).toContain("18"); + expect(listResult.stdout).toMatch(/1 file/); + }); + + it("extracts binary file contents exactly", async () => { + const vfs = createInMemoryFileSystem(); + const content = new Uint8Array(256); + for (let i = 0; i < 256; i++) content[i] = i; + await vfs.writeFile("/binary.bin", content); + + kernel = createKernel({ filesystem: vfs }); + await kernel.mount( + createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }), + ); + + const zipResult = await kernel.exec("zip /roundtrip.zip /binary.bin"); + expect(zipResult.exitCode, zipResult.stderr).toBe(0); + + const unzipResult = await kernel.exec("unzip -d /rt-out /roundtrip.zip"); + expect(unzipResult.exitCode, unzipResult.stderr).toBe(0); + + const extracted = await vfs.readFile("/rt-out/binary.bin"); + expect(extracted.length).toBe(256); + for (let i = 0; i < 256; i++) { + expect(extracted[i]).toBe(i); + } + }); + + it("fallback parser rejects an entry with a wrapping local offset", async () => { + const vfs = createInMemoryFileSystem(); + const bytes = buildFallbackArchive(new Uint8Array(0), [ + { + name: "evil.txt", + method: 0, + compressedSize: 4, + uncompressedSize: 4, + localOffset: 0xfffffff0, + }, + ]); + await vfs.writeFile("/evil.zip", bytes); + + kernel = createKernel({ filesystem: vfs }); + await kernel.mount( + createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }), + ); + + const result = await kernel.exec("unzip -d /out /evil.zip"); + expect(result.exitCode, result.stderr).toBe(1); + expect(result.stderr).toMatch(/error/); + expect(await vfs.exists("/out/evil.txt")).toBe(false); + }); + + it("fallback parser skips an entry whose normalized name is empty", async () => { + const vfs = createInMemoryFileSystem(); + const bytes = buildFallbackArchive(new Uint8Array(0), [ + { + name: "/", + method: 0, + compressedSize: 0, + uncompressedSize: 0, + localOffset: 0, + }, + ]); + await vfs.writeFile("/empty-name.zip", bytes); + + kernel = createKernel({ filesystem: vfs }); + await kernel.mount( + createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }), + ); + + const result = await kernel.exec("unzip /empty-name.zip"); + expect(result.exitCode, result.stderr).toBe(0); + expect(result.stdout).not.toMatch(/error/); + expect(result.stderr).not.toMatch(/error/); + }); + + it("fallback parser caps hostile uncompressed sizes before allocating", async () => { + const vfs = createInMemoryFileSystem(); + const prefix = new Uint8Array(31); + const pdv = new DataView(prefix.buffer); + pdv.setUint32(0, 0x04034b50, true); + pdv.setUint16(4, 20, true); + pdv.setUint16(26, 0, true); + pdv.setUint16(28, 0, true); + prefix[30] = 0x41; + const bytes = buildFallbackArchive(prefix, [ + { + name: "big.bin", + method: 0, + compressedSize: 1, + uncompressedSize: 0xffffffff, + localOffset: 0, + }, + ]); + await vfs.writeFile("/big.zip", bytes); + + kernel = createKernel({ filesystem: vfs }); + await kernel.mount( + createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }), + ); + + const result = await kernel.exec("unzip -d /cap-out /big.zip"); + expect(result.exitCode, result.stderr).toBe(1); + expect(result.stderr).toMatch(/too large/); + expect(await vfs.exists("/cap-out/big.bin")).toBe(false); + }); + }, +); diff --git a/registry/tests/wasmvm/wget.test.ts b/registry/software/wget/test/wget.test.ts similarity index 96% rename from registry/tests/wasmvm/wget.test.ts rename to registry/software/wget/test/wget.test.ts index e1121f6b36..04cc909503 100644 --- a/registry/tests/wasmvm/wget.test.ts +++ b/registry/software/wget/test/wget.test.ts @@ -12,9 +12,9 @@ */ import { describe, it, expect, afterEach, beforeAll, afterAll } from 'vitest'; -import { createWasmVmRuntime } from '../helpers.js'; -import { C_BUILD_DIR, COMMANDS_DIR, createKernel, describeIf, hasCWasmBinaries } from '../helpers.js'; -import type { Kernel } from '../helpers.js'; +import { createWasmVmRuntime } from '@rivet-dev/agentos-vm-test-harness'; +import { C_BUILD_DIR, COMMANDS_DIR, createKernel, describeIf, hasCWasmBinaries } from '@rivet-dev/agentos-vm-test-harness'; +import type { Kernel } from '@rivet-dev/agentos-vm-test-harness'; import { createServer, type Server, type IncomingMessage, type ServerResponse } from 'node:http'; // Minimal in-memory VFS for kernel tests @@ -118,7 +118,7 @@ class SimpleVFS { } // TODO(P6): requires wget WASM artifact, intentionally excluded from the fast registry-build gate. -describe.skip('wget command', () => { +describeIf(hasCWasmBinaries('wget'), 'wget command', () => { let kernel: Kernel; let server: Server; let port: number; diff --git a/registry/software/zip/test/zip.test.ts b/registry/software/zip/test/zip.test.ts new file mode 100644 index 0000000000..13df09a301 --- /dev/null +++ b/registry/software/zip/test/zip.test.ts @@ -0,0 +1,56 @@ +/** + * Package-owned integration tests for the zip command. + */ + +import { afterEach, expect, it } from "vitest"; +import { + C_BUILD_DIR, + COMMANDS_DIR, + createInMemoryFileSystem, + createKernel, + createWasmVmRuntime, + describeIf, + hasCWasmBinaries, + type Kernel, +} from "@rivet-dev/agentos-vm-test-harness"; + +describeIf(hasCWasmBinaries("zip"), "zip command", { timeout: 10_000 }, () => { + let kernel: Kernel; + + afterEach(async () => { + await kernel?.dispose(); + }); + + it("creates a zip archive for a single file", async () => { + const vfs = createInMemoryFileSystem(); + await vfs.writeFile("/hello.txt", "Hello, World!\n"); + + kernel = createKernel({ filesystem: vfs }); + await kernel.mount( + createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }), + ); + + const result = await kernel.exec("zip /archive.zip /hello.txt"); + expect(result.exitCode, result.stderr).toBe(0); + + const archive = await vfs.readFile("/archive.zip"); + expect(archive.length).toBeGreaterThan(0); + expect(Array.from(archive.slice(0, 2))).toEqual([0x50, 0x4b]); + }); + + it("creates a zip archive recursively", async () => { + const vfs = createInMemoryFileSystem(); + await vfs.mkdir("/mydir"); + await vfs.writeFile("/mydir/a.txt", "file a\n"); + await vfs.writeFile("/mydir/b.txt", "file b\n"); + + kernel = createKernel({ filesystem: vfs }); + await kernel.mount( + createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }), + ); + + const result = await kernel.exec("zip -r /dir.zip /mydir"); + expect(result.exitCode, result.stderr).toBe(0); + expect(await vfs.exists("/dir.zip")).toBe(true); + }); +}); diff --git a/registry/test-status.json b/registry/test-status.json new file mode 100644 index 0000000000..9eb54598a4 --- /dev/null +++ b/registry/test-status.json @@ -0,0 +1,247 @@ +{ + "schemaVersion": 1, + "generatedAt": "2026-07-07T23:56:44.480Z", + "packages": { + "software/browserbase": { + "baselineStatus": "no-test", + "status": "no-test", + "commands": [ + "browse" + ], + "notes": "External CLI wrapper allowlisted by the registry test standardization baseline." + }, + "software/build-essential": { + "baselineStatus": "meta", + "status": "meta", + "commands": [], + "notes": "Aggregate bundle with no direct command test." + }, + "software/codex-cli": { + "baselineStatus": "not-buildable", + "status": "failing", + "commands": [ + "codex", + "codex-exec" + ], + "notes": "Requires external codex-rs fork artifacts." + }, + "software/common": { + "baselineStatus": "meta", + "status": "meta", + "commands": [], + "notes": "Aggregate bundle with no direct command test." + }, + "software/coreutils": { + "baselineStatus": "working", + "status": "working", + "commands": [ + "sh" + ] + }, + "software/curl": { + "baselineStatus": "failing", + "status": "disabled", + "commands": [ + "curl" + ], + "notes": "Tracked functional failures, including --version." + }, + "software/diffutils": { + "baselineStatus": "no-test", + "status": "no-test", + "commands": [ + "diff" + ] + }, + "software/duckdb": { + "baselineStatus": "disabled", + "status": "disabled", + "commands": [ + "duckdb" + ] + }, + "software/everything": { + "baselineStatus": "meta", + "status": "meta", + "commands": [], + "notes": "Aggregate bundle with no direct command test." + }, + "software/fd": { + "baselineStatus": "working", + "status": "working", + "commands": [ + "fd" + ] + }, + "software/file": { + "baselineStatus": "no-test", + "status": "no-test", + "commands": [ + "file" + ] + }, + "software/findutils": { + "baselineStatus": "working", + "status": "working", + "commands": [ + "find", + "xargs" + ] + }, + "software/gawk": { + "baselineStatus": "no-test", + "status": "no-test", + "commands": [ + "awk" + ] + }, + "software/git": { + "baselineStatus": "disabled", + "status": "working", + "commands": [ + "git" + ] + }, + "software/grep": { + "baselineStatus": "no-test", + "status": "no-test", + "commands": [ + "grep" + ] + }, + "software/gzip": { + "baselineStatus": "no-test", + "status": "no-test", + "commands": [ + "gzip" + ] + }, + "software/http-get": { + "baselineStatus": "no-test", + "status": "no-test", + "commands": [ + "http_get" + ] + }, + "software/jq": { + "baselineStatus": "no-test", + "status": "no-test", + "commands": [ + "jq" + ] + }, + "software/ripgrep": { + "baselineStatus": "no-test", + "status": "no-test", + "commands": [ + "rg" + ] + }, + "software/sed": { + "baselineStatus": "no-test", + "status": "no-test", + "commands": [ + "sed" + ] + }, + "software/sqlite3": { + "baselineStatus": "failing", + "status": "disabled", + "commands": [ + "sqlite3" + ], + "notes": "Tracked VFS pwrite failure." + }, + "software/tar": { + "baselineStatus": "no-test", + "status": "no-test", + "commands": [ + "tar" + ] + }, + "software/tree": { + "baselineStatus": "working", + "status": "working", + "commands": [ + "tree" + ] + }, + "software/unzip": { + "baselineStatus": "failing", + "status": "disabled", + "commands": [ + "unzip" + ], + "notes": "Tracked hardening failures." + }, + "software/vim": { + "baselineStatus": "no-test", + "status": "no-test", + "commands": [ + "vim" + ], + "notes": "Compile status unverified; heavy make target." + }, + "software/vix": { + "baselineStatus": "not-buildable", + "status": "not-buildable", + "commands": [ + "vix" + ], + "notes": "External artifact absent from checkout." + }, + "software/wget": { + "baselineStatus": "not-compiling", + "status": "disabled", + "commands": [ + "wget" + ], + "notes": "Tracked duplicate getpeername build failure." + }, + "software/yq": { + "baselineStatus": "no-test", + "status": "no-test", + "commands": [ + "yq" + ] + }, + "software/zip": { + "baselineStatus": "failing", + "status": "disabled", + "commands": [ + "zip" + ], + "notes": "Tracked hardening failures." + }, + "agent/claude": { + "baselineStatus": "no-test", + "status": "no-test", + "commands": [], + "notes": "Adapter smoke tests are tracked as follow-up work." + }, + "agent/codex": { + "baselineStatus": "no-test", + "status": "no-test", + "commands": [], + "notes": "Adapter smoke tests are tracked as follow-up work." + }, + "agent/opencode": { + "baselineStatus": "no-test", + "status": "no-test", + "commands": [], + "notes": "Adapter smoke tests are tracked as follow-up work." + }, + "agent/pi": { + "baselineStatus": "no-test", + "status": "no-test", + "commands": [], + "notes": "Adapter smoke tests are tracked as follow-up work." + }, + "agent/pi-cli": { + "baselineStatus": "no-test", + "status": "no-test", + "commands": [], + "notes": "Adapter smoke tests are tracked as follow-up work." + } + } +} diff --git a/registry/tests/helpers.ts b/registry/tests/helpers.ts deleted file mode 100644 index 963f5afd7b..0000000000 --- a/registry/tests/helpers.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { existsSync } from "node:fs"; -import { resolve, dirname } from "node:path"; -import { fileURLToPath } from "node:url"; -import { describe, it } from "vitest"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); - -/** Directory containing WASM command binaries built from Rust. */ -export const COMMANDS_DIR = resolve( - process.env.AGENTOS_WASM_COMMANDS_DIR ?? - resolve(__dirname, "../native/target/wasm32-wasip1/release/commands"), -); - -/** Directory containing C-compiled WASM binaries. */ -export const C_BUILD_DIR = resolve( - process.env.AGENTOS_C_WASM_COMMANDS_DIR ?? - resolve(__dirname, "../native/c/build/"), -); - -/** Whether the main WASM command binaries are available (includes 'sh'). */ -export const hasWasmBinaries = - existsSync(COMMANDS_DIR) && existsSync(resolve(COMMANDS_DIR, "sh")); - -/** - * Check whether specific C WASM binaries are present. - * @param names - Binary names to check for inside C_BUILD_DIR. - * @returns true if all requested binaries exist. - */ -export function hasCWasmBinaries(...names: string[]): boolean { - if (!existsSync(C_BUILD_DIR)) return false; - return names.every((name) => existsSync(resolve(C_BUILD_DIR, name))); -} - -/** - * Returns a skip-reason string if WASM binaries are missing, or false if - * they are available and tests should run. - */ -export function skipReason(): string | false { - if (!hasWasmBinaries) { - return `WASM binaries not found at ${COMMANDS_DIR} — build with \`make wasm\` first`; - } - return false; -} - -export function describeIf( - condition: unknown, - ...args: Parameters -): void { - if (condition) { - // Vitest's overloaded tuple shape is awkward to preserve across helper forwarding. - // @ts-expect-error forwarded describe() arguments stay runtime-compatible. - describe(...args); - return; - } - const [name] = args; - describe.skip(`${String(name)} [environment prerequisites not met]`, () => {}); -} - -export function itIf( - condition: unknown, - ...args: Parameters -): void { - if (condition) { - // Vitest's overloaded tuple shape is awkward to preserve across helper forwarding. - // @ts-expect-error forwarded it() arguments stay runtime-compatible. - it(...args); - return; - } - const [name] = args; - it.skip(`${String(name)} [environment prerequisites not met]`, () => {}); -} - -// Re-exports from the repo-owned generic runtime surface. -export { - AF_INET, - AF_UNIX, - allowAll, - createInMemoryFileSystem, - SIGTERM, - SOCK_DGRAM, - SOCK_STREAM, -} from "@rivet-dev/agentos-runtime-core/test-runtime"; -import { - allowAll, - createKernel as createKernelBase, -} from "@rivet-dev/agentos-runtime-core/test-runtime"; -export type { - DriverProcess, - Kernel, - KernelInterface, - KernelRuntimeDriver, - ProcessContext, - VirtualFileSystem, -} from "@rivet-dev/agentos-runtime-core/test-runtime"; -export { - createWasmVmRuntime, - DEFAULT_FIRST_PARTY_TIERS, - WASMVM_COMMANDS, - type PermissionTier, - type WasmVmRuntimeOptions, -} from "@rivet-dev/agentos-runtime-core/test-runtime"; -export { - createNodeHostNetworkAdapter, - createNodeRuntime, - NodeFileSystem, -} from "@rivet-dev/agentos-runtime-core/test-runtime"; -export { TerminalHarness } from "./terminal-harness.js"; - -/** - * Registry integration tests assume they can bootstrap runtimes and /bin stubs - * unless they explicitly opt into a stricter permission policy. - */ -export function createKernel( - options: Parameters[0], -): ReturnType { - return createKernelBase({ - ...options, - permissions: options.permissions ?? allowAll, - }); -} diff --git a/registry/tests/kernel/helpers.ts b/registry/tests/kernel/helpers.ts deleted file mode 100644 index 07be2a7f2c..0000000000 --- a/registry/tests/kernel/helpers.ts +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Integration test helpers for kernel tests that depend on WASM command binaries. - * - * Re-exports infrastructure from the parent helpers.ts and provides - * createIntegrationKernel / skipUnlessWasmBuilt for cross-runtime tests. - */ - -import { - AF_INET, - AF_UNIX, - COMMANDS_DIR, - C_BUILD_DIR, - describeIf, - hasWasmBinaries, - itIf, - NodeFileSystem, - SIGTERM, - SOCK_DGRAM, - SOCK_STREAM, - TerminalHarness, - skipReason, - createInMemoryFileSystem, - createKernel, - createWasmVmRuntime, - createNodeRuntime, -} from "../helpers.js"; -import type { Kernel, Permissions, VirtualFileSystem } from "../helpers.js"; - -export { - AF_INET, - AF_UNIX, - COMMANDS_DIR, - C_BUILD_DIR, - describeIf, - hasWasmBinaries, - itIf, - NodeFileSystem, - SIGTERM, - SOCK_DGRAM, - SOCK_STREAM, - TerminalHarness, - skipReason, - createInMemoryFileSystem, - createKernel, - createWasmVmRuntime, - createNodeRuntime, -} from "../helpers.js"; -export type { Kernel, Permissions, VirtualFileSystem } from "../helpers.js"; - -export interface IntegrationKernelResult { - kernel: Kernel; - vfs: VirtualFileSystem; - dispose: () => Promise; -} - -export interface IntegrationKernelOptions { - runtimes?: ("wasmvm" | "node")[]; - loopbackExemptPorts?: number[]; - commandDirs?: string[]; - permissions?: Permissions; -} - -/** - * Create a kernel with the in-scope runtime drivers for integration testing. - * - * Mount order matters. Last-mounted driver wins for overlapping commands: - * 1. WasmVM first: provides sh/bash/coreutils (90+ commands) - * 2. Node second: overrides WasmVM's 'node' stub with real V8 - */ -export async function createIntegrationKernel( - options?: IntegrationKernelOptions, -): Promise { - const runtimes = options?.runtimes ?? ["wasmvm"]; - const vfs = createInMemoryFileSystem(); - const kernel = createKernel({ - filesystem: vfs, - loopbackExemptPorts: options?.loopbackExemptPorts, - permissions: options?.permissions, - }); - - if (runtimes.includes("wasmvm")) { - await kernel.mount( - createWasmVmRuntime({ commandDirs: options?.commandDirs ?? [COMMANDS_DIR] }), - ); - } - if (runtimes.includes("node")) { - await kernel.mount(createNodeRuntime()); - } - - return { - kernel, - vfs, - dispose: () => kernel.dispose(), - }; -} - -/** - * Skip helper: returns a reason string if the WASM binaries are not built, - * or false if the commands directory exists and tests can run. - */ -export function skipUnlessWasmBuilt(): string | false { - return skipReason(); -} diff --git a/registry/tests/wasmvm/terminal-harness.ts b/registry/tests/wasmvm/terminal-harness.ts deleted file mode 100644 index d5d80772f0..0000000000 --- a/registry/tests/wasmvm/terminal-harness.ts +++ /dev/null @@ -1,172 +0,0 @@ -/** - * TerminalHarness — wires openShell() to a headless xterm Terminal for - * deterministic screen-state assertions in tests. - * - * Duplicated from packages/kernel/test/terminal-harness.ts because cross-package - * test imports aren't supported. - */ - -import { Terminal } from "@xterm/headless"; -import type { Kernel } from "../helpers.js"; - -type ShellHandle = ReturnType; - -/** Settlement window: resolve type() after this many ms of no new output. */ -const SETTLE_MS = 50; -/** Poll interval for waitFor(). */ -const POLL_MS = 20; -/** Default waitFor() timeout. */ -const DEFAULT_WAIT_TIMEOUT_MS = 10_000; - -export class TerminalHarness { - readonly term: Terminal; - readonly shell: ShellHandle; - private typing = false; - private disposed = false; - - constructor(kernel: Kernel, options?: { cols?: number; rows?: number; env?: Record; cwd?: string }) { - const cols = options?.cols ?? 80; - const rows = options?.rows ?? 24; - - this.term = new Terminal({ cols, rows, allowProposedApi: true }); - - this.shell = kernel.openShell({ cols, rows, env: options?.env, cwd: options?.cwd }); - - // Wire shell output → xterm - this.shell.onData = (data: Uint8Array) => { - this.term.write(data); - }; - } - - /** - * Send input through the PTY. Resolves after output settles (no new bytes - * received for SETTLE_MS). - */ - async type(input: string): Promise { - if (this.typing) { - throw new Error("TerminalHarness.type() called while previous type() is still in-flight"); - } - this.typing = true; - try { - await this.typeInternal(input); - } finally { - this.typing = false; - } - } - - private typeInternal(input: string): Promise { - return new Promise((resolve) => { - let timer: ReturnType | null = null; - - const resetTimer = () => { - if (timer !== null) clearTimeout(timer); - timer = setTimeout(() => { - this.shell.onData = originalOnData; - resolve(); - }, SETTLE_MS); - }; - - const originalOnData = this.shell.onData; - this.shell.onData = (data: Uint8Array) => { - this.term.write(data); - resetTimer(); - }; - - resetTimer(); - this.shell.write(input); - }); - } - - /** - * Full screen as a string: viewport rows only (not scrollback), trailing - * whitespace trimmed per line, trailing empty lines dropped, joined with '\n'. - */ - screenshotTrimmed(): string { - const buf = this.term.buffer.active; - const rows = this.term.rows; - const lines: string[] = []; - - for (let y = 0; y < rows; y++) { - const line = buf.getLine(buf.viewportY + y); - lines.push(line ? line.translateToString(true) : ""); - } - - while (lines.length > 0 && lines[lines.length - 1] === "") { - lines.pop(); - } - - return lines.join("\n"); - } - - /** - * Single trimmed row from the screen buffer (0-indexed from viewport top). - */ - line(row: number): string { - const buf = this.term.buffer.active; - const line = buf.getLine(buf.viewportY + row); - return line ? line.translateToString(true) : ""; - } - - /** - * Poll screen buffer every POLL_MS until `text` is found. Throws a - * descriptive error on timeout. - */ - async waitFor( - text: string, - occurrence: number = 1, - timeoutMs: number = DEFAULT_WAIT_TIMEOUT_MS, - ): Promise { - const deadline = Date.now() + timeoutMs; - - while (true) { - const screen = this.screenshotTrimmed(); - - let count = 0; - let idx = -1; - while (true) { - idx = screen.indexOf(text, idx + 1); - if (idx === -1) break; - count++; - if (count >= occurrence) return; - } - - if (Date.now() >= deadline) { - throw new Error( - `waitFor("${text}", ${occurrence}) timed out after ${timeoutMs}ms.\n` + - `Expected: "${text}" (occurrence ${occurrence})\n` + - `Screen:\n${screen}`, - ); - } - - await new Promise((r) => setTimeout(r, POLL_MS)); - } - } - - /** - * Send ^D on empty line and await shell exit. Returns exit code. - */ - async exit(): Promise { - this.shell.write("\x04"); - return this.shell.wait(); - } - - /** - * Kill shell and dispose terminal. Safe to call multiple times. - */ - async dispose(): Promise { - if (this.disposed) return; - this.disposed = true; - - try { - this.shell.kill(); - await Promise.race([ - this.shell.wait(), - new Promise((r) => setTimeout(r, 500)), - ]); - } catch { - // Shell may already be dead - } - - this.term.dispose(); - } -} diff --git a/registry/tests/wasmvm/zip-unzip.test.ts b/registry/tests/wasmvm/zip-unzip.test.ts deleted file mode 100644 index db330c1e59..0000000000 --- a/registry/tests/wasmvm/zip-unzip.test.ts +++ /dev/null @@ -1,249 +0,0 @@ -/** - * Integration tests for zip and unzip C commands. - * - * Verifies zip/unzip roundtrip, recursive compression, list mode, - * and extract-to-directory via kernel.exec() with real WASM binaries. - */ - -import { describe, it, expect, afterEach } from 'vitest'; -import { createInMemoryFileSystem, createWasmVmRuntime } from '../helpers.js'; -import { C_BUILD_DIR, COMMANDS_DIR, createKernel } from '../helpers.js'; -import type { Kernel } from '../helpers.js'; - -interface HostileEntry { - name: string; - method: number; // 0 = store, 8 = deflate - compressedSize: number; - uncompressedSize: number; - localOffset: number; -} - -/** Builds a ZIP whose EOCD cd-size field is corrupt so minizip rejects it and - * unzip's raw central-directory fallback parser is exercised. The nonzero - * version fields on each central directory record also make minizip reject - * the archive under the VM's stream semantics, where its reopen-based seek - * callback reads EOCD fields from offset 0 instead of the EOCD record. - * `prefix` bytes (e.g. a real local file header) are placed at offset 0. */ -function buildFallbackArchive(prefix: Uint8Array, entries: HostileEntry[]): Uint8Array { - const enc = new TextEncoder(); - const cdParts: Uint8Array[] = []; - for (const e of entries) { - const nameBytes = enc.encode(e.name); - const cd = new Uint8Array(46 + nameBytes.length); - const dv = new DataView(cd.buffer); - dv.setUint32(0, 0x02014b50, true); // central directory signature - dv.setUint16(4, 20, true); // version made by - dv.setUint16(6, 20, true); // version needed to extract - dv.setUint16(10, e.method, true); - dv.setUint32(20, e.compressedSize, true); - dv.setUint32(24, e.uncompressedSize, true); - dv.setUint16(28, nameBytes.length, true); - dv.setUint32(42, e.localOffset, true); - cd.set(nameBytes, 46); - cdParts.push(cd); - } - const cdOffset = prefix.length; - const cdLen = cdParts.reduce((n, p) => n + p.length, 0); - const eocd = new Uint8Array(22); - const dv = new DataView(eocd.buffer); - dv.setUint32(0, 0x06054b50, true); // EOCD signature - dv.setUint16(8, entries.length, true); // entries on this disk - dv.setUint16(10, entries.length, true);// total entries - dv.setUint32(12, 0xffffffff, true); // corrupt cd size: forces the fallback parser - dv.setUint32(16, cdOffset, true); - const out = new Uint8Array(prefix.length + cdLen + 22); - out.set(prefix, 0); - let off = cdOffset; - for (const p of cdParts) { out.set(p, off); off += p.length; } - out.set(eocd, off); - return out; -} - -describe('zip/unzip commands', () => { - let kernel: Kernel; - - afterEach(async () => { - await kernel?.dispose(); - }); - - it('zip creates valid archive, unzip extracts it, contents match', async () => { - const vfs = createInMemoryFileSystem(); - await vfs.writeFile('/hello.txt', 'Hello, World!\n'); - - kernel = createKernel({ filesystem: vfs }); - await kernel.mount( - createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }), - ); - - // Create zip archive - const zipResult = await kernel.exec('zip /archive.zip /hello.txt'); - expect(zipResult.exitCode, zipResult.stderr).toBe(0); - - // Verify archive was created - expect(await vfs.exists('/archive.zip')).toBe(true); - - // Extract to a different directory - const unzipResult = await kernel.exec('unzip -d /extracted /archive.zip'); - expect(unzipResult.exitCode, unzipResult.stderr).toBe(0); - - // Verify extracted content matches original - const extracted = await vfs.readTextFile('/extracted/hello.txt'); - expect(extracted).toBe('Hello, World!\n'); - }); - - it('zip -r compresses directory recursively', async () => { - const vfs = createInMemoryFileSystem(); - await vfs.mkdir('/mydir'); - await vfs.writeFile('/mydir/a.txt', 'file a\n'); - await vfs.writeFile('/mydir/b.txt', 'file b\n'); - - kernel = createKernel({ filesystem: vfs }); - await kernel.mount( - createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }), - ); - - const zipResult = await kernel.exec('zip -r /dir.zip /mydir'); - expect(zipResult.exitCode, zipResult.stderr).toBe(0); - expect(await vfs.exists('/dir.zip')).toBe(true); - - // Extract and verify - const unzipResult = await kernel.exec('unzip -d /out /dir.zip'); - expect(unzipResult.exitCode, unzipResult.stderr).toBe(0); - - const a = await vfs.readTextFile('/out/mydir/a.txt'); - const b = await vfs.readTextFile('/out/mydir/b.txt'); - expect(a).toBe('file a\n'); - expect(b).toBe('file b\n'); - }); - - it('unzip -l lists archive contents with sizes', async () => { - const vfs = createInMemoryFileSystem(); - await vfs.writeFile('/data.txt', 'some data content\n'); - - kernel = createKernel({ filesystem: vfs }); - await kernel.mount( - createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }), - ); - - // Create archive first - const zipResult = await kernel.exec('zip /list-test.zip /data.txt'); - expect(zipResult.exitCode, zipResult.stderr).toBe(0); - - // List contents - const listResult = await kernel.exec('unzip -l /list-test.zip'); - expect(listResult.exitCode, listResult.stderr).toBe(0); - expect(listResult.stdout).toContain('data.txt'); - // Should show the file size (18 bytes) - expect(listResult.stdout).toContain('18'); - // Should show summary line with file count - expect(listResult.stdout).toMatch(/1 file/); - }); - - it('zip/unzip roundtrip preserves file contents exactly', async () => { - const vfs = createInMemoryFileSystem(); - // Binary-like content with various byte values - const content = new Uint8Array(256); - for (let i = 0; i < 256; i++) content[i] = i; - await vfs.writeFile('/binary.bin', content); - - kernel = createKernel({ filesystem: vfs }); - await kernel.mount( - createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }), - ); - - const zipResult = await kernel.exec('zip /roundtrip.zip /binary.bin'); - expect(zipResult.exitCode, zipResult.stderr).toBe(0); - - const unzipResult = await kernel.exec('unzip -d /rt-out /roundtrip.zip'); - expect(unzipResult.exitCode, unzipResult.stderr).toBe(0); - - const extracted = await vfs.readFile('/rt-out/binary.bin'); - expect(extracted.length).toBe(256); - for (let i = 0; i < 256; i++) { - expect(extracted[i]).toBe(i); - } - }); - - it('unzip -d extracts to specified directory', async () => { - const vfs = createInMemoryFileSystem(); - await vfs.writeFile('/src.txt', 'target content\n'); - - kernel = createKernel({ filesystem: vfs }); - await kernel.mount( - createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }), - ); - - const zipResult = await kernel.exec('zip /dest-test.zip /src.txt'); - expect(zipResult.exitCode, zipResult.stderr).toBe(0); - - // Extract to a new directory - const unzipResult = await kernel.exec('unzip -d /custom-dir /dest-test.zip'); - expect(unzipResult.exitCode, unzipResult.stderr).toBe(0); - - expect(await vfs.exists('/custom-dir/src.txt')).toBe(true); - const extracted = await vfs.readTextFile('/custom-dir/src.txt'); - expect(extracted).toBe('target content\n'); - }); - - it('fallback parser rejects an entry with a wrapping local offset', async () => { - const vfs = createInMemoryFileSystem(); - const bytes = buildFallbackArchive(new Uint8Array(0), [ - { name: 'evil.txt', method: 0, compressedSize: 4, uncompressedSize: 4, localOffset: 0xfffffff0 }, - ]); - await vfs.writeFile('/evil.zip', bytes); - - kernel = createKernel({ filesystem: vfs }); - await kernel.mount( - createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }), - ); - - const result = await kernel.exec('unzip -d /out /evil.zip'); - expect(result.exitCode, result.stderr).toBe(1); - expect(result.stderr).toMatch(/error/); - expect(await vfs.exists('/out/evil.txt')).toBe(false); - }); - - it('fallback parser skips an entry whose normalized name is empty', async () => { - const vfs = createInMemoryFileSystem(); - const bytes = buildFallbackArchive(new Uint8Array(0), [ - { name: '/', method: 0, compressedSize: 0, uncompressedSize: 0, localOffset: 0 }, - ]); - await vfs.writeFile('/empty-name.zip', bytes); - - kernel = createKernel({ filesystem: vfs }); - await kernel.mount( - createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }), - ); - - const result = await kernel.exec('unzip /empty-name.zip'); - expect(result.exitCode, result.stderr).toBe(0); - expect(result.stdout).not.toMatch(/error/); - expect(result.stderr).not.toMatch(/error/); - }); - - it('fallback parser caps hostile uncompressed sizes before allocating', async () => { - const vfs = createInMemoryFileSystem(); - // A real 31-byte local header for a 1-byte stored payload. - const prefix = new Uint8Array(31); - const pdv = new DataView(prefix.buffer); - pdv.setUint32(0, 0x04034b50, true); // local file header signature - pdv.setUint16(4, 20, true); // version needed to extract - pdv.setUint16(26, 0, true); // name length - pdv.setUint16(28, 0, true); // extra length - prefix[30] = 0x41; // one payload byte - const bytes = buildFallbackArchive(prefix, [ - { name: 'big.bin', method: 0, compressedSize: 1, uncompressedSize: 0xffffffff, localOffset: 0 }, - ]); - await vfs.writeFile('/big.zip', bytes); - - kernel = createKernel({ filesystem: vfs }); - await kernel.mount( - createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }), - ); - - const result = await kernel.exec('unzip -d /cap-out /big.zip'); - expect(result.exitCode, result.stderr).toBe(1); - expect(result.stderr).toMatch(/too large/); - expect(await vfs.exists('/cap-out/big.bin')).toBe(false); - }); -}); diff --git a/turbo.json b/turbo.json index fac7639fd5..f5591c2f46 100644 --- a/turbo.json +++ b/turbo.json @@ -28,7 +28,14 @@ ] }, "test": { - "inputs": ["src/**", "tests/**", "package.json"], + "inputs": [ + "src/**", + "tests/**", + "software/**/test/**", + "native/tests/**", + "scripts/**", + "package.json" + ], "dependsOn": ["^build", "check-types"] }, "@rivet-dev/agentos-sidecar#build": {