|
| 1 | +# Wave 3: Auto-Install StatusLine + tmux Sidebar + Config Change |
| 2 | + |
| 3 | +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. |
| 4 | +
|
| 5 | +**Goal:** Wire up statusLine auto-installation in session-start, add tmux sidebar auto-setup, and set `CODINGBUDDY_AUTO_TUI=0`. All changes are in `session-start.py`. |
| 6 | + |
| 7 | +**Architecture:** Three new functions added to `session-start.py`, inserted as Step 2.5, Step 4.5, and Step 6.5 in the existing `main()` flow. |
| 8 | + |
| 9 | +**Tech Stack:** Python 3, shutil, subprocess, json |
| 10 | + |
| 11 | +**Issues:** #1089, #1091, #1092 |
| 12 | + |
| 13 | +## Alternatives |
| 14 | + |
| 15 | +### Decision: HUD script source discovery |
| 16 | + |
| 17 | +| Criteria | Reuse find_plugin_source() with param | Separate find function | |
| 18 | +|---|---|---| |
| 19 | +| DRY | Reuses existing 3-tier search | Duplicates logic | |
| 20 | +| Flexibility | Need to parameterize filename | Hardcoded to one file | |
| 21 | +| Risk | Changing shared function may break hook install | Isolated | |
| 22 | + |
| 23 | +**Decision:** Separate helper `_find_hud_source()` that follows the same 3-tier pattern but searches for `codingbuddy-hud.py`. Simpler and zero risk to existing hook installation. |
| 24 | + |
| 25 | +--- |
| 26 | + |
| 27 | +## Part A: #1089 — Auto-Install StatusLine |
| 28 | + |
| 29 | +### Step A1: Write test — `_install_statusline` |
| 30 | + |
| 31 | +**File:** `packages/claude-code-plugin/tests/test_session_start_hud.py` |
| 32 | + |
| 33 | +Tests: |
| 34 | +- `test_installs_hud_script_to_claude_hud_dir` — copies file, sets permissions |
| 35 | +- `test_sets_statusline_in_settings` — writes statusLine config |
| 36 | +- `test_replaces_omc_statusline` — replaces omc-hud with codingbuddy-hud |
| 37 | +- `test_skips_custom_statusline` — preserves non-OMC custom statusLine |
| 38 | +- `test_skips_if_already_installed` — no-op when codingbuddy-hud already set |
| 39 | +- `test_sets_auto_tui_to_zero` — changes CODINGBUDDY_AUTO_TUI from 1 to 0 |
| 40 | + |
| 41 | +### Step A2: Implement `_find_hud_source()` |
| 42 | + |
| 43 | +Same 3-tier search as `find_plugin_source()` but for `codingbuddy-hud.py`: |
| 44 | +1. `CLAUDE_PLUGIN_DIR` env → `hooks/codingbuddy-hud.py` |
| 45 | +2. Plugin cache paths → `hooks/codingbuddy-hud.py` |
| 46 | +3. Dev paths → `hooks/codingbuddy-hud.py` |
| 47 | + |
| 48 | +### Step A3: Implement `_install_statusline(home, settings_file)` |
| 49 | + |
| 50 | +```python |
| 51 | +def _install_statusline(home: Path, settings_file: Path) -> None: |
| 52 | + """Install codingbuddy statusLine and set CODINGBUDDY_AUTO_TUI=0.""" |
| 53 | + # 1. Find source |
| 54 | + source = _find_hud_source() |
| 55 | + if not source: |
| 56 | + return |
| 57 | + |
| 58 | + # 2. Copy to ~/.claude/hud/ |
| 59 | + hud_dir = home / ".claude" / "hud" |
| 60 | + hud_dir.mkdir(parents=True, exist_ok=True) |
| 61 | + target = hud_dir / "codingbuddy-hud.py" |
| 62 | + shutil.copy(source, target) |
| 63 | + target.chmod(0o755) |
| 64 | + |
| 65 | + # 3. Update settings.json |
| 66 | + settings = _read_settings_file(settings_file) if settings_file.exists() else {} |
| 67 | + |
| 68 | + # Check existing statusLine |
| 69 | + current_sl = settings.get("statusLine", {}).get("command", "") |
| 70 | + if "codingbuddy-hud" in current_sl: |
| 71 | + pass # already installed |
| 72 | + elif "omc-hud" in current_sl or not current_sl: |
| 73 | + settings["statusLine"] = { |
| 74 | + "type": "command", |
| 75 | + "command": f'python3 "{home}/.claude/hud/codingbuddy-hud.py"' |
| 76 | + } |
| 77 | + # else: custom statusLine, preserve |
| 78 | + |
| 79 | + # 4. Set CODINGBUDDY_AUTO_TUI=0 (#1092) |
| 80 | + env = settings.setdefault("env", {}) |
| 81 | + if env.get("CODINGBUDDY_AUTO_TUI") == "1": |
| 82 | + env["CODINGBUDDY_AUTO_TUI"] = "0" |
| 83 | + |
| 84 | + _write_settings_file(settings_file, settings) |
| 85 | +``` |
| 86 | + |
| 87 | +### Step A4: Wire into `main()` as Step 2.5 |
| 88 | + |
| 89 | +After line 492 (after status message), before Step 3: |
| 90 | +```python |
| 91 | + # Step 2.5: Install codingbuddy statusLine (#1089, #1092) |
| 92 | + try: |
| 93 | + _install_statusline(home, settings_file) |
| 94 | + except Exception: |
| 95 | + pass |
| 96 | +``` |
| 97 | + |
| 98 | +### Step A5: Implement Step 4.5 — Init HUD state |
| 99 | + |
| 100 | +After line 525 (after stats init): |
| 101 | +```python |
| 102 | + # Step 4.5: Initialize HUD state (#1089) |
| 103 | + try: |
| 104 | + _ensure_lib_path() |
| 105 | + from hud_state import init_hud_state |
| 106 | + from session_utils import get_session_id as _get_sid_hud |
| 107 | + init_hud_state(_get_sid_hud(), "5.1.1") |
| 108 | + except Exception: |
| 109 | + pass |
| 110 | +``` |
| 111 | + |
| 112 | +--- |
| 113 | + |
| 114 | +## Part B: #1091 — tmux Sidebar Auto-Setup |
| 115 | + |
| 116 | +### Step B1: Write test — tmux detection + sidebar |
| 117 | + |
| 118 | +**File:** `packages/claude-code-plugin/tests/test_tmux_sidebar.py` |
| 119 | + |
| 120 | +Tests: |
| 121 | +- `test_detects_tmux_env` — returns True when $TMUX set |
| 122 | +- `test_no_tmux_env` — returns False when $TMUX unset |
| 123 | +- `test_sidebar_pane_exists_detection` — detects existing codingbuddy pane |
| 124 | +- `test_prints_tmux_suggestion_when_not_in_tmux` — outputs tip message |
| 125 | + |
| 126 | +### Step B2: Implement `_setup_tmux_sidebar()` |
| 127 | + |
| 128 | +```python |
| 129 | +import subprocess |
| 130 | + |
| 131 | +TMUX_SUGGESTION = { |
| 132 | + "en": ( |
| 133 | + "╭───────────────────────────────────────────────╮\n" |
| 134 | + "│ ◕‿◕ Tip: Run Claude Code inside tmux for │\n" |
| 135 | + "│ the full CodingBuddy sidebar experience! │\n" |
| 136 | + "│ │\n" |
| 137 | + "│ tmux new -s dev │\n" |
| 138 | + "│ claude │\n" |
| 139 | + "╰───────────────────────────────────────────────╯" |
| 140 | + ), |
| 141 | + "ko": ( |
| 142 | + "╭───────────────────────────────────────────────╮\n" |
| 143 | + "│ ◕‿◕ Tip: tmux 안에서 Claude Code를 실행하면 │\n" |
| 144 | + "│ CodingBuddy 사이드바를 볼 수 있어요! │\n" |
| 145 | + "│ │\n" |
| 146 | + "│ tmux new -s dev │\n" |
| 147 | + "│ claude │\n" |
| 148 | + "╰───────────────────────────────────────────────╯" |
| 149 | + ), |
| 150 | +} |
| 151 | + |
| 152 | +def _sidebar_pane_exists() -> bool: |
| 153 | + try: |
| 154 | + result = subprocess.run( |
| 155 | + ["tmux", "list-panes", "-F", "#{pane_current_command}"], |
| 156 | + capture_output=True, text=True, timeout=2, |
| 157 | + ) |
| 158 | + return "codingbuddy" in result.stdout |
| 159 | + except Exception: |
| 160 | + return False |
| 161 | + |
| 162 | +def _setup_tmux_sidebar() -> None: |
| 163 | + if not os.environ.get("TMUX"): |
| 164 | + # Print suggestion |
| 165 | + lang = _get_cached_language() |
| 166 | + tip = TMUX_SUGGESTION.get(lang, TMUX_SUGGESTION["en"]) |
| 167 | + print(tip, file=sys.stderr) |
| 168 | + return |
| 169 | + |
| 170 | + if _sidebar_pane_exists(): |
| 171 | + return |
| 172 | + |
| 173 | + subprocess.Popen( |
| 174 | + ["tmux", "split-window", "-h", "-l", "25%", "-d", "codingbuddy", "tui"], |
| 175 | + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, |
| 176 | + ) |
| 177 | + subprocess.Popen( |
| 178 | + ["tmux", "select-pane", "-L"], |
| 179 | + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, |
| 180 | + ) |
| 181 | +``` |
| 182 | + |
| 183 | +### Step B3: Wire into `main()` as Step 6.5 |
| 184 | + |
| 185 | +After buddy greeting (end of Step 6): |
| 186 | +```python |
| 187 | + # Step 6.5: tmux sidebar auto-setup (#1091) |
| 188 | + try: |
| 189 | + _setup_tmux_sidebar() |
| 190 | + except Exception: |
| 191 | + pass |
| 192 | +``` |
| 193 | + |
| 194 | +--- |
| 195 | + |
| 196 | +## Execution Order |
| 197 | + |
| 198 | +1. Write tests (A1 + B1) |
| 199 | +2. Implement functions (A2-A5 + B2-B3) |
| 200 | +3. Run all tests |
| 201 | +4. Commit + ship |
| 202 | + |
| 203 | +## Files Modified |
| 204 | + |
| 205 | +| File | Changes | |
| 206 | +|------|---------| |
| 207 | +| `hooks/session-start.py` | Add `_find_hud_source`, `_install_statusline`, `_setup_tmux_sidebar`, `_sidebar_pane_exists`, `TMUX_SUGGESTION` + wire Steps 2.5, 4.5, 6.5 | |
| 208 | +| `tests/test_session_start_hud.py` | NEW — statusLine install tests | |
| 209 | +| `tests/test_tmux_sidebar.py` | NEW — tmux detection tests | |
| 210 | + |
| 211 | +## Verification |
| 212 | + |
| 213 | +1. `python3 -m pytest tests/test_session_start_hud.py tests/test_tmux_sidebar.py -v` |
| 214 | +2. `python3 -m pytest tests/ -q` (full regression) |
| 215 | +3. Manual: Start new Claude Code session → check `~/.claude/settings.json` statusLine |
| 216 | +4. Manual (tmux): Start Claude Code in tmux → verify sidebar pane appears |
0 commit comments