dor agent-browser: browser-chrome header (nav + URL + dev-server link)#141
Merged
Conversation
Pull the "Iframe Surface: Limitations And Status" section out of dor-cli.md into a dedicated docs/specs/dor-iframe.md (mirroring dor-agent-browser.md), and append the roadmap discussed for case-3 (tools/plugins) as Future Work: - the transparent proxy + injected keyboard shim (the substrate), framed as resolving limitations #1-#4 by making Dormouse the server of the bytes - the two-axis render-backend model: (screencast | embed) x (URL | owned-backend) - Path 1 (swappable render backend via in-place renderer replacement) and Path 2 (plugin system: process supervisor + the per-surface teardown hook) dor-cli.md now points to dor-iframe.md from the command list; the dor-agent-browser.md cross-ref is repointed. Status reframed: the iframe surface is kept and re-backed by the proxy for local tools, not dropped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reshape the agent-browser surface header to read like a browser: the active tab's URL as primary text (HTML title demoted to tooltip), Chrome-style back/forward/reload, a badge for non-default --key, and a dev-server connection chip that correlates a loopback URL's port to the terminal pane serving it and focuses that pane on click. - Extend the body↔header bridge (agent-browser-screen) with a separate chrome-snapshot channel (URL / key / connection) plus nav actions, so tab/status updates don't churn the SYNCED/SCALED screen snapshot; AgentBrowserPanel computes and publishes it. - New browser-url helpers (host+path display, loopback-port parsing) and a port→pane correlation store (agent-browser-ports) driven Wall-side via use-dev-server-ports — getOpenPorts' first UI consumer — with a new onFocusPane WallAction to jump to the serving terminal (0.0.0.0/wildcard binds count as serving localhost; specific non-loopback interfaces do not). - Add reload/back/forward to the agentBrowserCommand allowlist. - Reorder the shared SurfacePaneHeader for browser surfaces (sync chip far-left, nav, key badge, URL, connection chip, spacer) with responsive collapse; terminals/iframes unchanged. - Storybook playground (BrowserChromeHeader) + unit and render tests; move the feature out of the spec's Future Expansions into the built surface. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The connection-chip correlation was async but fired a full N-pane `getOpenPorts` scan the instant a loopback URL appeared — i.e. exactly as the tab opened — and then re-scanned every 5s. Each scan shells out (`lsof`/PowerShell) per pane on the same host that drives the live screencast, so the burst contended with the opening tab's first screenshots and the steady poll kept the host busy. Make the decoration strictly off the hot path: - debounce interest changes (~600ms) so tab-open/navigation settles first and never triggers a synchronous scan; - run the scan in requestIdleCallback time (timeout fallback for webviews without it), yielding to rendering + the screencast; - pace adaptively — poll quickly (4s) only while a wanted port is still unmatched (a dev server may start after the tab), back off to 15s once matched, and stop entirely when no loopback URL is on screen. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stop the periodic re-scan. Once a loopback port is matched to a pane it's remembered and never rescanned — the serving pane rarely moves, so the steady-state getOpenPorts poll was wasted work. We keep retrying (slow idle poll) only while a wanted port is still unmatched (the dev server may start after the tab opened). A surface reload un-settles every port and re-validates, but optimistically: the published resolution stays in place until the rescan overwrites it, so the chip never flickers when nothing changed. Navigating to a different loopback port re-scans naturally (the old port leaves the wanted set). Wire the header reload button to triggerDevServerRescan(). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Importing the contexts from '../components/Wall' dragged the whole Wall orchestrator — and its `dor/commands/shell-quote` import — into the story graph, which Storybook's Vite can't resolve (the story crashed with "Failed to resolve import 'dor/commands/shell-quote'"). Pull the contexts + WallActions type straight from wall-context instead (type-only deps, no runtime dor import), which is also the right layering for a header story. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Storybook's Vite doesn't read tsconfig paths, so the tsconfig.app.json mapping `dor/* → ../dor/src/*` never applied — any story importing Wall (TerminalPaneHeader, MouseHeaderIcon, ShellCwd, …) crashed at load with "Failed to resolve import 'dor/commands/shell-quote' from Wall.tsx". The main app + webview builds resolve it; only Storybook was missing the mapping. Add a `dor` alias to viteFinal mirroring the tsconfig path. Verified against a fresh Storybook instance: all three previously-broken stories now render. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the text key badge with a single filled KeyIcon; the key name moves to the hover tooltip (`--key <name>`). Non-default-keys-only behavior is unchanged. Update the header test to assert the icon's aria-label instead of the old badge text. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Move the dev-server connection chip in front of the URL. - When the chip is shown the URL drops the now-redundant domain and shows only the path (new pathDisplay helper); with no chip it keeps host+path. - Drop the chip's fixed 14ch command cap so the whole command shows when there's room, and give the URL a much higher shrink priority so it truncates long before the command does. - Remove the green status dot from the chip. - Simplify header opacity: full-strength at rest everywhere except a single /70 accent on the chip's :port; /10 stays the lone hover wash. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The chrome snapshot carried connected/connecting/lost, but nothing in the header ever rendered it — the pane *body* placeholder uses the underlying status/connectionLost directly, which is untouched. Remove the dead field, its panel computation, the Storybook control + ConnectionLost story, and the spec mention. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the filled key icon with the key name inline, small + /70 quiet, so it reads as a quiet label next to the URL. Hover still reveals `--key <name>`; non-default-keys-only behavior unchanged. Drop the now unused KeyIcon import and update the header test to assert the inline text. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Clicking the header URL opens an inline editor (the terminal-rename pattern) pre-filled with the full URL, all selected. Enter navigates, Escape/blur cancels (browser-omnibox style). - New chromeActions.navigate(url) issues `open <url>`; `open` added to the agentBrowserCommand allowlist. - normalizeNavUrl keeps an explicit scheme, else adds http:// for loopback hosts (a bare localhost:5173 SSL-errors under https) and https:// for the rest. - Keyboard coordination: the editor flags dialog-keyboard so the Wall's chord handler stands down, and the panel's key-forwarder now skips editable targets so a header input keeps its keystrokes (also hardens the screen modal's fields). - Tests for normalizeNavUrl and the editor open/navigate/cancel flow; spec updated (allowlist + click-to-navigate note). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
/simplify cleanups: - normalizeNavUrl reuses isLoopbackHostname instead of inlining a second (already-drifting) copy of the loopback-host set. - Drop the redundant displayUrl dep from the chrome publish effect (displayUrl is hostPathDisplay(url), so url already covers it). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…play Cross-codebase dedup of three patterns /simplify flagged but I'd left inside the agent-browser diff: - isEditableTarget(target) (new lib/dom.ts) replaces three hand-rolled "is this a form field" predicates that had drifted: the mouse-selection chord guard (keeps its xterm-helper-textarea carve-out on top), the mobile blur, and AgentBrowserPanel's key-forwarder (drops a speculative SELECT). - deriveSurfaceLabel(pane, visible, appTitleForPane, fallback) (terminal-state) is now the one place to compose deriveHeader + resolveDisplayPrimary for a single pane; Baseboard.deriveDoorTitle, Wall.buildDorSurfaces, and the dev-server chip's labelForPane all call it. - hostPathDisplay gains an includeSearch flag; Wall's duplicate iframeTitle is deleted in favor of hostPathDisplay(url, true). Tests for the new helpers; full suite green (592). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deploying mouseterm with
|
| Latest commit: |
3d0eb63
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://1f1d3cca.mouseterm.pages.dev |
| Branch Preview URL: | https://browser-spike.mouseterm.pages.dev |
dormouse-bot
approved these changes
Jun 17, 2026
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.
Reshapes the
dor agent-browsersurface header to read like a real browser, and adds the one thing only Dormouse can show: which terminal pane in the workspace is serving the localhost URL you're looking at. Builds on the agent-browser surface from #140.What's new
SurfacePaneHeader.tsx) — left→right like Chrome: SYNCED/SCALED chip · back/forward/reload · a quiet inline--keylabel (non-default keys only) · the URL · the dev-server link. Width-responsive; terminals/iframes untouched.<title>→ tooltip). When a dev-server link fronts it, the URL collapses to just the path (the domain is redundant with the chip).open <url>, scheme-normalized —http://for loopback so a barelocalhost:5173doesn't SSL-error); Escape/blur cancels, omnibox-style.<port>to the terminal pane serving it (viagetOpenPorts, its first UI consumer) and surfacepnpm dev :5173; click focuses that terminal. Resolution is strictly off the hot path: debounced + idle-scheduled (never competes with the tab's first screencast frames), scans once then settles, and re-validates only on reload.Notable internals
onFocusPaneaction (visible pane → focus, minimized door → reattach).Storybook
New Components/BrowserChromeHeader playground (every piece driven by controls); fixed a pre-existing
dor/*resolution gap in Storybook's Vite config that broke all Wall-importing stories.DRY / cleanup
A
/simplifypass plus cross-codebase dedup: sharedisEditableTarget(3 drifted copies),deriveSurfaceLabel(thederiveHeader+resolveDisplayPrimarytriple across Baseboard/Wall/dev-server), andhostPathDisplay(url, includeSearch)replacing Wall's duplicateiframeTitle.Spec & tests
docs/specs/dor-agent-browser.mdupdated throughout. Full suite green (592 tests), typecheck clean; verified live indor abagainst a running Storybook. Also carries thedocs: split the iframe surface into its own speccommit the agent-browser spec links to.🤖 Generated with Claude Code