betterterm 1.0.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -22,6 +22,10 @@ The installer handles everything else (tmux, yazi, carbonyl).
22
22
  - Sets up yazi as a toggleable file explorer with cd-to-terminal sync
23
23
  - Adds an in-terminal browser (carbonyl) toggled via hotkey
24
24
  - Patches your Ghostty config with Cmd-key shortcuts that map to tmux
25
+ - Layout presets (1-4 panes) with auto-launch of Claude Code
26
+ - Agent-aware status bar showing running AI agents per pane
27
+ - Project session save/restore
28
+ - Broadcast mode, pane zoom, and directional pane swapping
25
29
 
26
30
  ## Keybindings
27
31
 
@@ -40,6 +44,21 @@ The installer handles everything else (tmux, yazi, carbonyl).
40
44
  | `Cmd+R` | Reload tmux config |
41
45
  | `Ctrl+B, Tab` | Toggle between panes |
42
46
 
47
+ ### Layout & Agents
48
+
49
+ | Key | Action |
50
+ |-----|--------|
51
+ | `Cmd+1` | Focus mode (1 pane + claude) |
52
+ | `Cmd+2` | Dual mode (2 panes + claude) |
53
+ | `Cmd+3` | Triple mode (3 panes + claude) |
54
+ | `Cmd+4` | Quad mode (4 panes + claude) |
55
+ | `Cmd+Z` | Zoom pane toggle |
56
+ | `Cmd+Shift+B` | Broadcast toggle (type in all panes) |
57
+ | `Cmd+S` | Save session |
58
+ | `Cmd+O` | Load session |
59
+ | `Cmd+Shift+Arrow` | Swap pane position |
60
+ | `Cmd+?` | Help menu (clickable) |
61
+
43
62
  ## Uninstall
44
63
 
45
64
  The installer backs up any existing configs to `*.backup` files. To revert:
@@ -52,7 +71,7 @@ mv ~/.config/yazi/keymap.toml.backup ~/.config/yazi/keymap.toml
52
71
 
53
72
  # Remove betterterm block from Ghostty config (between the marker comments)
54
73
  # Remove scripts
55
- rm ~/.local/bin/betterterm*.sh ~/.local/bin/toggle-*.sh ~/.local/bin/open-browser.sh ~/.local/bin/close-browser.sh ~/.local/bin/browser-nav.sh
74
+ rm ~/.local/bin/betterterm*.sh ~/.local/bin/toggle-*.sh ~/.local/bin/open-browser.sh ~/.local/bin/close-browser.sh ~/.local/bin/browser-nav.sh ~/.local/bin/layout.sh ~/.local/bin/session-*.sh ~/.local/bin/swap-pane.sh
56
75
  ```
57
76
 
58
77
  ## License
package/bin/cli.js CHANGED
@@ -239,4 +239,16 @@ console.log(`
239
239
  Cmd+R Reload tmux config
240
240
  Ctrl+B, Tab Toggle between panes
241
241
  Opt+Enter Send Enter to terminal
242
+
243
+ \x1b[1mLayout & Agents:\x1b[0m
244
+ Cmd+1 Focus mode (1 pane + claude)
245
+ Cmd+2 Dual mode (2 panes + claude)
246
+ Cmd+3 Triple mode (3 panes + claude)
247
+ Cmd+4 Quad mode (4 panes + claude)
248
+ Cmd+Z Zoom pane toggle
249
+ Cmd+Shift+B Broadcast toggle (type in all panes)
250
+ Cmd+S Save session
251
+ Cmd+O Load session
252
+ Cmd+Shift+Arrow Swap pane position
253
+ Cmd+? Help menu (clickable)
242
254
  `);
@@ -21,4 +21,33 @@ keybind = cmd+t=text:\x02c
21
21
  keybind = cmd+]=text:\x02n
22
22
  keybind = cmd+[=text:\x02p
23
23
 
24
+ # Layout presets (unbind Ghostty tab-switching defaults first)
25
+ keybind = cmd+1=unbind
26
+ keybind = cmd+2=unbind
27
+ keybind = cmd+3=unbind
28
+ keybind = cmd+4=unbind
29
+ keybind = cmd+1=text:\x021
30
+ keybind = cmd+2=text:\x022
31
+ keybind = cmd+3=text:\x023
32
+ keybind = cmd+4=text:\x024
33
+
34
+ # Project sessions
35
+ keybind = cmd+s=text:\x02S
36
+ keybind = cmd+o=text:\x02O
37
+
38
+ # Pane zoom toggle
39
+ keybind = cmd+z=text:\x02z
40
+
41
+ # Broadcast toggle (type in all panes)
42
+ keybind = cmd+shift+b=text:\x02a
43
+
44
+ # Help menu
45
+ keybind = cmd+shift+slash=text:\x02?
46
+
47
+ # Pane swap
48
+ keybind = cmd+shift+up=text:\x02K
49
+ keybind = cmd+shift+down=text:\x02J
50
+ keybind = cmd+shift+left=text:\x02H
51
+ keybind = cmd+shift+right=text:\x02L
52
+
24
53
  # --- betterterm end ---
package/configs/tmux.conf CHANGED
@@ -34,6 +34,31 @@ bind -r Right resize-pane -R 5
34
34
  # Reload config with prefix + r
35
35
  bind r source-file ~/.tmux.conf \; display "Config reloaded"
36
36
 
37
+ # Layout presets (auto-launch claude)
38
+ bind 1 run-shell "~/.local/bin/layout.sh 1"
39
+ bind 2 run-shell "~/.local/bin/layout.sh 2"
40
+ bind 3 run-shell "~/.local/bin/layout.sh 3"
41
+ bind 4 run-shell "~/.local/bin/layout.sh 4"
42
+
43
+ # Project sessions
44
+ bind S run-shell "~/.local/bin/session-save.sh"
45
+ bind O run-shell "~/.local/bin/session-load.sh"
46
+
47
+ # Pane zoom (built-in toggle)
48
+ bind z resize-pane -Z
49
+
50
+ # Broadcast toggle (type in all panes simultaneously)
51
+ bind a setw synchronize-panes
52
+
53
+ # Help menu (Cmd+?)
54
+ bind ? run-shell "~/.local/bin/help-menu.sh"
55
+
56
+ # Pane swap
57
+ bind K swap-pane -U
58
+ bind J swap-pane -D
59
+ bind H run-shell "~/.local/bin/swap-pane.sh left"
60
+ bind L run-shell "~/.local/bin/swap-pane.sh right"
61
+
37
62
  # Better split keybindings
38
63
  bind | split-window -h -c "#{pane_current_path}"
39
64
  bind - split-window -v -c "#{pane_current_path}"
@@ -45,17 +70,17 @@ set -g allow-rename off
45
70
  set -g status-position bottom
46
71
  set -g status-style "bg=#1a1a1a,fg=#888888"
47
72
 
48
- # Left: status buttons (visual indicators + hotkey reminders)
49
- set -g status-left-length 50
50
- set -g status-left "#[fg=#888888,bg=#2a2a2a] Files:Cmd+E #[default] #[fg=#888888,bg=#2a2a2a] Browser:Cmd+Y #[default] "
73
+ # Left: agent-aware pane status (or hint bar when single pane)
74
+ set -g status-left-length 80
75
+ set -g status-left "#(~/.local/bin/betterterm-panes.sh)"
51
76
 
52
77
  # Window list
53
78
  setw -g window-status-format "#[fg=#555555]#I:#W"
54
79
  setw -g window-status-current-format "#[fg=#cccccc,bold]#I:#W"
55
80
 
56
- # Right: system stats + time
57
- set -g status-right-length 60
58
- set -g status-right "#[fg=#555555]#(~/.local/bin/betterterm-stats.sh) #[fg=#888888]%H:%M"
81
+ # Right: broadcast indicator + system stats + time
82
+ set -g status-right-length 80
83
+ set -g status-right "#{?synchronize-panes,#[fg=#1a1a1a,bg=#ff5555,bold] BROADCAST #[default] ,}#[fg=#555555]#(~/.local/bin/betterterm-stats.sh) #[fg=#888888]%H:%M"
59
84
  set -g status-interval 5
60
85
 
61
86
  set -g pane-border-style "fg=#333333"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "betterterm",
3
- "version": "1.0.2",
3
+ "version": "2.0.0",
4
4
  "description": "Terminal IDE setup: Ghostty + tmux + yazi + carbonyl browser",
5
5
  "bin": {
6
6
  "betterterm": "bin/cli.js"
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env bash
2
+ # Agent-aware pane status for the tmux status bar
3
+
4
+ PANE_COUNT=$(tmux list-panes -F "#{pane_id}" | wc -l | tr -d ' ')
5
+
6
+ # Single pane: show original hint bar
7
+ if [ "$PANE_COUNT" -le 1 ]; then
8
+ echo "#[fg=#888888,bg=#2a2a2a] Files:Cmd+E #[default] #[fg=#888888,bg=#2a2a2a] Browser:Cmd+Y #[default] "
9
+ exit 0
10
+ fi
11
+
12
+ # Multi-pane: show per-pane agent status
13
+ AGENTS="claude|aider|codex"
14
+ OUTPUT=""
15
+
16
+ while read -r idx cmd; do
17
+ label="$cmd"
18
+
19
+ # Detect known agents
20
+ if echo "$cmd" | grep -qiE "$AGENTS"; then
21
+ label=$(echo "$cmd" | grep -oiE "$AGENTS" | head -1 | tr '[:upper:]' '[:lower:]')
22
+ OUTPUT="${OUTPUT}#[fg=#1a1a1a,bg=#5af78e] ${idx}:${label} #[default] "
23
+ else
24
+ # Check if pane is idle (shell with no foreground process)
25
+ if echo "$cmd" | grep -qE "^(bash|zsh|sh|fish)$"; then
26
+ label="idle"
27
+ fi
28
+ OUTPUT="${OUTPUT}#[fg=#888888,bg=#2a2a2a] ${idx}:${label} #[default] "
29
+ fi
30
+ done < <(tmux list-panes -F "#{pane_index} #{pane_current_command}")
31
+
32
+ echo -n "$OUTPUT"
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env bash
2
+ # Interactive help menu with clickable actions
3
+
4
+ tmux display-menu -T "#[align=centre,bold] betterterm " -x C -y C \
5
+ "" \
6
+ "#[bold,align=centre]── Files & Browser ──" "" "" \
7
+ "#{?#{==:#{pane_current_command},yazi},Close,Open} File Explorer Cmd+E" e "run-shell '~/.local/bin/toggle-yazi.sh'" \
8
+ "Toggle Browser Cmd+Y" b "run-shell '~/.local/bin/toggle-browser.sh'" \
9
+ "Close Browser Cmd+Sh+Y" B "run-shell '~/.local/bin/close-browser.sh'" \
10
+ "Browser URL Bar Cmd+L" l "run-shell '~/.local/bin/browser-nav.sh'" \
11
+ "" \
12
+ "#[bold,align=centre]── Layout Presets ──" "" "" \
13
+ "Focus (1 pane) Cmd+1" 1 "run-shell '~/.local/bin/layout.sh 1'" \
14
+ "Dual (2 panes) Cmd+2" 2 "run-shell '~/.local/bin/layout.sh 2'" \
15
+ "Triple (3 panes) Cmd+3" 3 "run-shell '~/.local/bin/layout.sh 3'" \
16
+ "Quad (4 panes) Cmd+4" 4 "run-shell '~/.local/bin/layout.sh 4'" \
17
+ "" \
18
+ "#[bold,align=centre]── Panes ──" "" "" \
19
+ "Zoom Pane Toggle Cmd+Z" z "resize-pane -Z" \
20
+ "Broadcast Toggle Cmd+Sh+B" a "setw synchronize-panes" \
21
+ "Swap Pane Up Cmd+Sh+Up" K "swap-pane -U" \
22
+ "Swap Pane Down Cmd+Sh+Down" J "swap-pane -D" \
23
+ "Swap Pane Left Cmd+Sh+Left" H "run-shell '~/.local/bin/swap-pane.sh left'" \
24
+ "Swap Pane Right Cmd+Sh+Right" L "run-shell '~/.local/bin/swap-pane.sh right'" \
25
+ "" \
26
+ "#[bold,align=centre]── Windows ──" "" "" \
27
+ "New Window Cmd+T" c "new-window" \
28
+ "Next Window Cmd+]" n "next-window" \
29
+ "Previous Window Cmd+[" p "previous-window" \
30
+ "Split Vertical Cmd+\\" "|" "split-window -h -c '#{pane_current_path}'" \
31
+ "Split Horizontal Cmd+-" - "split-window -v -c '#{pane_current_path}'" \
32
+ "" \
33
+ "#[bold,align=centre]── Sessions ──" "" "" \
34
+ "Save Session Cmd+S" S "run-shell '~/.local/bin/session-save.sh'" \
35
+ "Load Session Cmd+O" O "run-shell '~/.local/bin/session-load.sh'" \
36
+ "" \
37
+ "Reload Config Cmd+R" r "source-file ~/.tmux.conf ; display 'Config reloaded'"
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env bash
2
+ # Layout presets: 1-4 panes with optional auto-launch of claude
3
+
4
+ COUNT="${1:-1}"
5
+
6
+ # Capture current working directory before killing panes
7
+ PWD=$(tmux display-message -p '#{pane_current_path}')
8
+
9
+ # Kill all panes except pane 1, then reset it
10
+ tmux kill-pane -a -t "{top-left}" 2>/dev/null
11
+ tmux respawn-pane -k -c "$PWD" -t "{top-left}"
12
+
13
+ # Detect if claude is available
14
+ HAS_CLAUDE=0
15
+ if command -v claude >/dev/null 2>&1; then
16
+ HAS_CLAUDE=1
17
+ fi
18
+
19
+ launch_claude() {
20
+ local pane="$1"
21
+ if [ "$HAS_CLAUDE" -eq 1 ]; then
22
+ tmux send-keys -t "$pane" "claude --dangerously-skip-permissions" Enter
23
+ fi
24
+ }
25
+
26
+ case "$COUNT" in
27
+ 1)
28
+ # Focus mode: single pane
29
+ launch_claude 1
30
+ ;;
31
+ 2)
32
+ # Dual mode: side-by-side
33
+ tmux split-window -h -c "$PWD"
34
+ tmux select-pane -t 1
35
+ launch_claude 1
36
+ launch_claude 2
37
+ ;;
38
+ 3)
39
+ # Triple: big left + 2 stacked right
40
+ tmux split-window -h -p 40 -c "$PWD"
41
+ tmux split-window -v -c "$PWD"
42
+ tmux select-pane -t 1
43
+ launch_claude 1
44
+ launch_claude 2
45
+ launch_claude 3
46
+ ;;
47
+ 4)
48
+ # Quad grid
49
+ tmux split-window -h -c "$PWD"
50
+ tmux split-window -v -c "$PWD"
51
+ tmux select-pane -t 1
52
+ tmux split-window -v -c "$PWD"
53
+ tmux select-pane -t 1
54
+ launch_claude 1
55
+ launch_claude 2
56
+ launch_claude 3
57
+ launch_claude 4
58
+ ;;
59
+ *)
60
+ tmux display-message "Usage: layout.sh [1-4]"
61
+ ;;
62
+ esac
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env bash
2
+ # Restore a saved session: layout + per-pane directories + agents
3
+
4
+ NAME="$1"
5
+ if [ -z "$NAME" ]; then
6
+ tmux display-message "Session name required"
7
+ exit 1
8
+ fi
9
+
10
+ SESSION_FILE="$HOME/.local/share/betterterm/sessions/$NAME.session"
11
+
12
+ if [ ! -f "$SESSION_FILE" ]; then
13
+ tmux display-message "Session not found: $NAME"
14
+ exit 1
15
+ fi
16
+
17
+ # Read layout
18
+ LAYOUT=$(grep "^LAYOUT=" "$SESSION_FILE" | cut -d= -f2-)
19
+
20
+ # Read pane info (index|path|command)
21
+ PANE_LINES=()
22
+ while IFS= read -r line; do
23
+ [[ "$line" == LAYOUT=* ]] && continue
24
+ [[ -z "$line" ]] && continue
25
+ PANE_LINES+=("$line")
26
+ done < "$SESSION_FILE"
27
+
28
+ PANE_COUNT=${#PANE_LINES[@]}
29
+ [ "$PANE_COUNT" -eq 0 ] && PANE_COUNT=1
30
+
31
+ # Kill all panes except first, respawn first
32
+ tmux kill-pane -a -t "{top-left}" 2>/dev/null
33
+
34
+ # Get first pane's directory
35
+ FIRST_DIR=$(echo "${PANE_LINES[0]}" | cut -d'|' -f2)
36
+ tmux respawn-pane -k -c "${FIRST_DIR:-$HOME}"
37
+
38
+ # Create remaining panes
39
+ for ((i = 1; i < PANE_COUNT; i++)); do
40
+ DIR=$(echo "${PANE_LINES[$i]}" | cut -d'|' -f2)
41
+ tmux split-window -c "${DIR:-$HOME}"
42
+ done
43
+
44
+ # Apply saved layout
45
+ tmux select-layout "$LAYOUT" 2>/dev/null
46
+
47
+ # Re-launch known agents in each pane
48
+ AGENTS_RE="^(claude|aider|codex)$"
49
+ for ((i = 0; i < PANE_COUNT; i++)); do
50
+ CMD=$(echo "${PANE_LINES[$i]}" | cut -d'|' -f3)
51
+ PANE_IDX=$((i + 1))
52
+
53
+ if echo "$CMD" | grep -qiE "$AGENTS_RE"; then
54
+ tmux send-keys -t "$PANE_IDX" "$CMD" Enter
55
+ fi
56
+ done
57
+
58
+ tmux select-pane -t 1
59
+ tmux display-message "Session loaded: $NAME"
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env bash
2
+ # Prompt user to pick a saved session, then restore it
3
+
4
+ SESSION_DIR="$HOME/.local/share/betterterm/sessions"
5
+
6
+ if [ ! -d "$SESSION_DIR" ] || [ -z "$(ls -A "$SESSION_DIR" 2>/dev/null)" ]; then
7
+ tmux display-message "No saved sessions found"
8
+ exit 0
9
+ fi
10
+
11
+ # List available sessions (strip .session extension)
12
+ SESSIONS=$(ls "$SESSION_DIR"/*.session 2>/dev/null | xargs -I{} basename {} .session | tr '\n' ',' | sed 's/,$//')
13
+
14
+ tmux command-prompt -p "Load session ($SESSIONS):" "run-shell '~/.local/bin/session-load-exec.sh \"%%\"'"
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env bash
2
+ # Save current tmux layout and pane state to a session file
3
+
4
+ NAME="$1"
5
+ if [ -z "$NAME" ]; then
6
+ tmux display-message "Session name required"
7
+ exit 1
8
+ fi
9
+
10
+ SESSION_DIR="$HOME/.local/share/betterterm/sessions"
11
+ mkdir -p "$SESSION_DIR"
12
+
13
+ SESSION_FILE="$SESSION_DIR/$NAME.session"
14
+
15
+ # Capture layout string
16
+ LAYOUT=$(tmux display-message -p "#{window_layout}")
17
+
18
+ # Capture per-pane info: index, working directory, current command
19
+ PANES=""
20
+ while IFS= read -r line; do
21
+ PANES="${PANES}${line}\n"
22
+ done < <(tmux list-panes -F "#{pane_index}|#{pane_current_path}|#{pane_current_command}")
23
+
24
+ cat > "$SESSION_FILE" <<EOF
25
+ LAYOUT=$LAYOUT
26
+ $PANES
27
+ EOF
28
+
29
+ tmux display-message "Session saved: $NAME"
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+ # Prompt user for session name, then run the actual save
3
+ tmux command-prompt -p "Save session as:" "run-shell '~/.local/bin/session-save-exec.sh \"%%\"'"
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env bash
2
+ # Swap pane in the given direction (left or right)
3
+
4
+ DIRECTION="${1:-left}"
5
+
6
+ case "$DIRECTION" in
7
+ left)
8
+ TARGET=$(tmux display-message -p -t "{left-of}" "#{pane_id}" 2>/dev/null)
9
+ ;;
10
+ right)
11
+ TARGET=$(tmux display-message -p -t "{right-of}" "#{pane_id}" 2>/dev/null)
12
+ ;;
13
+ *)
14
+ tmux display-message "Usage: swap-pane.sh [left|right]"
15
+ exit 1
16
+ ;;
17
+ esac
18
+
19
+ if [ -n "$TARGET" ]; then
20
+ tmux swap-pane -t "$TARGET"
21
+ else
22
+ tmux display-message "No pane ${DIRECTION}"
23
+ fi
@@ -1,13 +1,19 @@
1
1
  #!/bin/bash
2
- # Toggle yazi file explorer pane in tmux
2
+ # Toggle yazi file explorer as a left-side pane without disrupting layout
3
3
  export PATH="/opt/homebrew/bin:/usr/local/bin:$HOME/.local/bin:$PATH"
4
4
  T=$(command -v tmux)
5
- pane_count=$($T display-message -p '#{window_panes}')
6
- if [ "$pane_count" -gt 1 ]; then
7
- $T kill-pane -t {right}
5
+ DIR=$($T display-message -p '#{pane_current_path}')
6
+
7
+ # Check if yazi is already running in any pane
8
+ YAZI_PANE=$($T list-panes -F "#{pane_id} #{pane_current_command}" | grep -i yazi | head -1 | awk '{print $1}')
9
+
10
+ if [ -n "$YAZI_PANE" ]; then
11
+ # Yazi is open — kill just that pane
12
+ $T kill-pane -t "$YAZI_PANE"
8
13
  else
9
- DIR=$($T display-message -p '#{pane_current_path}')
10
- $T split-window -h -l 30% -c "$DIR" "env TERM=xterm-256color $(command -v yazi) $DIR"
11
- $T select-pane -t 0
14
+ # Open yazi as a left-side pane (25% width), keep focus on original pane
15
+ CURRENT=$($T display-message -p '#{pane_id}')
16
+ $T split-window -hf -l 25% -c "$DIR" "env TERM=xterm-256color $(command -v yazi) $DIR"
17
+ $T select-pane -t "$CURRENT"
12
18
  fi
13
19
  exit 0