48 lines
2.2 KiB
Markdown
48 lines
2.2 KiB
Markdown
# Reproduction: Chat UI stops updating until the desktop app is restarted (#2638)
|
|||
|
|
|
||
|
|
Reproduces https://github.com/openchamber/openchamber/issues/2638 using the
|
||
|
|
real server modules (`lifecycle.js`, `global-hub.js`, `network-runtime.js`),
|
||
|
|
real processes, and real ports — no mocks.
|
||
|
|
|
||
|
|
## Run
|
||
|
|
|
||
|
|
```sh
|
||
|
|
# Windows-orphan scenario (the reported bug):
|
||
|
|
node scripts/repro/issue-2638/reproduce-2638.mjs
|
||
|
|
|
||
|
|
# Control: healthy restart on Linux (hub reconnects, UI keeps updating):
|
||
|
|
node scripts/repro/issue-2638/reproduce-2638.mjs --baseline
|
||
|
|
```
|
||
|
|
|
||
|
|
Requires `lsof` (used only for cleanup). The default run simulates Windows
|
||
|
|
(`process.platform` is temporarily overridden to `win32`) because the bug is
|
||
|
|
specific to the Windows process-lifecycle path.
|
||
|
|
|
||
|
|
## What it demonstrates
|
||
|
|
|
||
|
|
1. A managed OpenCode process starts; the global message-stream hub connects to
|
||
|
|
its `/global/event` SSE stream and chat events flow to the UI.
|
||
|
|
2. The managed process "exits" but the actual server process survives on the
|
||
|
|
old port (on Windows `killProcessOnPort` is a no-op and `taskkill` cannot
|
||
|
|
reach the orphaned tree — the report shows leftover `opencode.exe serve`
|
||
|
|
processes on historical ports).
|
||
|
|
3. `restartOpenCode()` gives up after 5 s — logs
|
||
|
|
`Timed out waiting for OpenCode port <old> to be released` — and spawns a
|
||
|
|
fresh server on a NEW port, leaving the orphaned process running.
|
||
|
|
4. HTTP/proxy traffic follows `state.openCodePort` to the new server, but the
|
||
|
|
hub's upstream SSE reader stays pinned to the OLD server's `/global/event`
|
||
|
|
stream (that connection never closed), so events emitted by the new server
|
||
|
|
never reach the UI: the chat UI goes stale while the new server keeps
|
||
|
|
persisting session data — visible only after restarting the app.
|
||
|
|
|
||
|
|
The `--baseline` control proves the reconnect logic itself is fine: when the
|
||
|
|
old process dies and the port is properly released, the hub reconnects to the
|
||
|
|
new port and events are delivered.
|
||
|
|
|
||
|
|
## Files
|
||
|
|
|
||
|
|
- `reproduce-2638.mjs` — the reproduction driver (assertions + summary).
|
||
|
|
- `fake-opencode-serve.mjs` — a fake `opencode serve` binary whose launcher
|
||
|
|
spawns a detached server core that survives the launcher's death
|
||
|
|
(Windows-style orphan), plus an in-process mode for the baseline control.
|