@jx0/jmux 0.2.0 → 0.3.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 +20 -12
- package/config/core.conf +17 -0
- package/config/defaults.conf +106 -0
- package/config/tmux.conf +18 -113
- package/package.json +1 -1
- package/src/main.ts +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ You lose context constantly. You forget what's running where. You can't see at a
|
|
|
14
14
|
|
|
15
15
|
## The Solution
|
|
16
16
|
|
|
17
|
-
jmux wraps tmux with a persistent sidebar that shows all your sessions, all the time. It
|
|
17
|
+
jmux wraps tmux with a persistent sidebar that shows all your sessions, all the time. It works with your existing `~/.tmux.conf` — your plugins, your colors, your keybindings — and layers a sidebar on top.
|
|
18
18
|
|
|
19
19
|
**What you get:**
|
|
20
20
|
- Every session visible at all times with git branch and window count
|
|
@@ -23,7 +23,7 @@ jmux wraps tmux with a persistent sidebar that shows all your sessions, all the
|
|
|
23
23
|
- Activity indicators (green dot) and attention flags (orange `!`) for agentic workflows
|
|
24
24
|
- Mouse click to switch sessions
|
|
25
25
|
- New session modal with fuzzy directory picker
|
|
26
|
-
-
|
|
26
|
+
- Bring your own `~/.tmux.conf` — your plugins and keybindings just work
|
|
27
27
|
|
|
28
28
|

|
|
29
29
|
|
|
@@ -31,7 +31,7 @@ jmux wraps tmux with a persistent sidebar that shows all your sessions, all the
|
|
|
31
31
|
|
|
32
32
|
jmux owns the terminal. It spawns tmux in a PTY, feeds the output through a headless terminal emulator ([xterm.js](https://xtermjs.org/)), and composites a 24-column sidebar alongside the tmux rendering. A separate tmux control mode connection provides real-time session metadata via push notifications.
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
jmux sources your `~/.tmux.conf` first, then layers its own defaults and the few settings the sidebar requires. Your existing setup carries over — jmux just adds the sidebar.
|
|
35
35
|
|
|
36
36
|
```
|
|
37
37
|
┌─ jmux sidebar ──┬─ your normal tmux ──────────────────────┐
|
|
@@ -144,7 +144,7 @@ The session is created in the selected directory and the sidebar updates immedia
|
|
|
144
144
|
|-----|--------|
|
|
145
145
|
| `Ctrl-a \|` | Split horizontal |
|
|
146
146
|
| `Ctrl-a -` | Split vertical |
|
|
147
|
-
| `Shift-arrows` | Navigate panes
|
|
147
|
+
| `Shift-arrows` | Navigate panes |
|
|
148
148
|
| `Ctrl-a arrows` | Resize panes |
|
|
149
149
|
| `Ctrl-a P` | Toggle pane border titles |
|
|
150
150
|
|
|
@@ -185,17 +185,25 @@ jmux shows an orange `!` indicator. When you switch to that session, the flag cl
|
|
|
185
185
|
4. Work in one session while others run in the background
|
|
186
186
|
5. Orange `!` flags appear when Claude finishes — switch instantly with `Ctrl-Shift-Down`
|
|
187
187
|
|
|
188
|
-
##
|
|
188
|
+
## Configuration
|
|
189
189
|
|
|
190
|
-
jmux
|
|
190
|
+
jmux loads config in three layers:
|
|
191
191
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
192
|
+
```
|
|
193
|
+
config/defaults.conf ← jmux defaults (baseline)
|
|
194
|
+
~/.tmux.conf ← your config (overrides defaults)
|
|
195
|
+
config/core.conf ← jmux requirements (always wins)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
jmux defaults are applied first as a baseline. Your `~/.tmux.conf` is sourced next — anything you set overrides the defaults. Finally, the core settings the sidebar depends on are applied last and cannot be overridden.
|
|
199
|
+
|
|
200
|
+
**Core settings** (cannot be overridden):
|
|
201
|
+
- `detach-on-destroy off` — switch to next session on kill, don't exit jmux
|
|
202
|
+
- `mouse on` — required for sidebar clicks
|
|
203
|
+
- `prefix + n` — new session modal
|
|
204
|
+
- Empty `status-left` — session info is in the sidebar
|
|
197
205
|
|
|
198
|
-
|
|
206
|
+
Everything else is yours to customize. See [docs/configuration.md](docs/configuration.md) for details.
|
|
199
207
|
|
|
200
208
|
## Architecture
|
|
201
209
|
|
package/config/core.conf
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# jmux core — required settings that jmux depends on.
|
|
2
|
+
# These are sourced LAST and override any user config.
|
|
3
|
+
# Do not edit unless you know what you're doing.
|
|
4
|
+
|
|
5
|
+
# Session lifecycle — jmux expects to switch sessions, not detach
|
|
6
|
+
set -g detach-on-destroy off
|
|
7
|
+
|
|
8
|
+
# Mouse — required for sidebar click handling
|
|
9
|
+
set -g mouse on
|
|
10
|
+
|
|
11
|
+
# New session modal — bound to prefix+n
|
|
12
|
+
unbind n
|
|
13
|
+
bind-key n display-popup -E -w 60% -h 70% -b heavy -S 'fg=#4f565d' "$JMUX_DIR/config/new-session.sh"
|
|
14
|
+
|
|
15
|
+
# Status bar — session info is in the sidebar, keep status bar for windows only
|
|
16
|
+
set -g status-left ""
|
|
17
|
+
set -g status-left-length 0
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# jmux default configuration
|
|
2
|
+
# Opinionated defaults — override anything here via ~/.tmux.conf
|
|
3
|
+
|
|
4
|
+
# --- Prefix ---
|
|
5
|
+
set -g prefix C-a
|
|
6
|
+
unbind C-b
|
|
7
|
+
bind-key C-a send-prefix
|
|
8
|
+
|
|
9
|
+
unbind p # free up for future use
|
|
10
|
+
|
|
11
|
+
# --- Windows ---
|
|
12
|
+
set -g base-index 1
|
|
13
|
+
set -g pane-base-index 1
|
|
14
|
+
set -g renumber-windows on
|
|
15
|
+
set -g automatic-rename on
|
|
16
|
+
set -g automatic-rename-format "#{pane_current_command}"
|
|
17
|
+
bind c new-window -c ~
|
|
18
|
+
bind -n C-Right next-window
|
|
19
|
+
bind -n C-Left previous-window
|
|
20
|
+
|
|
21
|
+
# Reorder windows with Ctrl-Shift-Left/Right
|
|
22
|
+
bind-key -n C-S-Left run-shell 'W=#{window_index}; T=$((W-1)); [ $T -ge 1 ] && tmux swap-window -s ":$W" -t ":$T" && tmux select-window -t ":$T"'
|
|
23
|
+
bind-key -n C-S-Right run-shell 'W=#{window_index}; T=$((W+1)); MAX=$(tmux list-windows | wc -l | tr -d " "); [ $T -le $MAX ] && tmux swap-window -s ":$W" -t ":$T" && tmux select-window -t ":$T"'
|
|
24
|
+
|
|
25
|
+
# --- Panes ---
|
|
26
|
+
bind | split-window -h -c "#{pane_current_path}"
|
|
27
|
+
bind - split-window -v -c "#{pane_current_path}"
|
|
28
|
+
unbind '"'
|
|
29
|
+
unbind %
|
|
30
|
+
bind -r Left resize-pane -L 5
|
|
31
|
+
bind -r Down resize-pane -D 5
|
|
32
|
+
bind -r Up resize-pane -U 5
|
|
33
|
+
bind -r Right resize-pane -R 5
|
|
34
|
+
|
|
35
|
+
# Smart-splits.nvim integration
|
|
36
|
+
is_vim="ps -o state= -o comm= -t '#{pane_tty}' | grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|l?n?vim?x?|fzf)(diff)?$'"
|
|
37
|
+
bind -n S-Left if-shell "$is_vim" "send-keys S-Left" "select-pane -L"
|
|
38
|
+
bind -n S-Right if-shell "$is_vim" "send-keys S-Right" "select-pane -R"
|
|
39
|
+
bind -n S-Up if-shell "$is_vim" "send-keys S-Up" "select-pane -U"
|
|
40
|
+
bind -n S-Down if-shell "$is_vim" "send-keys S-Down" "select-pane -D"
|
|
41
|
+
|
|
42
|
+
# --- Pane borders ---
|
|
43
|
+
set -g pane-border-lines heavy
|
|
44
|
+
set -g pane-border-status off
|
|
45
|
+
set -g pane-border-style 'fg=#3a4450'
|
|
46
|
+
set -g pane-active-border-style 'fg=#4f565d'
|
|
47
|
+
set -g pane-border-format "#{?pane_active, #[fg=#9fe8c3 bold]#{pane_title} #[fg=#b5bcc9 nobold]#{b:pane_current_path} #[fg=#4f565d]| #{pane_current_command} , #[fg=#4f565d]#{pane_title} #[fg=#3a4450]#{b:pane_current_path} | #{pane_current_command} }"
|
|
48
|
+
|
|
49
|
+
# Auto-show pane borders only when window has multiple panes
|
|
50
|
+
set-hook -g window-layout-changed 'if -F "#{==:#{window_panes},1}" "set -w pane-border-status off" "set -w pane-border-status top"'
|
|
51
|
+
set-hook -g after-select-window 'if -F "#{==:#{window_panes},1}" "set -w pane-border-status off" "set -w pane-border-status top"'
|
|
52
|
+
bind-key P set -w pane-border-status
|
|
53
|
+
|
|
54
|
+
# --- Window styles ---
|
|
55
|
+
set -g window-style 'fg=#6b7280'
|
|
56
|
+
set -g window-active-style 'fg=#b5bcc9'
|
|
57
|
+
|
|
58
|
+
# --- Utilities ---
|
|
59
|
+
bind k send-keys -R \; clear-history \; display-message "Pane cleared"
|
|
60
|
+
bind y run-shell "tmux capture-pane -pS - -E - | grep . | pbcopy" \; display-message "Copied pane to clipboard"
|
|
61
|
+
|
|
62
|
+
# Window switcher popup (C-a j) — jmux overrides this for sidebar mode,
|
|
63
|
+
# but it's still available if sidebar mode changes
|
|
64
|
+
bind-key j display-popup -E -x 0 -y 0 -w 30% -h 100% -b heavy -S 'fg=#4f565d' \
|
|
65
|
+
"tmux list-windows -F '#I: #W#{?window_active, *, }' | \
|
|
66
|
+
fzf --reverse --no-info --prompt=' Window> ' --pointer='▸' \
|
|
67
|
+
--color='bg:#0c1117,fg:#6b7280,hl:#fbd4b8,fg+:#b5bcc9,hl+:#fbd4b8,pointer:#9fe8c3,prompt:#9fe8c3' | \
|
|
68
|
+
cut -d: -f1 | \
|
|
69
|
+
xargs -I{} tmux select-window -t :{}"
|
|
70
|
+
|
|
71
|
+
# --- Terminal ---
|
|
72
|
+
set -g default-terminal "tmux-256color"
|
|
73
|
+
set -g set-clipboard on
|
|
74
|
+
set -g focus-events on
|
|
75
|
+
set -g mouse on
|
|
76
|
+
set -gq status-utf8 on
|
|
77
|
+
set-window-option -gq utf8 on
|
|
78
|
+
set-option -ga terminal-overrides ",xterm-256color:Tc"
|
|
79
|
+
set-option -ga terminal-overrides ',*:Smulx=\E[4::%p1%dm'
|
|
80
|
+
set-option -ga terminal-overrides ',*:Setulc=\E[58::2::%p1%{65536}%/%d::%p1%{256}%/%{255}%&%d::%p1%{255}%&%d%;m'
|
|
81
|
+
|
|
82
|
+
# --- Bell / Activity ---
|
|
83
|
+
set-window-option -g visual-bell off
|
|
84
|
+
set-window-option -g bell-action other
|
|
85
|
+
set-window-option -g monitor-activity off
|
|
86
|
+
set-window-option -g visual-activity off
|
|
87
|
+
set-hook -g pane-focus-in 'setw monitor-bell off; setw monitor-bell on'
|
|
88
|
+
unbind -T root DoubleClick1Pane
|
|
89
|
+
unbind -T root TripleClick1Pane
|
|
90
|
+
|
|
91
|
+
# --- Status bar ---
|
|
92
|
+
# Minimal — session indicator handled by jmux sidebar, no system metrics
|
|
93
|
+
set -g status-position bottom
|
|
94
|
+
set -g status-interval 1
|
|
95
|
+
set -g status-justify left
|
|
96
|
+
set -g status-bg "#181f26"
|
|
97
|
+
set -g status-left ""
|
|
98
|
+
set -g status-right ""
|
|
99
|
+
set -g status-left-length 0
|
|
100
|
+
set -g status-right-length 0
|
|
101
|
+
|
|
102
|
+
# Window tabs
|
|
103
|
+
setw -g window-status-current-format "#[bg=#181f26 fg=#fbd4b8]◢#[bg=#fbd4b8 fg=#131a21] #W #{?window_zoomed_flag, ,}#[bg=#181f26 fg=#fbd4b8]◣"
|
|
104
|
+
setw -g window-status-format "#{?window_bell_flag,#[bg=#181f26 fg=#ced4df] #W #{?window_zoomed_flag, ,},#[bg=#181f26 fg=#4f565d] #W #{?window_zoomed_flag, ,}}"
|
|
105
|
+
set -g window-status-bell-style 'fg=#ced4df,bg=#0c1117'
|
|
106
|
+
set -g window-status-activity-style 'fg=#b5bcc9,bg=#4e555c,bold'
|
package/config/tmux.conf
CHANGED
|
@@ -1,113 +1,18 @@
|
|
|
1
|
-
# jmux tmux configuration
|
|
2
|
-
#
|
|
3
|
-
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
#
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
bind c new-window -c ~
|
|
20
|
-
bind -n C-Right next-window
|
|
21
|
-
bind -n C-Left previous-window
|
|
22
|
-
|
|
23
|
-
# Reorder windows with Ctrl-Shift-Left/Right
|
|
24
|
-
bind-key -n C-S-Left run-shell 'W=#{window_index}; T=$((W-1)); [ $T -ge 1 ] && tmux swap-window -s ":$W" -t ":$T" && tmux select-window -t ":$T"'
|
|
25
|
-
bind-key -n C-S-Right run-shell 'W=#{window_index}; T=$((W+1)); MAX=$(tmux list-windows | wc -l | tr -d " "); [ $T -le $MAX ] && tmux swap-window -s ":$W" -t ":$T" && tmux select-window -t ":$T"'
|
|
26
|
-
|
|
27
|
-
# --- Panes ---
|
|
28
|
-
bind | split-window -h -c "#{pane_current_path}"
|
|
29
|
-
bind - split-window -v -c "#{pane_current_path}"
|
|
30
|
-
unbind '"'
|
|
31
|
-
unbind %
|
|
32
|
-
bind -r Left resize-pane -L 5
|
|
33
|
-
bind -r Down resize-pane -D 5
|
|
34
|
-
bind -r Up resize-pane -U 5
|
|
35
|
-
bind -r Right resize-pane -R 5
|
|
36
|
-
|
|
37
|
-
# Smart-splits.nvim integration
|
|
38
|
-
is_vim="ps -o state= -o comm= -t '#{pane_tty}' | grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|l?n?vim?x?|fzf)(diff)?$'"
|
|
39
|
-
bind -n S-Left if-shell "$is_vim" "send-keys S-Left" "select-pane -L"
|
|
40
|
-
bind -n S-Right if-shell "$is_vim" "send-keys S-Right" "select-pane -R"
|
|
41
|
-
bind -n S-Up if-shell "$is_vim" "send-keys S-Up" "select-pane -U"
|
|
42
|
-
bind -n S-Down if-shell "$is_vim" "send-keys S-Down" "select-pane -D"
|
|
43
|
-
|
|
44
|
-
# --- Pane borders ---
|
|
45
|
-
set -g pane-border-lines heavy
|
|
46
|
-
set -g pane-border-status off
|
|
47
|
-
set -g pane-border-style 'fg=#3a4450'
|
|
48
|
-
set -g pane-active-border-style 'fg=#4f565d'
|
|
49
|
-
set -g pane-border-format "#{?pane_active, #[fg=#9fe8c3 bold]#{pane_title} #[fg=#b5bcc9 nobold]#{b:pane_current_path} #[fg=#4f565d]| #{pane_current_command} , #[fg=#4f565d]#{pane_title} #[fg=#3a4450]#{b:pane_current_path} | #{pane_current_command} }"
|
|
50
|
-
|
|
51
|
-
# Auto-show pane borders only when window has multiple panes
|
|
52
|
-
set-hook -g window-layout-changed 'if -F "#{==:#{window_panes},1}" "set -w pane-border-status off" "set -w pane-border-status top"'
|
|
53
|
-
set-hook -g after-select-window 'if -F "#{==:#{window_panes},1}" "set -w pane-border-status off" "set -w pane-border-status top"'
|
|
54
|
-
bind-key P set -w pane-border-status
|
|
55
|
-
|
|
56
|
-
# --- Window styles ---
|
|
57
|
-
set -g window-style 'fg=#6b7280'
|
|
58
|
-
set -g window-active-style 'fg=#b5bcc9'
|
|
59
|
-
|
|
60
|
-
# --- Utilities ---
|
|
61
|
-
bind k send-keys -R \; clear-history \; display-message "Pane cleared"
|
|
62
|
-
bind y run-shell "tmux capture-pane -pS - -E - | grep . | pbcopy" \; display-message "Copied pane to clipboard"
|
|
63
|
-
|
|
64
|
-
# Window switcher popup (C-a j) — jmux overrides this for sidebar mode,
|
|
65
|
-
# but it's still available if sidebar mode changes
|
|
66
|
-
bind-key j display-popup -E -x 0 -y 0 -w 30% -h 100% -b heavy -S 'fg=#4f565d' \
|
|
67
|
-
"tmux list-windows -F '#I: #W#{?window_active, *, }' | \
|
|
68
|
-
fzf --reverse --no-info --prompt=' Window> ' --pointer='▸' \
|
|
69
|
-
--color='bg:#0c1117,fg:#6b7280,hl:#fbd4b8,fg+:#b5bcc9,hl+:#fbd4b8,pointer:#9fe8c3,prompt:#9fe8c3' | \
|
|
70
|
-
cut -d: -f1 | \
|
|
71
|
-
xargs -I{} tmux select-window -t :{}"
|
|
72
|
-
|
|
73
|
-
# --- Session lifecycle ---
|
|
74
|
-
# When a session is killed, switch to the next one instead of detaching.
|
|
75
|
-
# jmux only exits when the last session is destroyed.
|
|
76
|
-
set -g detach-on-destroy off
|
|
77
|
-
|
|
78
|
-
# --- Terminal ---
|
|
79
|
-
set -g default-terminal "tmux-256color"
|
|
80
|
-
set -g set-clipboard on
|
|
81
|
-
set -g focus-events on
|
|
82
|
-
set -g mouse on
|
|
83
|
-
set -gq status-utf8 on
|
|
84
|
-
set-window-option -gq utf8 on
|
|
85
|
-
set-option -ga terminal-overrides ",xterm-256color:Tc"
|
|
86
|
-
set-option -ga terminal-overrides ',*:Smulx=\E[4::%p1%dm'
|
|
87
|
-
set-option -ga terminal-overrides ',*:Setulc=\E[58::2::%p1%{65536}%/%d::%p1%{256}%/%{255}%&%d::%p1%{255}%&%d%;m'
|
|
88
|
-
|
|
89
|
-
# --- Bell / Activity ---
|
|
90
|
-
set-window-option -g visual-bell off
|
|
91
|
-
set-window-option -g bell-action other
|
|
92
|
-
set-window-option -g monitor-activity off
|
|
93
|
-
set-window-option -g visual-activity off
|
|
94
|
-
set-hook -g pane-focus-in 'setw monitor-bell off; setw monitor-bell on'
|
|
95
|
-
unbind -T root DoubleClick1Pane
|
|
96
|
-
unbind -T root TripleClick1Pane
|
|
97
|
-
|
|
98
|
-
# --- Status bar ---
|
|
99
|
-
# Minimal — session indicator handled by jmux sidebar, no system metrics
|
|
100
|
-
set -g status-position bottom
|
|
101
|
-
set -g status-interval 1
|
|
102
|
-
set -g status-justify left
|
|
103
|
-
set -g status-bg "#181f26"
|
|
104
|
-
set -g status-left ""
|
|
105
|
-
set -g status-right ""
|
|
106
|
-
set -g status-left-length 0
|
|
107
|
-
set -g status-right-length 0
|
|
108
|
-
|
|
109
|
-
# Window tabs
|
|
110
|
-
setw -g window-status-current-format "#[bg=#181f26 fg=#fbd4b8]◢#[bg=#fbd4b8 fg=#131a21] #W #{?window_zoomed_flag, ,}#[bg=#181f26 fg=#fbd4b8]◣"
|
|
111
|
-
setw -g window-status-format "#{?window_bell_flag,#[bg=#181f26 fg=#ced4df] #W #{?window_zoomed_flag, ,},#[bg=#181f26 fg=#4f565d] #W #{?window_zoomed_flag, ,}}"
|
|
112
|
-
set -g window-status-bell-style 'fg=#ced4df,bg=#0c1117'
|
|
113
|
-
set -g window-status-activity-style 'fg=#b5bcc9,bg=#4e555c,bold'
|
|
1
|
+
# jmux tmux configuration loader
|
|
2
|
+
#
|
|
3
|
+
# Source order:
|
|
4
|
+
# 1. jmux defaults — opinionated keybindings, colors, status bar
|
|
5
|
+
# 2. User's ~/.tmux.conf (if it exists) — overrides defaults
|
|
6
|
+
# 3. jmux core — required settings that jmux depends on (sourced last, wins)
|
|
7
|
+
#
|
|
8
|
+
# Users can override any default in ~/.tmux.conf. Only core settings
|
|
9
|
+
# (mouse, detach-on-destroy, prefix+n) cannot be overridden.
|
|
10
|
+
|
|
11
|
+
# Step 1: jmux defaults (baseline)
|
|
12
|
+
source-file "$JMUX_DIR/config/defaults.conf"
|
|
13
|
+
|
|
14
|
+
# Step 2: User config (overrides defaults)
|
|
15
|
+
if-shell "test -f ~/.tmux.conf" "source-file ~/.tmux.conf"
|
|
16
|
+
|
|
17
|
+
# Step 3: jmux core (non-negotiable — must be last)
|
|
18
|
+
source-file "$JMUX_DIR/config/core.conf"
|
package/package.json
CHANGED