Repository navigation
feat(browser): open local files from the session's checkout - #981
Merged
Merged
Conversation
A file: URL stays blocked: its page follows links anywhere on the machine, outside a confined session's sandbox, and its null origin breaks module scripts and fetch. A path or file: URL inside the session's checkout now loads from a loopback static server rooted in an os.Root, one per checkout, on its LICH_WORKTREE_PORT plus 1000 (25000-25999), moving to the next free port when that one is taken.
A root held for the server's life keeps the directory open, and Windows refuses to remove an open directory: a worktree could not be deleted while its preview ran, which is also what failed the suite's TempDir cleanup on the Windows runner. SessionCheckout's test moves beside the Unix-only store stub it uses, so the package vets on GOOS=windows.
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.
Summary
A session's browser could not open a local file:
file:is blocked, and previewing anindex.htmlmeant the agent startingpython -m http.serverornpx http-serveron whatever port it picked.file:stays blocked. Its page follows its own links to any path on the machine, and the Chromium loading it runs outside a confined session's sandbox; its null origin also breaks module scripts andfetch. Instead, a path orfile:URL inside the session's checkout loads over http:internal/preview: one static server per checkout, rooted in anos.Root(refuses..and symlinks leading out), bound on first use and closed when lich exits. A path outside the checkout is refused.LICH_WORKTREE_PORTplus 1000 (25000-25999), so each worktree is its own origin and never takes the dev server's port. A taken port moves to the next free one in the window, wrapping at its end.browser.SetLocalresolves a local URL forbrowser_open,browser_navigateand the address field;terminal.SessionCheckoutnames the session's spawn directory and reserved port. A blocked URL still fails before the browser is looked up.https://.docs/ceilings.md: the server is static (no reload, no SPA fallback), serves everything under the spawn directory (all of home for a session started there), roots at the checkout so a Vite build with the defaultbaseloads blank fromdist/index.html, and a moved port changes the origin and its storage.docs/browser-tab.md, MCP tool descriptions andCHANGELOG.mdupdated.Provider-independent: the browser belongs to the session, so all eight providers get it the same way.
Test plan
internal/preview: serves a path and afile:URL, reuses one listener per checkout, refuses outside paths, other hosts and a symlink out, picks the port above the dev-server window, moves past a taken port and wraps, fails only with the whole window taken.internal/browser: local resolution goes to the owner's checkout; a blocked URL is refused before the browser lookup inNavigateandNav.internal/terminal:SessionCheckoutreads the spawn and its reservation.native:typedURLpasses an absolute path through.go test ./...for the backend andnative/;GOOS=darwin|windows go veton the touched packages.