shipwright-cli 1.7.1 → 1.9.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.
Files changed (105) hide show
  1. package/.claude/agents/code-reviewer.md +90 -0
  2. package/.claude/agents/devops-engineer.md +142 -0
  3. package/.claude/agents/pipeline-agent.md +80 -0
  4. package/.claude/agents/shell-script-specialist.md +150 -0
  5. package/.claude/agents/test-specialist.md +196 -0
  6. package/.claude/hooks/post-tool-use.sh +38 -0
  7. package/.claude/hooks/pre-tool-use.sh +25 -0
  8. package/.claude/hooks/session-started.sh +37 -0
  9. package/README.md +212 -814
  10. package/claude-code/CLAUDE.md.shipwright +54 -0
  11. package/claude-code/hooks/notify-idle.sh +2 -2
  12. package/claude-code/hooks/session-start.sh +24 -0
  13. package/claude-code/hooks/task-completed.sh +6 -2
  14. package/claude-code/settings.json.template +12 -0
  15. package/dashboard/public/app.js +4422 -0
  16. package/dashboard/public/index.html +816 -0
  17. package/dashboard/public/styles.css +4755 -0
  18. package/dashboard/server.ts +4315 -0
  19. package/docs/KNOWN-ISSUES.md +18 -10
  20. package/docs/TIPS.md +38 -26
  21. package/docs/patterns/README.md +33 -23
  22. package/package.json +9 -5
  23. package/scripts/adapters/iterm2-adapter.sh +1 -1
  24. package/scripts/adapters/tmux-adapter.sh +52 -23
  25. package/scripts/adapters/wezterm-adapter.sh +26 -14
  26. package/scripts/lib/compat.sh +200 -0
  27. package/scripts/lib/helpers.sh +72 -0
  28. package/scripts/postinstall.mjs +72 -13
  29. package/scripts/{cct → sw} +109 -21
  30. package/scripts/sw-adversarial.sh +274 -0
  31. package/scripts/sw-architecture-enforcer.sh +330 -0
  32. package/scripts/sw-checkpoint.sh +390 -0
  33. package/scripts/{cct-cleanup.sh → sw-cleanup.sh} +3 -1
  34. package/scripts/sw-connect.sh +619 -0
  35. package/scripts/{cct-cost.sh → sw-cost.sh} +368 -34
  36. package/scripts/{cct-daemon.sh → sw-daemon.sh} +2217 -204
  37. package/scripts/sw-dashboard.sh +477 -0
  38. package/scripts/sw-developer-simulation.sh +252 -0
  39. package/scripts/sw-docs.sh +635 -0
  40. package/scripts/sw-doctor.sh +907 -0
  41. package/scripts/{cct-fix.sh → sw-fix.sh} +10 -6
  42. package/scripts/{cct-fleet.sh → sw-fleet.sh} +498 -22
  43. package/scripts/sw-github-checks.sh +521 -0
  44. package/scripts/sw-github-deploy.sh +533 -0
  45. package/scripts/sw-github-graphql.sh +972 -0
  46. package/scripts/sw-heartbeat.sh +293 -0
  47. package/scripts/{cct-init.sh → sw-init.sh} +144 -11
  48. package/scripts/sw-intelligence.sh +1196 -0
  49. package/scripts/sw-jira.sh +643 -0
  50. package/scripts/sw-launchd.sh +364 -0
  51. package/scripts/sw-linear.sh +648 -0
  52. package/scripts/{cct-logs.sh → sw-logs.sh} +72 -2
  53. package/scripts/{cct-loop.sh → sw-loop.sh} +534 -44
  54. package/scripts/{cct-memory.sh → sw-memory.sh} +321 -38
  55. package/scripts/sw-patrol-meta.sh +417 -0
  56. package/scripts/sw-pipeline-composer.sh +455 -0
  57. package/scripts/{cct-pipeline.sh → sw-pipeline.sh} +2319 -178
  58. package/scripts/sw-predictive.sh +820 -0
  59. package/scripts/{cct-prep.sh → sw-prep.sh} +339 -49
  60. package/scripts/{cct-ps.sh → sw-ps.sh} +6 -4
  61. package/scripts/{cct-reaper.sh → sw-reaper.sh} +6 -4
  62. package/scripts/sw-remote.sh +687 -0
  63. package/scripts/sw-self-optimize.sh +947 -0
  64. package/scripts/sw-session.sh +519 -0
  65. package/scripts/sw-setup.sh +234 -0
  66. package/scripts/sw-status.sh +605 -0
  67. package/scripts/{cct-templates.sh → sw-templates.sh} +9 -4
  68. package/scripts/sw-tmux.sh +591 -0
  69. package/scripts/sw-tracker-jira.sh +277 -0
  70. package/scripts/sw-tracker-linear.sh +292 -0
  71. package/scripts/sw-tracker.sh +409 -0
  72. package/scripts/{cct-upgrade.sh → sw-upgrade.sh} +103 -46
  73. package/scripts/{cct-worktree.sh → sw-worktree.sh} +3 -0
  74. package/templates/pipelines/autonomous.json +27 -5
  75. package/templates/pipelines/full.json +12 -0
  76. package/templates/pipelines/standard.json +12 -0
  77. package/tmux/{claude-teams-overlay.conf → shipwright-overlay.conf} +27 -9
  78. package/tmux/templates/accessibility.json +34 -0
  79. package/tmux/templates/api-design.json +35 -0
  80. package/tmux/templates/architecture.json +1 -0
  81. package/tmux/templates/bug-fix.json +9 -0
  82. package/tmux/templates/code-review.json +1 -0
  83. package/tmux/templates/compliance.json +36 -0
  84. package/tmux/templates/data-pipeline.json +36 -0
  85. package/tmux/templates/debt-paydown.json +34 -0
  86. package/tmux/templates/devops.json +1 -0
  87. package/tmux/templates/documentation.json +1 -0
  88. package/tmux/templates/exploration.json +1 -0
  89. package/tmux/templates/feature-dev.json +1 -0
  90. package/tmux/templates/full-stack.json +8 -0
  91. package/tmux/templates/i18n.json +34 -0
  92. package/tmux/templates/incident-response.json +36 -0
  93. package/tmux/templates/migration.json +1 -0
  94. package/tmux/templates/observability.json +35 -0
  95. package/tmux/templates/onboarding.json +33 -0
  96. package/tmux/templates/performance.json +35 -0
  97. package/tmux/templates/refactor.json +1 -0
  98. package/tmux/templates/release.json +35 -0
  99. package/tmux/templates/security-audit.json +8 -0
  100. package/tmux/templates/spike.json +34 -0
  101. package/tmux/templates/testing.json +1 -0
  102. package/tmux/tmux.conf +98 -9
  103. package/scripts/cct-doctor.sh +0 -414
  104. package/scripts/cct-session.sh +0 -284
  105. package/scripts/cct-status.sh +0 -169
@@ -0,0 +1,591 @@
1
+ #!/usr/bin/env bash
2
+ # ╔═══════════════════════════════════════════════════════════════════════════╗
3
+ # ║ sw-tmux.sh — tmux Health & Plugin Management ║
4
+ # ║ ║
5
+ # ║ Diagnoses tmux + Claude Code compatibility, installs TPM plugins, ║
6
+ # ║ and auto-fixes common issues. Part of the Shipwright CLI. ║
7
+ # ║ ║
8
+ # ║ Usage: ║
9
+ # ║ shipwright tmux doctor — Check tmux features + Claude compat ║
10
+ # ║ shipwright tmux install — Install TPM + all plugins ║
11
+ # ║ shipwright tmux fix — Auto-fix common issues ║
12
+ # ║ shipwright tmux reload — Reload tmux config ║
13
+ # ╚═══════════════════════════════════════════════════════════════════════════╝
14
+ VERSION="1.9.0"
15
+ set -euo pipefail
16
+ trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
17
+
18
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
19
+ REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
20
+
21
+ # ─── Colors ──────────────────────────────────────────────────────────────────
22
+ CYAN='\033[38;2;0;212;255m'
23
+ PURPLE='\033[38;2;124;58;237m'
24
+ GREEN='\033[38;2;74;222;128m'
25
+ YELLOW='\033[38;2;250;204;21m'
26
+ RED='\033[38;2;248;113;113m'
27
+ DIM='\033[2m'
28
+ BOLD='\033[1m'
29
+ RESET='\033[0m'
30
+
31
+ # ─── Cross-platform compatibility ──────────────────────────────────────────
32
+ # shellcheck source=lib/compat.sh
33
+ [[ -f "$SCRIPT_DIR/lib/compat.sh" ]] && source "$SCRIPT_DIR/lib/compat.sh"
34
+ info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
35
+ success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
36
+ warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*"; }
37
+ error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
38
+
39
+ PASS=0
40
+ WARN=0
41
+ FAIL=0
42
+
43
+ check_pass() { success "$*"; PASS=$((PASS + 1)); }
44
+ check_warn() { warn "$*"; WARN=$((WARN + 1)); }
45
+ check_fail() { error "$*"; FAIL=$((FAIL + 1)); }
46
+
47
+ # ═════════════════════════════════════════════════════════════════════════════
48
+ # tmux doctor — Comprehensive tmux + Claude Code compatibility check
49
+ # ═════════════════════════════════════════════════════════════════════════════
50
+
51
+ tmux_doctor() {
52
+ echo ""
53
+ echo -e "${CYAN}${BOLD} Shipwright — tmux Doctor${RESET}"
54
+ echo -e "${DIM} $(date '+%Y-%m-%d %H:%M:%S')${RESET}"
55
+ echo -e "${DIM} ══════════════════════════════════════════${RESET}"
56
+ echo ""
57
+
58
+ # ─── 1. tmux installed + version ─────────────────────────────────────
59
+ echo -e "${BOLD}1. tmux Version${RESET}"
60
+ if ! command -v tmux &>/dev/null; then
61
+ check_fail "tmux not installed"
62
+ echo -e " ${DIM}brew install tmux (macOS)${RESET}"
63
+ echo -e " ${DIM}sudo apt install tmux (Ubuntu/Debian)${RESET}"
64
+ echo ""
65
+ echo -e "${RED}${BOLD}Cannot continue without tmux.${RESET}"
66
+ return 1
67
+ fi
68
+
69
+ local tmux_version tmux_major tmux_minor
70
+ tmux_version="$(tmux -V | grep -oE '[0-9]+\.[0-9a-z]+')"
71
+ tmux_major="$(echo "$tmux_version" | cut -d. -f1)"
72
+ tmux_minor="$(echo "$tmux_version" | cut -d. -f2 | tr -dc '0-9')"
73
+
74
+ if [[ "$tmux_major" -ge 3 && "$tmux_minor" -ge 3 ]] || [[ "$tmux_major" -ge 4 ]]; then
75
+ check_pass "tmux ${tmux_version} (all features supported)"
76
+ elif [[ "$tmux_major" -ge 3 && "$tmux_minor" -ge 2 ]]; then
77
+ check_warn "tmux ${tmux_version} — 3.3+ recommended for popup styling + allow-passthrough"
78
+ else
79
+ check_fail "tmux ${tmux_version} — 3.2+ required for popups, 3.3+ for passthrough"
80
+ echo -e " ${DIM}brew upgrade tmux${RESET}"
81
+ fi
82
+ echo ""
83
+
84
+ # ─── 2. Claude Code compatibility features ──────────────────────────
85
+ echo -e "${BOLD}2. Claude Code Compatibility${RESET}"
86
+
87
+ if [[ -n "${TMUX:-}" ]]; then
88
+ # Check allow-passthrough (DEC 2026 synchronized output)
89
+ local passthrough
90
+ passthrough="$(tmux show-option -gv allow-passthrough 2>/dev/null || echo "off")"
91
+ if [[ "$passthrough" == "on" ]]; then
92
+ check_pass "allow-passthrough: on (DEC 2026 synchronized output works)"
93
+ else
94
+ check_fail "allow-passthrough: ${passthrough} — Claude Code will flicker"
95
+ echo -e " ${DIM}Fix: set -g allow-passthrough on${RESET}"
96
+ fi
97
+
98
+ # Check extended-keys
99
+ local extkeys
100
+ extkeys="$(tmux show-option -gv extended-keys 2>/dev/null || echo "off")"
101
+ if [[ "$extkeys" == "on" ]]; then
102
+ check_pass "extended-keys: on (better key handling for TUI apps)"
103
+ else
104
+ check_warn "extended-keys: ${extkeys} — some key combos may not work"
105
+ echo -e " ${DIM}Fix: set -g extended-keys on${RESET}"
106
+ fi
107
+
108
+ # Check escape-time
109
+ local esc_time
110
+ esc_time="$(tmux show-option -gv escape-time 2>/dev/null || echo "500")"
111
+ if [[ "$esc_time" -le 10 ]]; then
112
+ check_pass "escape-time: ${esc_time}ms (no input delay)"
113
+ else
114
+ check_fail "escape-time: ${esc_time}ms — causes input lag in Claude Code"
115
+ echo -e " ${DIM}Fix: set -sg escape-time 0${RESET}"
116
+ fi
117
+
118
+ # Check set-clipboard
119
+ local clipboard
120
+ clipboard="$(tmux show-option -gv set-clipboard 2>/dev/null || echo "off")"
121
+ if [[ "$clipboard" == "on" || "$clipboard" == "external" ]]; then
122
+ check_pass "set-clipboard: ${clipboard} (OSC 52 clipboard works)"
123
+ else
124
+ check_warn "set-clipboard: ${clipboard} — clipboard may not work in SSH"
125
+ echo -e " ${DIM}Fix: set -g set-clipboard on${RESET}"
126
+ fi
127
+
128
+ # Check history-limit
129
+ local hist
130
+ hist="$(tmux show-option -gv history-limit 2>/dev/null || echo "2000")"
131
+ if [[ "$hist" -ge 100000 ]]; then
132
+ check_pass "history-limit: ${hist} (sufficient for Claude Code output)"
133
+ elif [[ "$hist" -ge 50000 ]]; then
134
+ check_warn "history-limit: ${hist} — 250000+ recommended for long agent runs"
135
+ else
136
+ check_fail "history-limit: ${hist} — will overflow during Claude Code streaming"
137
+ echo -e " ${DIM}Fix: set -g history-limit 250000${RESET}"
138
+ fi
139
+
140
+ # Check focus-events
141
+ local focus
142
+ focus="$(tmux show-option -gv focus-events 2>/dev/null || echo "off")"
143
+ if [[ "$focus" == "on" ]]; then
144
+ check_pass "focus-events: on"
145
+ else
146
+ check_warn "focus-events: ${focus} — some TUI features won't work"
147
+ fi
148
+
149
+ # Check default-terminal
150
+ local term
151
+ term="$(tmux show-option -gv default-terminal 2>/dev/null || echo "unknown")"
152
+ if [[ "$term" == *"256color"* ]]; then
153
+ check_pass "default-terminal: ${term}"
154
+ else
155
+ check_warn "default-terminal: ${term} — 256color variant recommended"
156
+ fi
157
+ else
158
+ info "Not in tmux session — checking config file instead"
159
+ if [[ -f "$HOME/.tmux.conf" ]]; then
160
+ if grep -q "allow-passthrough" "$HOME/.tmux.conf" 2>/dev/null; then
161
+ check_pass "allow-passthrough found in ~/.tmux.conf"
162
+ else
163
+ check_fail "allow-passthrough not in ~/.tmux.conf — Claude Code will flicker"
164
+ fi
165
+ if grep -q "extended-keys" "$HOME/.tmux.conf" 2>/dev/null; then
166
+ check_pass "extended-keys found in ~/.tmux.conf"
167
+ else
168
+ check_warn "extended-keys not in ~/.tmux.conf"
169
+ fi
170
+ else
171
+ check_fail "No ~/.tmux.conf found"
172
+ fi
173
+ fi
174
+ echo ""
175
+
176
+ # ─── 3. Plugin Manager ───────────────────────────────────────────────
177
+ echo -e "${BOLD}3. Plugin Manager (TPM)${RESET}"
178
+
179
+ if [[ -d "$HOME/.tmux/plugins/tpm" ]]; then
180
+ check_pass "TPM installed: ~/.tmux/plugins/tpm"
181
+ else
182
+ check_fail "TPM not installed"
183
+ echo -e " ${DIM}Run: shipwright tmux install${RESET}"
184
+ fi
185
+
186
+ # Check individual plugins
187
+ local plugins=("tmux-sensible" "tmux-resurrect" "tmux-continuum" "tmux-yank" "tmux-fzf")
188
+ for plugin in "${plugins[@]}"; do
189
+ local plugin_dir=""
190
+ # tmux-fzf is under sainnhe org
191
+ if [[ "$plugin" == "tmux-fzf" ]]; then
192
+ plugin_dir="$HOME/.tmux/plugins/tmux-fzf"
193
+ else
194
+ plugin_dir="$HOME/.tmux/plugins/${plugin}"
195
+ fi
196
+ if [[ -d "$plugin_dir" ]]; then
197
+ check_pass "Plugin: ${plugin}"
198
+ else
199
+ check_warn "Plugin not installed: ${plugin}"
200
+ echo -e " ${DIM}Press prefix + I inside tmux to install${RESET}"
201
+ fi
202
+ done
203
+ echo ""
204
+
205
+ # ─── 4. Shipwright overlay ───────────────────────────────────────────
206
+ echo -e "${BOLD}4. Shipwright Integration${RESET}"
207
+
208
+ if [[ -f "$HOME/.tmux/shipwright-overlay.conf" ]]; then
209
+ check_pass "Overlay: ~/.tmux/shipwright-overlay.conf"
210
+ else
211
+ check_fail "Overlay not found"
212
+ echo -e " ${DIM}Run: shipwright init${RESET}"
213
+ fi
214
+
215
+ if [[ -f "$HOME/.tmux.conf" ]] && grep -q "shipwright-overlay" "$HOME/.tmux.conf" 2>/dev/null; then
216
+ check_pass "Overlay sourced in ~/.tmux.conf"
217
+ else
218
+ check_warn "Overlay not sourced in ~/.tmux.conf"
219
+ echo -e " ${DIM}Add: source-file -q ~/.tmux/shipwright-overlay.conf${RESET}"
220
+ fi
221
+
222
+ if [[ -n "${TMUX:-}" ]]; then
223
+ # Check pane-border-status
224
+ local border_status
225
+ border_status="$(tmux show-option -gv pane-border-status 2>/dev/null || echo "off")"
226
+ if [[ "$border_status" == "top" ]]; then
227
+ check_pass "pane-border-status: top (agent names visible)"
228
+ else
229
+ check_warn "pane-border-status: ${border_status} — agent names won't show"
230
+ fi
231
+
232
+ # Check dark theme hooks
233
+ if tmux show-hooks -g 2>/dev/null | grep -q "after-split-window"; then
234
+ check_pass "Dark theme hooks active"
235
+ else
236
+ check_warn "Dark theme hooks not active — new panes may flash white"
237
+ fi
238
+
239
+ # Check mouse
240
+ local mouse
241
+ mouse="$(tmux show-option -gv mouse 2>/dev/null || echo "off")"
242
+ if [[ "$mouse" == "on" ]]; then
243
+ check_pass "Mouse: on"
244
+ else
245
+ check_warn "Mouse: off — enable for better agent pane interaction"
246
+ fi
247
+ fi
248
+ echo ""
249
+
250
+ # ─── 5. Known Issues ─────────────────────────────────────────────────
251
+ echo -e "${BOLD}5. Known Issues Check${RESET}"
252
+
253
+ if [[ -n "${TMUX:-}" ]]; then
254
+ # Check pane-base-index compatibility
255
+ local pbi
256
+ pbi="$(tmux show-window-option -gv pane-base-index 2>/dev/null || echo "0")"
257
+ if [[ "$pbi" != "0" ]]; then
258
+ check_warn "pane-base-index: ${pbi} — Claude Code teammate mode may misaddress panes"
259
+ echo -e " ${DIM}Shipwright adapter uses pane IDs to work around this${RESET}"
260
+ else
261
+ check_pass "pane-base-index: 0 (Claude Code compatible)"
262
+ fi
263
+
264
+ # Check for MouseDown1Status fix
265
+ local mouse_bind
266
+ mouse_bind="$(tmux list-keys 2>/dev/null | grep 'MouseDown1Status' | head -1 || true)"
267
+ if echo "$mouse_bind" | grep -q "select-window"; then
268
+ check_pass "MouseDown1Status: select-window (clicks work correctly)"
269
+ elif [[ -n "$mouse_bind" ]]; then
270
+ check_warn "MouseDown1Status: may switch sessions instead of windows"
271
+ echo -e " ${DIM}Fix: bind -T root MouseDown1Status select-window -t =${RESET}"
272
+ fi
273
+ fi
274
+
275
+ # Check terminal emulator
276
+ local parent_term="${LC_TERMINAL:-${TERM_PROGRAM:-unknown}}"
277
+ case "$parent_term" in
278
+ *Ghostty*|*ghostty*)
279
+ check_pass "Terminal: Ghostty (best Claude Code + tmux compat)"
280
+ ;;
281
+ *iTerm*|*iterm*)
282
+ check_pass "Terminal: iTerm2 (good compat, true color)"
283
+ ;;
284
+ *kitty*)
285
+ check_pass "Terminal: kitty (good compat)"
286
+ ;;
287
+ *WezTerm*|*wezterm*)
288
+ check_pass "Terminal: WezTerm (good compat)"
289
+ ;;
290
+ *Alacritty*|*alacritty*)
291
+ check_pass "Terminal: Alacritty (good compat)"
292
+ ;;
293
+ *Apple_Terminal*|*Terminal*)
294
+ check_warn "Terminal: Apple Terminal — limited color support, no true color"
295
+ echo -e " ${DIM}Recommend: iTerm2, Ghostty, or WezTerm for full experience${RESET}"
296
+ ;;
297
+ *)
298
+ info "Terminal: ${parent_term}"
299
+ ;;
300
+ esac
301
+ echo ""
302
+
303
+ # ─── Summary ─────────────────────────────────────────────────────────
304
+ echo -e "${DIM} ──────────────────────────────────────────${RESET}"
305
+ echo -e " ${GREEN}${BOLD}${PASS} passed${RESET} ${YELLOW}${BOLD}${WARN} warnings${RESET} ${RED}${BOLD}${FAIL} failed${RESET}"
306
+
307
+ if [[ $FAIL -gt 0 ]]; then
308
+ echo ""
309
+ echo -e " Run ${CYAN}${BOLD}shipwright tmux fix${RESET} to auto-fix issues."
310
+ elif [[ $WARN -gt 0 ]]; then
311
+ echo ""
312
+ echo -e " ${GREEN}Good shape!${RESET} Warnings are informational."
313
+ else
314
+ echo ""
315
+ echo -e " ${GREEN}${BOLD}Perfect setup!${RESET} tmux + Claude Code fully optimized."
316
+ fi
317
+ echo ""
318
+ }
319
+
320
+ # ═════════════════════════════════════════════════════════════════════════════
321
+ # tmux install — Install TPM and all plugins
322
+ # ═════════════════════════════════════════════════════════════════════════════
323
+
324
+ tmux_install() {
325
+ echo ""
326
+ echo -e "${CYAN}${BOLD} Shipwright — tmux Plugin Installer${RESET}"
327
+ echo -e "${DIM} ══════════════════════════════════════════${RESET}"
328
+ echo ""
329
+
330
+ # Install TPM if not present
331
+ if [[ ! -d "$HOME/.tmux/plugins/tpm" ]]; then
332
+ info "Installing TPM (Tmux Plugin Manager)..."
333
+ if git clone https://github.com/tmux-plugins/tpm "$HOME/.tmux/plugins/tpm" 2>/dev/null; then
334
+ success "TPM installed"
335
+ else
336
+ error "Failed to clone TPM — check git + network"
337
+ return 1
338
+ fi
339
+ else
340
+ success "TPM already installed"
341
+ fi
342
+
343
+ # Install Shipwright tmux.conf if not present
344
+ if [[ -f "$REPO_DIR/tmux/tmux.conf" ]]; then
345
+ if [[ ! -f "$HOME/.tmux.conf" ]]; then
346
+ cp "$REPO_DIR/tmux/tmux.conf" "$HOME/.tmux.conf"
347
+ success "Installed ~/.tmux.conf"
348
+ else
349
+ info "~/.tmux.conf exists — run 'shipwright init' to update"
350
+ fi
351
+ fi
352
+
353
+ # Install overlay
354
+ if [[ -f "$REPO_DIR/tmux/shipwright-overlay.conf" ]]; then
355
+ mkdir -p "$HOME/.tmux"
356
+ cp "$REPO_DIR/tmux/shipwright-overlay.conf" "$HOME/.tmux/shipwright-overlay.conf"
357
+ success "Installed ~/.tmux/shipwright-overlay.conf"
358
+ fi
359
+
360
+ # Trigger TPM plugin install
361
+ if [[ -x "$HOME/.tmux/plugins/tpm/bin/install_plugins" ]]; then
362
+ info "Installing tmux plugins via TPM..."
363
+ "$HOME/.tmux/plugins/tpm/bin/install_plugins" 2>/dev/null && \
364
+ success "All plugins installed" || \
365
+ warn "Some plugins may not have installed — press prefix + I inside tmux"
366
+ else
367
+ warn "TPM install script not found — press prefix + I inside tmux to install plugins"
368
+ fi
369
+
370
+ # Reload config if inside tmux
371
+ if [[ -n "${TMUX:-}" ]]; then
372
+ tmux source-file "$HOME/.tmux.conf" 2>/dev/null && \
373
+ success "tmux config reloaded" || true
374
+ fi
375
+
376
+ echo ""
377
+ success "tmux setup complete!"
378
+ echo ""
379
+ echo -e "${BOLD}Plugins installed:${RESET}"
380
+ echo -e " ${CYAN}tmux-sensible${RESET} — Sensible defaults everyone agrees on"
381
+ echo -e " ${CYAN}tmux-resurrect${RESET} — Persist sessions across restarts"
382
+ echo -e " ${CYAN}tmux-continuum${RESET} — Auto-save every 15 min, auto-restore"
383
+ echo -e " ${CYAN}tmux-yank${RESET} — System clipboard integration (OSC 52)"
384
+ echo -e " ${CYAN}tmux-fzf${RESET} — Fuzzy finder for sessions/windows/panes"
385
+ echo ""
386
+ echo -e "${BOLD}Key bindings added:${RESET}"
387
+ echo -e " ${CYAN}prefix + F${RESET} — Floating popup terminal"
388
+ echo -e " ${CYAN}prefix + C-f${RESET} — FZF session switcher"
389
+ echo -e " ${CYAN}prefix + T${RESET} — Launch Shipwright team session"
390
+ echo -e " ${CYAN}prefix + C-t${RESET} — Team dashboard popup"
391
+ echo -e " ${CYAN}prefix + M-d${RESET} — Full dashboard popup"
392
+ echo -e " ${CYAN}prefix + M-m${RESET} — Memory system popup"
393
+ echo -e " ${CYAN}prefix + R${RESET} — Reap dead agent panes"
394
+ echo ""
395
+ }
396
+
397
+ # ═════════════════════════════════════════════════════════════════════════════
398
+ # tmux fix — Auto-fix common tmux + Claude Code issues
399
+ # ═════════════════════════════════════════════════════════════════════════════
400
+
401
+ tmux_fix() {
402
+ echo ""
403
+ echo -e "${CYAN}${BOLD} Shipwright — tmux Auto-Fix${RESET}"
404
+ echo -e "${DIM} ══════════════════════════════════════════${RESET}"
405
+ echo ""
406
+
407
+ local fixed=0
408
+
409
+ if [[ -z "${TMUX:-}" ]]; then
410
+ error "Not inside a tmux session — start tmux first"
411
+ return 1
412
+ fi
413
+
414
+ # Fix 1: allow-passthrough
415
+ local passthrough
416
+ passthrough="$(tmux show-option -gv allow-passthrough 2>/dev/null || echo "off")"
417
+ if [[ "$passthrough" != "on" ]]; then
418
+ tmux set -g allow-passthrough on 2>/dev/null
419
+ success "Fixed: allow-passthrough → on (eliminates Claude Code flicker)"
420
+ fixed=$((fixed + 1))
421
+ fi
422
+
423
+ # Fix 2: extended-keys
424
+ local extkeys
425
+ extkeys="$(tmux show-option -gv extended-keys 2>/dev/null || echo "off")"
426
+ if [[ "$extkeys" != "on" ]]; then
427
+ tmux set -g extended-keys on 2>/dev/null
428
+ success "Fixed: extended-keys → on"
429
+ fixed=$((fixed + 1))
430
+ fi
431
+
432
+ # Fix 3: escape-time
433
+ local esc_time
434
+ esc_time="$(tmux show-option -gv escape-time 2>/dev/null || echo "500")"
435
+ if [[ "$esc_time" -gt 10 ]]; then
436
+ tmux set -sg escape-time 0 2>/dev/null
437
+ success "Fixed: escape-time → 0 (was ${esc_time}ms)"
438
+ fixed=$((fixed + 1))
439
+ fi
440
+
441
+ # Fix 4: set-clipboard
442
+ local clipboard
443
+ clipboard="$(tmux show-option -gv set-clipboard 2>/dev/null || echo "off")"
444
+ if [[ "$clipboard" == "off" ]]; then
445
+ tmux set -g set-clipboard on 2>/dev/null
446
+ success "Fixed: set-clipboard → on"
447
+ fixed=$((fixed + 1))
448
+ fi
449
+
450
+ # Fix 5: history-limit
451
+ local hist
452
+ hist="$(tmux show-option -gv history-limit 2>/dev/null || echo "2000")"
453
+ if [[ "$hist" -lt 100000 ]]; then
454
+ tmux set -g history-limit 250000 2>/dev/null
455
+ success "Fixed: history-limit → 250000 (was ${hist})"
456
+ fixed=$((fixed + 1))
457
+ fi
458
+
459
+ # Fix 6: focus-events
460
+ local focus
461
+ focus="$(tmux show-option -gv focus-events 2>/dev/null || echo "off")"
462
+ if [[ "$focus" != "on" ]]; then
463
+ tmux set -g focus-events on 2>/dev/null
464
+ success "Fixed: focus-events → on"
465
+ fixed=$((fixed + 1))
466
+ fi
467
+
468
+ # Fix 7: mouse
469
+ local mouse
470
+ mouse="$(tmux show-option -gv mouse 2>/dev/null || echo "off")"
471
+ if [[ "$mouse" != "on" ]]; then
472
+ tmux set -g mouse on 2>/dev/null
473
+ success "Fixed: mouse → on"
474
+ fixed=$((fixed + 1))
475
+ fi
476
+
477
+ # Fix 8: MouseDown1Status
478
+ local mouse_bind
479
+ mouse_bind="$(tmux list-keys 2>/dev/null | grep 'MouseDown1Status' | head -1 || true)"
480
+ if ! echo "$mouse_bind" | grep -q "select-window"; then
481
+ tmux bind -T root MouseDown1Status select-window -t = 2>/dev/null
482
+ success "Fixed: MouseDown1Status → select-window"
483
+ fixed=$((fixed + 1))
484
+ fi
485
+
486
+ # Fix 9: dark theme hooks
487
+ if ! tmux show-hooks -g 2>/dev/null | grep -q "after-split-window"; then
488
+ tmux set-hook -g after-split-window "select-pane -P 'bg=#1a1a2e,fg=#e4e4e7'" 2>/dev/null
489
+ tmux set-hook -g after-new-window "select-pane -P 'bg=#1a1a2e,fg=#e4e4e7'" 2>/dev/null
490
+ tmux set-hook -g after-new-session "select-pane -P 'bg=#1a1a2e,fg=#e4e4e7'" 2>/dev/null
491
+ success "Fixed: dark theme hooks installed"
492
+ fixed=$((fixed + 1))
493
+ fi
494
+
495
+ # Fix 10: pane-border-status
496
+ local border_status
497
+ border_status="$(tmux show-option -gv pane-border-status 2>/dev/null || echo "off")"
498
+ if [[ "$border_status" != "top" ]]; then
499
+ tmux set -g pane-border-status top 2>/dev/null
500
+ success "Fixed: pane-border-status → top (agent names visible)"
501
+ fixed=$((fixed + 1))
502
+ fi
503
+
504
+ echo ""
505
+ if [[ $fixed -eq 0 ]]; then
506
+ success "No fixes needed — tmux is already optimized!"
507
+ else
508
+ success "Applied ${fixed} fixes"
509
+ echo ""
510
+ echo -e "${DIM}These fixes are applied to the running session only.${RESET}"
511
+ echo -e "${DIM}For persistence, update your tmux config:${RESET}"
512
+ echo -e "${DIM} shipwright init${RESET}"
513
+ fi
514
+ echo ""
515
+ }
516
+
517
+ # ═════════════════════════════════════════════════════════════════════════════
518
+ # tmux reload — Reload tmux configuration
519
+ # ═════════════════════════════════════════════════════════════════════════════
520
+
521
+ tmux_reload() {
522
+ if [[ -z "${TMUX:-}" ]]; then
523
+ error "Not inside a tmux session"
524
+ return 1
525
+ fi
526
+
527
+ if [[ -f "$HOME/.tmux.conf" ]]; then
528
+ tmux source-file "$HOME/.tmux.conf" 2>/dev/null && \
529
+ success "tmux config reloaded" || \
530
+ error "Failed to reload — check config syntax"
531
+ else
532
+ error "No ~/.tmux.conf found"
533
+ fi
534
+ }
535
+
536
+ # ═════════════════════════════════════════════════════════════════════════════
537
+ # Main dispatcher
538
+ # ═════════════════════════════════════════════════════════════════════════════
539
+
540
+ show_help() {
541
+ echo -e "${CYAN}${BOLD}shipwright tmux${RESET} — tmux Health & Plugin Management"
542
+ echo ""
543
+ echo -e "${BOLD}USAGE${RESET}"
544
+ echo -e " shipwright tmux <command>"
545
+ echo ""
546
+ echo -e "${BOLD}COMMANDS${RESET}"
547
+ echo -e " ${CYAN}doctor${RESET} Check tmux features + Claude Code compatibility"
548
+ echo -e " ${CYAN}install${RESET} Install TPM + all plugins"
549
+ echo -e " ${CYAN}fix${RESET} Auto-fix common issues in running session"
550
+ echo -e " ${CYAN}reload${RESET} Reload tmux configuration"
551
+ echo ""
552
+ echo -e "${BOLD}Claude Code Compatibility${RESET}"
553
+ echo -e " Shipwright configures tmux for optimal Claude Code TUI compatibility:"
554
+ echo -e " ${DIM}• allow-passthrough: DEC 2026 synchronized output (no flicker)${RESET}"
555
+ echo -e " ${DIM}• extended-keys: better key handling for TUI apps${RESET}"
556
+ echo -e " ${DIM}• escape-time 0: no input delay${RESET}"
557
+ echo -e " ${DIM}• history-limit 250000: handles Claude Code's high output volume${RESET}"
558
+ echo -e " ${DIM}• set-clipboard on: native OSC 52 clipboard${RESET}"
559
+ echo -e " ${DIM}• pane IDs (not indices): fixes teammate pane-base-index bug${RESET}"
560
+ echo ""
561
+ echo -e "${BOLD}Plugins${RESET}"
562
+ echo -e " ${DIM}tmux-sensible — Sensible defaults${RESET}"
563
+ echo -e " ${DIM}tmux-resurrect — Persist sessions across restarts${RESET}"
564
+ echo -e " ${DIM}tmux-continuum — Auto-save + auto-restore${RESET}"
565
+ echo -e " ${DIM}tmux-yank — System clipboard (OSC 52)${RESET}"
566
+ echo -e " ${DIM}tmux-fzf — Fuzzy finder for sessions/windows/panes${RESET}"
567
+ echo ""
568
+ }
569
+
570
+ case "${1:-}" in
571
+ doctor|check|status)
572
+ tmux_doctor
573
+ ;;
574
+ install|setup)
575
+ tmux_install
576
+ ;;
577
+ fix|repair)
578
+ tmux_fix
579
+ ;;
580
+ reload)
581
+ tmux_reload
582
+ ;;
583
+ --help|-h|help|"")
584
+ show_help
585
+ ;;
586
+ *)
587
+ error "Unknown command: $1"
588
+ echo -e " Run ${CYAN}shipwright tmux --help${RESET} for usage."
589
+ exit 1
590
+ ;;
591
+ esac