fix(opencode): preserve managed process liveness
This commit is contained in:
@@ -69,7 +69,9 @@ export const createOpenCodeLifecycleRuntime = (deps) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasChildProcessExited = (child) => !child || child.exitCode !== null || child.signalCode !== null;
|
const hasChildProcessExited = (child) => !child
|
||||||
|
|| (child.exitCode !== null && child.exitCode !== undefined)
|
||||||
|
|| (child.signalCode !== null && child.signalCode !== undefined);
|
||||||
|
|
||||||
const isManagedOpenCodeProcessAlive = () => {
|
const isManagedOpenCodeProcessAlive = () => {
|
||||||
const child = state.openCodeProcess;
|
const child = state.openCodeProcess;
|
||||||
@@ -365,6 +367,12 @@ export const createOpenCodeLifecycleRuntime = (deps) => {
|
|||||||
return {
|
return {
|
||||||
url,
|
url,
|
||||||
pid: child.pid || null,
|
pid: child.pid || null,
|
||||||
|
get exitCode() {
|
||||||
|
return child.exitCode;
|
||||||
|
},
|
||||||
|
get signalCode() {
|
||||||
|
return child.signalCode;
|
||||||
|
},
|
||||||
async close() {
|
async close() {
|
||||||
await closeManagedOpenCodeChild(child);
|
await closeManagedOpenCodeChild(child);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -233,6 +233,30 @@ describe('OpenCode lifecycle', () => {
|
|||||||
warn.mockRestore();
|
warn.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('does not mistake a live managed process wrapper for an exited child', async () => {
|
||||||
|
const close = vi.fn(async () => {});
|
||||||
|
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
||||||
|
globalThis.fetch = vi.fn(async () => ({
|
||||||
|
ok: false,
|
||||||
|
json: async () => null,
|
||||||
|
}));
|
||||||
|
const runtime = createRuntime({}, {
|
||||||
|
openCodePort: 45678,
|
||||||
|
openCodeProcess: {
|
||||||
|
pid: process.pid,
|
||||||
|
close,
|
||||||
|
},
|
||||||
|
isOpenCodeReady: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
await runtime.triggerHealthCheck();
|
||||||
|
|
||||||
|
expect(close).not.toHaveBeenCalled();
|
||||||
|
expect(spawnMock).not.toHaveBeenCalled();
|
||||||
|
expect(warn).toHaveBeenCalledWith(expect.stringContaining('(1/20)'));
|
||||||
|
warn.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
it('restarts an exited managed process without waiting for the failure interval', async () => {
|
it('restarts an exited managed process without waiting for the failure interval', async () => {
|
||||||
const close = vi.fn(async () => {});
|
const close = vi.fn(async () => {});
|
||||||
const replacement = createMockChild();
|
const replacement = createMockChild();
|
||||||
@@ -281,8 +305,11 @@ describe('OpenCode lifecycle', () => {
|
|||||||
expect(options.env.PATH).toBe('/home/user/.bun/bin:/usr/local/bin:/usr/bin');
|
expect(options.env.PATH).toBe('/home/user/.bun/bin:/usr/local/bin:/usr/bin');
|
||||||
expect(options.env.SHELL_ONLY).toBe('yes');
|
expect(options.env.SHELL_ONLY).toBe('yes');
|
||||||
expect(options.env.OPENCODE_SERVER_PASSWORD).toBe('password');
|
expect(options.env.OPENCODE_SERVER_PASSWORD).toBe('password');
|
||||||
|
expect(server.exitCode).toBeNull();
|
||||||
|
expect(server.signalCode).toBeNull();
|
||||||
|
|
||||||
await server.close();
|
await server.close();
|
||||||
|
expect(server.signalCode).toBe('SIGTERM');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('adds managed OpenChamber tool environment without allowing it to replace launch invariants', async () => {
|
it('adds managed OpenChamber tool environment without allowing it to replace launch invariants', async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user