From a4f6e3f67bfd47b5c00ba19fb9de4f05e1cddfd2 Mon Sep 17 00:00:00 2001 From: morluto Date: Thu, 12 Mar 2026 19:01:19 +0800 Subject: [PATCH] fix: stop waiting on recreated state files Wait for the requested daemon pid to exit instead of treating raw state-file existence as part of shutdown completion. --- browse/src/cli.ts | 4 +--- browse/test/commands.test.ts | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/browse/src/cli.ts b/browse/src/cli.ts index 2e52ce1b7..714413bdf 100644 --- a/browse/src/cli.ts +++ b/browse/src/cli.ts @@ -226,9 +226,7 @@ async function ensureServer(): Promise { async function waitForServerStop(pid: number, timeout = MAX_START_WAIT): Promise { const start = Date.now(); while (Date.now() - start < timeout) { - const alive = isProcessAlive(pid); - const stateExists = fs.existsSync(STATE_FILE); - if (!alive && !stateExists) { + if (!isProcessAlive(pid)) { return; } await Bun.sleep(100); diff --git a/browse/test/commands.test.ts b/browse/test/commands.test.ts index 4d819a726..79cdb06c3 100644 --- a/browse/test/commands.test.ts +++ b/browse/test/commands.test.ts @@ -767,6 +767,39 @@ describe('CLI lifecycle', () => { await cleanupCliState(stateFile); } }, 25000); + + test('stop ignores recreated state file once the target pid exits', async () => { + const stateFile = `/tmp/browse-stop-recreated-state-${Date.now()}.json`; + const port = reservePort(); + const env = { + BROWSE_STATE_FILE: stateFile, + BROWSE_PORT: String(port), + }; + + try { + const started = await runCliCommand(['status'], env); + const startedState = readJson<{ pid: number; port: number; token: string; startedAt: string; serverPath: string }>(stateFile); + expect(started.code).toBe(0); + expect(startedState?.pid).toBeTruthy(); + + const stopPromise = runCliCommand(['stop'], env); + await waitFor(() => !fs.existsSync(stateFile) ? true : null, 5000); + + fs.writeFileSync(stateFile, JSON.stringify({ + pid: 999999, + port, + token: 'fake-token', + startedAt: new Date().toISOString(), + serverPath: '/tmp/fake-server.ts', + })); + + const stop = await stopPromise; + expect(stop.code).toBe(0); + expect(stop.stdout).toContain('Server stopped'); + } finally { + await cleanupCliState(stateFile); + } + }, 20000); }); // ─── Buffer bounds ──────────────────────────────────────────────