batipanel 0.4.21 → 0.4.24

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
@@ -118,13 +118,12 @@ b server start # Docker 서버 시작 — 끝!
118
118
 
119
119
  ```bash
120
120
  # Install (pick one)
121
- npx batipanel # npm/npx
122
- brew install batiai/tap/batipanel # Homebrew
123
- curl -fsSL https://batipanel.com/install.sh | bash # Shell script (domain)
124
- curl -fsSL https://raw.githubusercontent.com/batiai/batipanel/master/scripts/web-install.sh | bash # Shell script (GitHub)
121
+ curl -fsSL https://batipanel.com/install.sh | bash # Recommended
122
+ npx batipanel # npm/npx
123
+ brew install batiai/tap/batipanel # Homebrew
125
124
 
126
125
  # Run — the setup wizard guides you through everything
127
- batipanel
126
+ b
128
127
  ```
129
128
 
130
129
  That's it. The wizard asks 2 questions (screen size + workflow) and sets up your workspace.
@@ -144,25 +143,17 @@ That's it. The wizard asks 2 questions (screen size + workflow) and sets up your
144
143
 
145
144
  2. **설치 명령어 실행** (복사 후 붙여넣기):
146
145
  ```bash
147
- git clone https://github.com/batiai/batipanel.git
148
- cd batipanel
149
- bash install.sh
146
+ curl -fsSL https://batipanel.com/install.sh | bash
150
147
  ```
151
- - tmux 없으면 설치 방법을 안내합니다 (Homebrew, MacPorts, Nix 등)
152
- - 비밀번호를 물어보면 Mac 로그인 비밀번호 입력
148
+ - tmux, 기타 도구를 자동으로 설치합니다
149
+ - Homebrew가 없으면 안내를 따르세요
153
150
 
154
151
  3. **새 터미널 열기** 후 실행:
155
152
  ```bash
156
153
  b
157
154
  ```
158
155
 
159
- > **npm/npx로 설치하고 싶다면**: 먼저 [nvm](https://github.com/nvm-sh/nvm)을 설치하세요:
160
- > ```bash
161
- > curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
162
- > source ~/.zshrc
163
- > nvm install --lts
164
- > npx batipanel
165
- > ```
156
+ > **다른 설치 방법**: `npx batipanel` (Node.js 필요) 또는 `brew install batiai/tap/batipanel` (Homebrew)
166
157
 
167
158
  </details>
168
159
 
@@ -173,9 +164,7 @@ That's it. The wizard asks 2 questions (screen size + workflow) and sets up your
173
164
 
174
165
  2. **설치 명령어 실행**:
175
166
  ```bash
176
- git clone https://github.com/batiai/batipanel.git
177
- cd batipanel
178
- bash install.sh
167
+ curl -fsSL https://batipanel.com/install.sh | bash
179
168
  ```
180
169
  - 모든 도구(tmux, btop 등)가 자동 설치됩니다
181
170
 
@@ -184,13 +173,7 @@ That's it. The wizard asks 2 questions (screen size + workflow) and sets up your
184
173
  b
185
174
  ```
186
175
 
187
- > **npm/npx 설치하고 싶다면**: 먼저 [nvm](https://github.com/nvm-sh/nvm)을 설치하세요:
188
- > ```bash
189
- > curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
190
- > source ~/.bashrc
191
- > nvm install --lts
192
- > npx batipanel
193
- > ```
176
+ > **다른 설치 방법**: `npx batipanel` (Node.js 필요) 또는 수동 설치: `git clone https://github.com/batiai/batipanel.git && cd batipanel && bash install.sh`
194
177
 
195
178
  </details>
196
179
 
@@ -219,7 +202,7 @@ All dependencies (tmux, lazygit, btop, yazi, eza) are installed automatically.
219
202
 
220
203
  ```bash
221
204
  # One-line install (no npm/Node.js required)
222
- curl -fsSL https://raw.githubusercontent.com/batiai/batipanel/master/scripts/web-install.sh | bash
205
+ curl -fsSL https://batipanel.com/install.sh | bash
223
206
  ```
224
207
 
225
208
  Or clone and install manually:
package/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.21
1
+ 0.4.24
package/bin/start.sh CHANGED
@@ -24,6 +24,7 @@ show_help() {
24
24
  echo " b config layout [name] Set default layout"
25
25
  echo " b theme [name] Change color theme"
26
26
  echo " b doctor Check system health"
27
+ echo " b reset Kill tmux, clear projects, re-test"
27
28
  echo " b server [init|start|stop|status] AI server (Telegram bot)"
28
29
  echo " b help Show this help"
29
30
  echo ""
@@ -106,6 +107,9 @@ case "${ARGS[0]:-}" in
106
107
  doctor)
107
108
  tmux_doctor
108
109
  ;;
110
+ reset)
111
+ tmux_reset
112
+ ;;
109
113
  server)
110
114
  server_cmd "${ARGS[1]:-}" "${ARGS[2]:-}" "${ARGS[3]:-}"
111
115
  ;;
@@ -0,0 +1,5 @@
1
+ # powerline status bar (Nerd Font override)
2
+ set -g status-left '#[fg=colour232,bg=colour2,bold] #S #[fg=colour2,bg=colour234,nobold] '
3
+ set -g status-right '#[fg=colour240,bg=colour234]#[fg=colour249,bg=colour240] #{session_windows}W #{window_panes}P #[fg=colour2,bg=colour240]#[fg=colour232,bg=colour2,bold] %H:%M %m-%d '
4
+ setw -g window-status-format '#[fg=colour234,bg=colour238]#[fg=colour249,bg=colour238] #I #W #[fg=colour238,bg=colour234]'
5
+ setw -g window-status-current-format '#[fg=colour234,bg=colour33]#[fg=colour255,bg=colour33,bold] #I #W #[fg=colour33,bg=colour234]'
package/config/tmux.conf CHANGED
@@ -1,8 +1,15 @@
1
1
  # batipanel tmux configuration
2
+ # NOTE: no if-shell commands — platform settings are in tmux-platform.conf
2
3
 
3
4
  # === terminal & color support ===
4
- set -g default-terminal "tmux-256color"
5
+ set -g default-terminal "xterm-256color"
5
6
  set -as terminal-overrides ",xterm*:RGB"
7
+ set -sg escape-time 10
8
+ set -g focus-events on
9
+
10
+ # prevent window/pane names from cycling through running commands
11
+ setw -g automatic-rename off
12
+ set -g allow-rename off
6
13
 
7
14
  # enable mouse (click, drag, scroll, resize)
8
15
  set -g mouse on
@@ -11,29 +18,25 @@ set -g mouse on
11
18
  set -g base-index 1
12
19
  setw -g pane-base-index 1
13
20
 
14
- # === status bar - powerline style ===
21
+ # === status bar ===
15
22
  set -g status-position bottom
16
23
  set -g status-style "bg=colour234,fg=colour137"
17
- set -g status-left '#[fg=colour232,bg=colour2,bold] #S #[fg=colour2,bg=colour234,nobold] '
18
- set -g status-right '#[fg=colour240,bg=colour234]#[fg=colour249,bg=colour240] #{session_windows}W #{window_panes}P #[fg=colour2,bg=colour240]#[fg=colour232,bg=colour2,bold] %H:%M %m-%d '
19
24
  set -g status-left-length 30
20
25
  set -g status-right-length 50
21
-
22
- # window status - powerline style
23
- setw -g window-status-format '#[fg=colour234,bg=colour238]#[fg=colour249,bg=colour238] #I #W #[fg=colour238,bg=colour234]'
24
- setw -g window-status-current-format '#[fg=colour234,bg=colour33]#[fg=colour255,bg=colour33,bold] #I #W #[fg=colour33,bg=colour234]'
26
+ set -g status-left '#[fg=colour232,bg=colour2,bold] #S #[fg=colour2,bg=colour234,nobold]| '
27
+ set -g status-right '#[fg=colour249,bg=colour240] #{session_windows}W #{window_panes}P #[fg=colour232,bg=colour2,bold] %H:%M %m-%d '
28
+ setw -g window-status-format '#[fg=colour249,bg=colour238] #I #W #[fg=colour238,bg=colour234]|'
29
+ setw -g window-status-current-format '#[fg=colour255,bg=colour33,bold] #I #W #[fg=colour33,bg=colour234]|'
25
30
 
26
31
  # === pane borders ===
27
32
  set -g pane-border-style "fg=colour240"
28
33
  set -g pane-active-border-style "fg=colour2,bold"
29
-
30
- # pane labels (show tool name in border)
31
34
  set -g pane-border-status top
32
35
  set -g pane-border-format "#[fg=colour240] #{pane_index}:#{pane_title} "
33
36
 
34
37
  # === terminal title ===
35
38
  set -g set-titles on
36
- set -g set-titles-string "batipanel #S:#W"
39
+ set -g set-titles-string "batipanel - #S:#W"
37
40
 
38
41
  # === messages ===
39
42
  set -g display-time 2000
@@ -41,7 +44,6 @@ set -g message-style "bg=colour33,fg=colour255,bold"
41
44
  set -g message-command-style "bg=colour33,fg=colour255"
42
45
 
43
46
  # === pane navigation ===
44
- # Alt+hjkl or Alt+arrow: move between panes
45
47
  bind -n M-Left select-pane -L
46
48
  bind -n M-Right select-pane -R
47
49
  bind -n M-Up select-pane -U
@@ -50,50 +52,34 @@ bind -n M-h select-pane -L
50
52
  bind -n M-l select-pane -R
51
53
  bind -n M-k select-pane -U
52
54
  bind -n M-j select-pane -D
53
-
54
- # Alt+Space: toggle last pane
55
55
  bind -n M-Space select-pane -l
56
-
57
- # Alt+f: zoom/focus current pane (toggle)
58
56
  bind -n M-f resize-pane -Z
59
57
 
60
58
  # === pane swapping ===
61
- # Alt+Shift+hjkl: swap pane in direction
62
59
  bind -n M-H swap-pane -s '{left-of}'
63
60
  bind -n M-L swap-pane -s '{right-of}'
64
61
  bind -n M-K swap-pane -s '{up-of}'
65
62
  bind -n M-J swap-pane -s '{down-of}'
66
63
 
67
64
  # === pane resizing ===
68
- # prefix+arrow: resize by 5 units
69
65
  bind -r Left resize-pane -L 5
70
66
  bind -r Right resize-pane -R 5
71
67
  bind -r Up resize-pane -U 3
72
68
  bind -r Down resize-pane -D 3
73
-
74
- # Alt+Shift+arrow: fine resize (1 unit)
75
69
  bind -n M-S-Left resize-pane -L 1
76
70
  bind -n M-S-Right resize-pane -R 1
77
71
  bind -n M-S-Up resize-pane -U 1
78
72
  bind -n M-S-Down resize-pane -D 1
79
-
80
- # prefix+=: equalize all pane sizes
81
73
  bind = select-layout -E
82
74
 
83
75
  # === quick splits ===
84
- # Alt+\: vertical split, Alt+-: horizontal split (keep current path)
85
76
  bind -n M-\\ split-window -h -c "#{pane_current_path}"
86
77
  bind -n M-- split-window -v -c "#{pane_current_path}"
87
78
 
88
79
  # === window management ===
89
- # Alt+n: new window
90
80
  bind -n M-n new-window -c "#{pane_current_path}"
91
-
92
- # Alt+[/]: previous/next window
93
81
  bind -n M-[ previous-window
94
82
  bind -n M-] next-window
95
-
96
- # Alt+1~9: direct window select
97
83
  bind -n M-1 select-window -t 1
98
84
  bind -n M-2 select-window -t 2
99
85
  bind -n M-3 select-window -t 3
@@ -103,8 +89,6 @@ bind -n M-6 select-window -t 6
103
89
  bind -n M-7 select-window -t 7
104
90
  bind -n M-8 select-window -t 8
105
91
  bind -n M-9 select-window -t 9
106
-
107
- # Alt+x: kill pane (with confirm)
108
92
  bind -n M-x confirm-before -p "Kill pane? (y/n)" kill-pane
109
93
 
110
94
  # === copy mode (vi style) ===
@@ -113,29 +97,13 @@ bind -T copy-mode-vi v send-keys -X begin-selection
113
97
  bind -T copy-mode-vi C-v send-keys -X rectangle-toggle
114
98
  bind -T copy-mode-vi Escape send-keys -X cancel
115
99
 
116
- # clipboard integration (copy-mode → system clipboard)
117
- # macOS
118
- if-shell "uname -s | grep -q Darwin" \
119
- "bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel 'pbcopy'"
120
- # WSL
121
- if-shell "grep -qi microsoft /proc/version 2>/dev/null" \
122
- "bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel 'clip.exe'"
123
- # Linux (X11/Wayland)
124
- if-shell "command -v xclip >/dev/null 2>&1" \
125
- "bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel 'xclip -selection clipboard'"
126
-
127
100
  # === session management ===
128
101
  bind s choose-session -ZN
129
102
  bind S new-session -c "#{pane_current_path}"
130
-
131
- # Reload config
132
103
  bind r source-file ~/.tmux.conf \; display "tmux.conf reloaded"
133
104
 
134
105
  # scroll history
135
106
  set -g history-limit 10000
136
107
 
137
- # Use the user's default shell
138
- set -g default-shell "$SHELL"
139
-
140
- # theme overlay (generated by 'b theme')
141
- if-shell "test -f ~/.batipanel/config/theme.conf" "source-file ~/.batipanel/config/theme.conf"
108
+ # platform-specific settings (generated by install.sh — clipboard, shell, theme)
109
+ source-file ~/.batipanel/config/tmux-platform.conf
package/install.sh CHANGED
@@ -138,10 +138,45 @@ fi
138
138
  if ! command -v tmux &>/dev/null; then
139
139
  echo ""
140
140
  echo "tmux is required but could not be installed."
141
- echo "Please install tmux manually and re-run this installer."
141
+ if [ "$OS" = "Darwin" ]; then
142
+ echo "Install via Homebrew: brew install tmux"
143
+ else
144
+ echo "Install via package manager: sudo apt install tmux (or equivalent)"
145
+ fi
142
146
  exit 1
143
147
  fi
144
148
 
149
+ # smoke test: verify tmux can actually start a server
150
+ _tmux_smoke_ok=0
151
+ if tmux -f /dev/null new-session -d -s _bp_smoke -x 10 -y 5 2>/dev/null; then
152
+ tmux kill-session -t _bp_smoke 2>/dev/null || true
153
+ _tmux_smoke_ok=1
154
+ fi
155
+
156
+ if [ "$_tmux_smoke_ok" = "0" ]; then
157
+ echo ""
158
+ echo "WARNING: tmux is installed but fails to start (server exited unexpectedly)."
159
+ # if mamba tmux exists, it may be the broken one — remove wrapper so brew takes priority
160
+ if [ -f "$BATIPANEL_HOME/bin/tmux" ] && [ -d "$BATIPANEL_HOME/.mamba" ]; then
161
+ echo " Removing unstable conda-forge tmux..."
162
+ rm -f "$BATIPANEL_HOME/bin/tmux"
163
+ fi
164
+ if [ "$OS" = "Darwin" ]; then
165
+ echo " Please install tmux via Homebrew: brew install tmux"
166
+ else
167
+ echo " Please install tmux via package manager: sudo apt install tmux"
168
+ fi
169
+ # re-check after removing mamba wrapper
170
+ if command -v tmux &>/dev/null && tmux -f /dev/null new-session -d -s _bp_smoke2 -x 10 -y 5 2>/dev/null; then
171
+ tmux kill-session -t _bp_smoke2 2>/dev/null || true
172
+ echo " Found working system tmux: $(tmux -V)"
173
+ else
174
+ echo ""
175
+ echo "tmux is required. Install it and re-run this installer."
176
+ exit 1
177
+ fi
178
+ fi
179
+
145
180
  # ensure git >= 2.32 (required by lazygit)
146
181
  if has_cmd git; then
147
182
  GIT_VER=$(git --version | grep -oE '[0-9]+\.[0-9]+' | head -1)
@@ -431,24 +466,64 @@ fi
431
466
  # === 6. install tmux.conf ===
432
467
  mkdir -p "$BATIPANEL_HOME/config"
433
468
  cp "$SCRIPT_DIR/config/tmux.conf" "$BATIPANEL_HOME/config/tmux.conf"
469
+ cp "$SCRIPT_DIR/config/tmux-powerline.conf" "$BATIPANEL_HOME/config/tmux-powerline.conf" 2>/dev/null || true
470
+
471
+ # generate platform-specific config (no if-shell needed — detected at install time)
472
+ _PLATFORM_CONF="$BATIPANEL_HOME/config/tmux-platform.conf"
473
+ {
474
+ echo "# batipanel platform config (auto-generated by install.sh)"
475
+ echo ""
434
476
 
477
+ # clipboard
478
+ case "$OS" in
479
+ Darwin)
480
+ echo "# macOS clipboard"
481
+ echo "bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel 'pbcopy'"
482
+ ;;
483
+ *)
484
+ if command -v xclip &>/dev/null; then
485
+ echo "# Linux clipboard (xclip)"
486
+ echo "bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel 'xclip -selection clipboard'"
487
+ elif grep -qi microsoft /proc/version 2>/dev/null; then
488
+ echo "# WSL clipboard"
489
+ echo "bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel 'clip.exe'"
490
+ fi
491
+ ;;
492
+ esac
493
+
494
+ # default shell
495
+ local_shell="${SHELL:-}"
496
+ if [ -n "$local_shell" ] && [ -x "$local_shell" ]; then
497
+ echo ""
498
+ echo "# user shell"
499
+ echo "set -g default-shell \"$local_shell\""
500
+ fi
501
+
502
+ echo ""
503
+ echo "# theme overlay (generated by 'b theme')"
504
+ echo "source-file $BATIPANEL_HOME/config/theme.conf"
505
+ } > "$_PLATFORM_CONF"
506
+ echo " Generated platform config"
507
+
508
+ # guarantee theme.conf exists (empty = no theme = default tmux colors)
509
+ if [ ! -f "$BATIPANEL_HOME/config/theme.conf" ]; then
510
+ echo "# batipanel theme (auto-generated, use 'b theme' to change)" > "$BATIPANEL_HOME/config/theme.conf"
511
+ fi
512
+
513
+ # kill stale tmux server so new config takes effect
514
+ tmux kill-server 2>/dev/null || true
515
+
516
+ # clean ~/.tmux.conf (remove ALL old batipanel lines, then add fresh)
435
517
  BATIPANEL_SOURCE_LINE="source-file $BATIPANEL_HOME/config/tmux.conf"
436
518
  if [ -f ~/.tmux.conf ]; then
437
- if ! grep -qF "$BATIPANEL_SOURCE_LINE" ~/.tmux.conf 2>/dev/null; then
438
- {
439
- echo ""
440
- echo "# batipanel"
441
- echo "$BATIPANEL_SOURCE_LINE"
442
- } >> ~/.tmux.conf
443
- echo " Added batipanel source line to ~/.tmux.conf"
444
- else
445
- echo " ~/.tmux.conf already configured"
446
- fi
447
- else
448
- echo "# batipanel" > ~/.tmux.conf
449
- echo "$BATIPANEL_SOURCE_LINE" >> ~/.tmux.conf
450
- echo " Created ~/.tmux.conf with batipanel source"
519
+ sed_i '/batipanel/d' ~/.tmux.conf 2>/dev/null || true
451
520
  fi
521
+ {
522
+ echo ""
523
+ echo "# batipanel"
524
+ echo "$BATIPANEL_SOURCE_LINE"
525
+ } >> ~/.tmux.conf
526
+ echo " Configured ~/.tmux.conf"
452
527
 
453
528
  # === 7. register aliases ===
454
529
  # detect user's login shell via $SHELL (not $BASH_VERSION which reflects the script interpreter)
@@ -480,7 +555,7 @@ esac
480
555
 
481
556
  BATIPANEL_ALIAS="alias batipanel='bash \"$BATIPANEL_HOME/bin/start.sh\"'"
482
557
  # b is a function (not alias) so theme changes can auto-reload the prompt
483
- SHORT_FUNC="b() { bash \"$BATIPANEL_HOME/bin/start.sh\" \"\$@\"; if [[ \"\${1:-}\" == \"theme\" || (\"\${1:-}\" == \"config\" && \"\${2:-}\" == \"theme\") ]]; then local _pf=\"$BATIPANEL_HOME/config/bash-prompt.sh\"; [ -f \"\$_pf\" ] && source \"\$_pf\"; fi; }"
558
+ SHORT_FUNC="b() { bash \"$BATIPANEL_HOME/bin/start.sh\" \"\$@\"; if [[ \"\${1:-}\" == \"theme\" || (\"\${1:-}\" == \"config\" && \"\${2:-}\" == \"theme\") ]]; then if [ -n \"\${ZSH_VERSION:-}\" ]; then local _pf=\"$BATIPANEL_HOME/config/zsh-prompt.zsh\"; [ -f \"\$_pf\" ] && source \"\$_pf\"; else local _pf=\"$BATIPANEL_HOME/config/bash-prompt.sh\"; [ -f \"\$_pf\" ] && source \"\$_pf\"; fi; fi; }"
484
559
 
485
560
  # Always register 'batipanel' alias
486
561
  if grep -q "alias batipanel=" "$SHELL_RC" 2>/dev/null; then
package/lib/doctor.sh CHANGED
@@ -17,7 +17,23 @@ tmux_doctor() {
17
17
  ver=$(tmux -V 2>/dev/null | grep -oE '[0-9]+\.[0-9]+' | head -1)
18
18
  local major="${ver%%.*}" minor="${ver#*.}"
19
19
  if [[ -n "$ver" ]] && (( major >= 2 && (major > 2 || minor >= 6) )); then
20
- echo -e " [$ok] tmux $ver"
20
+ # functional test: actually create and destroy a test session
21
+ local test_sess="_bp_doctor_test_$$"
22
+ local tmux_test_err
23
+ if tmux_test_err=$(tmux new-session -d -s "$test_sess" -x 10 -y 5 2>&1); then
24
+ tmux kill-session -t "$test_sess" 2>/dev/null
25
+ echo -e " [$ok] tmux $ver (functional)"
26
+ else
27
+ echo -e " [$fail] tmux $ver installed but cannot create sessions"
28
+ if [[ "$tmux_test_err" == *"open terminal failed"* ]]; then
29
+ echo " terminfo issue — try: export TERM=xterm-256color"
30
+ elif [[ "$tmux_test_err" == *"library"* ]] || [[ "$tmux_test_err" == *"dylib"* ]]; then
31
+ echo " library issue — try reinstalling tmux"
32
+ else
33
+ echo " error: $tmux_test_err"
34
+ fi
35
+ issues=$((issues + 1))
36
+ fi
21
37
  else
22
38
  echo -e " [$fail] tmux ${ver:-unknown} (need 2.6+)"
23
39
  issues=$((issues + 1))
@@ -107,7 +123,7 @@ tmux_doctor() {
107
123
  # 9. tab completion
108
124
  local comp_found=0
109
125
  for rc in "$HOME/.zshrc" "$HOME/.bashrc" "$HOME/.bash_profile" "$HOME/.profile"; do
110
- if [ -f "$rc" ] && grep -q "completions/batipanel" "$rc" 2>/dev/null; then
126
+ if [ -f "$rc" ] && grep -qE "(completions/batipanel|_batipanel|\.zfunc)" "$rc" 2>/dev/null; then
111
127
  comp_found=1
112
128
  break
113
129
  fi
package/lib/layout.sh CHANGED
@@ -16,16 +16,35 @@ init_layout() {
16
16
  # tmux auto-resizes to actual terminal dimensions on attach.
17
17
  debug_log "init_layout: session=$session project=$project"
18
18
  tmux kill-session -t "$session" 2>/dev/null || true
19
- if ! tmux new-session -d -s "$session" -c "$project" -x 220 -y 60; then
20
- # check if session was created by a concurrent invocation
21
- if tmux has-session -t "$session" 2>/dev/null; then
22
- debug_log "init_layout: session already exists (concurrent creation)"
23
- return 0
24
- fi
25
- echo -e "${RED}Failed to create tmux session '$session'${NC}"
26
- echo " Is another tmux server blocking? Try: tmux kill-server"
27
- return 1
28
- fi
19
+
20
+ # try creating session; capture stderr for debug output
21
+ local tmux_err
22
+ tmux_err=$(tmux new-session -d -s "$session" -c "$project" -x 220 -y 60 2>&1) || {
23
+ debug_log "init_layout: first attempt failed: $tmux_err"
24
+ # retry with safe TERM
25
+ debug_log "init_layout: retrying with TERM=xterm-256color"
26
+ tmux_err=$(TERM=xterm-256color tmux new-session -d -s "$session" -c "$project" -x 220 -y 60 2>&1) || {
27
+ debug_log "init_layout: second attempt failed: $tmux_err"
28
+ # check if session was created by a concurrent invocation
29
+ if tmux has-session -t "$session" 2>/dev/null; then
30
+ debug_log "init_layout: session already exists (concurrent creation)"
31
+ return 0
32
+ fi
33
+ echo -e "${RED}Failed to create tmux session '$session'${NC}"
34
+ # provide specific guidance based on error
35
+ if [[ "$tmux_err" == *"open terminal failed"* ]]; then
36
+ echo " Error: open terminal failed (terminfo issue)"
37
+ echo " Try: export TERM=xterm-256color && b $session"
38
+ elif [[ "$tmux_err" == *"server"* ]] || [[ "$tmux_err" == *"socket"* ]]; then
39
+ echo " Stale tmux server? Try: tmux kill-server"
40
+ elif [[ "$tmux_err" == *"library"* ]] || [[ "$tmux_err" == *"dylib"* ]]; then
41
+ echo " Library issue — try reinstalling tmux"
42
+ else
43
+ echo " tmux error: $tmux_err"
44
+ fi
45
+ return 1
46
+ }
47
+ }
29
48
  }
30
49
 
31
50
  # Wait for shell init after pane splits
@@ -156,8 +175,16 @@ load_layout() {
156
175
 
157
176
  debug_log "load_layout: $layout_file"
158
177
 
178
+ # temporarily disable errexit so partial split failures don't kill the session
179
+ set +e
159
180
  # shellcheck source=/dev/null
160
181
  source "$layout_file" "$session" "$project"
182
+ local rc=$?
183
+ set -e
184
+
185
+ if [ "$rc" -ne 0 ]; then
186
+ debug_log "load_layout: layout exited with code $rc (partial setup possible)"
187
+ fi
161
188
  }
162
189
 
163
190
  # List available layouts
package/lib/session.sh CHANGED
@@ -1,6 +1,19 @@
1
1
  #!/usr/bin/env bash
2
2
  # batipanel session - start, stop, list, project listing
3
3
 
4
+ # portable timeout: timeout → gtimeout → perl fallback
5
+ _tmux_timeout() {
6
+ local secs="$1"; shift
7
+ if command -v timeout &>/dev/null; then
8
+ timeout "$secs" "$@"
9
+ elif command -v gtimeout &>/dev/null; then
10
+ gtimeout "$secs" "$@"
11
+ else
12
+ # perl is always available on macOS/Linux
13
+ perl -e "alarm $secs; exec @ARGV" -- "$@"
14
+ fi
15
+ }
16
+
4
17
  tmux_start() {
5
18
  local SESSION="$1"
6
19
  local LAYOUT="${2:-}"
@@ -15,16 +28,33 @@ tmux_start() {
15
28
  return 1
16
29
  fi
17
30
 
18
- if tmux has-session -t "$SESSION" 2>/dev/null; then
31
+ if _tmux_timeout 3 tmux has-session -t "$SESSION" 2>/dev/null; then
19
32
  log_info "session resume: $SESSION"
20
33
  echo -e "${GREEN}Resuming session: $SESSION${NC}"
21
34
  else
22
35
  log_info "session start: $SESSION layout=${LAYOUT:-$DEFAULT_LAYOUT}"
23
36
  echo -e "${BLUE}Starting new session: $SESSION${NC}"
24
- if [ -n "$LAYOUT" ]; then
25
- LAYOUT="$LAYOUT" bash "$SCRIPT" "$SESSION"
26
- else
27
- bash "$SCRIPT" "$SESSION"
37
+ # run project script (creates tmux session + panes)
38
+ local script_err
39
+ set +e
40
+ script_err=$(bash "$SCRIPT" "$SESSION" 2>&1)
41
+ set -e
42
+
43
+ # verify session was actually created
44
+ if ! _tmux_timeout 3 tmux has-session -t "$SESSION" 2>/dev/null; then
45
+ echo -e "${RED}Failed to start session '$SESSION'${NC}"
46
+ if [ -n "$script_err" ]; then
47
+ echo -e "${YELLOW}Error output:${NC}"
48
+ echo "$script_err" | head -20
49
+ fi
50
+ echo ""
51
+ echo "Troubleshooting:"
52
+ echo " 1. Run: b doctor (check tmux installation)"
53
+ echo " 2. Run: tmux new-session -d -s test && tmux kill-session -t test"
54
+ echo " (test if tmux works at all)"
55
+ echo " 3. Run: b reset (clean up stale state)"
56
+ echo " 4. Try: export TERM=xterm-256color && b $SESSION"
57
+ return 1
28
58
  fi
29
59
  fi
30
60
 
@@ -48,6 +78,8 @@ tmux_start() {
48
78
  _save_config "BATIPANEL_ITERM_CC" "$BATIPANEL_ITERM_CC"
49
79
  fi
50
80
 
81
+ echo -e " ${YELLOW}Tip:${NC} Detach with Ctrl+b d | Stop with: b stop $SESSION"
82
+ # attach to session (exec replaces this process)
51
83
  if [ "${BATIPANEL_ITERM_CC:-0}" = "1" ]; then
52
84
  exec tmux -CC attach -t "$SESSION"
53
85
  else
@@ -60,7 +92,7 @@ tmux_stop() {
60
92
  local FORCE="${2:-}"
61
93
  validate_session_name "$SESSION" || return 1
62
94
 
63
- if tmux has-session -t "$SESSION" 2>/dev/null; then
95
+ if _tmux_timeout 3 tmux has-session -t "$SESSION" 2>/dev/null; then
64
96
  if [[ "$FORCE" != "-f" && -t 0 ]]; then
65
97
  printf "Stop session '%s'? [y/N] " "$SESSION"
66
98
  local answer
@@ -78,12 +110,79 @@ tmux_stop() {
78
110
 
79
111
  tmux_list() {
80
112
  echo -e "${BLUE}=== Active Sessions ===${NC}"
81
- tmux ls 2>/dev/null || echo " (none)"
113
+ # run tmux ls with 3s timeout to avoid hang on stale server
114
+ local tmux_out
115
+ if tmux_out=$(_tmux_timeout 3 tmux ls 2>/dev/null); then
116
+ echo "$tmux_out"
117
+ else
118
+ echo " (none)"
119
+ fi
82
120
  echo ""
83
121
  echo -e "${BLUE}=== Registered Projects ===${NC}"
84
122
  list_projects
85
123
  }
86
124
 
125
+ tmux_reset() {
126
+ echo ""
127
+ echo -e "${YELLOW}=== batipanel reset ===${NC}"
128
+ echo ""
129
+
130
+ # 1. kill tmux server
131
+ echo " Killing tmux server..."
132
+ tmux kill-server 2>/dev/null && echo " Done" || echo " No server running"
133
+
134
+ # 2. remove stale sockets
135
+ local socket_dir="${TMUX_TMPDIR:-${TMPDIR:-/tmp}}"
136
+ local cleaned=0
137
+ for sock in "$socket_dir"/tmux-"$(id -u)"/*; do
138
+ [ -e "$sock" ] || continue
139
+ rm -f "$sock" 2>/dev/null && cleaned=$((cleaned + 1))
140
+ done
141
+ if (( cleaned > 0 )); then
142
+ echo " Removed $cleaned stale socket(s)"
143
+ fi
144
+
145
+ # 3. remove registered projects
146
+ local proj_count=0
147
+ for f in "$BATIPANEL_HOME"/projects/*.sh; do
148
+ [ -f "$f" ] || continue
149
+ proj_count=$((proj_count + 1))
150
+ done
151
+ if (( proj_count > 0 )); then
152
+ rm -f "$BATIPANEL_HOME"/projects/*.sh
153
+ echo " Removed $proj_count registered project(s)"
154
+ fi
155
+
156
+ # 4. remove config (wizard will re-run)
157
+ if [ -f "$BATIPANEL_HOME/config.sh" ]; then
158
+ rm -f "$BATIPANEL_HOME/config.sh"
159
+ echo " Removed config.sh (wizard will re-run)"
160
+ fi
161
+
162
+ # 5. test tmux
163
+ echo ""
164
+ echo " Testing tmux..."
165
+ local test_sess="_bp_reset_test_$$"
166
+ local test_err
167
+ if test_err=$(tmux new-session -d -s "$test_sess" -x 10 -y 5 2>&1); then
168
+ tmux kill-session -t "$test_sess" 2>/dev/null
169
+ echo -e " ${GREEN}tmux is working!${NC}"
170
+ else
171
+ echo -e " ${RED}tmux cannot create sessions${NC}"
172
+ echo " Error: $test_err"
173
+ echo ""
174
+ echo " Possible fixes:"
175
+ echo " export TERM=xterm-256color"
176
+ echo " brew reinstall tmux (if using Homebrew)"
177
+ echo " rm -rf ~/.batipanel/.mamba (if using micromamba tmux)"
178
+ fi
179
+
180
+ echo ""
181
+ echo -e "${GREEN}Reset complete.${NC} Now try:"
182
+ echo " cd ~/your-project && b"
183
+ echo ""
184
+ }
185
+
87
186
  # list registered projects
88
187
  list_projects() {
89
188
  local found=0
@@ -61,15 +61,22 @@ _generate_zsh_prompt() {
61
61
  _bp_env="$HOME/.batipanel/config/theme-env.sh"
62
62
  [[ -f "$_bp_env" ]] && source "$_bp_env"
63
63
 
64
+ # set terminal colors via OSC sequences
65
+ if [[ "$TERM" != "dumb" ]] && [[ -n "${BP_BG:-}" ]]; then
66
+ printf '\e]11;%s\a' "$BP_BG"
67
+ printf '\e]10;%s\a' "$BP_FG"
68
+ printf '\e]12;%s\a' "$BP_CURSOR"
69
+ fi
70
+
64
71
  autoload -U colors && colors
65
72
  autoload -Uz vcs_info
66
73
  setopt PROMPT_SUBST
67
74
 
68
75
  precmd() { vcs_info }
69
- zstyle ':vcs_info:git:*' formats ' %F{green}(%b)%f'
76
+ zstyle ':vcs_info:git:*' formats " %F{${BP_C_GIT:-green}}(%b)%f"
70
77
  zstyle ':vcs_info:*' enable git
71
78
 
72
- PROMPT='%F{blue}%n%f %F{cyan}%~%f${vcs_info_msg_0_} %F{magenta}>%f '
79
+ PROMPT="%F{${BP_C_USER:-blue}}%n%f %F{${BP_C_DIR:-cyan}}%~%f\${vcs_info_msg_0_} %F{${BP_C_PROMPT:-magenta}}>%f "
73
80
  RPROMPT='%(?..%F{red}[%?]%f)'
74
81
  ZSH_PROMPT_EOF
75
82
  }
@@ -118,16 +118,43 @@ _generate_themed_prompt() {
118
118
  t_err_dir="\\[\\e[38;5;${t_err_fg};48;5;${prompt_dir}m\\]"
119
119
  fi
120
120
 
121
+ # detect glyph support: Nerd Font terminals get powerline arrows, others get ASCII
122
+ local use_powerline=0
123
+ case "${TERM_PROGRAM:-}" in
124
+ iTerm.app|WezTerm|kitty) use_powerline=1 ;;
125
+ esac
126
+ [[ "${BATIPANEL_ICONS:-0}" == "1" ]] && use_powerline=1
127
+
128
+ local sep_char git_icon_line
129
+ if (( use_powerline )); then
130
+ sep_char=\$\'\\\\uE0B0\'
131
+ git_icon_line=" local git_icon=\$'\\\\uE0A0'"
132
+ else
133
+ sep_char='>'
134
+ git_icon_line=' local git_icon=""'
135
+ fi
136
+
121
137
  mkdir -p "$BATIPANEL_HOME/config"
122
138
  cat > "$prompt_file" << PROMPT_EOF
123
139
  #!/usr/bin/env bash
124
140
  # batipanel bash prompt - theme: ${theme} (auto-generated)
125
141
 
142
+ # load theme colors for OSC
143
+ _bp_env="\$HOME/.batipanel/config/theme-env.sh"
144
+ [ -f "\$_bp_env" ] && source "\$_bp_env"
145
+
146
+ # set terminal colors via OSC sequences
147
+ if [[ "\$TERM" != "dumb" ]] && [[ -n "\${BP_BG:-}" ]]; then
148
+ printf '\e]11;%s\a' "\$BP_BG"
149
+ printf '\e]10;%s\a' "\$BP_FG"
150
+ printf '\e]12;%s\a' "\$BP_CURSOR"
151
+ fi
152
+
126
153
  __batipanel_prompt() {
127
154
  local exit_code=\$?
128
155
 
129
- # powerline arrow symbols (U+E0B0, U+E0B1)
130
- local sep=\$'\\uE0B0'
156
+ # glyph (powerline arrow or ASCII fallback)
157
+ local sep="${sep_char}"
131
158
 
132
159
  # colors (generated from theme: ${theme})
133
160
  local bg_user="${bg_user}"
@@ -167,8 +194,12 @@ __batipanel_prompt() {
167
194
 
168
195
  if [ -n "\$git_branch" ]; then
169
196
  ps+="\${t_dir_git}\${sep}"
170
- local git_icon=\$'\\uE0A0'
171
- ps+="\${bg_git}\${fg_git} \${git_icon} \${git_branch} "
197
+ ${git_icon_line}
198
+ if [ -n "\$git_icon" ]; then
199
+ ps+="\${bg_git}\${fg_git} \${git_icon} \${git_branch} "
200
+ else
201
+ ps+="\${bg_git}\${fg_git} \${git_branch} "
202
+ fi
172
203
  ps+="\${reset}\${t_git_end}\${sep}\${reset} "
173
204
  else
174
205
  ps+="\${reset}\${t_dir_end}\${sep}\${reset} "
package/lib/themes.sh CHANGED
@@ -26,6 +26,11 @@ _apply_theme() {
26
26
  generate_theme_env "$theme"
27
27
  fi
28
28
 
29
+ # regenerate zsh prompt file with new theme colors
30
+ if declare -f _generate_zsh_prompt &>/dev/null; then
31
+ _generate_zsh_prompt
32
+ fi
33
+
29
34
  # persist to config.sh
30
35
  if [ -f "$TMUX_CONFIG" ]; then
31
36
  if grep -qF "BATIPANEL_THEME=" "$TMUX_CONFIG"; then
@@ -53,7 +58,7 @@ _apply_theme() {
53
58
 
54
59
  log_info "theme applied: $theme"
55
60
  echo -e "${GREEN}Theme applied: ${theme}${NC}"
56
- echo " Terminal colors updated. Run: source ~/.zshrc (for prompt colors)"
61
+ echo " Terminal and prompt colors updated."
57
62
  }
58
63
 
59
64
  # CLI entry point: b theme [name]
package/lib/wizard.sh CHANGED
@@ -82,6 +82,13 @@ run_wizard() {
82
82
  cwd=$(pwd)
83
83
  proj_name=$(basename "$cwd" | tr -c 'a-zA-Z0-9_-' '-' | sed 's/-*$//')
84
84
 
85
+ # warn if current directory looks like a temp/clone directory
86
+ if [[ "$cwd" == /tmp/* ]] || [[ "$cwd" == /private/tmp/* ]] || { [[ "$cwd" == */batipanel ]] && [[ -f "$cwd/install.sh" ]]; }; then
87
+ echo -e "${YELLOW}Warning:${NC} Current directory looks like a temporary or installer path."
88
+ echo -e " You probably want to cd to your actual project directory first."
89
+ echo ""
90
+ fi
91
+
85
92
  echo -e "Register ${BLUE}${cwd}${NC} as project '${GREEN}${proj_name}${NC}'?"
86
93
  printf "[Y/n] "
87
94
  read -r reg_answer
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "batipanel",
3
- "version": "0.4.21",
3
+ "version": "0.4.24",
4
4
  "description": "AI-powered terminal workspace manager — multi-panel tmux layouts with Claude Code, git, monitoring, and more",
5
5
  "bin": {
6
6
  "batipanel": "./bin/cli.sh"
@@ -24,7 +24,7 @@
24
24
  "type": "git",
25
25
  "url": "git+https://github.com/batiai/batipanel.git"
26
26
  },
27
- "homepage": "https://github.com/batiai/batipanel",
27
+ "homepage": "https://batipanel.com",
28
28
  "bugs": {
29
29
  "url": "https://github.com/batiai/batipanel/issues"
30
30
  },
package/uninstall.sh CHANGED
@@ -48,23 +48,36 @@ if [ -f "$HOME/.tmux.conf" ]; then
48
48
  fi
49
49
  fi
50
50
 
51
- # 3. remove shell aliases and completion source lines
51
+ # 3. remove ALL batipanel lines from shell RC files
52
52
  for rc in "$HOME/.zshrc" "$HOME/.bashrc" "$HOME/.bash_profile" "$HOME/.profile"; do
53
53
  [ -f "$rc" ] || continue
54
- if grep -q "batipanel" "$rc" 2>/dev/null; then
54
+ if grep -qE "(batipanel|\.batipanel)" "$rc" 2>/dev/null; then
55
55
  _sed_i '/# batipanel/d' "$rc"
56
56
  _sed_i '/alias batipanel=/d' "$rc"
57
57
  _sed_i '/alias b=.*batipanel/d' "$rc"
58
+ # b() function (may span one line)
59
+ _sed_i '/b().*batipanel/d' "$rc"
60
+ # prompt source lines
61
+ _sed_i '/bash-prompt\.sh/d' "$rc"
62
+ _sed_i '/zsh-prompt\.zsh/d' "$rc"
63
+ _sed_i '/# batipanel shell theme/d' "$rc"
64
+ _sed_i '/# batipanel prompt theme/d' "$rc"
65
+ # completion lines
58
66
  _sed_i '/completions\/batipanel/d' "$rc"
59
- echo " Cleaned aliases and completions from $(basename "$rc")"
67
+ _sed_i '/_batipanel/d' "$rc"
68
+ # PATH additions
69
+ _sed_i '/\.batipanel\/bin/d' "$rc"
70
+ # clean up blank lines left behind (collapse multiple empty lines to one)
71
+ _sed_i '/^[[:space:]]*$/{ N; /^\n[[:space:]]*$/d; }' "$rc"
72
+ echo " Cleaned all batipanel entries from $(basename "$rc")"
60
73
  fi
61
74
  done
62
75
 
63
76
  # remove zsh completion from fpath
64
77
  local_zsh_comp="${ZDOTDIR:-$HOME}/.zfunc"
65
- if [ -f "$local_zsh_comp/_batipanel" ]; then
66
- rm -f "$local_zsh_comp/_batipanel"
67
- echo " Removed zsh completion"
78
+ rm -f "$local_zsh_comp/_batipanel" "$local_zsh_comp/_b" 2>/dev/null
79
+ if [ -d "$local_zsh_comp" ]; then
80
+ echo " Removed zsh completions from .zfunc"
68
81
  fi
69
82
 
70
83
  # 4. stop server containers (if running)