- Install dependencies:
npm install - Run all tests:
npm run test - Run harness tests only:
npm run test:harness - Run unit tests only:
npm run test:unit - Run e2e tests only:
npm run test:e2e - Run fuzz tests only:
npm run test:fuzz - Run a single e2e test file:
cd apps/tests && npx vitest run --project e2e tests/e2e/<name>.test.ts - Run a single test by name:
cd apps/tests && npx vitest run <path> -t "<test-name-or-id>"(e.g.-t "T-EXEC-10") - Build loopx package:
npm run build(turbo runstscinpackages/loop-extender/then postbuild, which chmodsdist/bin.js, copies README intodist/, and refreshes thenode_modules/loopxsymlinks at the repo root and underapps/tests/) npm run buildis required before any test that spawns the loopx CLI or imports fromloopx(postbuild populatesnode_modules/loopx); rebuild after any src/ changes. Turbo wires^buildinto the test tasks sonpm run test:*rebuilds automatically; bypassing turbo (cd apps/tests && npx vitest …) does not.- Type check:
npx tsc --noEmit -p packages/loop-extender/tsconfig.build.json - Install/global install & fuzz suites are slow — run them in the background (Bash
run_in_background) and wait for completion notifications rather than blocking the session.
runCLI(apps/tests/tests/helpers/cli.ts) has a default 30s per-invocation timeout that rejects with an error; fixtures that loop forever fail as a timeout, not an exit-code mismatch. To assert "exit 1 once implementation catches up," make fixture scripts print{"stop":true}or exit 0.- Workflow fixtures:
createWorkflowScript(project, workflow, script, ext, content),createBashWorkflowScript(project, workflow, script, body),createWorkflowPackageJson(project, workflow, content). LegacycreateScript/createDirScript/createBashScriptwere removed with ADR-0003 — do not reintroduce. - Version-check warning matchers in
apps/tests/tests/e2e/version-check.test.tsare regex-based and overlap between categories. Keep runtime warning prose free of the mismatch trigger words (version,mismatch,range,satisf) for non-mismatch cases; include them only for the actual mismatch warning. apps/tests/tests/helpers/api-driver.tsspawns<repo>/node_modules/.bin/tsxby absolute path (computed from animport.meta.url-derivedREPO_ROOT, notprocess.cwd()— vitest now runs fromapps/tests/), not vianpx. When the consumer cwd has anode_modules/(even one containing only a symlinked package),npm 11+/npxskips auto-install and exits 127 with "tsx: command not found". Preserve the absolute-path spawn in that helper.
- Bun's default JSX runtime is "automatic" (imports
react/jsx-runtime), which breaks workflow scripts that rely on a localReact.createElementshim.execution.tswrites a per-processbunfig.tomland passes--config=<path> --jsx-factory=React.createElement --jsx-fragment=React.Fragmentfor.tsx/.jsxfiles to force classic transform. - Bun is liberal about CJS in
.js—require()would succeed even when the workflow tree sets"type": "module". We force SPEC §6.3 rejection by passing--define require:nullto Bun, so anyrequire(...)call fails at parse-time substitution. - The npm package is named
loop-extenderbut scripts import fromloopx.execution.tscreates a per-process$TMPDIR/loopx-nodepath-shim-<pid>/loopx -> <loopx package root>symlink (the package root isresolve(__dirname, "..")—__dirnameis the compileddist/, and thepackage.jsonwithexportslives one level up) and prepends that directory toNODE_PATH, so both local and global installs resolveimport "loopx"under Bun. getVersion()inbin.tswalksdirname(process.argv[1])and__dirname, then each of their parents, looking forpackage.json. Walking the parents is required because the canonicalpackage.jsonnow sits next todist/, not inside it; relying on__dirnamealone would miss it.packages/loop-extender/package.jsondeclarestsxas a runtimedependency—src/execution.tsspawnstsxfor every JS/TS script, so removing that dep breaksnpm install -g loop-extenderlifecycle tests (T-INST-GLOBAL-01).
- Published package code lives in
packages/loop-extender/(src/compiled todist/) - Test harness code lives in
apps/tests/tests/with helpers inapps/tests/tests/helpers/ - Fixture script factories are in
apps/tests/tests/helpers/fixture-scripts.ts - Vitest config at
apps/tests/vitest.config.tsuses project-based setup with separate timeouts per suite - ESM-only (
"type": "module"in every package.json)