Conversation
…ash-proof The plugin crashed when its configured web-server port (default 4200) was taken: PTYServer.startWebServer called Bun.serve without EADDRINUSE handling and src/v2/index.ts setup awaited getOrCreateServer without a try/catch, so a busy port rejected createServer and took the whole plugin down. Port binding now keeps its semantics (undefined/0 -> OS-assigned ephemeral port, never a conflict) and for an explicit port retries port+1..port+N (N=10) before falling back to port 0 as a last resort, logging which ports were busy and the finally bound port. EADDRINUSE is detected robustly from Bun's error shape (own code property 'EADDRINUSE', verified at runtime, with a message-based fallback). Before binding an explicit port, a quick /health probe on 127.0.0.1 reports whether another opencode-pty instance already serves it (purely diagnostic; the bind loop stays the TOCTOU-safe authority). The foreign server is deliberately not reused: the PTY manager is in-process per plugin instance, so adopting a foreign server would show a foreign session list. v2 setup wraps autostart in try/catch and continues on failure: tools keep working in-process and the server can still come up later, because getOrCreateServer retries with the new port fallback on the next on-demand command invocation. Adds test/port-fallback.test.ts covering the pure helpers (resolveWebPort, portCandidates, isEaddrinuse), double-bind fallback with health verification, exhausted-fallback (all 11 ports blocked -> OS-assigned), port 0 semantics, and v2 setup resilience with a busy configured port.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The plugin crashes when its configured web-server port (default
4200) is already in use:PTYServer.startWebServercallsBun.serve({ port, ... })with noEADDRINUSEhandling.await getOrCreateServer(...)— a busy port rejectsPTYServer.createServer, which makes plugin setup throw, i.e. the plugin dies at load.Reproduced: with one opencode instance already serving on
4200, starting a second instance with the default config crashes its plugin.Fix
port: 0/unset semantics (OS-assigned, never conflicts). For an explicit port, try it and onEADDRINUSEwalkport+1 … port+10, with port0as the final fallback. Every attempt logs which port is busy; the final port is logged too.server.url/getWsUrlare unchanged, so the dynamic port flows into the web UI and/pty-show-server-urlcorrectly.EADDRINUSEdetection: checks the Bun errorcode, with a message-pattern fallback for differently-shaped environments./healthprobe detects an already-running opencode-pty server and logs that clearly instead of crashing. The bind loop stays the TOCTOU-safe authority. Cross-process "server reuse" is intentionally not attempted: the PTY manager is in-process per plugin instance, so adopting a foreign server would show a foreign session list.Tests
15 new tests in
test/port-fallback.test.ts:/healthOK on the new portport: 0→ random OS-assigned portPlugin.setupwithautostart: trueand a busy port → resolves, warning logged,getActiveServer()populatedEADDRINUSEdetection)Verification
bun run format/lint/typecheck/build:prod— cleanbun test— 97 pass; the only failures are the same 4 that also fail onmainin this environment (2 package tests neednpm, which is absent here; 2 are timing-sensitive and pass in CI)PTY_WEB_PORT=4200while 4200 was held → bound to4201, healthy, original server untouched, log shows the "already runs / next port" warningsStandalone PR (based on
main, 2 commits) — intentionally not part of #61.