Wrong-path correction: previous DECISIONS.md and handoff said toolbar.js deploys to /opt/sethmux/ 'on this host'. Caddy's 'root * /opt/sethmux' resolves against Caddy's filesystem, which is on the caddy CT (192.168.0.185), not steel141. Deployed copy on steel141 was harmless but unused; the served file came from caddy CT. Symptom: 'mux.sethpc.xyz looks the same' after a successful steel141 'cp'. Resolution: scp static/toolbar.js caddy:/opt/sethmux/. DECISIONS.md now documents the two-host split (Caddy serves static assets from its own disk; ttyd on steel141 serves --index).
3.3 KiB
sethmux — Decision Log
Project-local decisions specific to sethmux. Cross-cutting infra decisions live in ~/bin/DECISIONS.md.
Format: YYYY-MM-DD: <decision> — <why>
2026-04-24
-
Mobile compose bar instead of patching xterm.js IME handling. Added a third toolbar row (toggled by
Typebutton) holding a real<input>withautocorrect=on/enterkeyhint=send. Enter/Send flushes the assembled string to stdin in one shot. Why: xterm.js reads from a hidden textarea via per-keystroke events, but Gboard/iOS autocorrect, swipe, and predictions mutate.valuein bulk viainputType="insertReplacementText"events that xterm.js discards. Bridging that into xterm would mean forking; the compose bar sidesteps it entirely with a one-shot string send. The existingdisableMobileAutocomplete()on.xterm-helper-textareais preserved as belt-and-suspenders for chord/arrow keys typed outside the compose bar. -
Visual system: Google Workspace dark vocabulary, sethmux orange accent. Tokens: bar
#202124, button surface#303134, hairline#3c4043, primary text#e8eaed, accent#D35400(replaces Google blue), Roboto 12/500 + Roboto Mono 12/400 for chord keys. Why: the previous palette (#111/#222/2px orange top border) read as a generic terminal toolbar; the Workspace vocabulary makes the bar feel like a deliberate productivity surface while keeping#D35400as sethmux brand identity. -
Manual deploy is split across TWO hosts. Static assets that Caddy serves directly (
toolbar.js,manifest.json,icon-*.png) live in/opt/sethmux/on the caddy CT (192.168.0.185,ssh caddy). The ttyd index (index.html) and notify-server (notify-server.py) live in/opt/sethmux/on steel141 (192.168.0.141), where the systemd units run. Both hosts happen to use/opt/sethmux/— easy to confuse. Why: Caddy'shandle /toolbar.js { root * /opt/sethmux; file_server }resolves the root against Caddy's own filesystem, not the upstream's. Caddy is on the caddy CT, so that's where the file must live. Catch-allhandle { reverse_proxy 192.168.0.141:7683 }proxies the index page request to ttyd on steel141, which serves--index /opt/sethmux/index.htmlfrom its own disk.Deploy commands:
# Static assets served by Caddy → caddy CT scp static/toolbar.js static/manifest.json static/icon-*.png caddy:/opt/sethmux/ # ttyd index + notify-server → steel141 (this host) sudo cp static/index.html /opt/sethmux/ sudo cp notify-server.py /opt/sethmux/No daemon restart needed for static-asset changes. Restart
sethmux.service(steel141) only when changing ttyd args orindex.html.
Deferred / Rejected
-
Forking xterm.js to handle
inputType: insertReplacementTextevents. Considered as the "real" fix for mobile autocorrect. Rejected because compose-bar approach is smaller, preserves upstream xterm.js, and is more obviously correct (one-shot string send vs. interleaved IME state machine). -
inputmode="none"on the helper textarea ("nuclear option" fromAUTOCOMPLETE_FIX.md). Considered if mobile keyboard autocorrect still corrupts xterm input despite hardening. Rejected for now because it would fully disable the soft keyboard, requiring a separate toggle UX. The compose bar gives users the autocorrect surface they actually want without removing per-keystroke typing.