Skip to content

fix(run-commands): open a dev server's URL once it is listening - #196

Open
AThraen wants to merge 1 commit into
mainfrom
fix/run-url-opens-when-server-ready
Open

AThraen wants to merge 1 commit into
mainfrom
fix/run-url-opens-when-server-ready

Conversation

@AThraen

@AThraen AThraen commented Nov 11, 2026

Copy link
Copy Markdown
Contributor

Problem

When a session command has a URL, it never opens in the browser. The URL was opened only when the command exits 0, but these commands are almost always dev servers, which never exit. All five run commands with a URL in the reporter's state.json are servers: npm run dev, npm start, node tools/serve.js 8084, node tools/studio.js and a preview.ps1. crash.log has no PostRunUrl entries, so the URL was never rejected. The code to open it simply never ran.

Fix

The URL now opens once, on whichever happens first:

  • A loopback URL starts accepting TCP connections while the run is alive. It is polled every 500 ms for up to 2 minutes on a pool thread. Every address of the host is tried in parallel: localhost resolves to ::1 and 127.0.0.1, and a server usually binds only one of them. Trying them one after the other doesn't work on Windows, where a refused loopback connect takes about 2 s; the test against a real IPv4-only listener caught exactly that.
  • The run exits 0. This is the old rule, kept for one-shot commands such as a build followed by a report page.

The watcher stops on exit, Stop and Dispose, and a stopped run never opens late. Remote URLs and SSH parents are never polled:

  • A remote URL, such as a deploy target, can be reachable before the command has done anything.
  • An SSH run's server listens on the remote machine's loopback, which a local connection can't reach.

The validation of the URL (http or https only) and the rule of launching the validated string are unchanged.

The dialog tooltip and CLAUDE.md describe the new rule.

Tests

New PostRunUrlReadinessTests (19 cases):

  • a server opens without exiting;
  • a ready server that then exits opens only once;
  • a one-shot command opens on exit 0, and an exit of 1 never opens;
  • Stop before the server is ready never opens later;
  • a remote URL and an SSH parent are never probed;
  • a non-http URL is never probed or opened;
  • the loopback classification;
  • the real TCP probe against listeners on 127.0.0.1 and ::1, reached as localhost and 0.0.0.0, plus a port with nothing listening.

The full unit suite passes: 1203 of 1203.

Manual check

  • A session with npm run dev and http://localhost:5173: press ▶. The browser opens when Vite is up, not before, and only once.

🤖 Generated with Claude Code

A run command's URL opened only when the command exited 0, and the
commands it is used with are dev servers (npm run dev, npm start,
node serve.js) that never exit, so the URL never opened.

It now opens once, on whichever comes first:
- a loopback URL starts accepting TCP connections while the run is
  alive (polled every 500ms for up to 2 minutes, every address of the
  host in parallel, since localhost is both ::1 and 127.0.0.1);
- the run exits 0, which is the old rule, kept for one-shot commands.

Remote URLs and SSH parents keep the exit-0 rule only. A remote URL is
reachable before a deploy finishes, and an SSH run's server listens on
the remote machine's loopback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant