From 9f9c9758a1cd6c2f7d215626eb4a34b85e5449d1 Mon Sep 17 00:00:00 2001 From: roboomp Date: Sat, 1 Aug 2026 11:39:57 +0000 Subject: [PATCH] fix(tui): prevented test env from suppressing interactive launch Scoped test-runtime detection to explicit runner markers and Bun test entrypoints, so application NODE_ENV/BUN_ENV values no longer make ProcessTerminal headless. Added subprocess regression coverage and propagated the private marker to test children. Fixes #7261 --- packages/coding-agent/CHANGELOG.md | 4 +++ packages/tui/CHANGELOG.md | 4 +++ packages/utils/CHANGELOG.md | 4 +++ packages/utils/src/env.ts | 8 +++-- packages/utils/test/env.test.ts | 29 +++++++++++++++++++ .../utils/test/fixtures/test-runtime-probe.ts | 3 ++ scripts/ci-test-ts.ts | 7 +++-- 7 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 packages/utils/test/fixtures/test-runtime-probe.ts diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 1b632e9c5..70a7dc0a6 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed interactive launches hanging silently when a host project or its `.env` sets `NODE_ENV=test` or `BUN_ENV=test` ([#7261](https://github.com/can1357/oh-my-pi/issues/7261)). + ## [17.2.3] - 2026-08-01 ### Changed diff --git a/packages/tui/CHANGELOG.md b/packages/tui/CHANGELOG.md index ee822e5d5..6c3009e4b 100644 --- a/packages/tui/CHANGELOG.md +++ b/packages/tui/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed interactive terminals suppressing all output and input when the host project sets `NODE_ENV=test` or `BUN_ENV=test` ([#7261](https://github.com/can1357/oh-my-pi/issues/7261)). + ## [17.2.2] - 2026-07-31 ### Added diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md index 27466e466..ae31a9a6c 100644 --- a/packages/utils/CHANGELOG.md +++ b/packages/utils/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed Bun test-runtime detection treating application-owned `NODE_ENV=test` and `BUN_ENV=test` values as test-runner signals ([#7261](https://github.com/can1357/oh-my-pi/issues/7261)). + ## [17.2.1] - 2026-07-30 ### Added diff --git a/packages/utils/src/env.ts b/packages/utils/src/env.ts index 51c6cd8c7..76d4ef711 100644 --- a/packages/utils/src/env.ts +++ b/packages/utils/src/env.ts @@ -258,9 +258,13 @@ export function $envpos(name: string, defaultValue: number): number { return parsed; } -/** True when `BUN_ENV` or `NODE_ENV` is the string `test`. */ +const BUN_TEST_ENTRY_PATTERN = /\.(?:test|spec)\.[cm]?[jt]sx?$/; + +/** True when the process is an explicitly marked test child or Bun is running a test entrypoint. */ export function isBunTestRuntime(): boolean { - return Bun.env.BUN_ENV === "test" || Bun.env.NODE_ENV === "test"; + if (Bun.env.PI_TEST_RUNTIME === "1") return true; + const hasTestEnvironment = Bun.env.BUN_ENV === "test" || Bun.env.NODE_ENV === "test"; + return hasTestEnvironment && BUN_TEST_ENTRY_PATTERN.test(Bun.main); } let terminalHeadless = isBunTestRuntime(); diff --git a/packages/utils/test/env.test.ts b/packages/utils/test/env.test.ts index 49aefc363..c1e7ab56f 100644 --- a/packages/utils/test/env.test.ts +++ b/packages/utils/test/env.test.ts @@ -5,6 +5,7 @@ import * as path from "node:path"; import { filterProcessEnv, parseEnvFile } from "@oh-my-pi/pi-utils/env"; const tempDirs: string[] = []; +const runtimeProbePath = path.join(import.meta.dir, "fixtures", "test-runtime-probe.ts"); afterEach(() => { for (const dir of tempDirs.splice(0)) { @@ -20,6 +21,23 @@ function writeTempEnv(content: string): string { return filePath; } +async function runRuntimeProbe(env: Record): Promise { + const cwd = path.dirname(writeTempEnv("")); + const proc = Bun.spawn([process.execPath, runtimeProbePath], { + cwd, + env: { ...process.env, ...env }, + stdout: "pipe", + stderr: "pipe", + }); + const [stdout, stderr, exitCode] = await Promise.all([ + new Response(proc.stdout).text(), + new Response(proc.stderr).text(), + proc.exited, + ]); + expect(exitCode, stderr).toBe(0); + return JSON.parse(stdout) as boolean; +} + describe("parseEnvFile", () => { it("ignores malformed names and nul-containing values", () => { const filePath = writeTempEnv( @@ -121,3 +139,14 @@ describe("filterProcessEnv", () => { }); }); }); + +describe("isBunTestRuntime", () => { + it("does not treat shared application env names as a test runner signal", async () => { + expect(await runRuntimeProbe({ NODE_ENV: "test", BUN_ENV: undefined, PI_TEST_RUNTIME: undefined })).toBe(false); + expect(await runRuntimeProbe({ NODE_ENV: undefined, BUN_ENV: "test", PI_TEST_RUNTIME: undefined })).toBe(false); + }); + + it("honors the private test runner signal", async () => { + expect(await runRuntimeProbe({ NODE_ENV: undefined, BUN_ENV: undefined, PI_TEST_RUNTIME: "1" })).toBe(true); + }); +}); diff --git a/packages/utils/test/fixtures/test-runtime-probe.ts b/packages/utils/test/fixtures/test-runtime-probe.ts new file mode 100644 index 000000000..22e2ec782 --- /dev/null +++ b/packages/utils/test/fixtures/test-runtime-probe.ts @@ -0,0 +1,3 @@ +import { isBunTestRuntime } from "@oh-my-pi/pi-utils/env"; + +process.stdout.write(JSON.stringify(isBunTestRuntime())); diff --git a/scripts/ci-test-ts.ts b/scripts/ci-test-ts.ts index dda6c0dd3..ff2793276 100755 --- a/scripts/ci-test-ts.ts +++ b/scripts/ci-test-ts.ts @@ -467,9 +467,9 @@ async function runTestCommand(testCommand: TestCommand): Promise { } } -// Child env shared by every spawned test process: the parent env with all CI -// credential / cloud-config variables scrubbed (see SCRUBBED_ENV_* above) and -// GITHUB_ACTIONS cleared so suites resolve only against their own fixtures. +// Child env shared by every spawned test process: the parent env with the +// private test-runtime marker set, all CI credential / cloud-config variables +// scrubbed (see SCRUBBED_ENV_* above), and GITHUB_ACTIONS cleared. // // GC knobs (both needed — they gate different JSC mechanisms): // - `BUN_JSC_useConcurrentGC=0` stops the collector from marking concurrently @@ -493,6 +493,7 @@ function buildChildEnv(): Record { const env: Record = { ...Bun.env, GITHUB_ACTIONS: "", + PI_TEST_RUNTIME: "1", BUN_JSC_useConcurrentGC: "0", BUN_JSC_numberOfGCMarkers: "1", };