anvilsign in

collin/browser-terminal-extension

main / CLAUDE.md

RenderedSource

1# CLAUDE.md
2
3A 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
11See `README.md` for protocol, pairing, TLS, and the systemd socket activation
12story. 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
23until `./build.sh` runs and the sidebar (or the extension) is reloaded. This is
24the 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
29a plain tab for layout work, outside the extension.
30
31`.githooks/post-commit` runs `build.sh` after any commit that touched
32`extension/`, so a committed change is at least *in* `dist/`. Enable it once per
33clone (hooks live outside the repo, so this is what points git at the tracked
34copy):
35
36```sh
37git config core.hooksPath .githooks
38```
39
40It does not reload the sidebar, and it does nothing for an uncommitted edit —
41`./build.sh` by hand is still the loop while you are working.
42
43## Checks
44
45```sh
46npm test # node --test over extension/lib/*.test.js
47npm run check # tsc over both jsconfig projects, noEmit
48cd daemon && cargo test
49```
50
51`npm run check` is type checking only, never a build step. The extension files
52are classic scripts sharing one global scope (`sidebar.js` reaches `Themes`,
53`Sanitize`, `tbPickElement` with no imports), so nothing under `extension/` may
54introduce `import`/`export` syntax. There are two tsconfig projects because
55there are two global scopes: `jsconfig.json` (sidebar document) and
56`jsconfig.sw.json` (service worker), both extending `jsconfig.base.json`.
57
58Daemon tests use `/bin/sh` rather than tmux where they can, and skip themselves
59when tmux is missing; the tmux ones use a private socket so they never touch
60your real sessions.
61
62## Daemon edit loop
63
64If the daemon is installed as a user service (`termbridge install`), a rebuilt
65binary is picked up on the next activation, but only once the running one exits:
66
67```sh
68cd daemon && cargo build --release
69termbridge reload
70```
71
72Re-run `termbridge install` instead when the change affects what the unit
73encodes (port, idle timeout, pinned session, binary path).
74
75## Conventions
76
77- Both manifests (`manifest.chrome.json`, `manifest.firefox.json`) are hand
78 maintained. A permission or file change usually has to land in both.
79- `extension/lib/theme.js` is the single source of truth for both palettes: the
80 `ui` block becomes CSS custom properties, the `xterm` block goes to
81 `term.options.theme`. Do not hardcode colors in `sidebar.css`; use the
82 variables.
83- `sidebar.css` carries long comments explaining *why* a rule exists (the tab
84 silhouette, the separators, the seam the active tab covers). Keep that style
85 when editing it, and read the surrounding comment before changing a value.
86- `extension/vendor/` is vendored xterm.js. Do not edit it.