diff --git a/config/tmux.conf b/config/tmux.conf index a21ccf9..a15debc 100644 --- a/config/tmux.conf +++ b/config/tmux.conf @@ -1,57 +1,87 @@ -# Sethian tmux config +# sethmux — Sethian tmux config for AI CLI workflows +# Dvorak-optimized, mobile-friendly, built for long-running AI sessions -# Remap prefix to Ctrl-a (easier on mobile) +# --- Prefix --- unbind C-b set -g prefix C-a bind C-a send-prefix -# Easy tab management -bind -n M-t new-window +# --- Tab/Window management --- +bind -n M-t new-window -c "#{pane_current_path}" bind -n M-w kill-window -bind -n M-1 select-window -t 0 -bind -n M-2 select-window -t 1 -bind -n M-3 select-window -t 2 -bind -n M-4 select-window -t 3 -bind -n M-5 select-window -t 4 +bind -n M-1 select-window -t 1 +bind -n M-2 select-window -t 2 +bind -n M-3 select-window -t 3 +bind -n M-4 select-window -t 4 +bind -n M-5 select-window -t 5 bind -n M-Left previous-window bind -n M-Right next-window +bind c new-window -c "#{pane_current_path}" -# Mouse support (critical for mobile/touch) +# --- Dvorak-friendly splits --- +bind s split-window -v -c "#{pane_current_path}" +bind v split-window -h -c "#{pane_current_path}" + +# --- Pane navigation --- +bind o select-pane -t :.+ +bind z resize-pane -Z + +# --- Mouse --- set -g mouse on -# Scrollback -set -g history-limit 50000 +# --- Scrollback (huge for AI output) --- +set -g history-limit 200000 -# Start numbering at 1 +# --- Copy mode (vi-style) --- +setw -g mode-keys vi +bind -T copy-mode-vi v send -X begin-selection +bind -T copy-mode-vi y send -X copy-selection-and-cancel +bind -T copy-mode-vi MouseDragEnd1Pane send -X copy-selection-and-cancel + +# --- Capture & logging --- +# Ctrl-A S = save entire scrollback to file +bind S capture-pane -pS - \; save-buffer ~/logs/capture-#{session_name}-#{window_index}-#{pane_index}-#(date +%s).txt \; display "Pane captured to ~/logs/" + +# Ctrl-A L = toggle pipe-pane logging +bind L pipe-pane -o "cat >> ~/logs/live-#{session_name}-#{window_index}-#(date +%s).log" \; display "Logging toggled" + +# --- Clipboard --- +set -g set-clipboard on +# Copy on select (mouse) +bind -T copy-mode-vi MouseDragEnd1Pane send -X copy-pipe-and-cancel "cat" + +# --- Numbering --- set -g base-index 1 setw -g pane-base-index 1 - -# Renumber windows on close set -g renumber-windows on -# Status bar - Sethian dark + orange +# --- Adaptive resize --- +setw -g aggressive-resize on +set -g focus-events on + +# --- Status bar: git branch + cwd --- set -g status-style "bg=#1a1a1a,fg=#e0e0e0" set -g status-left "#[bg=#D35400,fg=#0a0a0a,bold] #S #[bg=#1a1a1a] " -set -g status-right "#[fg=#D35400]%H:%M #[fg=#666666]| #[fg=#e0e0e0]%b %d" +set -g status-right "#[fg=#666666]#{pane_current_path} #[fg=#D35400]#{?#{==:#{pane_current_command},bash},#(cd #{pane_current_path} && git branch --show-current 2>/dev/null),} #[fg=#666666]| #[fg=#e0e0e0]%H:%M" +set -g status-right-length 80 set -g status-left-length 20 -set -g status-right-length 30 +set -g status-interval 5 -# Window status +# --- Window status --- setw -g window-status-format " #[fg=#888888]#I:#W " setw -g window-status-current-format "#[bg=#D35400,fg=#0a0a0a,bold] #I:#W " setw -g window-status-separator "" -# Pane borders +# --- Pane borders --- set -g pane-border-style "fg=#333333" set -g pane-active-border-style "fg=#D35400" +set -g pane-border-format " #{pane_current_command} " +set -g pane-border-status off -# Terminal settings +# --- Terminal --- set -g default-terminal "tmux-256color" set -ga terminal-overrides ",xterm-256color:Tc" - -# Dvorak-friendly splits (s=horizontal, v=vertical) -bind s split-window -v -bind v split-window -h - -# Reduce escape delay set -sg escape-time 10 + +# --- Session startup layout --- +# Windows created by sethmux-start.sh: code, git, run, logs diff --git a/sethmux-start.sh b/sethmux-start.sh new file mode 100755 index 0000000..9aeffa2 --- /dev/null +++ b/sethmux-start.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# Start sethmux session with AI-workflow windows +SESSION="sethmux" + +# Kill stale session +tmux kill-session -t "$SESSION" 2>/dev/null +sleep 0.5 + +# Create session with named windows +tmux new-session -d -s "$SESSION" -n "code" -x 120 -y 40 +tmux new-window -t "$SESSION" -n "git" +tmux new-window -t "$SESSION" -n "run" +tmux new-window -t "$SESSION" -n "logs" +tmux select-window -t "$SESSION:1" + +# Ensure logs dir exists +mkdir -p ~/logs diff --git a/static/toolbar.js b/static/toolbar.js index 51c1efb..16ef820 100644 --- a/static/toolbar.js +++ b/static/toolbar.js @@ -5,16 +5,19 @@ var css=document.createElement('style'); css.textContent=` #mb{display:none;position:fixed;bottom:0;left:0;right:0;background:#111; - border-top:2px solid #D35400;padding:5px 4px;gap:4px;justify-content:center; + border-top:2px solid #D35400;padding:4px 3px;gap:3px;justify-content:center; flex-wrap:wrap;z-index:99999} #mb button{background:#222;color:#ccc;border:1px solid #444;border-radius:5px; - padding:10px 12px;font-size:14px;font-family:ui-monospace,monospace; + padding:9px 10px;font-size:13px;font-family:ui-monospace,monospace; cursor:pointer;touch-action:manipulation;-webkit-tap-highlight-color:transparent; - min-width:42px;text-align:center;user-select:none} + min-width:38px;text-align:center;user-select:none} #mb button:active{background:#D35400;color:#0a0a0a;border-color:#D35400} #mb button.hi{border-color:#D35400;color:#D35400} #mb button.on{background:#D35400;color:#0a0a0a;border-color:#D35400} - #mb .sep{width:1px;background:#333;margin:0 2px;align-self:stretch} + #mb button.grn{border-color:#4e9a06;color:#4e9a06} + #mb button.grn.on{background:#4e9a06;color:#0a0a0a} + #mb .sep{width:1px;background:#333;margin:0 1px;align-self:stretch} + #mb .row{display:flex;gap:3px;justify-content:center;width:100%} @media(max-width:900px){#mb{display:flex}} body.selmode .xterm-screen{pointer-events:none!important; user-select:text!important;-webkit-user-select:text!important} @@ -24,6 +27,7 @@ var bar=document.createElement('div'); bar.id='mb'; bar.innerHTML= + '
'+ ''+ ''+ ''+ @@ -36,12 +40,18 @@ ''+ ''+ ''+ - '
'+ + '
'+ + '
'+ ''+ + ''+ + ''+ + ''+ + '
'+ ''+ ''+ ''+ - ''; + ''+ + '
'; document.body.appendChild(bar); function send(k){ @@ -63,18 +73,44 @@ } } + function doPaste(){ + if(!navigator.clipboard||!navigator.clipboard.readText){ + alert('Clipboard access not available (needs HTTPS)'); + return; + } + navigator.clipboard.readText().then(function(text){ + if(text && window.term){ + window.term.input(text); + window.term.focus(); + } + }).catch(function(e){ + alert('Clipboard read failed: '+e.message); + }); + } + + function doSave(){ + // Trigger tmux capture-pane via the keybinding Ctrl-A S + send('\\x01S'); + var btn=document.querySelector('[data-save]'); + btn.classList.add('on'); + btn.textContent='\u2713'; + setTimeout(function(){btn.classList.remove('on');btn.textContent='Save';},1500); + } + bar.addEventListener('click',function(e){ var btn=e.target.closest('button'); if(!btn) return; if(btn.dataset.sel) return toggleSel(); + if(btn.dataset.paste) return doPaste(); + if(btn.dataset.save) return doSave(); if(btn.dataset.k) send(btn.dataset.k); }); - // Shrink terminal for toolbar on mobile + // Shrink terminal for toolbar on mobile (2 rows now) var obs=new MutationObserver(function(){ var el=document.querySelector('.xterm'); if(el && window.innerWidth<=900){ - el.style.height='calc(100vh - 54px)'; + el.style.height='calc(100vh - 88px)'; if(window.term && window.term.fit) window.term.fit(); } }); diff --git a/systemd/sethmux.service b/systemd/sethmux.service index 254bcb4..d97d8d8 100644 --- a/systemd/sethmux.service +++ b/systemd/sethmux.service @@ -7,7 +7,7 @@ Type=simple User=rdp Group=rdp -ExecStartPre=/bin/bash -c "/usr/bin/tmux kill-session -t sethmux 2>/dev/null; sleep 0.5; /usr/bin/tmux new-session -d -s sethmux -x 120 -y 40" +ExecStartPre=/opt/sethmux/sethmux-start.sh ExecStart=/usr/local/bin/ttyd \ --port 7683 \ --interface 0.0.0.0 \