fix(server): bound login-shell probes so a slow rc file cannot stall startup (#1742)
fix(cli): detect brew-installed opencode on macOS (#1720)
This commit is contained in:
@@ -5,6 +5,12 @@ import path from 'node:path';
|
|||||||
import { clearAppImageArgv0FromProcessEnv } from '../inherited-env.js';
|
import { clearAppImageArgv0FromProcessEnv } from '../inherited-env.js';
|
||||||
import { mergePathValues } from './path-utils.js';
|
import { mergePathValues } from './path-utils.js';
|
||||||
|
|
||||||
|
// Login-shell probes source the user's rc files. A slow or interactive rc
|
||||||
|
// (nvm, pyenv, a prompt waiting for input) must not hold server startup
|
||||||
|
// hostage: a probe that overruns is abandoned and resolution falls through
|
||||||
|
// to the next candidate. Electron's own login-shell probe uses the same bound.
|
||||||
|
const SHELL_PROBE_TIMEOUT_MS = 5_000;
|
||||||
|
|
||||||
export const createOpenCodeEnvRuntime = (deps) => {
|
export const createOpenCodeEnvRuntime = (deps) => {
|
||||||
const {
|
const {
|
||||||
state,
|
state,
|
||||||
@@ -208,6 +214,7 @@ export const createOpenCodeEnvRuntime = (deps) => {
|
|||||||
stdio: ['ignore', 'pipe', 'pipe'],
|
stdio: ['ignore', 'pipe', 'pipe'],
|
||||||
maxBuffer: 10 * 1024 * 1024,
|
maxBuffer: 10 * 1024 * 1024,
|
||||||
windowsHide: true,
|
windowsHide: true,
|
||||||
|
timeout: SHELL_PROBE_TIMEOUT_MS,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result.status !== 0) {
|
if (result.status !== 0) {
|
||||||
@@ -460,6 +467,7 @@ export const createOpenCodeEnvRuntime = (deps) => {
|
|||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
stdio: ['ignore', 'pipe', 'pipe'],
|
stdio: ['ignore', 'pipe', 'pipe'],
|
||||||
windowsHide: true,
|
windowsHide: true,
|
||||||
|
timeout: SHELL_PROBE_TIMEOUT_MS,
|
||||||
});
|
});
|
||||||
if (result.status === 0) {
|
if (result.status === 0) {
|
||||||
const found = (result.stdout || '').trim().split(/\s+/).pop() || '';
|
const found = (result.stdout || '').trim().split(/\s+/).pop() || '';
|
||||||
@@ -527,6 +535,7 @@ export const createOpenCodeEnvRuntime = (deps) => {
|
|||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
stdio: ['ignore', 'pipe', 'pipe'],
|
stdio: ['ignore', 'pipe', 'pipe'],
|
||||||
windowsHide: true,
|
windowsHide: true,
|
||||||
|
timeout: SHELL_PROBE_TIMEOUT_MS,
|
||||||
});
|
});
|
||||||
if (result.status === 0) {
|
if (result.status === 0) {
|
||||||
const found = (result.stdout || '').trim().split(/\s+/).pop() || '';
|
const found = (result.stdout || '').trim().split(/\s+/).pop() || '';
|
||||||
@@ -608,6 +617,7 @@ export const createOpenCodeEnvRuntime = (deps) => {
|
|||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
stdio: ['ignore', 'pipe', 'pipe'],
|
stdio: ['ignore', 'pipe', 'pipe'],
|
||||||
windowsHide: true,
|
windowsHide: true,
|
||||||
|
timeout: SHELL_PROBE_TIMEOUT_MS,
|
||||||
});
|
});
|
||||||
if (result.status === 0) {
|
if (result.status === 0) {
|
||||||
const found = (result.stdout || '').trim().split(/\s+/).pop() || '';
|
const found = (result.stdout || '').trim().split(/\s+/).pop() || '';
|
||||||
|
|||||||
@@ -334,6 +334,29 @@ describe('OpenCode env runtime', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('bounds every login-shell probe and falls through when one overruns', () => {
|
||||||
|
setPlatform('darwin');
|
||||||
|
process.env.PATH = createTempDir('openchamber-empty-path-');
|
||||||
|
process.env.SHELL = '/bin/zsh';
|
||||||
|
delete process.env.OPENCODE_BINARY;
|
||||||
|
const shellCalls = [];
|
||||||
|
const { runtime } = createRuntime({}, {
|
||||||
|
homedir: () => createTempDir('openchamber-empty-home-'),
|
||||||
|
spawnSync: (command, args, options) => {
|
||||||
|
shellCalls.push({ command, args, options });
|
||||||
|
// What spawnSync reports when `timeout` fires: no status, an error.
|
||||||
|
return { status: null, signal: 'SIGTERM', error: new Error('spawnSync ETIMEDOUT'), stdout: '', stderr: '' };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(runtime.resolveOpencodeCliPath()).toBeNull();
|
||||||
|
expect(shellCalls.length).toBeGreaterThan(0);
|
||||||
|
for (const call of shellCalls) {
|
||||||
|
expect(call.args).toContain('-lic');
|
||||||
|
expect(call.options.timeout).toBe(5_000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('does not auto-detect the Windows OpenCode desktop app as a CLI', () => {
|
it('does not auto-detect the Windows OpenCode desktop app as a CLI', () => {
|
||||||
setPlatform('win32');
|
setPlatform('win32');
|
||||||
const localAppData = createTempDir('openchamber-localappdata-');
|
const localAppData = createTempDir('openchamber-localappdata-');
|
||||||
|
|||||||
Reference in New Issue
Block a user