Skip to content

Architecture: Browy DevTools CLI internals

The DevTools CLI is a small, dependency-free plain JavaScript implementation living in extension/panel.{html,js,css}. It mounts inside the DevTools panel registered by extension/devtools.js.

For how to use it, see the DevTools CLI page. This page is for contributors curious about how it’s built.

FileRole
extension/devtools.htmlTiny shell that loads devtools.js
extension/devtools.jsCalls chrome.devtools.panels.create('Browy', icon, 'panel.html')
extension/panel.htmlToolbar + log + autocomplete listbox + textarea
extension/panel.cssStyles modeled on the DevTools Console, light or dark to match your DevTools theme
extension/panel.jsAll behavior: REPL, slash commands, port glue

panel.js keeps a single <div id="log"> of “rows” (user / assistant / tool / info / dim / ok / warn / err / banner). The textarea below is the prompt. On Enter, the panel echoes your input as a row, then:

  1. If the input starts with /, dispatch to the slash-command registry (COMMANDS array near line 250 of panel.js).
  2. In /js mode, evaluate the line in the inspected page with chrome.devtools.inspectedWindow.eval.
  3. Otherwise, send {type: 'chat.send', sessionId, text} over the port to the native host and stream chat.delta chunks into a single growing assistant row. Tool calls show up as cards that fill in when chat.tool_result arrives.

On Esc mid-flight, the panel posts {type: 'chat.cancel', sessionId} to the host and shows a “cancel requested” warning row.

Each command is a {name, help, run} triple:

const COMMANDS = [
{ name: '/help', help: 'Show available commands', run: cmdHelp },
{ name: '/clear', help: 'Clear the scrollback (Ctrl+L)', run: () => clearLog() },
{ name: '/new', help: 'Start a new conversation', run: cmdReset },
{ name: '/reset', help: 'Abandon this session and start fresh', run: cmdReset },
{ name: '/model', help: 'Show current model + pick from list: /model [id]', run: cmdModel },
{ name: '/login', help: 'Sign in to GitHub Copilot', run: cmdLogin },
// 16 more: /sessions, /copy, /version, /theme, /feedback, /url, /title,
// /tabs, /eval, /js, /dom, /snapshot, /export, /cancel, /history, /exit
];

/? → /help and /models → /model are aliases handled at dispatch time. New commands plug in by appending one entry.

The listbox #ac shows matching COMMANDS entries as you type a slash. Arrow keys move the selection, Tab / Enter accepts. Implemented as a prefix match on name.

/model with no argument fetches the model list from the host ({type: 'models.list'} → host calls the Copilot SDK’s listModels()) and renders each as a clickable row. Clicking a row sends {type: 'models.set', id}, the same message /model <id> sends. The toolbar’s #model badge updates on session.ready and models.current.

↑ steps back through past prompts when the cursor is on the first line of the input, and ↓ steps forward when it’s on the last line. Stored in-memory only. The panel page is rebuilt each time DevTools is closed and reopened, so history lasts as long as that DevTools window.

Each DevTools panel inspects a single tab. The panel keeps its sessionId in chrome.storage.local under browy.dt.sessionId.<tabId> and binds the session to that tab with inspectedTabId in session.start. Open DevTools on three tabs → three separate conversations. They share one agent in the host, which runs one turn at a time. Close and reopen DevTools on the same tab and you’re back in the same conversation.

This is intentional: it makes the DevTools CLI a per-page tool, in the same way the inspector is per-page.

We could have rendered the REPL in the side panel UI and called it “DevTools mode”. We didn’t, because:

  • DevTools panels live alongside the inspector, network, and console, giving power users context they want next to the agent.
  • The DevTools panel UI primitives (toolbar buttons, theming, host shortcuts like Ctrl+L to clear) are subtly different from a regular side panel. Keeping them separate avoids if (devtools) forks throughout the side-panel code.
  • It lets the two surfaces evolve independently: the side panel can stay friendly and chat-shaped; the DevTools CLI can grow more power-user features (REPL co-coding, attach to running session) without complicating the side panel.

These items are tracked on the GitHub project board:

  • REPL co-coding: explicit handoff syntax (:edit, :continue) for pair-programming with the agent on a single file.
  • Attach to running session: debug view of an active side-panel agent.