betterterm 2.0.0 → 2.0.2

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/configs/tmux.conf CHANGED
@@ -51,6 +51,7 @@ bind z resize-pane -Z
51
51
  bind a setw synchronize-panes
52
52
 
53
53
  # Help menu (Cmd+?)
54
+ unbind ?
54
55
  bind ? run-shell "~/.local/bin/help-menu.sh"
55
56
 
56
57
  # Pane swap
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "betterterm",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Terminal IDE setup: Ghostty + tmux + yazi + carbonyl browser",
5
5
  "bin": {
6
6
  "betterterm": "bin/cli.js"
@@ -1,16 +1,28 @@
1
1
  #!/bin/bash
2
- # Start tmux with just a terminal (no file explorer)
2
+ # Start or create a betterterm tmux session
3
3
  export PATH="/opt/homebrew/bin:/usr/local/bin:$HOME/.local/bin:$PATH"
4
4
  TMUX=$(command -v tmux)
5
5
 
6
6
  # Use first argument as starting dir, or current dir, or home
7
7
  DIR="${1:-${PWD:-$HOME}}"
8
8
 
9
- # Kill old session if it exists to get a clean start
10
- $TMUX kill-session -t main 2>/dev/null
9
+ # If already inside tmux, do nothing (let Ghostty handle new window)
10
+ if [ -n "$TMUX_PANE" ]; then
11
+ exit 0
12
+ fi
11
13
 
12
- # Create new session in the target directory (just the shell)
13
- $TMUX new-session -d -s main -c "$DIR"
14
+ # Find an existing unattached session to attach to
15
+ UNATTACHED=$($TMUX list-sessions -F "#{session_name}|#{session_attached}" 2>/dev/null | grep "|0$" | head -1 | cut -d'|' -f1)
14
16
 
15
- # Attach
16
- $TMUX attach-session -t main
17
+ if [ -n "$UNATTACHED" ]; then
18
+ $TMUX attach-session -t "$UNATTACHED"
19
+ else
20
+ # Create a new session with a unique name
21
+ SESSION="main-$(date +%s)"
22
+ # Use "main" for the first session
23
+ if ! $TMUX has-session -t main 2>/dev/null; then
24
+ SESSION="main"
25
+ fi
26
+ $TMUX new-session -d -s "$SESSION" -c "$DIR"
27
+ $TMUX attach-session -t "$SESSION"
28
+ fi
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bash
2
- # Restore a saved session: layout + per-pane directories + agents
2
+ # Restore a saved session: all windows, panes, layouts, directories, agents
3
3
 
4
4
  NAME="$1"
5
5
  if [ -z "$NAME" ]; then
@@ -14,46 +14,68 @@ if [ ! -f "$SESSION_FILE" ]; then
14
14
  exit 1
15
15
  fi
16
16
 
17
- # Read layout
18
- LAYOUT=$(grep "^LAYOUT=" "$SESSION_FILE" | cut -d= -f2-)
17
+ ACTIVE_WIN=$(grep "^ACTIVE_WINDOW=" "$SESSION_FILE" | cut -d= -f2-)
18
+
19
+ # Parse windows and their panes
20
+ CURRENT_WIN=""
21
+ FIRST_WINDOW=1
19
22
 
20
- # Read pane info (index|path|command)
21
- PANE_LINES=()
22
23
  while IFS= read -r line; do
23
- [[ "$line" == LAYOUT=* ]] && continue
24
+ [[ "$line" == ACTIVE_WINDOW=* ]] && continue
24
25
  [[ -z "$line" ]] && continue
25
- PANE_LINES+=("$line")
26
- done < "$SESSION_FILE"
27
26
 
28
- PANE_COUNT=${#PANE_LINES[@]}
29
- [ "$PANE_COUNT" -eq 0 ] && PANE_COUNT=1
27
+ if [[ "$line" == WINDOW=* ]]; then
28
+ DATA="${line#WINDOW=}"
29
+ WIN_IDX=$(echo "$DATA" | cut -d'|' -f1)
30
+ WIN_NAME=$(echo "$DATA" | cut -d'|' -f2)
31
+ WIN_LAYOUT=$(echo "$DATA" | cut -d'|' -f3)
32
+ CURRENT_WIN="$WIN_IDX"
33
+ PANE_NUM=0
30
34
 
31
- # Kill all panes except first, respawn first
32
- tmux kill-pane -a -t "{top-left}" 2>/dev/null
35
+ if [ "$FIRST_WINDOW" -eq 1 ]; then
36
+ # Reuse the existing first window
37
+ tmux kill-pane -a -t "{top-left}" 2>/dev/null
38
+ tmux rename-window "$WIN_NAME"
39
+ FIRST_WINDOW=0
40
+ else
41
+ tmux new-window -n "$WIN_NAME"
42
+ fi
33
43
 
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}"
44
+ elif [[ "$line" == PANE=* ]]; then
45
+ DATA="${line#PANE=}"
46
+ PANE_IDX=$(echo "$DATA" | cut -d'|' -f1)
47
+ PANE_DIR=$(echo "$DATA" | cut -d'|' -f2)
48
+ PANE_CMD=$(echo "$DATA" | cut -d'|' -f3-)
37
49
 
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
50
+ if [ "$PANE_NUM" -eq 0 ]; then
51
+ # First pane in window respawn existing pane
52
+ tmux respawn-pane -k -c "${PANE_DIR:-$HOME}"
53
+ else
54
+ # Additional panes
55
+ tmux split-window -c "${PANE_DIR:-$HOME}"
56
+ fi
57
+ PANE_NUM=$((PANE_NUM + 1))
43
58
 
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))
59
+ # Re-launch agents
60
+ if echo "$PANE_CMD" | grep -qiE "claude|aider|codex"; then
61
+ tmux send-keys "$PANE_CMD" Enter
62
+ fi
63
+ fi
64
+ done < "$SESSION_FILE"
52
65
 
53
- if echo "$CMD" | grep -qiE "$AGENTS_RE"; then
54
- tmux send-keys -t "$PANE_IDX" "$CMD" Enter
66
+ # Apply layouts per window (second pass since all panes need to exist first)
67
+ while IFS= read -r line; do
68
+ if [[ "$line" == WINDOW=* ]]; then
69
+ DATA="${line#WINDOW=}"
70
+ WIN_IDX=$(echo "$DATA" | cut -d'|' -f1)
71
+ WIN_LAYOUT=$(echo "$DATA" | cut -d'|' -f3)
72
+ tmux select-layout -t ":$WIN_IDX" "$WIN_LAYOUT" 2>/dev/null
55
73
  fi
56
- done
74
+ done < "$SESSION_FILE"
57
75
 
76
+ # Switch to the previously active window
77
+ tmux select-window -t ":${ACTIVE_WIN:-1}" 2>/dev/null
58
78
  tmux select-pane -t 1
59
- tmux display-message "Session loaded: $NAME"
79
+
80
+ WIN_COUNT=$(grep -c "^WINDOW=" "$SESSION_FILE")
81
+ tmux display-message "Session loaded: $NAME ($WIN_COUNT tabs)"
@@ -8,7 +8,12 @@ if [ ! -d "$SESSION_DIR" ] || [ -z "$(ls -A "$SESSION_DIR" 2>/dev/null)" ]; then
8
8
  exit 0
9
9
  fi
10
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/,$//')
11
+ # Show available sessions as a tmux menu instead of a prompt
12
+ MENU_ARGS=(-T "#[align=centre,bold] Load Session ")
13
13
 
14
- tmux command-prompt -p "Load session ($SESSIONS):" "run-shell '~/.local/bin/session-load-exec.sh \"%%\"'"
14
+ for f in "$SESSION_DIR"/*.session; do
15
+ NAME=$(basename "$f" .session)
16
+ MENU_ARGS+=("$NAME" "" "run-shell '~/.local/bin/session-load-exec.sh \"$NAME\"'")
17
+ done
18
+
19
+ tmux display-menu -x C -y C "${MENU_ARGS[@]}"
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bash
2
- # Save current tmux layout and pane state to a session file
2
+ # Save current tmux session: all windows, panes, layouts, directories, agents
3
3
 
4
4
  NAME="$1"
5
5
  if [ -z "$NAME" ]; then
@@ -11,19 +11,38 @@ SESSION_DIR="$HOME/.local/share/betterterm/sessions"
11
11
  mkdir -p "$SESSION_DIR"
12
12
 
13
13
  SESSION_FILE="$SESSION_DIR/$NAME.session"
14
+ > "$SESSION_FILE"
14
15
 
15
- # Capture layout string
16
- LAYOUT=$(tmux display-message -p "#{window_layout}")
16
+ # Save active window index
17
+ ACTIVE_WIN=$(tmux display-message -p '#{window_index}')
18
+ echo "ACTIVE_WINDOW=$ACTIVE_WIN" >> "$SESSION_FILE"
17
19
 
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}")
20
+ # Iterate all windows
21
+ tmux list-windows -F "#{window_index}|#{window_name}|#{window_layout}" | while read -r win_line; do
22
+ WIN_IDX=$(echo "$win_line" | cut -d'|' -f1)
23
+ WIN_NAME=$(echo "$win_line" | cut -d'|' -f2)
24
+ WIN_LAYOUT=$(echo "$win_line" | cut -d'|' -f3)
23
25
 
24
- cat > "$SESSION_FILE" <<EOF
25
- LAYOUT=$LAYOUT
26
- $PANES
27
- EOF
26
+ echo "WINDOW=$WIN_IDX|$WIN_NAME|$WIN_LAYOUT" >> "$SESSION_FILE"
28
27
 
29
- tmux display-message "Session saved: $NAME"
28
+ # Save each pane in this window
29
+ tmux list-panes -t ":$WIN_IDX" -F "#{pane_index}|#{pane_current_path}|#{pane_current_command}|#{pane_pid}" | while read -r pane_line; do
30
+ PANE_IDX=$(echo "$pane_line" | cut -d'|' -f1)
31
+ PANE_DIR=$(echo "$pane_line" | cut -d'|' -f2)
32
+ PANE_PID=$(echo "$pane_line" | cut -d'|' -f4)
33
+
34
+ # Check process tree for agents
35
+ AGENT_CMD=""
36
+ if ps -o command= -g "$PANE_PID" 2>/dev/null | grep -qiE "claude|aider|codex"; then
37
+ AGENT_CMD=$(ps -o command= -g "$PANE_PID" 2>/dev/null | grep -iE "claude|aider|codex" | head -1)
38
+ fi
39
+
40
+ if [ -n "$AGENT_CMD" ]; then
41
+ echo "PANE=$PANE_IDX|$PANE_DIR|$AGENT_CMD" >> "$SESSION_FILE"
42
+ else
43
+ echo "PANE=$PANE_IDX|$PANE_DIR|$(echo "$pane_line" | cut -d'|' -f3)" >> "$SESSION_FILE"
44
+ fi
45
+ done
46
+ done
47
+
48
+ tmux display-message "Session saved: $NAME ($(tmux list-windows | wc -l | tr -d ' ') tabs)"