Repository navigation
Commit 49d60d3
test(cli): spawn the source entry under node, not the tsx binary, in 34 test files (#28625)
<!-- claude-projects-attribution: {"github_login":"os-project-manager"}
-->
_Requested by **Leehom** · [project
thread](https://claude.ai/code/project/chan_01TenzsRopZj4jMbvjX8uz1X?thread=cmsg_01TenzsRopZj4jMbvjX8uz1X6ekcr8QawcG79EtN7Tzdbo)_
Part of #23181 (slice 29, the tsx wrapper lever across the cli test
files outside slices 24–28). The card stays open for later slices.
Clause-②: no
Metadata-protocol: none
## 维护者速读
- **改了什么**:`packages/cli` 里 34 个测试文件起 CLI 子进程时,不再经
`node_modules/.bin/tsx` 包一层,改为用当前进程自己的 `node`(`process.execPath`)直接跑
`bin/run-dev.js`,与 slice 12 对 migrate
文件的做法一致。入口、`src/`、`NODE_ENV=development`、子进程的 env、cwd、参数、超时都不变。
- **为什么改**:卡 #23181 的测试提速职责。tsx 包装只多出一个进程和一次自身的转译,每次子进程白付几秒;slice 27
实测同一条命令 tsx 9.5–11.8 s、node 5.3–5.4 s,stdout 字节相同。
- **风险与回滚**:只改测试文件,不发布任何东西(cli 的 `files[]` 只有
dist、README、CHANGELOG);没有改任何断言、用例名、超时、分层或 `// test-budget:` 头;回滚即
revert。
- **先看**:`packages/cli/test/generate-skill.e2e.test.ts`(唯一手改:CLI 走
node,解析探针是裸 `.ts` 文件,仍走
tsx);`packages/cli/test/package-install-local-handlers.integration.test.ts`(`os
start` 启动走 node);其余 32 个文件只是 `TSX` → `process.execPath` 并删掉常量。
- **两分钟验证**:`pnpm --filter @objectstack/cli exec vitest run
test/build-strict-body-count.test.ts` → 6/6 通过,墙钟约 26 s(改前约 33 s)。
- **需要你做的**:无,席位落地。
## What changes
The order lists 45 `packages/cli` test files that still name `tsx` on
`origin/main` outside slices 24–28 and `test/helpers/**`. I sorted each
one first.
**(a) The switch applies: 34 files.** Each spawned `bin/run-dev.js`
through the tsx binary, and none of them is about that entry. Each now
spawns `process.execPath` with `bin/run-dev.js` as the first argument,
slice 12's way. The child env, cwd, argv, stdin, `maxBuffer` and
timeouts are unchanged. The local `const TSX` (or the `TSX` import from
the shared helper) goes, a runner named `runTsx` whose every call spawns
the CLI is renamed `runCli`, and the prose that said "through tsx" now
says `node`.
`src/commands/validate-json-strict-exit.e2e` ·
`test/build-callable-names` · `build-connector-spec-file-artifact.e2e` ·
`build-demo-staff-artifact` · `build-docs-step-count.e2e` ·
`build-runtime-bundle-bodyless` · `build-seed-files-artifact.e2e` ·
`build-strict-body-count` · `build-view-container-name` ·
`create-refuses-invalid-project-name.e2e` · `dev-no-watch.pin` ·
`generate-agent-retired.e2e` · `generate-object-namespace-prefix.e2e` ·
`generate-refuses-name-outside-charset` ·
`generate-refuses-unimportable-alias` ·
`generate-refuses-unparseable-name` · `generate-skill.e2e` ·
`hook-body-build-reach.e2e` · `migrate-apply-refuses-before-ddl.e2e` ·
`migrate-exit-code.e2e` · `migrate-unloadable-host-config-exit.e2e` ·
`package-install-local-handlers.integration` · `qa-names-and-tags-run` ·
`qa-requires-skip-run` · `refusal-renders-once.e2e` ·
`retry-policy-key-validate-door` · `rule-line-explain-pointer.e2e` ·
`scaffold-emission-policy.e2e` ·
`serve-host-config-metadata-door.integration` ·
`stack-datasource-default-validate-door` ·
`validate-field-predicate-traversal` ·
`validate-json-warning-parity.e2e` · `validate-top-level-strict.e2e` ·
`validate-view-container-name`
- `generate-skill.e2e` is the one mixed file. Its two CLI spawns move to
node. Its parse probe imports a generated bare `.ts` module with an
extensionless specifier, which plain node cannot load, so the probe
stays on the tsx binary through a two-argument `runChild(bin, args,
cwd)`.
- `migrate-apply-refuses-before-ddl.e2e`,
`migrate-unloadable-host-config-exit.e2e`, `qa-names-and-tags-run`,
`qa-requires-skip-run`, `package-install-local-handlers.integration` and
`serve-host-config-metadata-door.integration` imported `TSX` from
`test/helpers/serve-process.ts` but spawn in their own code, so only the
import changes; the helper is untouched.
- The tier is unchanged: `vitest-tiers.ts` still reads every file as a
spawner through its `run-dev.js` entry name.
**(b) Already on node, or tsx in prose only: 6 files, nothing to do.**
| file | why |
|:--|:--|
| `src/commands/child-env-source-loader.pin` | spawns nothing; tsx
appears in prose and in a specimen string |
| `src/commands/migrate/plan.declared-default-datasource.integration` |
slice 12 moved it to `process.execPath`; prose only |
| `src/commands/migrate/plan.telemetry-sibling.integration` | same |
| `src/commands/dev-database-directory` | already `process.execPath`;
`--import tsx` loads an inline `-e` script that imports `src/` (`.js`
specifiers onto `.ts` files), not the CLI entry, and plain node cannot
resolve those |
| `src/utils/make-directory` | same shape as `dev-database-directory` |
| `test/serve-built-cli-prerequisite` | spawns nothing; tsx in prose
only |
**(c) The test pins the tsx or `run-dev.js` entry itself: 5 files, keep
tsx.**
| file | why |
|:--|:--|
| `test/run-dev-cwd-tsconfig-redirect.e2e` | its subject is tsx
honouring the cwd tsconfig and the shim's re-exec with
`TSX_TSCONFIG_PATH` |
| `test/start-signal-forwarding.e2e` | already `process.execPath`, with
the tsx loader as `--import` on purpose: the tsx CLI would put a relay
process between the test and the pid it signals |
| `test/invocation-loudness.e2e` | pins what a shell sees when the
package barrel `src/index.ts` is run as if it were the CLI (only tsx
runs a bare `.ts` file), plus the shims' own success path |
| `test/released-port-production-spawn.pin` | a source census; spawns
nothing; `TSX` appears only in specimen sources and in its own
vocabulary |
| `test/unbuilt-workspace-lead.test` | spawns nothing; pins the remedy
text, which names tsx |
Not changed: no assertion, expected output, case name, timeout, tier,
project, `// test-budget:` header or test helper. No source file.
## Tests
- **A/B** (one box, one lock hold, N=3, `--maxWorkers=1`, base and head
interleaved, base first in rounds 1 and 3, head first in round 2): for
each base leg the base file's bytes were written into the same path and
restored from `HEAD` after it, checked by blob hash, so both legs ran in
the same tier slot. `.e2e` files ran with `OS_TEST_TIERS=nightly`, the
rest with `queue` (the queue tier writes the oclif test manifest once
per run, as in CI). Whole process wall per run, in seconds:
| file | command | base | head | mean | change |
|:--|:--|:--|:--|:--|--:|
| `build-strict-body-count` | `os build` | 36.2, 31.5, 32.7 | 26.6,
26.6, 26.0 | 33.5 → 26.4 | −21.0% |
| `generate-refuses-unparseable-name` | `os generate` | 20.3, 20.9, 20.6
| 18.1, 18.6, 18.4 | 20.6 → 18.4 | −10.9% |
| `validate-view-container-name` | `os validate` | 32.3, 31.6, 31.6 |
28.9, 28.2, 28.8 | 31.8 → 28.6 | −10.0% |
| `qa-requires-skip-run` | `os qa` | 14.7, 13.3, 14.6 | 13.5, 13.2, 14.1
| 14.2 → 13.6 | −4.2% |
| `dev-no-watch.pin` | `os dev` | 53.2, 49.7, 50.4 | 41.4, 42.6, 41.0 |
51.1 → 41.6 | −18.5% |
| `migrate-exit-code.e2e` | `os migrate` | 40.2, 37.7, 39.3 | 23.8,
23.1, 23.2 | 39.1 → 23.4 | −40.1% |
| `create-refuses-invalid-project-name.e2e` | `os create` | 43.8, 42.2,
46.1 | 28.6, 28.9, 30.1 | 44.0 → 29.2 | −33.7% |
Every leg exit 0, with the same test count on both sides (6, 13, 5, 7,
8, 5, 6). The saving is larger on the nightly `.e2e` files, which run
without the queue tier's oclif manifest, so each tsx spawn there also
paid the full command import twice over.
- **All 34 switched files on head** `01d2b0d5` (and again on the merged
head, below): queue tier 17/17 files, 125/125 tests; nightly tier 17/17
files, 113/113 tests.
- Same output through both binaries: `node bin/run-dev.js --version` and
`tsx bin/run-dev.js --version` give byte-identical stdout and stderr on
this tree.
- `pnpm --filter @objectstack/cli typecheck` (tsc plus
`check:test-typecheck`) exit 0.
- No ablation: test-only, no tested behaviour changed.
## Acceptance notes
- **The biggest remaining tsx lever is the shared helper.**
`test/helpers/serve-process.ts` exports `TSX`, and `runServe()` spawns
`serve` through it; 20 cli test files call `runServe(`. The order keeps
`test/helpers/**` out of this slice because slices 24–28 run on top of
it. Carrier: #23181.
- **`invocation-loudness.e2e` could move half.** Its two
`bin/run-dev.js` spawns (`dev --no-ui`, `--version`) share one runner
with the barrel spawns. Kept on tsx as the order names the file, which
pins the shims. Carrier: #23181.
- **`package-install-local-handlers.integration`'s line-2 header still
says "the tsx source entry".** The order forbids touching `//
test-budget:` headers in this slice; the next shard-timings refresh
resizes and can reword it.
- **`skip-changeset`.** Test-only. `@objectstack/cli`'s `files[]` is
`dist`, `README.md`, `CHANGELOG.md`; `test/` and `src/**/*.test.ts` do
not build into `dist/`, so no `files[]` content changes.
## Verification
All readings on head `b2400351` (`git rev-parse --short HEAD`), the
merge of `origin/main` after slices 25, 26 and 27 landed (#28601,
#28599, #28592). None of them touched these 34 files; the merge had no
conflict.
- **Derived gate families:** `node scripts/pm/dispatch-gates.mjs
--commands --repo objectstack-ai/objectstack` gives 52 families. Each
ran with its exit code captured before any pipe, after a full `pnpm exec
turbo run build --concurrency=2` (118/118 tasks) on the merged tree.
`--ran` reconciliation: `✓ dispatch-gates --ran: 52 derived famil(ies)
accounted for — 52 run, 0 NOT-MEASURED`. On the pre-merge head
`01d2b0d5` the same set (51 families) was green too; there
`check:i18n-coverage` first exited 3 (an unbuilt
`@objectstack/connector-slack`) and read 0 after the full build, and
`check-plugin-teardown-shape.mjs --self-test` needed its
positive-control commit fetched on the shallow clone.
- **The 34 switched files on the merged head:** queue tier 17/17 files,
125/125 tests; nightly tier 17/17 files, 113/113 tests.
- **Hand gates:** `pnpm --filter @objectstack/cli typecheck` exit 0.
`pnpm exec eslint --no-inline-config` over the 34 files exit 0
(`@objectstack/cli` has no `lint` script; the repo-wide `pnpm lint` runs
in CI). `node scripts/check-commit-card-trailers.mjs --range
origin/main..HEAD` exit 0.
- **CI** families (Test Core with both cli tiers, the nightly `.e2e`
tier on `main`, the lint farm, the type-check lanes) are read off this
PR's check-runs by the seat.
- Evidence (gate lists with exit codes for both heads, every A/B row,
the A/B script): `pm-orders/server/evidence/23181-s29/` in the project
files.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01FEkQ5pFGjmwfPzsnkVqJPu
Co-authored-by: Claude <noreply@anthropic.com>1 parent d6e0967 commit 49d60d3
34 files changed
Lines changed: 135 additions & 159 deletions
File tree
- packages/cli
- src/commands
- test
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
98 | 98 | | |
99 | 99 | | |
100 | 100 | | |
101 | | - | |
| 101 | + | |
102 | 102 | | |
103 | 103 | | |
104 | 104 | | |
| |||
143 | 143 | | |
144 | 144 | | |
145 | 145 | | |
146 | | - | |
147 | 146 | | |
148 | 147 | | |
149 | 148 | | |
| |||
230 | 229 | | |
231 | 230 | | |
232 | 231 | | |
233 | | - | |
| 232 | + | |
234 | 233 | | |
235 | 234 | | |
236 | 235 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
45 | | - | |
| 45 | + | |
46 | 46 | | |
47 | 47 | | |
48 | 48 | | |
| |||
66 | 66 | | |
67 | 67 | | |
68 | 68 | | |
69 | | - | |
70 | 69 | | |
71 | | - | |
| 70 | + | |
72 | 71 | | |
73 | 72 | | |
74 | 73 | | |
| |||
258 | 257 | | |
259 | 258 | | |
260 | 259 | | |
261 | | - | |
| 260 | + | |
262 | 261 | | |
263 | 262 | | |
264 | 263 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
13 | | - | |
| 13 | + | |
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
28 | | - | |
29 | 28 | | |
30 | 29 | | |
31 | 30 | | |
| |||
72 | 71 | | |
73 | 72 | | |
74 | 73 | | |
75 | | - | |
| 74 | + | |
76 | 75 | | |
77 | 76 | | |
78 | 77 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
26 | | - | |
| 26 | + | |
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
| |||
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
42 | | - | |
43 | 42 | | |
44 | 43 | | |
45 | 44 | | |
| |||
79 | 78 | | |
80 | 79 | | |
81 | 80 | | |
82 | | - | |
| 81 | + | |
83 | 82 | | |
84 | 83 | | |
85 | 84 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
47 | | - | |
| 47 | + | |
48 | 48 | | |
49 | 49 | | |
50 | 50 | | |
| |||
62 | 62 | | |
63 | 63 | | |
64 | 64 | | |
65 | | - | |
66 | 65 | | |
67 | 66 | | |
68 | 67 | | |
| |||
73 | 72 | | |
74 | 73 | | |
75 | 74 | | |
76 | | - | |
| 75 | + | |
77 | 76 | | |
78 | 77 | | |
79 | 78 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
31 | | - | |
| 31 | + | |
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
| |||
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
47 | | - | |
48 | | - | |
| 47 | + | |
49 | 48 | | |
50 | 49 | | |
51 | 50 | | |
| |||
57 | 56 | | |
58 | 57 | | |
59 | 58 | | |
60 | | - | |
| 59 | + | |
61 | 60 | | |
62 | 61 | | |
63 | 62 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
14 | | - | |
| 14 | + | |
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
| |||
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
31 | | - | |
32 | 31 | | |
33 | 32 | | |
34 | 33 | | |
| |||
76 | 75 | | |
77 | 76 | | |
78 | 77 | | |
79 | | - | |
| 78 | + | |
80 | 79 | | |
81 | 80 | | |
82 | 81 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
24 | | - | |
| 24 | + | |
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
| |||
36 | 36 | | |
37 | 37 | | |
38 | 38 | | |
39 | | - | |
40 | | - | |
| 39 | + | |
41 | 40 | | |
42 | 41 | | |
43 | 42 | | |
| |||
49 | 48 | | |
50 | 49 | | |
51 | 50 | | |
52 | | - | |
| 51 | + | |
53 | 52 | | |
54 | 53 | | |
55 | 54 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
29 | | - | |
| 29 | + | |
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
| |||
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
45 | | - | |
46 | | - | |
| 45 | + | |
47 | 46 | | |
48 | 47 | | |
49 | 48 | | |
| |||
57 | 56 | | |
58 | 57 | | |
59 | 58 | | |
60 | | - | |
| 59 | + | |
61 | 60 | | |
62 | 61 | | |
63 | 62 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
47 | | - | |
| 47 | + | |
48 | 48 | | |
49 | 49 | | |
50 | 50 | | |
| |||
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
70 | | - | |
71 | 70 | | |
72 | | - | |
| 71 | + | |
73 | 72 | | |
74 | 73 | | |
75 | 74 | | |
| |||
93 | 92 | | |
94 | 93 | | |
95 | 94 | | |
96 | | - | |
| 95 | + | |
97 | 96 | | |
98 | 97 | | |
99 | 98 | | |
| |||
0 commit comments