fix(terminal): unset NODE_CHANNEL_FD for PTY shells on every POSIX host

The PTY runtime exported an empty NODE_CHANNEL_FD to override the daemon's
IPC descriptor, because bun-pty merges the native environ back into the
child and a JS-only delete does not stick. Node CLIs launched from the
shell (opencode, claude) then printed "warn: Failed to parse IPC channel
number ''" on exit.

The Linux-only env -u ARGV0 wrapper now applies on macOS and Linux and
also unsets NODE_CHANNEL_FD, so the variable is gone instead of empty.

Testing: runtime and inherited-env tests updated for the POSIX wrapper;
verified in the running app that exiting opencode no longer prints the
warning.
This commit is contained in:
Bohdan Triapitsyn
2026-09-07 12:18:22 +03:00
parent 39fa8c1917
commit ff75dc9bd5
5 changed files with 43 additions and 36 deletions
@@ -1,7 +1,7 @@
import { describe, expect, it } from 'vitest';
import {
clearAppImageArgv0FromProcessEnv,
resolveLinuxPtyLaunch,
resolvePosixPtyLaunch,
stripAppImageArgv0Leak,
} from './inherited-env.js';
@@ -46,18 +46,17 @@ describe('clearAppImageArgv0FromProcessEnv', () => {
});
});
describe('resolveLinuxPtyLaunch', () => {
it('wraps the shell with env -u ARGV0 on Linux', () => {
if (process.platform !== 'linux') return;
expect(resolveLinuxPtyLaunch('/bin/zsh', ['-l'])).toEqual({
describe('resolvePosixPtyLaunch', () => {
it('wraps the shell with env -u for every host-private variable on POSIX', () => {
if (process.platform === 'win32') return;
expect(resolvePosixPtyLaunch('/bin/zsh', ['-l'])).toEqual({
executable: expect.stringMatching(/\/env$/),
args: ['-u', 'ARGV0', '/bin/zsh', '-l'],
args: ['-u', 'ARGV0', '-u', 'NODE_CHANNEL_FD', '/bin/zsh', '-l'],
});
});
it('leaves non-Linux launches unchanged', () => {
if (process.platform === 'linux') return;
expect(resolveLinuxPtyLaunch('/bin/zsh', ['-l'])).toEqual({
it('leaves the launch unchanged with nothing to unset', () => {
expect(resolvePosixPtyLaunch('/bin/zsh', ['-l'], [])).toEqual({
executable: '/bin/zsh',
args: ['-l'],
});