collin/browser-terminal-extension
ea0845f8f1bbbfee8d4d3888ce10ee78e7fbe73b / CLAUDE.md
RenderedSource
| 1 | # CLAUDE.md |
| 2 | |
| 3 | A tmux sidebar for Chrome and Firefox. Two halves that ship separately: |
| 4 | |
| 5 | - `extension/` is the browser extension (named **terminal**). Plain files, no |
| 6 | bundler: the browser loads the `.js`/`.css`/`.html` on disk as they are. |
| 7 | - `daemon/` is `termbridge`, a Rust CLI that serves a WebSocket on |
| 8 | `127.0.0.1:7681`, spawns a pty, and runs tmux inside it. tmux, not the daemon, |
| 9 | is the persistence layer. |
| 10 | |
| 11 | See `README.md` for protocol, pairing, TLS, and the systemd socket activation |
| 12 | story. This file is the build and edit loop. |
| 13 | |
| 14 | ## Build |
| 15 | |
| 16 | ```sh |
| 17 | ./build.sh # extension -> dist/chrome and dist/firefox |
| 18 | ./run.sh # daemon: cargo build --release, then `termbridge serve` |
| 19 | ``` |
| 20 | |
| 21 | **`build.sh` copies files into `dist/`.** The browser loads `dist/chrome` (or |
| 22 | `dist/firefox`), never `extension/`. So an edit under `extension/` has no effect |
| 23 | until `./build.sh` runs and the sidebar (or the extension) is reloaded. This is |
| 24 | the most common reason a change "didn't work". |
| 25 | |
| 26 | `build.sh` copies an explicit list of files. A new file under `extension/` or |
| 27 | `extension/lib/` will not reach `dist/` until it is added to that list. |
| 28 | `extension/mock.html` is deliberately excluded: it renders the sidebar header in |
| 29 | a plain tab for layout work, outside the extension. |
| 30 | |
| 31 | ## Checks |
| 32 | |
| 33 | ```sh |
| 34 | npm test # node --test over extension/lib/*.test.js |
| 35 | npm run check # tsc over both jsconfig projects, noEmit |
| 36 | cd daemon && cargo test |
| 37 | ``` |
| 38 | |
| 39 | `npm run check` is type checking only, never a build step. The extension files |
| 40 | are classic scripts sharing one global scope (`sidebar.js` reaches `Themes`, |
| 41 | `Sanitize`, `tbPickElement` with no imports), so nothing under `extension/` may |
| 42 | introduce `import`/`export` syntax. There are two tsconfig projects because |
| 43 | there are two global scopes: `jsconfig.json` (sidebar document) and |
| 44 | `jsconfig.sw.json` (service worker), both extending `jsconfig.base.json`. |
| 45 | |
| 46 | Daemon tests use `/bin/sh` rather than tmux where they can, and skip themselves |
| 47 | when tmux is missing; the tmux ones use a private socket so they never touch |
| 48 | your real sessions. |
| 49 | |
| 50 | ## Daemon edit loop |
| 51 | |
| 52 | If the daemon is installed as a user service (`termbridge install`), a rebuilt |
| 53 | binary is picked up on the next activation, but only once the running one exits: |
| 54 | |
| 55 | ```sh |
| 56 | cd daemon && cargo build --release |
| 57 | termbridge reload |
| 58 | ``` |
| 59 | |
| 60 | Re-run `termbridge install` instead when the change affects what the unit |
| 61 | encodes (port, idle timeout, pinned session, binary path). |
| 62 | |
| 63 | ## Conventions |
| 64 | |
| 65 | - Both manifests (`manifest.chrome.json`, `manifest.firefox.json`) are hand |
| 66 | maintained. A permission or file change usually has to land in both. |
| 67 | - `extension/lib/theme.js` is the single source of truth for both palettes: the |
| 68 | `ui` block becomes CSS custom properties, the `xterm` block goes to |
| 69 | `term.options.theme`. Do not hardcode colors in `sidebar.css`; use the |
| 70 | variables. |
| 71 | - `sidebar.css` carries long comments explaining *why* a rule exists (the tab |
| 72 | silhouette, the separators, the seam the active tab covers). Keep that style |
| 73 | when editing it, and read the surrounding comment before changing a value. |
| 74 | - `extension/vendor/` is vendored xterm.js. Do not edit it. |