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,409 @@
1
+ #!/usr/bin/env bash
2
+ # ╔═══════════════════════════════════════════════════════════════════════════╗
3
+ # ║ shipwright tracker — Provider Router for Issue Tracker Integration ║
4
+ # ║ Route notifications · Configure providers · Linear & Jira support ║
5
+ # ╚═══════════════════════════════════════════════════════════════════════════╝
6
+ set -euo pipefail
7
+ trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
+
9
+ VERSION="1.9.0"
10
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
+ REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
+
13
+ # ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
14
+ CYAN='\033[38;2;0;212;255m' # #00d4ff — primary accent
15
+ PURPLE='\033[38;2;124;58;237m' # #7c3aed — secondary
16
+ BLUE='\033[38;2;0;102;255m' # #0066ff — tertiary
17
+ GREEN='\033[38;2;74;222;128m' # success
18
+ YELLOW='\033[38;2;250;204;21m' # warning
19
+ RED='\033[38;2;248;113;113m' # error
20
+ DIM='\033[2m'
21
+ BOLD='\033[1m'
22
+ RESET='\033[0m'
23
+
24
+ # ─── Cross-platform compatibility ──────────────────────────────────────────
25
+ # shellcheck source=lib/compat.sh
26
+ [[ -f "$SCRIPT_DIR/lib/compat.sh" ]] && source "$SCRIPT_DIR/lib/compat.sh"
27
+ # ─── Output Helpers ─────────────────────────────────────────────────────────
28
+ info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
29
+ success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
30
+ warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*"; }
31
+ error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
32
+
33
+ now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
34
+ now_epoch() { date +%s; }
35
+
36
+ # ─── Structured Event Log ──────────────────────────────────────────────────
37
+ EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
38
+
39
+ emit_event() {
40
+ local event_type="$1"
41
+ shift
42
+ local json_fields=""
43
+ for kv in "$@"; do
44
+ local key="${kv%%=*}"
45
+ local val="${kv#*=}"
46
+ if [[ "$val" =~ ^-?[0-9]+\.?[0-9]*$ ]]; then
47
+ json_fields="${json_fields},\"${key}\":${val}"
48
+ else
49
+ val="${val//\"/\\\"}"
50
+ json_fields="${json_fields},\"${key}\":\"${val}\""
51
+ fi
52
+ done
53
+ mkdir -p "${HOME}/.shipwright"
54
+ echo "{\"ts\":\"$(now_iso)\",\"ts_epoch\":$(now_epoch),\"type\":\"${event_type}\"${json_fields}}" >> "$EVENTS_FILE"
55
+ }
56
+
57
+ # ─── Configuration ─────────────────────────────────────────────────────────
58
+ CONFIG_DIR="${HOME}/.shipwright"
59
+ TRACKER_CONFIG="${CONFIG_DIR}/tracker-config.json"
60
+ TRACKER_PROVIDER=""
61
+
62
+ # Load tracker config: reads provider, then sources the right provider script
63
+ load_tracker_config() {
64
+ # Already loaded?
65
+ if [[ -n "$TRACKER_PROVIDER" ]]; then
66
+ return 0
67
+ fi
68
+
69
+ # Check env var first
70
+ local provider="${TRACKER_PROVIDER_OVERRIDE:-}"
71
+
72
+ # Fall back to tracker-config.json
73
+ if [[ -z "$provider" && -f "$TRACKER_CONFIG" ]]; then
74
+ provider=$(jq -r '.provider // "none"' "$TRACKER_CONFIG" 2>/dev/null || echo "none")
75
+ fi
76
+
77
+ # Fall back to daemon-config.json tracker block
78
+ if [[ -z "$provider" || "$provider" == "none" ]]; then
79
+ local daemon_cfg=".claude/daemon-config.json"
80
+ if [[ -f "$daemon_cfg" ]]; then
81
+ provider=$(jq -r '.tracker.provider // "none"' "$daemon_cfg" 2>/dev/null || echo "none")
82
+ fi
83
+ fi
84
+
85
+ TRACKER_PROVIDER="${provider:-none}"
86
+
87
+ case "$TRACKER_PROVIDER" in
88
+ linear)
89
+ if [[ -f "$SCRIPT_DIR/sw-tracker-linear.sh" ]]; then
90
+ source "$SCRIPT_DIR/sw-tracker-linear.sh"
91
+ return 0
92
+ else
93
+ warn "Linear provider script not found: $SCRIPT_DIR/sw-tracker-linear.sh"
94
+ fi
95
+ ;;
96
+ jira)
97
+ if [[ -f "$SCRIPT_DIR/sw-tracker-jira.sh" ]]; then
98
+ source "$SCRIPT_DIR/sw-tracker-jira.sh"
99
+ return 0
100
+ else
101
+ warn "Jira provider script not found: $SCRIPT_DIR/sw-tracker-jira.sh"
102
+ fi
103
+ ;;
104
+ none|"") return 0 ;;
105
+ *)
106
+ warn "Unknown tracker provider: $TRACKER_PROVIDER"
107
+ TRACKER_PROVIDER="none"
108
+ ;;
109
+ esac
110
+ return 0
111
+ }
112
+
113
+ # Check if a tracker is configured and available
114
+ tracker_available() {
115
+ load_tracker_config
116
+ [[ "$TRACKER_PROVIDER" != "none" && -n "$TRACKER_PROVIDER" ]]
117
+ }
118
+
119
+ # Route notification to the active provider
120
+ # Usage: tracker_notify <event> <gh_issue> [detail]
121
+ # Events: spawn, started, stage_complete, stage_failed, review, pr-created, completed, done, failed
122
+ tracker_notify() {
123
+ local event="$1"
124
+ local gh_issue="${2:-}"
125
+ local detail="${3:-}"
126
+
127
+ load_tracker_config
128
+
129
+ if [[ "$TRACKER_PROVIDER" == "none" || -z "$TRACKER_PROVIDER" ]]; then
130
+ return 0 # silently skip when no provider configured
131
+ fi
132
+
133
+ # Provider scripts define provider_notify()
134
+ if type provider_notify &>/dev/null; then
135
+ provider_notify "$event" "$gh_issue" "$detail"
136
+ else
137
+ warn "Provider '$TRACKER_PROVIDER' loaded but provider_notify() not defined"
138
+ fi
139
+ }
140
+
141
+ # ─── Interactive Init ──────────────────────────────────────────────────────
142
+
143
+ cmd_init() {
144
+ echo -e "${PURPLE}${BOLD}━━━ Tracker Integration Setup ━━━${RESET}"
145
+ echo ""
146
+
147
+ mkdir -p "$CONFIG_DIR"
148
+
149
+ echo -e " ${BOLD}Select a tracker provider:${RESET}"
150
+ echo ""
151
+ echo -e " ${CYAN}1${RESET}) Linear"
152
+ echo -e " ${CYAN}2${RESET}) Jira"
153
+ echo -e " ${CYAN}3${RESET}) None (disable)"
154
+ echo ""
155
+ read -rp " Choice [1-3]: " choice
156
+
157
+ local provider="none"
158
+ case "$choice" in
159
+ 1) provider="linear" ;;
160
+ 2) provider="jira" ;;
161
+ 3) provider="none" ;;
162
+ *)
163
+ error "Invalid choice"
164
+ exit 1
165
+ ;;
166
+ esac
167
+
168
+ if [[ "$provider" == "none" ]]; then
169
+ # Write minimal config
170
+ local tmp_config="${TRACKER_CONFIG}.tmp"
171
+ jq -n --arg provider "none" --arg updated "$(now_iso)" \
172
+ '{provider: $provider, updated_at: $updated}' > "$tmp_config"
173
+ mv "$tmp_config" "$TRACKER_CONFIG"
174
+ success "Tracker disabled"
175
+ return 0
176
+ fi
177
+
178
+ if [[ "$provider" == "linear" ]]; then
179
+ _init_linear
180
+ elif [[ "$provider" == "jira" ]]; then
181
+ _init_jira
182
+ fi
183
+
184
+ emit_event "tracker.init" "provider=$provider"
185
+ }
186
+
187
+ _init_linear() {
188
+ echo ""
189
+ echo -e " ${CYAN}1.${RESET} Go to ${DIM}https://linear.app/settings/api${RESET}"
190
+ echo -e " ${CYAN}2.${RESET} Create a personal API key"
191
+ echo -e " ${CYAN}3.${RESET} Paste it below"
192
+ echo ""
193
+ read -rp " Linear API Key: " api_key
194
+ if [[ -z "$api_key" ]]; then
195
+ error "API key is required"
196
+ exit 1
197
+ fi
198
+
199
+ read -rp " Team ID [press Enter for default]: " team_id
200
+ team_id="${team_id:-}"
201
+ read -rp " Project ID [press Enter for default]: " project_id
202
+ project_id="${project_id:-}"
203
+
204
+ local tmp_config="${TRACKER_CONFIG}.tmp"
205
+ jq -n \
206
+ --arg provider "linear" \
207
+ --arg api_key "$api_key" \
208
+ --arg team_id "$team_id" \
209
+ --arg project_id "$project_id" \
210
+ --arg updated "$(now_iso)" \
211
+ '{
212
+ provider: $provider,
213
+ linear: {
214
+ api_key: $api_key,
215
+ team_id: $team_id,
216
+ project_id: $project_id
217
+ },
218
+ updated_at: $updated
219
+ }' > "$tmp_config"
220
+ mv "$tmp_config" "$TRACKER_CONFIG"
221
+ chmod 600 "$TRACKER_CONFIG"
222
+
223
+ success "Linear tracker configured"
224
+ echo ""
225
+
226
+ # Validate connection
227
+ info "Validating API key..."
228
+ local payload
229
+ payload=$(jq -n --arg q 'query { viewer { id name } }' '{query: $q}')
230
+ local response
231
+ response=$(curl -sf -X POST "https://api.linear.app/graphql" \
232
+ -H "Authorization: $api_key" \
233
+ -H "Content-Type: application/json" \
234
+ -d "$payload" 2>&1) || {
235
+ warn "Could not validate API key — check your key"
236
+ return 0
237
+ }
238
+ local viewer_name
239
+ viewer_name=$(echo "$response" | jq -r '.data.viewer.name // "Unknown"' 2>/dev/null || echo "Unknown")
240
+ success "Authenticated as: ${viewer_name}"
241
+ }
242
+
243
+ _init_jira() {
244
+ echo ""
245
+ echo -e " ${CYAN}1.${RESET} Enter your Jira instance URL (e.g. https://myteam.atlassian.net)"
246
+ echo -e " ${CYAN}2.${RESET} Create an API token at ${DIM}https://id.atlassian.com/manage-profile/security/api-tokens${RESET}"
247
+ echo ""
248
+ read -rp " Jira Base URL: " base_url
249
+ if [[ -z "$base_url" ]]; then
250
+ error "Base URL is required"
251
+ exit 1
252
+ fi
253
+ # Strip trailing slash
254
+ base_url="${base_url%/}"
255
+
256
+ read -rp " Jira Email: " email
257
+ if [[ -z "$email" ]]; then
258
+ error "Email is required"
259
+ exit 1
260
+ fi
261
+
262
+ read -rp " Jira API Token: " api_token
263
+ if [[ -z "$api_token" ]]; then
264
+ error "API token is required"
265
+ exit 1
266
+ fi
267
+
268
+ read -rp " Project Key (e.g. PROJ): " project_key
269
+ project_key="${project_key:-}"
270
+
271
+ local tmp_config="${TRACKER_CONFIG}.tmp"
272
+ jq -n \
273
+ --arg provider "jira" \
274
+ --arg base_url "$base_url" \
275
+ --arg email "$email" \
276
+ --arg api_token "$api_token" \
277
+ --arg project_key "$project_key" \
278
+ --arg updated "$(now_iso)" \
279
+ '{
280
+ provider: $provider,
281
+ jira: {
282
+ base_url: $base_url,
283
+ email: $email,
284
+ api_token: $api_token,
285
+ project_key: $project_key
286
+ },
287
+ updated_at: $updated
288
+ }' > "$tmp_config"
289
+ mv "$tmp_config" "$TRACKER_CONFIG"
290
+ chmod 600 "$TRACKER_CONFIG"
291
+
292
+ success "Jira tracker configured"
293
+ echo ""
294
+
295
+ # Validate connection
296
+ info "Validating connection..."
297
+ local auth
298
+ auth=$(printf '%s:%s' "$email" "$api_token" | base64)
299
+ local response
300
+ response=$(curl -sf -X GET "${base_url}/rest/api/3/myself" \
301
+ -H "Authorization: Basic $auth" \
302
+ -H "Content-Type: application/json" 2>&1) || {
303
+ warn "Could not validate connection — check your credentials"
304
+ return 0
305
+ }
306
+ local display_name
307
+ display_name=$(echo "$response" | jq -r '.displayName // "Unknown"' 2>/dev/null || echo "Unknown")
308
+ success "Authenticated as: ${display_name}"
309
+ }
310
+
311
+ # ─── Status ────────────────────────────────────────────────────────────────
312
+
313
+ cmd_status() {
314
+ load_tracker_config
315
+
316
+ echo -e "${PURPLE}${BOLD}━━━ Tracker Status ━━━${RESET}"
317
+ echo ""
318
+ echo -e " ${BOLD}Provider:${RESET} ${CYAN}${TRACKER_PROVIDER}${RESET}"
319
+
320
+ if [[ -f "$TRACKER_CONFIG" ]]; then
321
+ local updated
322
+ updated=$(jq -r '.updated_at // "unknown"' "$TRACKER_CONFIG" 2>/dev/null || echo "unknown")
323
+ echo -e " ${BOLD}Config:${RESET} ${DIM}${TRACKER_CONFIG}${RESET}"
324
+ echo -e " ${BOLD}Updated:${RESET} ${DIM}${updated}${RESET}"
325
+ else
326
+ echo -e " ${BOLD}Config:${RESET} ${DIM}(not configured — run 'shipwright tracker init')${RESET}"
327
+ fi
328
+
329
+ echo ""
330
+
331
+ # Show recent tracker events
332
+ if [[ -f "$EVENTS_FILE" ]]; then
333
+ local recent
334
+ recent=$(grep '"type":"tracker\.' "$EVENTS_FILE" 2>/dev/null | tail -5 || true)
335
+ if [[ -n "$recent" ]]; then
336
+ echo -e "${BOLD}Recent Tracker Activity${RESET}"
337
+ echo "$recent" | while IFS= read -r line; do
338
+ local ts type
339
+ ts=$(echo "$line" | jq -r '.ts' 2>/dev/null || true)
340
+ type=$(echo "$line" | jq -r '.type' 2>/dev/null || true)
341
+ echo -e " ${DIM}${ts}${RESET} ${type}"
342
+ done
343
+ echo ""
344
+ fi
345
+ fi
346
+ }
347
+
348
+ # ─── Help ──────────────────────────────────────────────────────────────────
349
+
350
+ show_help() {
351
+ echo -e "${CYAN}${BOLD}shipwright tracker${RESET} — Issue Tracker Provider Router"
352
+ echo ""
353
+ echo -e "${BOLD}USAGE${RESET}"
354
+ echo -e " ${CYAN}shipwright tracker${RESET} <command> [options]"
355
+ echo ""
356
+ echo -e "${BOLD}COMMANDS${RESET}"
357
+ echo -e " ${CYAN}init${RESET} Configure tracker provider"
358
+ echo -e " ${CYAN}status${RESET} Show tracker configuration"
359
+ echo -e " ${CYAN}available${RESET} Check if a tracker is configured"
360
+ echo -e " ${CYAN}notify${RESET} <event> <issue> [detail] Send notification to tracker"
361
+ echo -e " ${CYAN}help${RESET} Show this help"
362
+ echo ""
363
+ echo -e "${BOLD}PROVIDERS${RESET}"
364
+ echo -e " ${CYAN}linear${RESET} Linear.app (GraphQL API)"
365
+ echo -e " ${CYAN}jira${RESET} Atlassian Jira (REST API v3)"
366
+ echo ""
367
+ echo -e "${BOLD}NOTIFICATION EVENTS${RESET}"
368
+ echo -e " ${CYAN}spawn${RESET} Pipeline started"
369
+ echo -e " ${CYAN}stage_complete${RESET} Stage finished (detail: stage_id|duration|description)"
370
+ echo -e " ${CYAN}stage_failed${RESET} Stage failed (detail: stage_id|error_context)"
371
+ echo -e " ${CYAN}review${RESET} PR created (detail: pr_url)"
372
+ echo -e " ${CYAN}completed${RESET} Pipeline done"
373
+ echo -e " ${CYAN}failed${RESET} Pipeline failed (detail: error_message)"
374
+ echo ""
375
+ echo -e "${BOLD}CONFIGURATION${RESET}"
376
+ echo -e " Config file: ${DIM}~/.shipwright/tracker-config.json${RESET}"
377
+ echo -e " Env override: ${DIM}TRACKER_PROVIDER_OVERRIDE=linear|jira|none${RESET}"
378
+ echo -e " Daemon block: ${DIM}.claude/daemon-config.json → .tracker.provider${RESET}"
379
+ echo ""
380
+ echo -e "${BOLD}EXAMPLES${RESET}"
381
+ echo -e " ${DIM}shipwright tracker init${RESET} # Configure provider"
382
+ echo -e " ${DIM}shipwright tracker status${RESET} # Show config"
383
+ echo -e " ${DIM}shipwright tracker notify spawn 42${RESET} # Notify pipeline started"
384
+ echo -e " ${DIM}shipwright tracker notify completed 42${RESET} # Notify pipeline done"
385
+ echo -e " ${DIM}shipwright tracker notify review 42 'https://...'${RESET} # Notify PR created"
386
+ }
387
+
388
+ # ─── Command Router ─────────────────────────────────────────────────────────
389
+
390
+ main() {
391
+ local cmd="${1:-help}"
392
+ shift 2>/dev/null || true
393
+
394
+ case "$cmd" in
395
+ notify) tracker_notify "$@" ;;
396
+ available) tracker_available && echo "true" || echo "false" ;;
397
+ init) cmd_init "$@" ;;
398
+ status) cmd_status "$@" ;;
399
+ help|--help|-h) show_help ;;
400
+ *)
401
+ error "Unknown command: ${cmd}"
402
+ echo ""
403
+ show_help
404
+ exit 1
405
+ ;;
406
+ esac
407
+ }
408
+
409
+ main "$@"
@@ -1,11 +1,13 @@
1
1
  #!/usr/bin/env bash
2
2
  # ╔═══════════════════════════════════════════════════════════════════════════╗
3
- # ║ cct upgrade — Detect and apply updates from the repo ║
3
+ # ║ sw upgrade — Detect and apply updates from the repo ║
4
4
  # ╚═══════════════════════════════════════════════════════════════════════════╝
5
+ VERSION="1.9.0"
5
6
  set -euo pipefail
7
+ trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
6
8
 
7
9
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
- MANIFEST_DIR="$HOME/.claude-teams"
10
+ MANIFEST_DIR="$HOME/.shipwright"
9
11
  MANIFEST="$MANIFEST_DIR/manifest.json"
10
12
 
11
13
  # ─── Colors ────────────────────────────────────────────────────────────────
@@ -19,6 +21,9 @@ DIM='\033[2m'
19
21
  BOLD='\033[1m'
20
22
  RESET='\033[0m'
21
23
 
24
+ # ─── Cross-platform compatibility ──────────────────────────────────────────
25
+ # shellcheck source=lib/compat.sh
26
+ [[ -f "$SCRIPT_DIR/lib/compat.sh" ]] && source "$SCRIPT_DIR/lib/compat.sh"
22
27
  info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
23
28
  success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
24
29
  warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*"; }
@@ -59,7 +64,7 @@ find_repo() {
59
64
  # 3. Walk up from script dir
60
65
  local dir="$SCRIPT_DIR"
61
66
  while [[ "$dir" != "/" ]]; do
62
- if [[ -f "$dir/install.sh" && -d "$dir/scripts" && -f "$dir/scripts/cct" ]]; then
67
+ if [[ -f "$dir/install.sh" && -d "$dir/scripts" && -f "$dir/scripts/sw" ]]; then
63
68
  echo "$dir"
64
69
  return
65
70
  fi
@@ -94,52 +99,104 @@ BIN_DIR="$HOME/.local/bin"
94
99
 
95
100
  FILES=(
96
101
  "tmux.conf|tmux/tmux.conf|$HOME/.tmux.conf|false|false"
97
- "claude-teams-overlay.conf|tmux/claude-teams-overlay.conf|$HOME/.tmux/claude-teams-overlay.conf|false|false"
102
+ "shipwright-overlay.conf|tmux/shipwright-overlay.conf|$HOME/.tmux/shipwright-overlay.conf|false|false"
98
103
  "settings.json.template|claude-code/settings.json.template|$HOME/.claude/settings.json.template|false|false"
99
104
  "settings.json||$HOME/.claude/settings.json|true|false"
100
- "cct|scripts/cct|$BIN_DIR/cct|false|true"
101
- "cct-session.sh|scripts/cct-session.sh|$BIN_DIR/cct-session.sh|false|true"
102
- "cct-status.sh|scripts/cct-status.sh|$BIN_DIR/cct-status.sh|false|true"
103
- "cct-cleanup.sh|scripts/cct-cleanup.sh|$BIN_DIR/cct-cleanup.sh|false|true"
104
- "cct-upgrade.sh|scripts/cct-upgrade.sh|$BIN_DIR/cct-upgrade.sh|false|true"
105
- "cct-doctor.sh|scripts/cct-doctor.sh|$BIN_DIR/cct-doctor.sh|false|true"
106
- "cct-logs.sh|scripts/cct-logs.sh|$BIN_DIR/cct-logs.sh|false|true"
107
- "cct-ps.sh|scripts/cct-ps.sh|$BIN_DIR/cct-ps.sh|false|true"
108
- "cct-templates.sh|scripts/cct-templates.sh|$BIN_DIR/cct-templates.sh|false|true"
109
- "cct-loop.sh|scripts/cct-loop.sh|$BIN_DIR/cct-loop.sh|false|true"
110
- "cct-pipeline.sh|scripts/cct-pipeline.sh|$BIN_DIR/cct-pipeline.sh|false|true"
111
- "cct-pipeline-test.sh|scripts/cct-pipeline-test.sh|$BIN_DIR/cct-pipeline-test.sh|false|true"
112
- "cct-worktree.sh|scripts/cct-worktree.sh|$BIN_DIR/cct-worktree.sh|false|true"
113
- "cct-init.sh|scripts/cct-init.sh|$BIN_DIR/cct-init.sh|false|true"
114
- "cct-prep.sh|scripts/cct-prep.sh|$BIN_DIR/cct-prep.sh|false|true"
115
- "cct-daemon.sh|scripts/cct-daemon.sh|$BIN_DIR/cct-daemon.sh|false|true"
116
- "cct-daemon-test.sh|scripts/cct-daemon-test.sh|$BIN_DIR/cct-daemon-test.sh|false|true"
117
- "cct-prep-test.sh|scripts/cct-prep-test.sh|$BIN_DIR/cct-prep-test.sh|false|true"
118
- "cct-memory.sh|scripts/cct-memory.sh|$BIN_DIR/cct-memory.sh|false|true"
119
- "cct-memory-test.sh|scripts/cct-memory-test.sh|$BIN_DIR/cct-memory-test.sh|false|true"
120
- "cct-cost.sh|scripts/cct-cost.sh|$BIN_DIR/cct-cost.sh|false|true"
121
- "cct-fleet.sh|scripts/cct-fleet.sh|$BIN_DIR/cct-fleet.sh|false|true"
122
- "cct-fleet-test.sh|scripts/cct-fleet-test.sh|$BIN_DIR/cct-fleet-test.sh|false|true"
123
- "cct-fix.sh|scripts/cct-fix.sh|$BIN_DIR/cct-fix.sh|false|true"
124
- "cct-fix-test.sh|scripts/cct-fix-test.sh|$BIN_DIR/cct-fix-test.sh|false|true"
125
- "cct-reaper.sh|scripts/cct-reaper.sh|$BIN_DIR/cct-reaper.sh|false|true"
105
+ "sw|scripts/sw|$BIN_DIR/sw|false|true"
106
+ "sw-session.sh|scripts/sw-session.sh|$BIN_DIR/sw-session.sh|false|true"
107
+ "sw-status.sh|scripts/sw-status.sh|$BIN_DIR/sw-status.sh|false|true"
108
+ "sw-cleanup.sh|scripts/sw-cleanup.sh|$BIN_DIR/sw-cleanup.sh|false|true"
109
+ "sw-upgrade.sh|scripts/sw-upgrade.sh|$BIN_DIR/sw-upgrade.sh|false|true"
110
+ "sw-doctor.sh|scripts/sw-doctor.sh|$BIN_DIR/sw-doctor.sh|false|true"
111
+ "sw-logs.sh|scripts/sw-logs.sh|$BIN_DIR/sw-logs.sh|false|true"
112
+ "sw-ps.sh|scripts/sw-ps.sh|$BIN_DIR/sw-ps.sh|false|true"
113
+ "sw-templates.sh|scripts/sw-templates.sh|$BIN_DIR/sw-templates.sh|false|true"
114
+ "sw-loop.sh|scripts/sw-loop.sh|$BIN_DIR/sw-loop.sh|false|true"
115
+ "sw-pipeline.sh|scripts/sw-pipeline.sh|$BIN_DIR/sw-pipeline.sh|false|true"
116
+ "sw-pipeline-test.sh|scripts/sw-pipeline-test.sh|$BIN_DIR/sw-pipeline-test.sh|false|true"
117
+ "sw-worktree.sh|scripts/sw-worktree.sh|$BIN_DIR/sw-worktree.sh|false|true"
118
+ "sw-init.sh|scripts/sw-init.sh|$BIN_DIR/sw-init.sh|false|true"
119
+ "sw-setup.sh|scripts/sw-setup.sh|$BIN_DIR/sw-setup.sh|false|true"
120
+ "sw-prep.sh|scripts/sw-prep.sh|$BIN_DIR/sw-prep.sh|false|true"
121
+ "sw-daemon.sh|scripts/sw-daemon.sh|$BIN_DIR/sw-daemon.sh|false|true"
122
+ "sw-daemon-test.sh|scripts/sw-daemon-test.sh|$BIN_DIR/sw-daemon-test.sh|false|true"
123
+ "sw-prep-test.sh|scripts/sw-prep-test.sh|$BIN_DIR/sw-prep-test.sh|false|true"
124
+ "sw-memory.sh|scripts/sw-memory.sh|$BIN_DIR/sw-memory.sh|false|true"
125
+ "sw-memory-test.sh|scripts/sw-memory-test.sh|$BIN_DIR/sw-memory-test.sh|false|true"
126
+ "sw-cost.sh|scripts/sw-cost.sh|$BIN_DIR/sw-cost.sh|false|true"
127
+ "sw-fleet.sh|scripts/sw-fleet.sh|$BIN_DIR/sw-fleet.sh|false|true"
128
+ "sw-fleet-test.sh|scripts/sw-fleet-test.sh|$BIN_DIR/sw-fleet-test.sh|false|true"
129
+ "sw-fix.sh|scripts/sw-fix.sh|$BIN_DIR/sw-fix.sh|false|true"
130
+ "sw-fix-test.sh|scripts/sw-fix-test.sh|$BIN_DIR/sw-fix-test.sh|false|true"
131
+ "sw-reaper.sh|scripts/sw-reaper.sh|$BIN_DIR/sw-reaper.sh|false|true"
132
+ "sw-dashboard.sh|scripts/sw-dashboard.sh|$BIN_DIR/sw-dashboard.sh|false|true"
133
+ "sw-docs.sh|scripts/sw-docs.sh|$BIN_DIR/sw-docs.sh|false|true"
134
+ "sw-tmux.sh|scripts/sw-tmux.sh|$BIN_DIR/sw-tmux.sh|false|true"
135
+ "sw-connect.sh|scripts/sw-connect.sh|$BIN_DIR/sw-connect.sh|false|true"
136
+ "sw-tracker.sh|scripts/sw-tracker.sh|$BIN_DIR/sw-tracker.sh|false|true"
137
+ "sw-linear.sh|scripts/sw-linear.sh|$BIN_DIR/sw-linear.sh|false|true"
138
+ "sw-jira.sh|scripts/sw-jira.sh|$BIN_DIR/sw-jira.sh|false|true"
139
+ "sw-launchd.sh|scripts/sw-launchd.sh|$BIN_DIR/sw-launchd.sh|false|true"
140
+ "sw-checkpoint.sh|scripts/sw-checkpoint.sh|$BIN_DIR/sw-checkpoint.sh|false|true"
141
+ "sw-heartbeat.sh|scripts/sw-heartbeat.sh|$BIN_DIR/sw-heartbeat.sh|false|true"
142
+ "sw-intelligence.sh|scripts/sw-intelligence.sh|$BIN_DIR/sw-intelligence.sh|false|true"
143
+ "sw-pipeline-composer.sh|scripts/sw-pipeline-composer.sh|$BIN_DIR/sw-pipeline-composer.sh|false|true"
144
+ "sw-self-optimize.sh|scripts/sw-self-optimize.sh|$BIN_DIR/sw-self-optimize.sh|false|true"
145
+ "sw-predictive.sh|scripts/sw-predictive.sh|$BIN_DIR/sw-predictive.sh|false|true"
146
+ "sw-adversarial.sh|scripts/sw-adversarial.sh|$BIN_DIR/sw-adversarial.sh|false|true"
147
+ "sw-developer-simulation.sh|scripts/sw-developer-simulation.sh|$BIN_DIR/sw-developer-simulation.sh|false|true"
148
+ "sw-architecture-enforcer.sh|scripts/sw-architecture-enforcer.sh|$BIN_DIR/sw-architecture-enforcer.sh|false|true"
149
+ "sw-patrol-meta.sh|scripts/sw-patrol-meta.sh|$BIN_DIR/sw-patrol-meta.sh|false|true"
150
+ # GitHub API modules
151
+ "sw-github-graphql.sh|scripts/sw-github-graphql.sh|$BIN_DIR/sw-github-graphql.sh|false|true"
152
+ "sw-github-checks.sh|scripts/sw-github-checks.sh|$BIN_DIR/sw-github-checks.sh|false|true"
153
+ "sw-github-deploy.sh|scripts/sw-github-deploy.sh|$BIN_DIR/sw-github-deploy.sh|false|true"
154
+ # Tracker adapters
155
+ "sw-tracker-linear.sh|scripts/sw-tracker-linear.sh|$BIN_DIR/sw-tracker-linear.sh|false|true"
156
+ "sw-tracker-jira.sh|scripts/sw-tracker-jira.sh|$BIN_DIR/sw-tracker-jira.sh|false|true"
157
+ # Test suites
158
+ "sw-connect-test.sh|scripts/sw-connect-test.sh|$BIN_DIR/sw-connect-test.sh|false|true"
159
+ "sw-intelligence-test.sh|scripts/sw-intelligence-test.sh|$BIN_DIR/sw-intelligence-test.sh|false|true"
160
+ "sw-frontier-test.sh|scripts/sw-frontier-test.sh|$BIN_DIR/sw-frontier-test.sh|false|true"
161
+ "sw-self-optimize-test.sh|scripts/sw-self-optimize-test.sh|$BIN_DIR/sw-self-optimize-test.sh|false|true"
162
+ "sw-pipeline-composer-test.sh|scripts/sw-pipeline-composer-test.sh|$BIN_DIR/sw-pipeline-composer-test.sh|false|true"
163
+ "sw-predictive-test.sh|scripts/sw-predictive-test.sh|$BIN_DIR/sw-predictive-test.sh|false|true"
164
+ "sw-heartbeat-test.sh|scripts/sw-heartbeat-test.sh|$BIN_DIR/sw-heartbeat-test.sh|false|true"
165
+ "sw-github-graphql-test.sh|scripts/sw-github-graphql-test.sh|$BIN_DIR/sw-github-graphql-test.sh|false|true"
166
+ "sw-github-checks-test.sh|scripts/sw-github-checks-test.sh|$BIN_DIR/sw-github-checks-test.sh|false|true"
167
+ "sw-github-deploy-test.sh|scripts/sw-github-deploy-test.sh|$BIN_DIR/sw-github-deploy-test.sh|false|true"
168
+ "sw-tracker-test.sh|scripts/sw-tracker-test.sh|$BIN_DIR/sw-tracker-test.sh|false|true"
169
+ "sw-init-test.sh|scripts/sw-init-test.sh|$BIN_DIR/sw-init-test.sh|false|true"
170
+ "sw-session-test.sh|scripts/sw-session-test.sh|$BIN_DIR/sw-session-test.sh|false|true"
171
+ "sw-remote-test.sh|scripts/sw-remote-test.sh|$BIN_DIR/sw-remote-test.sh|false|true"
172
+ # Shared libraries
173
+ "compat.sh|scripts/lib/compat.sh|$BIN_DIR/lib/compat.sh|false|false"
126
174
  "CLAUDE.md.shipwright|claude-code/CLAUDE.md.shipwright|$HOME/.claude/CLAUDE.md|true|false"
127
175
  "teammate-idle.sh|claude-code/hooks/teammate-idle.sh|$HOME/.claude/hooks/teammate-idle.sh|false|true"
128
176
  "task-completed.sh|claude-code/hooks/task-completed.sh|$HOME/.claude/hooks/task-completed.sh|false|true"
129
177
  "notify-idle.sh|claude-code/hooks/notify-idle.sh|$HOME/.claude/hooks/notify-idle.sh|false|true"
130
178
  "pre-compact-save.sh|claude-code/hooks/pre-compact-save.sh|$HOME/.claude/hooks/pre-compact-save.sh|false|true"
131
- "feature-dev.json|tmux/templates/feature-dev.json|$HOME/.claude-teams/templates/feature-dev.json|false|false"
132
- "code-review.json|tmux/templates/code-review.json|$HOME/.claude-teams/templates/code-review.json|false|false"
133
- "refactor.json|tmux/templates/refactor.json|$HOME/.claude-teams/templates/refactor.json|false|false"
134
- "exploration.json|tmux/templates/exploration.json|$HOME/.claude-teams/templates/exploration.json|false|false"
135
- "definition-of-done.example.md|docs/definition-of-done.example.md|$HOME/.claude-teams/templates/definition-of-done.example.md|false|false"
136
- "pipeline-standard.json|templates/pipelines/standard.json|$HOME/.claude-teams/pipelines/standard.json|false|false"
137
- "pipeline-fast.json|templates/pipelines/fast.json|$HOME/.claude-teams/pipelines/fast.json|false|false"
138
- "pipeline-full.json|templates/pipelines/full.json|$HOME/.claude-teams/pipelines/full.json|false|false"
139
- "pipeline-hotfix.json|templates/pipelines/hotfix.json|$HOME/.claude-teams/pipelines/hotfix.json|false|false"
140
- "pipeline-autonomous.json|templates/pipelines/autonomous.json|$HOME/.claude-teams/pipelines/autonomous.json|false|false"
141
- "pipeline-cost-aware.json|templates/pipelines/cost-aware.json|$HOME/.claude-teams/pipelines/cost-aware.json|false|false"
142
- "pipeline-enterprise.json|templates/pipelines/enterprise.json|$HOME/.claude-teams/pipelines/enterprise.json|false|false"
179
+ "feature-dev.json|tmux/templates/feature-dev.json|$HOME/.shipwright/templates/feature-dev.json|false|false"
180
+ "code-review.json|tmux/templates/code-review.json|$HOME/.shipwright/templates/code-review.json|false|false"
181
+ "refactor.json|tmux/templates/refactor.json|$HOME/.shipwright/templates/refactor.json|false|false"
182
+ "exploration.json|tmux/templates/exploration.json|$HOME/.shipwright/templates/exploration.json|false|false"
183
+ "bug-fix.json|tmux/templates/bug-fix.json|$HOME/.shipwright/templates/bug-fix.json|false|false"
184
+ "testing.json|tmux/templates/testing.json|$HOME/.shipwright/templates/testing.json|false|false"
185
+ "full-stack.json|tmux/templates/full-stack.json|$HOME/.shipwright/templates/full-stack.json|false|false"
186
+ "security-audit.json|tmux/templates/security-audit.json|$HOME/.shipwright/templates/security-audit.json|false|false"
187
+ "migration.json|tmux/templates/migration.json|$HOME/.shipwright/templates/migration.json|false|false"
188
+ "documentation.json|tmux/templates/documentation.json|$HOME/.shipwright/templates/documentation.json|false|false"
189
+ "devops.json|tmux/templates/devops.json|$HOME/.shipwright/templates/devops.json|false|false"
190
+ "architecture.json|tmux/templates/architecture.json|$HOME/.shipwright/templates/architecture.json|false|false"
191
+ "definition-of-done.example.md|docs/definition-of-done.example.md|$HOME/.shipwright/templates/definition-of-done.example.md|false|false"
192
+ "pipeline-standard.json|templates/pipelines/standard.json|$HOME/.shipwright/pipelines/standard.json|false|false"
193
+ "pipeline-fast.json|templates/pipelines/fast.json|$HOME/.shipwright/pipelines/fast.json|false|false"
194
+ "pipeline-full.json|templates/pipelines/full.json|$HOME/.shipwright/pipelines/full.json|false|false"
195
+ "pipeline-hotfix.json|templates/pipelines/hotfix.json|$HOME/.shipwright/pipelines/hotfix.json|false|false"
196
+ "pipeline-autonomous.json|templates/pipelines/autonomous.json|$HOME/.shipwright/pipelines/autonomous.json|false|false"
197
+ "pipeline-cost-aware.json|templates/pipelines/cost-aware.json|$HOME/.shipwright/pipelines/cost-aware.json|false|false"
198
+ "pipeline-enterprise.json|templates/pipelines/enterprise.json|$HOME/.shipwright/pipelines/enterprise.json|false|false"
199
+ "pipeline-deployed.json|templates/pipelines/deployed.json|$HOME/.shipwright/pipelines/deployed.json|false|false"
143
200
  )
144
201
 
145
202
  # ─── Checksum helper ──────────────────────────────────────────────────────
@@ -353,7 +410,7 @@ if ! $APPLY; then
353
410
  fi
354
411
 
355
412
  # Apply upgrades
356
- CCT_SELF_UPGRADED=false
413
+ SW_SELF_UPGRADED=false
357
414
 
358
415
  echo -e "${BOLD}Applying...${RESET}"
359
416
  echo ""
@@ -387,8 +444,8 @@ if [[ ${#UPGRADEABLE[@]} -gt 0 ]]; then
387
444
  for item in "${UPGRADEABLE[@]}"; do
388
445
  IFS='|' read -r key src dest executable <<< "$item"
389
446
  apply_file "$key" "$src" "$dest" "$executable"
390
- if [[ "$key" == cct* ]]; then
391
- CCT_SELF_UPGRADED=true
447
+ if [[ "$key" == sw* ]]; then
448
+ SW_SELF_UPGRADED=true
392
449
  fi
393
450
  done
394
451
  fi
@@ -408,7 +465,7 @@ write_manifest
408
465
  success "Manifest updated: $MANIFEST"
409
466
 
410
467
  # Self-upgrade warning
411
- if $CCT_SELF_UPGRADED; then
468
+ if $SW_SELF_UPGRADED; then
412
469
  echo ""
413
470
  echo -e "${YELLOW}${BOLD}⚠${RESET} The Shipwright CLI itself was upgraded."
414
471
  echo -e " Your current command completed, but re-run to use the new version."
@@ -5,7 +5,9 @@
5
5
  # ║ Each agent gets its own worktree so parallel agents don't clobber ║
6
6
  # ║ each other's files. Worktrees live in .worktrees/ relative to root. ║
7
7
  # ╚═══════════════════════════════════════════════════════════════════════════╝
8
+ VERSION="1.9.0"
8
9
  set -euo pipefail
10
+ trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
9
11
 
10
12
  # ─── Colors ────────────────────────────────────────────────────────────────
11
13
  CYAN='\033[38;2;0;212;255m'
@@ -216,6 +218,7 @@ worktree_remove() {
216
218
  git worktree remove "$worktree_path" --force 2>/dev/null || {
217
219
  warn "Could not cleanly remove worktree $name, forcing..."
218
220
  rm -rf "$worktree_path"
221
+ git worktree prune 2>/dev/null || true
219
222
  }
220
223
  fi
221
224