shipwright-cli 1.7.0 → 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 (106) 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/sw-init.sh +522 -0
  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 -328
  104. package/scripts/cct-init.sh +0 -282
  105. package/scripts/cct-session.sh +0 -284
  106. package/scripts/cct-status.sh +0 -169
@@ -1,282 +0,0 @@
1
- #!/usr/bin/env bash
2
- # ╔═══════════════════════════════════════════════════════════════════════════╗
3
- # ║ shipwright init — One-command tmux setup + optional deploy configuration ║
4
- # ║ ║
5
- # ║ Installs tmux config, overlay, and templates. No interactive prompts, ║
6
- # ║ no hooks, no Claude Code settings — just tmux config. ║
7
- # ║ ║
8
- # ║ --deploy Detect platform and generate deployed.json template ║
9
- # ╚═══════════════════════════════════════════════════════════════════════════╝
10
- set -euo pipefail
11
-
12
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13
- REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
14
- ADAPTERS_DIR="$SCRIPT_DIR/adapters"
15
-
16
- # ─── Colors ──────────────────────────────────────────────────────────────────
17
- CYAN='\033[38;2;0;212;255m'
18
- GREEN='\033[38;2;74;222;128m'
19
- YELLOW='\033[38;2;250;204;21m'
20
- RED='\033[38;2;248;113;113m'
21
- DIM='\033[2m'
22
- BOLD='\033[1m'
23
- RESET='\033[0m'
24
-
25
- info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
26
- success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
27
- warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*"; }
28
- error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
29
-
30
- # ─── Flag parsing ───────────────────────────────────────────────────────────
31
- DEPLOY_SETUP=false
32
- DEPLOY_PLATFORM=""
33
- SKIP_CLAUDE_MD=false
34
-
35
- while [[ $# -gt 0 ]]; do
36
- case "$1" in
37
- --deploy)
38
- DEPLOY_SETUP=true
39
- shift
40
- ;;
41
- --platform)
42
- DEPLOY_PLATFORM="${2:-}"
43
- [[ -z "$DEPLOY_PLATFORM" ]] && { error "Missing value for --platform"; exit 1; }
44
- shift 2
45
- ;;
46
- --no-claude-md)
47
- SKIP_CLAUDE_MD=true
48
- shift
49
- ;;
50
- --help|-h)
51
- echo "Usage: shipwright init [--deploy] [--platform vercel|fly|railway|docker] [--no-claude-md]"
52
- echo ""
53
- echo "Options:"
54
- echo " --deploy Detect deploy platform and generate deployed.json"
55
- echo " --platform PLATFORM Skip detection, use specified platform"
56
- echo " --no-claude-md Skip creating .claude/CLAUDE.md"
57
- echo " --help, -h Show this help"
58
- exit 0
59
- ;;
60
- *)
61
- warn "Unknown option: $1"
62
- shift
63
- ;;
64
- esac
65
- done
66
-
67
- echo ""
68
- echo -e "${CYAN}${BOLD}shipwright init${RESET} — Quick tmux setup"
69
- echo -e "${DIM}══════════════════════════════════════════${RESET}"
70
- echo ""
71
-
72
- # ─── tmux.conf ────────────────────────────────────────────────────────────────
73
- if [[ -f "$HOME/.tmux.conf" ]]; then
74
- cp "$HOME/.tmux.conf" "$HOME/.tmux.conf.bak"
75
- warn "Backed up existing ~/.tmux.conf → ~/.tmux.conf.bak"
76
- fi
77
- cp "$REPO_DIR/tmux/tmux.conf" "$HOME/.tmux.conf"
78
- success "Installed ~/.tmux.conf"
79
-
80
- # ─── Overlay ──────────────────────────────────────────────────────────────────
81
- mkdir -p "$HOME/.tmux"
82
- cp "$REPO_DIR/tmux/claude-teams-overlay.conf" "$HOME/.tmux/claude-teams-overlay.conf"
83
- success "Installed ~/.tmux/claude-teams-overlay.conf"
84
-
85
- # ─── Templates ────────────────────────────────────────────────────────────────
86
- mkdir -p "$HOME/.claude-teams/templates"
87
- for tpl in "$REPO_DIR"/tmux/templates/*.json; do
88
- [[ -f "$tpl" ]] || continue
89
- cp "$tpl" "$HOME/.claude-teams/templates/$(basename "$tpl")"
90
- done
91
- success "Installed templates → ~/.claude-teams/templates/"
92
-
93
- # ─── CLAUDE.md — Agent instructions ──────────────────────────────────────────
94
- CLAUDE_MD_SRC="$REPO_DIR/claude-code/CLAUDE.md.shipwright"
95
- CLAUDE_MD_DST=".claude/CLAUDE.md"
96
-
97
- if [[ "$SKIP_CLAUDE_MD" == "false" && -f "$CLAUDE_MD_SRC" ]]; then
98
- if [[ -f "$CLAUDE_MD_DST" ]]; then
99
- # Check if it already contains Shipwright instructions
100
- if grep -q "Shipwright" "$CLAUDE_MD_DST" 2>/dev/null; then
101
- info "CLAUDE.md already contains Shipwright instructions — skipping"
102
- else
103
- # Append Shipwright section to existing CLAUDE.md
104
- {
105
- echo ""
106
- echo "---"
107
- echo ""
108
- cat "$CLAUDE_MD_SRC"
109
- } >> "$CLAUDE_MD_DST"
110
- success "Appended Shipwright instructions to ${CLAUDE_MD_DST}"
111
- fi
112
- else
113
- mkdir -p ".claude"
114
- cp "$CLAUDE_MD_SRC" "$CLAUDE_MD_DST"
115
- success "Created ${CLAUDE_MD_DST} with Shipwright agent instructions"
116
- fi
117
- fi
118
-
119
- # ─── Reload tmux if inside a session ──────────────────────────────────────────
120
- if [[ -n "${TMUX:-}" ]]; then
121
- tmux source-file "$HOME/.tmux.conf" 2>/dev/null && \
122
- success "Reloaded tmux config" || \
123
- warn "Could not reload tmux config (reload manually with prefix + r)"
124
- fi
125
-
126
- # ─── Quick-start instructions ─────────────────────────────────────────────────
127
- echo ""
128
- echo -e "${BOLD}Done!${RESET} tmux is configured for Claude Code Teams."
129
- echo ""
130
- echo -e "${BOLD}Quick start:${RESET}"
131
- if [[ -z "${TMUX:-}" ]]; then
132
- echo -e " ${DIM}1.${RESET} tmux new -s dev"
133
- echo -e " ${DIM}2.${RESET} shipwright session my-feature --template feature-dev"
134
- else
135
- echo -e " ${DIM}1.${RESET} shipwright session my-feature --template feature-dev"
136
- fi
137
- echo ""
138
- echo -e "${BOLD}Layout keybindings:${RESET}"
139
- echo -e " ${CYAN}prefix + M-1${RESET} main-horizontal (leader 65% left)"
140
- echo -e " ${CYAN}prefix + M-2${RESET} main-vertical (leader 60% top)"
141
- echo -e " ${CYAN}prefix + M-3${RESET} tiled (equal sizes)"
142
- echo ""
143
-
144
- # ─── Deploy setup (--deploy) ─────────────────────────────────────────────────
145
- [[ "$DEPLOY_SETUP" == "false" ]] && exit 0
146
-
147
- echo -e "${CYAN}${BOLD}Deploy Setup${RESET}"
148
- echo -e "${DIM}══════════════════════════════════════════${RESET}"
149
- echo ""
150
-
151
- # Platform detection
152
- detect_deploy_platform() {
153
- local detected=""
154
-
155
- for adapter_file in "$ADAPTERS_DIR"/*-deploy.sh; do
156
- [[ -f "$adapter_file" ]] || continue
157
- # Source the adapter in a subshell to get detection
158
- if ( source "$adapter_file" && detect_platform ); then
159
- local name
160
- name=$(basename "$adapter_file" | sed 's/-deploy\.sh$//')
161
- if [[ -n "$detected" ]]; then
162
- detected="$detected $name"
163
- else
164
- detected="$name"
165
- fi
166
- fi
167
- done
168
-
169
- echo "$detected"
170
- }
171
-
172
- if [[ -n "$DEPLOY_PLATFORM" ]]; then
173
- # User specified --platform, validate it
174
- if [[ ! -f "$ADAPTERS_DIR/${DEPLOY_PLATFORM}-deploy.sh" ]]; then
175
- error "Unknown platform: $DEPLOY_PLATFORM"
176
- echo -e " Available: vercel, fly, railway, docker"
177
- exit 1
178
- fi
179
- info "Using specified platform: ${BOLD}${DEPLOY_PLATFORM}${RESET}"
180
- else
181
- info "Detecting deploy platform..."
182
- detected=$(detect_deploy_platform)
183
-
184
- if [[ -z "$detected" ]]; then
185
- warn "No platform detected in current directory"
186
- echo ""
187
- echo -e " Supported platforms:"
188
- echo -e " ${CYAN}vercel${RESET} — vercel.json or .vercel/"
189
- echo -e " ${CYAN}fly${RESET} — fly.toml"
190
- echo -e " ${CYAN}railway${RESET} — railway.toml or .railway/"
191
- echo -e " ${CYAN}docker${RESET} — Dockerfile or docker-compose.yml"
192
- echo ""
193
- echo -e " Specify manually: ${DIM}shipwright init --deploy --platform vercel${RESET}"
194
- exit 1
195
- fi
196
-
197
- # If multiple platforms detected, use the first and warn
198
- platform_count=$(echo "$detected" | wc -w | tr -d ' ')
199
- DEPLOY_PLATFORM=$(echo "$detected" | awk '{print $1}')
200
-
201
- if [[ "$platform_count" -gt 1 ]]; then
202
- warn "Multiple platforms detected: ${BOLD}${detected}${RESET}"
203
- info "Using: ${BOLD}${DEPLOY_PLATFORM}${RESET}"
204
- echo -e " ${DIM}Override with: shipwright init --deploy --platform <name>${RESET}"
205
- echo ""
206
- else
207
- success "Detected platform: ${BOLD}${DEPLOY_PLATFORM}${RESET}"
208
- fi
209
-
210
- # Confirm with user
211
- read -rp "$(echo -e "${CYAN}${BOLD}▸${RESET} Configure deploy for ${BOLD}${DEPLOY_PLATFORM}${RESET}? [Y/n] ")" confirm
212
- if [[ "${confirm,,}" == "n" ]]; then
213
- info "Aborted. Use --platform to specify manually."
214
- exit 0
215
- fi
216
- fi
217
-
218
- # Source the adapter to get command values
219
- ADAPTER_FILE="$ADAPTERS_DIR/${DEPLOY_PLATFORM}-deploy.sh"
220
- source "$ADAPTER_FILE"
221
-
222
- staging_cmd=$(get_staging_cmd)
223
- production_cmd=$(get_production_cmd)
224
- rollback_cmd=$(get_rollback_cmd)
225
- health_url=$(get_health_url)
226
- smoke_cmd=$(get_smoke_cmd)
227
-
228
- # Generate deployed.json from template
229
- TEMPLATE_SRC="$REPO_DIR/templates/pipelines/deployed.json"
230
- TEMPLATE_DST=".claude/pipeline-templates/deployed.json"
231
-
232
- if [[ ! -f "$TEMPLATE_SRC" ]]; then
233
- error "Template not found: $TEMPLATE_SRC"
234
- exit 1
235
- fi
236
-
237
- mkdir -p ".claude/pipeline-templates"
238
-
239
- # Use jq to properly fill in the template values
240
- jq --arg staging "$staging_cmd" \
241
- --arg production "$production_cmd" \
242
- --arg rollback "$rollback_cmd" \
243
- --arg health "$health_url" \
244
- --arg smoke "$smoke_cmd" \
245
- --arg platform "$DEPLOY_PLATFORM" \
246
- '
247
- .name = "deployed-" + $platform |
248
- .description = "Autonomous pipeline with " + $platform + " deploy — generated by shipwright init --deploy" |
249
- (.stages[] | select(.id == "deploy") | .config) |= {
250
- staging_cmd: $staging,
251
- production_cmd: $production,
252
- rollback_cmd: $rollback
253
- } |
254
- (.stages[] | select(.id == "validate") | .config) |= {
255
- smoke_cmd: $smoke,
256
- health_url: $health,
257
- close_issue: true
258
- } |
259
- (.stages[] | select(.id == "monitor") | .config) |= (
260
- .health_url = $health |
261
- .rollback_cmd = $rollback
262
- )
263
- ' "$TEMPLATE_SRC" > "$TEMPLATE_DST"
264
-
265
- success "Generated ${BOLD}${TEMPLATE_DST}${RESET}"
266
-
267
- echo ""
268
- echo -e "${BOLD}Deploy configured for ${DEPLOY_PLATFORM}!${RESET}"
269
- echo ""
270
- echo -e "${BOLD}Commands configured:${RESET}"
271
- echo -e " ${DIM}staging:${RESET} $staging_cmd"
272
- echo -e " ${DIM}production:${RESET} $production_cmd"
273
- echo -e " ${DIM}rollback:${RESET} $rollback_cmd"
274
- if [[ -n "$health_url" ]]; then
275
- echo -e " ${DIM}health:${RESET} $health_url"
276
- fi
277
- echo ""
278
- echo -e "${BOLD}Usage:${RESET}"
279
- echo -e " ${DIM}shipwright pipeline start --issue 42 --template .claude/pipeline-templates/deployed.json${RESET}"
280
- echo ""
281
- echo -e "${DIM}Edit ${TEMPLATE_DST} to customize deploy commands, gates, or thresholds.${RESET}"
282
- echo ""
@@ -1,284 +0,0 @@
1
- #!/usr/bin/env bash
2
- # ╔═══════════════════════════════════════════════════════════════════════════╗
3
- # ║ cct-session.sh — Launch a Claude Code team session in a new tmux window║
4
- # ║ ║
5
- # ║ Uses new-window (NOT split-window) to avoid the tmux send-keys race ║
6
- # ║ condition that affects 4+ agents. See KNOWN-ISSUES.md for details. ║
7
- # ║ ║
8
- # ║ Supports --template to scaffold from a team template and --terminal ║
9
- # ║ to select a terminal adapter (tmux, iterm2, wezterm). ║
10
- # ╚═══════════════════════════════════════════════════════════════════════════╝
11
- set -euo pipefail
12
-
13
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
14
-
15
- # ─── Colors ──────────────────────────────────────────────────────────────────
16
- CYAN='\033[38;2;0;212;255m'
17
- PURPLE='\033[38;2;124;58;237m'
18
- GREEN='\033[38;2;74;222;128m'
19
- YELLOW='\033[38;2;250;204;21m'
20
- RED='\033[38;2;248;113;113m'
21
- DIM='\033[2m'
22
- BOLD='\033[1m'
23
- RESET='\033[0m'
24
-
25
- info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
26
- success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
27
- warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*"; }
28
- error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
29
-
30
- # ─── Parse Arguments ────────────────────────────────────────────────────────
31
-
32
- TEAM_NAME=""
33
- TEMPLATE_NAME=""
34
- TERMINAL_ADAPTER=""
35
-
36
- while [[ $# -gt 0 ]]; do
37
- case "$1" in
38
- --template|-t)
39
- TEMPLATE_NAME="${2:-}"
40
- [[ -z "$TEMPLATE_NAME" ]] && { error "Missing template name after --template"; exit 1; }
41
- shift 2
42
- ;;
43
- --terminal)
44
- TERMINAL_ADAPTER="${2:-}"
45
- [[ -z "$TERMINAL_ADAPTER" ]] && { error "Missing adapter name after --terminal"; exit 1; }
46
- shift 2
47
- ;;
48
- --help|-h)
49
- echo -e "${CYAN}${BOLD}shipwright session${RESET} — Create a new team session"
50
- echo ""
51
- echo -e "${BOLD}USAGE${RESET}"
52
- echo -e " shipwright session [name] [--template <name>] [--terminal <adapter>]"
53
- echo ""
54
- echo -e "${BOLD}OPTIONS${RESET}"
55
- echo -e " ${CYAN}--template, -t${RESET} <name> Use a team template (see: shipwright templates list)"
56
- echo -e " ${CYAN}--terminal${RESET} <adapter> Terminal adapter: tmux (default), iterm2, wezterm"
57
- echo ""
58
- echo -e "${BOLD}EXAMPLES${RESET}"
59
- echo -e " ${DIM}shipwright session refactor${RESET}"
60
- echo -e " ${DIM}shipwright session my-feature --template feature-dev${RESET}"
61
- echo -e " ${DIM}shipwright session my-feature --terminal iterm2${RESET}"
62
- exit 0
63
- ;;
64
- -*)
65
- error "Unknown option: $1"
66
- exit 1
67
- ;;
68
- *)
69
- # Positional: team name
70
- [[ -z "$TEAM_NAME" ]] && TEAM_NAME="$1" || { error "Unexpected argument: $1"; exit 1; }
71
- shift
72
- ;;
73
- esac
74
- done
75
-
76
- TEAM_NAME="${TEAM_NAME:-team-$(date +%s)}"
77
- WINDOW_NAME="claude-${TEAM_NAME}"
78
-
79
- # ─── Template Loading ───────────────────────────────────────────────────────
80
-
81
- TEMPLATE_FILE=""
82
- TEMPLATE_LAYOUT=""
83
- TEMPLATE_LAYOUT_STYLE=""
84
- TEMPLATE_MAIN_PANE_PERCENT=""
85
- TEMPLATE_DESC=""
86
- TEMPLATE_AGENTS=() # Populated as "name|role|focus" entries
87
-
88
- if [[ -n "$TEMPLATE_NAME" ]]; then
89
- # Search for template: user dir first, then repo dir
90
- USER_TEMPLATES_DIR="${HOME}/.claude-teams/templates"
91
- REPO_TEMPLATES_DIR="$(cd "$SCRIPT_DIR/../tmux/templates" 2>/dev/null && pwd)" || REPO_TEMPLATES_DIR=""
92
-
93
- TEMPLATE_NAME="${TEMPLATE_NAME%.json}"
94
-
95
- if [[ -f "$USER_TEMPLATES_DIR/${TEMPLATE_NAME}.json" ]]; then
96
- TEMPLATE_FILE="$USER_TEMPLATES_DIR/${TEMPLATE_NAME}.json"
97
- elif [[ -n "$REPO_TEMPLATES_DIR" && -f "$REPO_TEMPLATES_DIR/${TEMPLATE_NAME}.json" ]]; then
98
- TEMPLATE_FILE="$REPO_TEMPLATES_DIR/${TEMPLATE_NAME}.json"
99
- else
100
- error "Template '${TEMPLATE_NAME}' not found."
101
- echo -e " Run ${DIM}shipwright templates list${RESET} to see available templates."
102
- exit 1
103
- fi
104
-
105
- info "Loading template: ${PURPLE}${BOLD}${TEMPLATE_NAME}${RESET}"
106
-
107
- # Parse template — single jq call extracts all fields + agents in one pass
108
- if command -v jq &>/dev/null; then
109
- # Single jq call: outputs metadata lines then agent lines
110
- # Format: META<tab>field<tab>value for metadata, AGENT<tab>name|role|focus for agents
111
- while IFS=$'\t' read -r tag key value; do
112
- case "$tag" in
113
- META)
114
- case "$key" in
115
- description) TEMPLATE_DESC="$value" ;;
116
- layout) TEMPLATE_LAYOUT="$value" ;;
117
- layout_style) TEMPLATE_LAYOUT_STYLE="$value" ;;
118
- main_pane_percent) TEMPLATE_MAIN_PANE_PERCENT="$value" ;;
119
- esac
120
- ;;
121
- AGENT) [[ -n "$key" ]] && TEMPLATE_AGENTS+=("$key") ;;
122
- esac
123
- done < <(jq -r '
124
- "META\tdescription\t\(.description // "")",
125
- "META\tlayout\t\(.layout // "tiled")",
126
- "META\tlayout_style\t\(.layout_style // "")",
127
- "META\tmain_pane_percent\t\(.main_pane_percent // "")",
128
- (.agents // [] | .[] | "AGENT\t\(.name)|\(.role // "")|\(.focus // "")\t")
129
- ' "$TEMPLATE_FILE")
130
- else
131
- error "jq is required for template parsing."
132
- echo -e " ${DIM}brew install jq${RESET}"
133
- exit 1
134
- fi
135
-
136
- echo -e " ${DIM}${TEMPLATE_DESC}${RESET}"
137
- echo -e " ${DIM}Agents: ${#TEMPLATE_AGENTS[@]} Layout: ${TEMPLATE_LAYOUT}${RESET}"
138
- fi
139
-
140
- # ─── Resolve Terminal Adapter ───────────────────────────────────────────────
141
-
142
- # Auto-detect if not specified
143
- if [[ -z "$TERMINAL_ADAPTER" ]]; then
144
- TERMINAL_ADAPTER="tmux"
145
- fi
146
-
147
- ADAPTER_FILE="$SCRIPT_DIR/adapters/${TERMINAL_ADAPTER}-adapter.sh"
148
- if [[ -f "$ADAPTER_FILE" ]]; then
149
- # shellcheck source=/dev/null
150
- source "$ADAPTER_FILE"
151
- else
152
- # Default to inline tmux behavior (backwards compatible)
153
- if [[ "$TERMINAL_ADAPTER" != "tmux" ]]; then
154
- error "Terminal adapter '${TERMINAL_ADAPTER}' not found."
155
- echo -e " Available: tmux (default), iterm2, wezterm"
156
- echo -e " Adapter dir: ${DIM}${SCRIPT_DIR}/adapters/${RESET}"
157
- exit 1
158
- fi
159
- fi
160
-
161
- # ─── Create Session (tmux default path) ─────────────────────────────────────
162
-
163
- if [[ "$TERMINAL_ADAPTER" == "tmux" && ! -f "$ADAPTER_FILE" ]]; then
164
- # Inline tmux path — original behavior (adapter not required for tmux)
165
-
166
- # Check if a window with this name already exists
167
- if tmux list-windows -F '#W' 2>/dev/null | grep -qx "$WINDOW_NAME"; then
168
- warn "Window '${WINDOW_NAME}' already exists. Switching to it."
169
- tmux select-window -t "$WINDOW_NAME"
170
- exit 0
171
- fi
172
-
173
- info "Creating team session: ${CYAN}${BOLD}${TEAM_NAME}${RESET}"
174
-
175
- # Create a new window (not split-window — avoids race condition #23615)
176
- tmux new-window -n "$WINDOW_NAME" -c "#{pane_current_path}"
177
-
178
- # Force dark theme on the new pane (belt-and-suspenders with overlay hooks)
179
- tmux select-pane -t "$WINDOW_NAME" -P 'bg=#1a1a2e,fg=#e4e4e7'
180
-
181
- # Set the pane title so the overlay shows the team name
182
- tmux send-keys -t "$WINDOW_NAME" "printf '\\033]2;${TEAM_NAME}-lead\\033\\\\'" Enter
183
-
184
- sleep 0.2
185
- tmux send-keys -t "$WINDOW_NAME" "clear" Enter
186
-
187
- # ─── Template: Create Agent Panes ────────────────────────────────────────
188
- if [[ ${#TEMPLATE_AGENTS[@]} -gt 0 ]]; then
189
- info "Scaffolding ${#TEMPLATE_AGENTS[@]} agent panes..."
190
-
191
- for agent_entry in "${TEMPLATE_AGENTS[@]}"; do
192
- IFS='|' read -r aname arole afocus <<< "$agent_entry"
193
-
194
- # Split the window to create a new pane
195
- tmux split-window -t "$WINDOW_NAME" -c "#{pane_current_path}"
196
- sleep 0.1
197
-
198
- # Force dark theme on agent pane
199
- tmux select-pane -t "$WINDOW_NAME" -P 'bg=#1a1a2e,fg=#e4e4e7'
200
-
201
- # Set the pane title to the agent name
202
- tmux send-keys -t "$WINDOW_NAME" "printf '\\033]2;${TEAM_NAME}-${aname}\\033\\\\'" Enter
203
- sleep 0.1
204
- tmux send-keys -t "$WINDOW_NAME" "clear" Enter
205
- done
206
-
207
- # Apply the layout from the template (layout_style takes precedence over layout)
208
- if [[ -n "$TEMPLATE_LAYOUT_STYLE" ]]; then
209
- tmux select-layout -t "$WINDOW_NAME" "$TEMPLATE_LAYOUT_STYLE" 2>/dev/null || \
210
- tmux select-layout -t "$WINDOW_NAME" "${TEMPLATE_LAYOUT:-tiled}" 2>/dev/null || true
211
- else
212
- tmux select-layout -t "$WINDOW_NAME" "${TEMPLATE_LAYOUT:-tiled}" 2>/dev/null || true
213
- fi
214
-
215
- # Resize leader pane to desired percentage
216
- if [[ -n "$TEMPLATE_MAIN_PANE_PERCENT" && -n "$TEMPLATE_LAYOUT_STYLE" ]]; then
217
- case "$TEMPLATE_LAYOUT_STYLE" in
218
- main-horizontal) tmux resize-pane -t "$WINDOW_NAME.0" -x "${TEMPLATE_MAIN_PANE_PERCENT}%" 2>/dev/null ;;
219
- main-vertical) tmux resize-pane -t "$WINDOW_NAME.0" -y "${TEMPLATE_MAIN_PANE_PERCENT}%" 2>/dev/null ;;
220
- esac
221
- fi
222
-
223
- # Select the first pane (leader)
224
- tmux select-pane -t "$WINDOW_NAME.0"
225
- fi
226
-
227
- else
228
- # ─── Adapter-based session creation ──────────────────────────────────────
229
-
230
- if type -t spawn_agent &>/dev/null; then
231
- info "Creating team session: ${CYAN}${BOLD}${TEAM_NAME}${RESET} ${DIM}(${TERMINAL_ADAPTER})${RESET}"
232
-
233
- # Spawn leader
234
- spawn_agent "${TEAM_NAME}-lead" "#{pane_current_path}" ""
235
-
236
- # Spawn template agents if provided
237
- if [[ ${#TEMPLATE_AGENTS[@]} -gt 0 ]]; then
238
- info "Scaffolding ${#TEMPLATE_AGENTS[@]} agents..."
239
- for agent_entry in "${TEMPLATE_AGENTS[@]}"; do
240
- IFS='|' read -r aname arole afocus <<< "$agent_entry"
241
- spawn_agent "${TEAM_NAME}-${aname}" "#{pane_current_path}" ""
242
- done
243
- fi
244
- else
245
- error "Adapter '${TERMINAL_ADAPTER}' loaded but spawn_agent() not found."
246
- exit 1
247
- fi
248
- fi
249
-
250
- # ─── Summary ────────────────────────────────────────────────────────────────
251
-
252
- echo ""
253
- success "Team session ${CYAN}${BOLD}${TEAM_NAME}${RESET} ready!"
254
-
255
- if [[ ${#TEMPLATE_AGENTS[@]} -gt 0 ]]; then
256
- echo ""
257
- echo -e "${BOLD}Team from template ${PURPLE}${TEMPLATE_NAME}${RESET}${BOLD}:${RESET}"
258
- echo -e " ${CYAN}${BOLD}lead${RESET} ${DIM}— Team coordinator${RESET}"
259
- for agent_entry in "${TEMPLATE_AGENTS[@]}"; do
260
- IFS='|' read -r aname arole afocus <<< "$agent_entry"
261
- echo -e " ${PURPLE}${BOLD}${aname}${RESET} ${DIM}— ${arole}${RESET}"
262
- done
263
- echo ""
264
- echo -e "${BOLD}Next steps:${RESET}"
265
- echo -e " ${CYAN}1.${RESET} Switch to window ${DIM}${WINDOW_NAME}${RESET}"
266
- echo -e " ${CYAN}2.${RESET} Start ${DIM}claude${RESET} in the lead pane (top-left)"
267
- echo -e " ${CYAN}3.${RESET} Ask Claude to use the team — agents are ready in their panes"
268
- else
269
- echo ""
270
- echo -e "${BOLD}Next steps:${RESET}"
271
- echo -e " ${CYAN}1.${RESET} Switch to window ${DIM}${WINDOW_NAME}${RESET} ${DIM}(prefix + $(tmux list-windows -F '#I #W' | grep "$WINDOW_NAME" | cut -d' ' -f1))${RESET}"
272
- echo -e " ${CYAN}2.${RESET} Start Claude Code:"
273
- echo -e " ${DIM}claude${RESET}"
274
- echo -e " ${CYAN}3.${RESET} Ask Claude to create a team:"
275
- echo -e " ${DIM}\"Create a team with 2 agents to refactor the auth module\"${RESET}"
276
- fi
277
-
278
- echo ""
279
- echo -e "${PURPLE}${BOLD}Tip:${RESET} For file isolation between agents, use git worktrees:"
280
- echo -e " ${DIM}git worktree add ../project-${TEAM_NAME} -b ${TEAM_NAME}${RESET}"
281
- echo -e " Then launch Claude inside the worktree directory."
282
- echo ""
283
- echo -e "${DIM}Settings: ~/.claude/settings.json (see settings.json.template)${RESET}"
284
- echo -e "${DIM}Keybinding: prefix + T re-runs this command${RESET}"