juxtapoandClaude Opus 5 f97ee19f88 cc-sidepanel: bundle JetBrainsMono Nerd Font Mono (0.3.0)
The panel should match kitty's font, but extension pages can't reach system
fonts by name — CSP blocks `local()` — so the TTFs ship in the repo:

  fonts/JBMono-Regular.ttf  2.5MB  weight 400
  fonts/JBMono-Bold.ttf     2.5MB  weight 700

Copied from /usr/share/fonts/TTF/JetBrainsMonoNerdFontMono-{Regular,Bold}.ttf.
Heavy, but it's local-only — the panel never downloads them.

`@font-face` in sidepanel.html, fallback chain kept (ui-monospace, SF Mono,
Menlo, monospace). Line-height 1.4 -> 1.5 for JBMono's taller glyphs.

The Nerd Font variant means nerd-font glyphs leaking out of the pane render
properly instead of as boxes.

No `web_accessible_resources` needed: the side panel is an extension page on the
same chrome-extension:// origin, so bundled files are directly reachable. That
key is only for files injected into web pages.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-13 02:02:46 +08:00

CC Sidepanel

A Brave/Chrome MV3 side-panel extension that puts a live Claude Code seat in your browser sidebar — type in the sidebar, it lands in the real terminal pane. Two-way.

Built by Monica (bridge + extension skeleton), parser and styling pass by Selene, 2026-09-11.

Pieces

  • bridge.py — a localhost HTTP shim on :8988. Browser extensions can't reach a unix socket, so this proxies JSON to injectd.py's socket at /tmp/injectd.sock (ops: seats, screen, inject). CORS is locked to one chrome-extension:// origin — no wildcard.
  • extension/ — MV3 side panel. Polls /screen every 1.5s, parses the raw kitty pane into typed blocks (user / assistant / tool / thinking / live-heartbeat / meta), and sends text back via /inject.

Dependencies / pre-reqs

  • injectd.py is house infrastructure, not part of this repo. The bridge expects the socket /tmp/injectd.sock to already exist (created by injectd, which runs separately and is shared by every seat).
  • The extension ID is deliberately not in the code. bridge.py reads CCSIDEPANEL_EXT_ID from the environment and refuses to start if it's unset (no silent fallback).

Setup

  1. Load the extension unpacked from extension/ at brave://extensions.

  2. Copy its ID from the brave://extensions page.

  3. Create the env file:

    cp cc-sidepanel.env.example /etc/cc-sidepanel.env
    # fill in CCSIDEPANEL_EXT_ID=<your-id>
    
  4. Start/restart the bridge:

    systemctl restart cc-sidepanel-bridge   # unit: /etc/systemd/system/cc-sidepanel-bridge.service
    

    The systemd unit runs as juxtapo and reads config via EnvironmentFile=/etc/cc-sidepanel.env — both files live outside the repo (documented here, not committed).

Gotcha: reloading = new ID

Reloading the extension from a different path gives it a new ID, and the panel gets CORS-blocked with no visible error. If the panel stops working after a reload, copy the new ID, update /etc/cc-sidepanel.env, and restart the unit.

License

House project — MIT.

S
Description
No description provided
Readme
3 MiB
Languages
JavaScript 60.1%
HTML 22.8%
Python 17.1%