shipwright-cli 1.7.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 (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +926 -0
  3. package/claude-code/CLAUDE.md.shipwright +125 -0
  4. package/claude-code/hooks/notify-idle.sh +35 -0
  5. package/claude-code/hooks/pre-compact-save.sh +57 -0
  6. package/claude-code/hooks/task-completed.sh +170 -0
  7. package/claude-code/hooks/teammate-idle.sh +68 -0
  8. package/claude-code/settings.json.template +184 -0
  9. package/completions/_shipwright +140 -0
  10. package/completions/shipwright.bash +89 -0
  11. package/completions/shipwright.fish +107 -0
  12. package/docs/KNOWN-ISSUES.md +199 -0
  13. package/docs/TIPS.md +331 -0
  14. package/docs/definition-of-done.example.md +16 -0
  15. package/docs/patterns/README.md +139 -0
  16. package/docs/patterns/audit-loop.md +149 -0
  17. package/docs/patterns/bug-hunt.md +183 -0
  18. package/docs/patterns/feature-implementation.md +159 -0
  19. package/docs/patterns/refactoring.md +183 -0
  20. package/docs/patterns/research-exploration.md +144 -0
  21. package/docs/patterns/test-generation.md +173 -0
  22. package/package.json +49 -0
  23. package/scripts/adapters/docker-deploy.sh +50 -0
  24. package/scripts/adapters/fly-deploy.sh +41 -0
  25. package/scripts/adapters/iterm2-adapter.sh +122 -0
  26. package/scripts/adapters/railway-deploy.sh +34 -0
  27. package/scripts/adapters/tmux-adapter.sh +87 -0
  28. package/scripts/adapters/vercel-deploy.sh +35 -0
  29. package/scripts/adapters/wezterm-adapter.sh +103 -0
  30. package/scripts/cct +242 -0
  31. package/scripts/cct-cleanup.sh +172 -0
  32. package/scripts/cct-cost.sh +590 -0
  33. package/scripts/cct-daemon.sh +3189 -0
  34. package/scripts/cct-doctor.sh +328 -0
  35. package/scripts/cct-fix.sh +478 -0
  36. package/scripts/cct-fleet.sh +904 -0
  37. package/scripts/cct-init.sh +282 -0
  38. package/scripts/cct-logs.sh +273 -0
  39. package/scripts/cct-loop.sh +1332 -0
  40. package/scripts/cct-memory.sh +1148 -0
  41. package/scripts/cct-pipeline.sh +3844 -0
  42. package/scripts/cct-prep.sh +1352 -0
  43. package/scripts/cct-ps.sh +168 -0
  44. package/scripts/cct-reaper.sh +390 -0
  45. package/scripts/cct-session.sh +284 -0
  46. package/scripts/cct-status.sh +169 -0
  47. package/scripts/cct-templates.sh +242 -0
  48. package/scripts/cct-upgrade.sh +422 -0
  49. package/scripts/cct-worktree.sh +405 -0
  50. package/scripts/postinstall.mjs +96 -0
  51. package/templates/pipelines/autonomous.json +71 -0
  52. package/templates/pipelines/cost-aware.json +95 -0
  53. package/templates/pipelines/deployed.json +79 -0
  54. package/templates/pipelines/enterprise.json +114 -0
  55. package/templates/pipelines/fast.json +63 -0
  56. package/templates/pipelines/full.json +104 -0
  57. package/templates/pipelines/hotfix.json +63 -0
  58. package/templates/pipelines/standard.json +91 -0
  59. package/tmux/claude-teams-overlay.conf +109 -0
  60. package/tmux/templates/architecture.json +19 -0
  61. package/tmux/templates/bug-fix.json +24 -0
  62. package/tmux/templates/code-review.json +24 -0
  63. package/tmux/templates/devops.json +19 -0
  64. package/tmux/templates/documentation.json +19 -0
  65. package/tmux/templates/exploration.json +19 -0
  66. package/tmux/templates/feature-dev.json +24 -0
  67. package/tmux/templates/full-stack.json +24 -0
  68. package/tmux/templates/migration.json +24 -0
  69. package/tmux/templates/refactor.json +19 -0
  70. package/tmux/templates/security-audit.json +24 -0
  71. package/tmux/templates/testing.json +24 -0
  72. package/tmux/tmux.conf +167 -0
@@ -0,0 +1,328 @@
1
+ #!/usr/bin/env bash
2
+ # ╔═══════════════════════════════════════════════════════════════════════════╗
3
+ # ║ cct-doctor.sh — Validate Claude Code Teams setup ║
4
+ # ║ ║
5
+ # ║ Checks prerequisites, installed files, PATH, and common issues. ║
6
+ # ╚═══════════════════════════════════════════════════════════════════════════╝
7
+ set -euo pipefail
8
+
9
+ # ─── Colors ──────────────────────────────────────────────────────────────────
10
+ CYAN='\033[38;2;0;212;255m'
11
+ PURPLE='\033[38;2;124;58;237m'
12
+ BLUE='\033[38;2;0;102;255m'
13
+ GREEN='\033[38;2;74;222;128m'
14
+ YELLOW='\033[38;2;250;204;21m'
15
+ RED='\033[38;2;248;113;113m'
16
+ DIM='\033[2m'
17
+ BOLD='\033[1m'
18
+ RESET='\033[0m'
19
+
20
+ # ─── Helpers ─────────────────────────────────────────────────────────────────
21
+ info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
22
+ success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
23
+ warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*"; }
24
+ error() { echo -e "${RED}${BOLD}✗${RESET} $*"; }
25
+
26
+ PASS=0
27
+ WARN=0
28
+ FAIL=0
29
+
30
+ check_pass() { success "$*"; PASS=$((PASS + 1)); }
31
+ check_warn() { warn "$*"; WARN=$((WARN + 1)); }
32
+ check_fail() { error "$*"; FAIL=$((FAIL + 1)); }
33
+
34
+ # ─── Header ─────────────────────────────────────────────────────────────────
35
+ echo ""
36
+ echo -e "${CYAN}${BOLD} Claude Code Teams — Doctor${RESET}"
37
+ echo -e "${DIM} $(date '+%Y-%m-%d %H:%M:%S')${RESET}"
38
+ echo -e "${DIM} ══════════════════════════════════════════${RESET}"
39
+ echo ""
40
+
41
+ # ═════════════════════════════════════════════════════════════════════════════
42
+ # 1. Prerequisites
43
+ # ═════════════════════════════════════════════════════════════════════════════
44
+ echo -e "${PURPLE}${BOLD} PREREQUISITES${RESET}"
45
+ echo -e "${DIM} ──────────────────────────────────────────${RESET}"
46
+
47
+ # tmux
48
+ if command -v tmux &>/dev/null; then
49
+ TMUX_VERSION="$(tmux -V | grep -oE '[0-9]+\.[0-9a-z]+')"
50
+ TMUX_MAJOR="$(echo "$TMUX_VERSION" | cut -d. -f1)"
51
+ TMUX_MINOR="$(echo "$TMUX_VERSION" | cut -d. -f2 | tr -dc '0-9')"
52
+ if [[ "$TMUX_MAJOR" -ge 3 && "$TMUX_MINOR" -ge 2 ]] || [[ "$TMUX_MAJOR" -ge 4 ]]; then
53
+ check_pass "tmux ${TMUX_VERSION}"
54
+ else
55
+ check_warn "tmux ${TMUX_VERSION} — 3.2+ recommended for pane-border-format"
56
+ fi
57
+ else
58
+ check_fail "tmux not installed"
59
+ echo -e " ${DIM}brew install tmux (macOS)${RESET}"
60
+ echo -e " ${DIM}sudo apt install tmux (Ubuntu/Debian)${RESET}"
61
+ fi
62
+
63
+ # jq
64
+ if command -v jq &>/dev/null; then
65
+ check_pass "jq $(jq --version 2>&1 | tr -d 'jq-')"
66
+ else
67
+ check_fail "jq not installed — required for template parsing"
68
+ echo -e " ${DIM}brew install jq${RESET} (macOS)"
69
+ echo -e " ${DIM}sudo apt install jq${RESET} (Ubuntu/Debian)"
70
+ fi
71
+
72
+ # Claude Code CLI
73
+ if command -v claude &>/dev/null; then
74
+ check_pass "Claude Code CLI found"
75
+ else
76
+ check_fail "Claude Code CLI not found"
77
+ echo -e " ${DIM}npm install -g @anthropic-ai/claude-code${RESET}"
78
+ fi
79
+
80
+ # Node.js
81
+ if command -v node &>/dev/null; then
82
+ NODE_VERSION="$(node -v | tr -d 'v')"
83
+ NODE_MAJOR="$(echo "$NODE_VERSION" | cut -d. -f1)"
84
+ if [[ "$NODE_MAJOR" -ge 20 ]]; then
85
+ check_pass "Node.js ${NODE_VERSION}"
86
+ else
87
+ check_warn "Node.js ${NODE_VERSION} — 20+ recommended"
88
+ fi
89
+ else
90
+ check_fail "Node.js not found"
91
+ fi
92
+
93
+ # Git
94
+ if command -v git &>/dev/null; then
95
+ check_pass "git $(git --version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')"
96
+ else
97
+ check_fail "git not found"
98
+ fi
99
+
100
+ # ═════════════════════════════════════════════════════════════════════════════
101
+ # 2. Installed Files
102
+ # ═════════════════════════════════════════════════════════════════════════════
103
+ echo ""
104
+ echo -e "${PURPLE}${BOLD} INSTALLED FILES${RESET}"
105
+ echo -e "${DIM} ──────────────────────────────────────────${RESET}"
106
+
107
+ # tmux overlay
108
+ if [[ -f "$HOME/.tmux/claude-teams-overlay.conf" ]]; then
109
+ check_pass "Overlay: ~/.tmux/claude-teams-overlay.conf"
110
+ else
111
+ check_fail "Overlay not found: ~/.tmux/claude-teams-overlay.conf"
112
+ echo -e " ${DIM}Re-run install.sh to install it${RESET}"
113
+ fi
114
+
115
+ # Overlay sourced in tmux.conf
116
+ if [[ -f "$HOME/.tmux.conf" ]]; then
117
+ if grep -q "claude-teams-overlay" "$HOME/.tmux.conf" 2>/dev/null; then
118
+ check_pass "Overlay sourced in ~/.tmux.conf"
119
+ else
120
+ check_warn "Overlay not sourced in ~/.tmux.conf"
121
+ echo -e " ${DIM}Add: source-file -q ~/.tmux/claude-teams-overlay.conf${RESET}"
122
+ fi
123
+ else
124
+ check_warn "No ~/.tmux.conf found"
125
+ fi
126
+
127
+ # Claude settings
128
+ if [[ -f "$HOME/.claude/settings.json" ]]; then
129
+ check_pass "Settings: ~/.claude/settings.json"
130
+ else
131
+ check_warn "No ~/.claude/settings.json"
132
+ echo -e " ${DIM}Copy from settings.json.template${RESET}"
133
+ fi
134
+
135
+ # Hooks directory
136
+ HOOKS_DIR="$HOME/.claude/hooks"
137
+ if [[ -d "$HOOKS_DIR" ]]; then
138
+ hook_count=0
139
+ non_exec=0
140
+ while IFS= read -r hook; do
141
+ [[ -z "$hook" ]] && continue
142
+ hook_count=$((hook_count + 1))
143
+ if [[ ! -x "$hook" ]]; then
144
+ non_exec=$((non_exec + 1))
145
+ fi
146
+ done < <(find "$HOOKS_DIR" -maxdepth 1 -name '*.sh' -type f 2>/dev/null)
147
+
148
+ if [[ $hook_count -gt 0 && $non_exec -eq 0 ]]; then
149
+ check_pass "Hooks: ${hook_count} scripts, all executable"
150
+ elif [[ $hook_count -gt 0 && $non_exec -gt 0 ]]; then
151
+ check_warn "Hooks: ${non_exec}/${hook_count} scripts not executable"
152
+ echo -e " ${DIM}chmod +x ~/.claude/hooks/*.sh${RESET}"
153
+ else
154
+ check_warn "Hooks dir exists but no .sh scripts found"
155
+ fi
156
+ else
157
+ check_warn "No hooks directory at ~/.claude/hooks/"
158
+ fi
159
+
160
+ # ═════════════════════════════════════════════════════════════════════════════
161
+ # 3. PATH & CLI
162
+ # ═════════════════════════════════════════════════════════════════════════════
163
+ echo ""
164
+ echo -e "${PURPLE}${BOLD} PATH & CLI${RESET}"
165
+ echo -e "${DIM} ──────────────────────────────────────────${RESET}"
166
+
167
+ BIN_DIR="$HOME/.local/bin"
168
+
169
+ if echo "$PATH" | tr ':' '\n' | grep -q "$BIN_DIR"; then
170
+ check_pass "${BIN_DIR} is in PATH"
171
+ else
172
+ check_warn "${BIN_DIR} is NOT in PATH"
173
+ echo -e " ${DIM}Add to ~/.zshrc or ~/.bashrc:${RESET}"
174
+ echo -e " ${DIM}export PATH=\"\$HOME/.local/bin:\$PATH\"${RESET}"
175
+ fi
176
+
177
+ # Check cct subcommands are installed alongside the router
178
+ if command -v cct &>/dev/null; then
179
+ CCT_DIR="$(dirname "$(command -v cct)")"
180
+ check_pass "shipwright router found at ${CCT_DIR}/cct"
181
+
182
+ missing_subs=()
183
+ for sub in cct-session.sh cct-status.sh cct-cleanup.sh; do
184
+ if [[ ! -x "${CCT_DIR}/${sub}" ]]; then
185
+ missing_subs+=("$sub")
186
+ fi
187
+ done
188
+
189
+ if [[ ${#missing_subs[@]} -eq 0 ]]; then
190
+ check_pass "All core subcommands installed"
191
+ else
192
+ check_warn "Missing subcommands: ${missing_subs[*]}"
193
+ echo -e " ${DIM}Re-run install.sh or shipwright upgrade --apply${RESET}"
194
+ fi
195
+ else
196
+ check_fail "shipwright command not found in PATH"
197
+ echo -e " ${DIM}Re-run install.sh to install the CLI${RESET}"
198
+ fi
199
+
200
+ # ═════════════════════════════════════════════════════════════════════════════
201
+ # 4. Pane Display
202
+ # ═════════════════════════════════════════════════════════════════════════════
203
+ echo ""
204
+ echo -e "${PURPLE}${BOLD} PANE DISPLAY${RESET}"
205
+ echo -e "${DIM} ──────────────────────────────────────────${RESET}"
206
+
207
+ # Check overlay file exists
208
+ if [[ -f "$HOME/.tmux/claude-teams-overlay.conf" ]]; then
209
+ # Check for set-hook color enforcement
210
+ if grep -q "set-hook.*after-split-window" "$HOME/.tmux/claude-teams-overlay.conf" 2>/dev/null; then
211
+ check_pass "Overlay has color hooks (set-hook)"
212
+ else
213
+ check_warn "Overlay missing color hooks — new panes may flash white"
214
+ echo -e " ${DIM}Run: shipwright upgrade --apply or shipwright init${RESET}"
215
+ fi
216
+ else
217
+ check_fail "Overlay not found — pane display features unavailable"
218
+ fi
219
+
220
+ # Check if set-hook commands are active in tmux
221
+ if [[ -n "${TMUX:-}" ]]; then
222
+ if tmux show-hooks -g 2>/dev/null | grep -q "after-split-window"; then
223
+ check_pass "set-hook commands active in tmux"
224
+ else
225
+ check_warn "set-hook commands not active — reload config: prefix + r"
226
+ fi
227
+
228
+ # Check default-terminal
229
+ TMUX_TERM="$(tmux show-option -gv default-terminal 2>/dev/null || echo "unknown")"
230
+ if [[ "$TMUX_TERM" == *"256color"* ]]; then
231
+ check_pass "default-terminal: $TMUX_TERM"
232
+ else
233
+ check_warn "default-terminal: $TMUX_TERM — 256color variant recommended"
234
+ echo -e " ${DIM}set -g default-terminal 'tmux-256color'${RESET}"
235
+ fi
236
+
237
+ # Check pane border includes cyan accent
238
+ BORDER_FMT="$(tmux show-option -gv pane-border-format 2>/dev/null || echo "")"
239
+ if echo "$BORDER_FMT" | grep -q "#00d4ff"; then
240
+ check_pass "Pane border format includes cyan accent"
241
+ else
242
+ check_warn "Pane border format missing cyan accent — overlay may not be loaded"
243
+ fi
244
+ else
245
+ info "Not in tmux session — skipping runtime display checks"
246
+ fi
247
+
248
+ # ═════════════════════════════════════════════════════════════════════════════
249
+ # 5. Orphaned Sessions
250
+ # ═════════════════════════════════════════════════════════════════════════════
251
+ echo ""
252
+ echo -e "${PURPLE}${BOLD} ORPHAN CHECK${RESET}"
253
+ echo -e "${DIM} ──────────────────────────────────────────${RESET}"
254
+
255
+ orphaned_teams=0
256
+ TEAMS_DIR="$HOME/.claude/teams"
257
+ if [[ -d "$TEAMS_DIR" ]]; then
258
+ while IFS= read -r team_dir; do
259
+ [[ -z "$team_dir" ]] && continue
260
+ team_name="$(basename "$team_dir")"
261
+ config_file="${team_dir}/config.json"
262
+ if [[ ! -f "$config_file" ]]; then
263
+ orphaned_teams=$((orphaned_teams + 1))
264
+ check_warn "Orphaned team dir: ${team_name} (no config.json)"
265
+ fi
266
+ done < <(find "$TEAMS_DIR" -mindepth 1 -maxdepth 1 -type d 2>/dev/null)
267
+ fi
268
+
269
+ if [[ $orphaned_teams -eq 0 ]]; then
270
+ check_pass "No orphaned team sessions"
271
+ fi
272
+
273
+ # ═════════════════════════════════════════════════════════════════════════════
274
+ # 6. Terminal Compatibility
275
+ # ═════════════════════════════════════════════════════════════════════════════
276
+ echo ""
277
+ echo -e "${PURPLE}${BOLD} TERMINAL${RESET}"
278
+ echo -e "${DIM} ──────────────────────────────────────────${RESET}"
279
+
280
+ TERM_PROGRAM="${TERM_PROGRAM:-unknown}"
281
+
282
+ case "$TERM_PROGRAM" in
283
+ iTerm.app|iTerm2)
284
+ check_pass "iTerm2 — full support"
285
+ ;;
286
+ Apple_Terminal)
287
+ check_pass "Terminal.app — supported"
288
+ ;;
289
+ WezTerm)
290
+ check_pass "WezTerm — full support"
291
+ ;;
292
+ tmux)
293
+ check_pass "Running inside tmux (nested)"
294
+ ;;
295
+ vscode)
296
+ check_warn "VS Code integrated terminal"
297
+ echo -e " ${DIM}Some pane border features may not render correctly.${RESET}"
298
+ echo -e " ${DIM}Consider running tmux in an external terminal.${RESET}"
299
+ ;;
300
+ Ghostty)
301
+ check_warn "Ghostty — may have tmux rendering quirks"
302
+ echo -e " ${DIM}If pane borders look wrong, try: set -g default-terminal 'xterm-256color'${RESET}"
303
+ ;;
304
+ *)
305
+ info "Terminal: ${TERM_PROGRAM}"
306
+ ;;
307
+ esac
308
+
309
+ # ═════════════════════════════════════════════════════════════════════════════
310
+ # Summary
311
+ # ═════════════════════════════════════════════════════════════════════════════
312
+ echo ""
313
+ echo -e "${DIM} ══════════════════════════════════════════${RESET}"
314
+ echo ""
315
+
316
+ TOTAL=$((PASS + WARN + FAIL))
317
+
318
+ echo -e " ${GREEN}${BOLD}${PASS}${RESET} passed ${YELLOW}${BOLD}${WARN}${RESET} warnings ${RED}${BOLD}${FAIL}${RESET} failed ${DIM}(${TOTAL} checks)${RESET}"
319
+ echo ""
320
+
321
+ if [[ $FAIL -gt 0 ]]; then
322
+ error "Some checks failed. Fix the issues above and re-run ${CYAN}shipwright doctor${RESET}"
323
+ elif [[ $WARN -gt 0 ]]; then
324
+ warn "Setup mostly OK, but there are warnings above"
325
+ else
326
+ success "Everything looks good!"
327
+ fi
328
+ echo ""