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,200 @@
1
+ #!/usr/bin/env bash
2
+ # ╔═══════════════════════════════════════════════════════════════════════════╗
3
+ # ║ shipwright compat — Cross-platform compatibility helpers ║
4
+ # ║ Source this AFTER color definitions for NO_COLOR + platform support ║
5
+ # ╚═══════════════════════════════════════════════════════════════════════════╝
6
+ #
7
+ # Usage:
8
+ # source "$SCRIPT_DIR/lib/compat.sh"
9
+ #
10
+ # Provides:
11
+ # - NO_COLOR / dumb terminal / non-tty detection (auto-blanks color vars)
12
+ # - sed_i() — cross-platform sed in-place editing
13
+ # - open_url() — cross-platform browser open
14
+ # - tmp_dir() — returns best temp directory for platform
15
+ # - is_wsl() — detect WSL environment
16
+ # - is_macos() / is_linux() — platform checks
17
+
18
+ # ─── NO_COLOR support (https://no-color.org/) ─────────────────────────────
19
+ # Blanks standard color variables when:
20
+ # - NO_COLOR is set (any value)
21
+ # - TERM is "dumb" (e.g. Emacs shell, CI without tty)
22
+ # - stdout is not a terminal (piped output)
23
+ if [[ -n "${NO_COLOR:-}" ]] || [[ "${TERM:-}" == "dumb" ]] || { [[ -z "${SHIPWRIGHT_FORCE_COLOR:-}" ]] && [[ ! -t 1 ]]; }; then
24
+ CYAN='' PURPLE='' BLUE='' GREEN='' YELLOW='' RED='' DIM='' BOLD='' RESET=''
25
+ UNDERLINE='' ITALIC=''
26
+ fi
27
+
28
+ # ─── Platform detection ───────────────────────────────────────────────────
29
+ _COMPAT_UNAME="${_COMPAT_UNAME:-$(uname -s 2>/dev/null || echo "Unknown")}"
30
+
31
+ is_macos() { [[ "$_COMPAT_UNAME" == "Darwin" ]]; }
32
+ is_linux() { [[ "$_COMPAT_UNAME" == "Linux" ]]; }
33
+ is_wsl() { is_linux && [[ -n "${WSL_DISTRO_NAME:-}" || -f /proc/version ]] && grep -qi microsoft /proc/version 2>/dev/null; }
34
+
35
+ # ─── sed -i (macOS vs GNU) ────────────────────────────────────────────────
36
+ # macOS sed requires '' after -i, GNU sed does not
37
+ sed_i() {
38
+ if is_macos; then
39
+ sed -i '' "$@"
40
+ else
41
+ sed -i "$@"
42
+ fi
43
+ }
44
+
45
+ # ─── Open URL in browser ──────────────────────────────────────────────────
46
+ open_url() {
47
+ local url="$1"
48
+ if is_macos; then
49
+ open "$url"
50
+ elif is_wsl; then
51
+ # WSL: use wslview (from wslu) or powershell
52
+ if command -v wslview &>/dev/null; then
53
+ wslview "$url"
54
+ elif command -v powershell.exe &>/dev/null; then
55
+ powershell.exe -Command "Start-Process '$url'" 2>/dev/null
56
+ else
57
+ return 1
58
+ fi
59
+ elif command -v xdg-open &>/dev/null; then
60
+ xdg-open "$url"
61
+ else
62
+ return 1
63
+ fi
64
+ }
65
+
66
+ # ─── Temp directory (respects Windows %TEMP% and %TMP%) ──────────────────
67
+ tmp_dir() {
68
+ echo "${TMPDIR:-${TEMP:-${TMP:-/tmp}}}"
69
+ }
70
+
71
+ # ─── Process existence check (portable) ──────────────────────────────────
72
+ pid_exists() {
73
+ local pid="$1"
74
+ kill -0 "$pid" 2>/dev/null
75
+ }
76
+
77
+ # ─── Shared Error Taxonomy ───────────────────────────────────────────────
78
+ # Canonical error categories used by sw-pipeline.sh, sw-memory.sh, and others.
79
+ # Extend via ~/.shipwright/optimization/error-taxonomy.json
80
+ SW_ERROR_CATEGORIES="test_failure build_error lint_error timeout dependency flaky config security permission unknown"
81
+
82
+ sw_valid_error_category() {
83
+ local category="${1:-}"
84
+ local custom_file="$HOME/.shipwright/optimization/error-taxonomy.json"
85
+ # Check custom taxonomy first
86
+ if [[ -f "$custom_file" ]] && command -v jq &>/dev/null; then
87
+ local custom_cats
88
+ custom_cats=$(jq -r '.categories[]? // empty' "$custom_file" 2>/dev/null || true)
89
+ if [[ -n "$custom_cats" ]]; then
90
+ local cat_item
91
+ while IFS= read -r cat_item; do
92
+ if [[ "$cat_item" == "$category" ]]; then
93
+ return 0
94
+ fi
95
+ done <<< "$custom_cats"
96
+ fi
97
+ fi
98
+ # Check built-in categories
99
+ local builtin
100
+ for builtin in $SW_ERROR_CATEGORIES; do
101
+ if [[ "$builtin" == "$category" ]]; then
102
+ return 0
103
+ fi
104
+ done
105
+ return 1
106
+ }
107
+
108
+ # ─── Complexity Bucketing ────────────────────────────────────────────────
109
+ # Shared by sw-intelligence.sh and sw-self-optimize.sh.
110
+ # Thresholds tunable via ~/.shipwright/optimization/complexity-clusters.json
111
+ complexity_bucket() {
112
+ local complexity="${1:-5}"
113
+ local config_file="$HOME/.shipwright/optimization/complexity-clusters.json"
114
+ local low_boundary=3
115
+ local high_boundary=6
116
+ if [[ -f "$config_file" ]] && command -v jq &>/dev/null; then
117
+ local lb hb
118
+ lb=$(jq -r '.low_boundary // 3' "$config_file" 2>/dev/null || echo "3")
119
+ hb=$(jq -r '.high_boundary // 6' "$config_file" 2>/dev/null || echo "6")
120
+ [[ "$lb" =~ ^[0-9]+$ ]] && low_boundary="$lb"
121
+ [[ "$hb" =~ ^[0-9]+$ ]] && high_boundary="$hb"
122
+ fi
123
+ if [[ "$complexity" -le "$low_boundary" ]]; then
124
+ echo "low"
125
+ elif [[ "$complexity" -le "$high_boundary" ]]; then
126
+ echo "medium"
127
+ else
128
+ echo "high"
129
+ fi
130
+ }
131
+
132
+ # ─── Framework / Language Detection ──────────────────────────────────────
133
+ # Shared by sw-prep.sh and sw-pipeline.sh.
134
+ detect_primary_language() {
135
+ local dir="${1:-.}"
136
+ if [[ -f "$dir/package.json" ]]; then
137
+ if [[ -f "$dir/tsconfig.json" ]]; then
138
+ echo "typescript"
139
+ else
140
+ echo "javascript"
141
+ fi
142
+ elif [[ -f "$dir/requirements.txt" || -f "$dir/pyproject.toml" || -f "$dir/setup.py" ]]; then
143
+ echo "python"
144
+ elif [[ -f "$dir/go.mod" ]]; then
145
+ echo "go"
146
+ elif [[ -f "$dir/Cargo.toml" ]]; then
147
+ echo "rust"
148
+ elif [[ -f "$dir/build.gradle" || -f "$dir/pom.xml" ]]; then
149
+ echo "java"
150
+ elif [[ -f "$dir/mix.exs" ]]; then
151
+ echo "elixir"
152
+ else
153
+ echo "unknown"
154
+ fi
155
+ }
156
+
157
+ detect_test_framework() {
158
+ local dir="${1:-.}"
159
+ if [[ -f "$dir/package.json" ]] && command -v jq &>/dev/null; then
160
+ local runner
161
+ runner=$(jq -r '
162
+ if .devDependencies.vitest then "vitest"
163
+ elif .devDependencies.jest then "jest"
164
+ elif .devDependencies.mocha then "mocha"
165
+ elif .devDependencies.ava then "ava"
166
+ elif .devDependencies.tap then "tap"
167
+ else ""
168
+ end' "$dir/package.json" 2>/dev/null || echo "")
169
+ if [[ -n "$runner" ]]; then
170
+ echo "$runner"
171
+ return 0
172
+ fi
173
+ fi
174
+ if [[ -f "$dir/pytest.ini" || -f "$dir/pyproject.toml" ]]; then
175
+ echo "pytest"
176
+ elif [[ -f "$dir/go.mod" ]]; then
177
+ echo "go test"
178
+ elif [[ -f "$dir/Cargo.toml" ]]; then
179
+ echo "cargo test"
180
+ elif [[ -f "$dir/build.gradle" ]]; then
181
+ echo "gradle test"
182
+ else
183
+ echo ""
184
+ fi
185
+ }
186
+
187
+ # ─── Cross-platform MD5 ──────────────────────────────────────────────────
188
+ # Usage:
189
+ # compute_md5 --string "some text" → md5 hash of string
190
+ # compute_md5 /path/to/file → md5 hash of file
191
+ compute_md5() {
192
+ if [[ "${1:-}" == "--string" ]]; then
193
+ shift
194
+ printf '%s' "$1" | md5 2>/dev/null || printf '%s' "$1" | md5sum 2>/dev/null | cut -d' ' -f1
195
+ else
196
+ # File mode
197
+ local file="$1"
198
+ md5 -q "$file" 2>/dev/null || md5sum "$file" 2>/dev/null | awk '{print $1}'
199
+ fi
200
+ }
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env bash
2
+ # ═══════════════════════════════════════════════════════════════════
3
+ # shipwright shared helpers — Colors, output, events, timestamps
4
+ # Source this from any script: source "$SCRIPT_DIR/lib/helpers.sh"
5
+ # ═══════════════════════════════════════════════════════════════════
6
+ #
7
+ # This is the canonical reference for common boilerplate that was
8
+ # previously duplicated across 18+ scripts. Existing scripts are NOT
9
+ # being modified to source this (too risky for a sweep), but all NEW
10
+ # scripts should source this instead of copy-pasting the boilerplate.
11
+ #
12
+ # Provides:
13
+ # - Color definitions (respects NO_COLOR)
14
+ # - Output helpers: info(), success(), warn(), error()
15
+ # - Timestamp helpers: now_iso(), now_epoch()
16
+ # - Event logging: emit_event()
17
+ #
18
+ # Usage in new scripts:
19
+ # SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
20
+ # source "$SCRIPT_DIR/lib/helpers.sh"
21
+ # # Optional: source "$SCRIPT_DIR/lib/compat.sh" for platform helpers
22
+
23
+ # ─── Double-source guard ─────────────────────────────────────────
24
+ [[ -n "${_SW_HELPERS_LOADED:-}" ]] && return 0
25
+ _SW_HELPERS_LOADED=1
26
+
27
+ # ─── Colors (matches Seth's tmux theme) ──────────────────────────
28
+ if [[ -z "${NO_COLOR:-}" ]]; then
29
+ CYAN='\033[38;2;0;212;255m' # #00d4ff — primary accent
30
+ PURPLE='\033[38;2;124;58;237m' # #7c3aed — secondary
31
+ BLUE='\033[38;2;0;102;255m' # #0066ff — tertiary
32
+ GREEN='\033[38;2;74;222;128m' # success
33
+ YELLOW='\033[38;2;250;204;21m' # warning
34
+ RED='\033[38;2;248;113;113m' # error
35
+ DIM='\033[2m'
36
+ BOLD='\033[1m'
37
+ RESET='\033[0m'
38
+ else
39
+ CYAN='' PURPLE='' BLUE='' GREEN='' YELLOW='' RED='' DIM='' BOLD='' RESET=''
40
+ fi
41
+
42
+ # ─── Output Helpers ──────────────────────────────────────────────
43
+ info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
44
+ success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
45
+ warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*"; }
46
+ error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
47
+
48
+ # ─── Timestamp Helpers ───────────────────────────────────────────
49
+ now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
50
+ now_epoch() { date +%s; }
51
+
52
+ # ─── Structured Event Log ────────────────────────────────────────
53
+ # Appends JSON events to ~/.shipwright/events.jsonl for metrics/traceability
54
+ EVENTS_FILE="${EVENTS_FILE:-${HOME}/.shipwright/events.jsonl}"
55
+
56
+ emit_event() {
57
+ local event_type="$1"
58
+ shift
59
+ local json_fields=""
60
+ for kv in "$@"; do
61
+ local key="${kv%%=*}"
62
+ local val="${kv#*=}"
63
+ if [[ "$val" =~ ^-?[0-9]+\.?[0-9]*$ ]]; then
64
+ json_fields="${json_fields},\"${key}\":${val}"
65
+ else
66
+ val="${val//\"/\\\"}"
67
+ json_fields="${json_fields},\"${key}\":\"${val}\""
68
+ fi
69
+ done
70
+ mkdir -p "${HOME}/.shipwright"
71
+ echo "{\"ts\":\"$(now_iso)\",\"ts_epoch\":$(now_epoch),\"type\":\"${event_type}\"${json_fields}}" >> "$EVENTS_FILE"
72
+ }
@@ -4,7 +4,14 @@
4
4
  // ║ Copies templates and migrates legacy config directories ║
5
5
  // ╚═══════════════════════════════════════════════════════════════════════════╝
6
6
 
7
- import { existsSync, mkdirSync, cpSync, readFileSync, writeFileSync, appendFileSync } from "fs";
7
+ import {
8
+ existsSync,
9
+ mkdirSync,
10
+ cpSync,
11
+ readFileSync,
12
+ writeFileSync,
13
+ appendFileSync,
14
+ } from "fs";
8
15
  import { join } from "path";
9
16
 
10
17
  const HOME = process.env.HOME || process.env.USERPROFILE;
@@ -20,9 +27,15 @@ const DIM = "\x1b[2m";
20
27
  const BOLD = "\x1b[1m";
21
28
  const RESET = "\x1b[0m";
22
29
 
23
- function info(msg) { console.log(`${CYAN}${BOLD}▸${RESET} ${msg}`); }
24
- function success(msg) { console.log(`${GREEN}${BOLD}✓${RESET} ${msg}`); }
25
- function warn(msg) { console.log(`${YELLOW}${BOLD}⚠${RESET} ${msg}`); }
30
+ function info(msg) {
31
+ console.log(`${CYAN}${BOLD}▸${RESET} ${msg}`);
32
+ }
33
+ function success(msg) {
34
+ console.log(`${GREEN}${BOLD}✓${RESET} ${msg}`);
35
+ }
36
+ function warn(msg) {
37
+ console.log(`${YELLOW}${BOLD}⚠${RESET} ${msg}`);
38
+ }
26
39
 
27
40
  function ensureDir(dir) {
28
41
  if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
@@ -35,16 +48,32 @@ function copyDir(src, dest) {
35
48
  }
36
49
 
37
50
  try {
51
+ // Ensure expected directories exist
52
+ ensureDir(CLAUDE_DIR);
53
+ ensureDir(join(CLAUDE_DIR, "hooks"));
54
+ ensureDir(LEGACY_DIR);
55
+ ensureDir(SHIPWRIGHT_DIR);
56
+
38
57
  // Copy team templates → ~/.shipwright/templates/
39
- copyDir(join(PKG_DIR, "tmux", "templates"), join(SHIPWRIGHT_DIR, "templates"));
58
+ copyDir(
59
+ join(PKG_DIR, "tmux", "templates"),
60
+ join(SHIPWRIGHT_DIR, "templates"),
61
+ );
40
62
  success("Installed team templates");
41
63
 
42
64
  // Copy pipeline templates → ~/.shipwright/pipelines/
43
- copyDir(join(PKG_DIR, "templates", "pipelines"), join(SHIPWRIGHT_DIR, "pipelines"));
65
+ copyDir(
66
+ join(PKG_DIR, "templates", "pipelines"),
67
+ join(SHIPWRIGHT_DIR, "pipelines"),
68
+ );
44
69
  success("Installed pipeline templates");
45
70
 
46
71
  // Copy settings template → ~/.claude/settings.json.template (if missing)
47
- const settingsTemplate = join(PKG_DIR, "claude-code", "settings.json");
72
+ const settingsTemplate = join(
73
+ PKG_DIR,
74
+ "claude-code",
75
+ "settings.json.template",
76
+ );
48
77
  const settingsDest = join(CLAUDE_DIR, "settings.json.template");
49
78
  if (existsSync(settingsTemplate) && !existsSync(settingsDest)) {
50
79
  ensureDir(CLAUDE_DIR);
@@ -52,6 +81,22 @@ try {
52
81
  success("Installed settings template");
53
82
  }
54
83
 
84
+ // Install agent definitions → ~/.claude/agents/
85
+ const agentsSrc = join(PKG_DIR, ".claude", "agents");
86
+ const agentsDest = join(CLAUDE_DIR, "agents");
87
+ if (existsSync(agentsSrc)) {
88
+ copyDir(agentsSrc, agentsDest);
89
+ success("Installed agent definitions");
90
+ }
91
+
92
+ // Install repo hooks → ~/.claude/hooks/
93
+ const hooksSrc = join(PKG_DIR, ".claude", "hooks");
94
+ const hooksDest = join(CLAUDE_DIR, "hooks");
95
+ if (existsSync(hooksSrc)) {
96
+ copyDir(hooksSrc, hooksDest);
97
+ success("Installed hooks");
98
+ }
99
+
55
100
  // Install CLAUDE.md agent instructions → ~/.claude/CLAUDE.md (idempotent)
56
101
  const claudeMdSrc = join(PKG_DIR, "claude-code", "CLAUDE.md.shipwright");
57
102
  const claudeMdDest = join(CLAUDE_DIR, "CLAUDE.md");
@@ -60,7 +105,10 @@ try {
60
105
  if (existsSync(claudeMdDest)) {
61
106
  const existing = readFileSync(claudeMdDest, "utf8");
62
107
  if (!existing.includes("Shipwright")) {
63
- appendFileSync(claudeMdDest, "\n---\n\n" + readFileSync(claudeMdSrc, "utf8"));
108
+ appendFileSync(
109
+ claudeMdDest,
110
+ "\n---\n\n" + readFileSync(claudeMdSrc, "utf8"),
111
+ );
64
112
  success("Appended Shipwright instructions to ~/.claude/CLAUDE.md");
65
113
  } else {
66
114
  success("~/.claude/CLAUDE.md already contains Shipwright instructions");
@@ -72,7 +120,10 @@ try {
72
120
  }
73
121
 
74
122
  // Migrate ~/.claude-teams/ → ~/.shipwright/ (non-destructive)
75
- if (existsSync(LEGACY_DIR) && !existsSync(join(SHIPWRIGHT_DIR, ".migrated"))) {
123
+ if (
124
+ existsSync(LEGACY_DIR) &&
125
+ !existsSync(join(SHIPWRIGHT_DIR, ".migrated"))
126
+ ) {
76
127
  info("Migrating legacy ~/.claude-teams/ config...");
77
128
  copyDir(LEGACY_DIR, SHIPWRIGHT_DIR);
78
129
  writeFileSync(join(SHIPWRIGHT_DIR, ".migrated"), new Date().toISOString());
@@ -80,14 +131,22 @@ try {
80
131
  }
81
132
 
82
133
  // Print success banner
83
- const version = JSON.parse(readFileSync(join(PKG_DIR, "package.json"), "utf8")).version;
134
+ const version = JSON.parse(
135
+ readFileSync(join(PKG_DIR, "package.json"), "utf8"),
136
+ ).version;
84
137
  console.log();
85
138
  console.log(`${CYAN}${BOLD} ⚓ Shipwright v${version} installed${RESET}`);
86
139
  console.log();
87
140
  console.log(` Next steps:`);
88
- console.log(` ${DIM}$${RESET} shipwright doctor ${DIM}# Verify your setup${RESET}`);
89
- console.log(` ${DIM}$${RESET} shipwright session ${DIM}# Launch an agent team${RESET}`);
90
- console.log(` ${DIM}$${RESET} shipwright pipeline ${DIM}# Run a delivery pipeline${RESET}`);
141
+ console.log(
142
+ ` ${DIM}$${RESET} shipwright doctor ${DIM}# Verify your setup${RESET}`,
143
+ );
144
+ console.log(
145
+ ` ${DIM}$${RESET} shipwright session ${DIM}# Launch an agent team${RESET}`,
146
+ );
147
+ console.log(
148
+ ` ${DIM}$${RESET} shipwright pipeline ${DIM}# Run a delivery pipeline${RESET}`,
149
+ );
91
150
  console.log();
92
151
  } catch (err) {
93
152
  warn(`Postinstall encountered an issue: ${err.message}`);
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env bash
2
2
  # ╔═══════════════════════════════════════════════════════════════════════════╗
3
- # ║ Shipwright CLI (cct) ║
3
+ # ║ Shipwright CLI (sw) ║
4
4
  # ║ Orchestrate autonomous Claude Code agent teams in tmux ║
5
5
  # ╚═══════════════════════════════════════════════════════════════════════════╝
6
6
  set -euo pipefail
7
7
 
8
- VERSION="1.7.1"
8
+ VERSION="1.9.0"
9
9
 
10
10
  # Resolve symlinks (required for npm global install where bin/ symlinks to node_modules/)
11
11
  SOURCE="${BASH_SOURCE[0]}"
@@ -27,6 +27,9 @@ DIM='\033[2m'
27
27
  BOLD='\033[1m'
28
28
  RESET='\033[0m'
29
29
 
30
+ # ─── Cross-platform compatibility ──────────────────────────────────────────
31
+ # shellcheck source=lib/compat.sh
32
+ [[ -f "$SCRIPT_DIR/lib/compat.sh" ]] && source "$SCRIPT_DIR/lib/compat.sh"
30
33
  # ─── Helpers ─────────────────────────────────────────────────────────────────
31
34
 
32
35
  info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
@@ -81,7 +84,22 @@ show_help() {
81
84
  echo -e " ${CYAN}cost${RESET} <cmd> ${BOLD}Cost intelligence${RESET} — track tokens, budgets, model routing"
82
85
  echo -e " ${CYAN}fleet${RESET} <cmd> ${BOLD}Multi-repo fleet${RESET} — orchestrate daemons across repos"
83
86
  echo -e " ${CYAN}fix${RESET} \"goal\" [opts] ${BOLD}Bulk fix${RESET} — apply a fix across multiple repos"
87
+ echo -e " ${CYAN}dashboard${RESET} <cmd> ${BOLD}Fleet Command${RESET} — real-time WebSocket dashboard"
88
+ echo -e " ${CYAN}jira${RESET} <cmd> ${BOLD}Jira sync${RESET} — bidirectional issue sync with Jira"
89
+ echo -e " ${CYAN}linear${RESET} <cmd> ${BOLD}Linear sync${RESET} — bidirectional issue sync with Linear"
90
+ echo -e " ${CYAN}tracker${RESET} <cmd> ${BOLD}Issue tracker${RESET} — configure Linear/Jira integration"
91
+ echo -e " ${CYAN}heartbeat${RESET} <cmd> ${BOLD}Agent heartbeat${RESET} — write/check/list/clear heartbeats"
92
+ echo -e " ${CYAN}checkpoint${RESET} <cmd> ${BOLD}Checkpoints${RESET} — save/restore agent state mid-stage"
93
+ echo -e " ${CYAN}connect${RESET} <cmd> ${BOLD}Team connect${RESET} — sync local state to team dashboard"
94
+ echo -e " ${CYAN}remote${RESET} <cmd> ${BOLD}Remote machines${RESET} — register and manage distributed workers"
95
+ echo -e " ${CYAN}launchd${RESET} <cmd> ${BOLD}Process supervision${RESET} — auto-start daemon + dashboard on boot"
96
+ echo -e " ${CYAN}docs${RESET} <cmd> ${BOLD}Documentation keeper${RESET} — auto-sync docs from source"
97
+ echo -e " ${CYAN}tmux${RESET} <cmd> ${BOLD}tmux health${RESET} — doctor, install plugins, fix issues"
98
+ echo -e " ${CYAN}github${RESET} ${BOLD}GitHub context${RESET} — repo metadata, security, blame"
99
+ echo -e " ${CYAN}checks${RESET} ${BOLD}GitHub checks${RESET} — CI check runs and status"
100
+ echo -e " ${CYAN}deploys${RESET} ${BOLD}Deployments${RESET} — deployment history and environments"
84
101
  echo -e " ${CYAN}init${RESET} ${BOLD}Quick tmux setup${RESET} — one command, no prompts"
102
+ echo -e " ${CYAN}setup${RESET} ${BOLD}Guided setup${RESET} — prerequisites, init, doctor, quick start"
85
103
  echo -e " ${CYAN}help${RESET} Show this help message"
86
104
  echo -e " ${CYAN}version${RESET} Show version"
87
105
  echo ""
@@ -123,6 +141,13 @@ show_help() {
123
141
  echo -e " ${DIM}shipwright prep --check${RESET} # Audit existing prep quality"
124
142
  echo -e " ${DIM}shipwright prep --with-claude${RESET} # Deep analysis using Claude Code"
125
143
  echo ""
144
+ echo -e "${BOLD}GITHUB INTEGRATION${RESET} ${DIM}(repo context, checks, deployments)${RESET}"
145
+ echo -e " ${DIM}shipwright github context${RESET} # Show repo GitHub context"
146
+ echo -e " ${DIM}shipwright github security${RESET} # Show security alerts"
147
+ echo -e " ${DIM}shipwright github blame <path>${RESET} # Show file ownership"
148
+ echo -e " ${DIM}shipwright checks list${RESET} # Show check runs"
149
+ echo -e " ${DIM}shipwright deploys list${RESET} # Show deployment history"
150
+ echo ""
126
151
  echo -e "${BOLD}TEST SUITES${RESET} ${DIM}(validate shipwright components)${RESET}"
127
152
  echo -e " ${DIM}shipwright daemon test${RESET} # Run daemon test suite"
128
153
  echo -e " ${DIM}shipwright prep test${RESET} # Run prep test suite"
@@ -164,65 +189,128 @@ main() {
164
189
  session)
165
190
  check_tmux
166
191
  check_in_tmux
167
- exec "$SCRIPT_DIR/cct-session.sh" "$@"
192
+ exec "$SCRIPT_DIR/sw-session.sh" "$@"
168
193
  ;;
169
194
  status)
170
195
  check_tmux
171
- exec "$SCRIPT_DIR/cct-status.sh" "$@"
196
+ exec "$SCRIPT_DIR/sw-status.sh" "$@"
172
197
  ;;
173
198
  ps)
174
199
  check_tmux
175
- exec "$SCRIPT_DIR/cct-ps.sh" "$@"
200
+ exec "$SCRIPT_DIR/sw-ps.sh" "$@"
176
201
  ;;
177
202
  logs)
178
- exec "$SCRIPT_DIR/cct-logs.sh" "$@"
203
+ exec "$SCRIPT_DIR/sw-logs.sh" "$@"
179
204
  ;;
180
205
  templates)
181
- exec "$SCRIPT_DIR/cct-templates.sh" "$@"
206
+ exec "$SCRIPT_DIR/sw-templates.sh" "$@"
182
207
  ;;
183
208
  doctor)
184
- exec "$SCRIPT_DIR/cct-doctor.sh" "$@"
209
+ exec "$SCRIPT_DIR/sw-doctor.sh" "$@"
185
210
  ;;
186
211
  cleanup)
187
212
  check_tmux
188
- exec "$SCRIPT_DIR/cct-cleanup.sh" "$@"
213
+ exec "$SCRIPT_DIR/sw-cleanup.sh" "$@"
189
214
  ;;
190
215
  reaper)
191
216
  check_tmux
192
- exec "$SCRIPT_DIR/cct-reaper.sh" "$@"
217
+ exec "$SCRIPT_DIR/sw-reaper.sh" "$@"
193
218
  ;;
194
219
  upgrade)
195
- exec "$SCRIPT_DIR/cct-upgrade.sh" "$@"
220
+ exec "$SCRIPT_DIR/sw-upgrade.sh" "$@"
196
221
  ;;
197
222
  loop)
198
- exec "$SCRIPT_DIR/cct-loop.sh" "$@"
223
+ exec "$SCRIPT_DIR/sw-loop.sh" "$@"
199
224
  ;;
200
225
  pipeline)
201
- exec "$SCRIPT_DIR/cct-pipeline.sh" "$@"
226
+ exec "$SCRIPT_DIR/sw-pipeline.sh" "$@"
202
227
  ;;
203
228
  worktree)
204
- exec "$SCRIPT_DIR/cct-worktree.sh" "$@"
229
+ exec "$SCRIPT_DIR/sw-worktree.sh" "$@"
205
230
  ;;
206
231
  prep)
207
- exec "$SCRIPT_DIR/cct-prep.sh" "$@"
232
+ exec "$SCRIPT_DIR/sw-prep.sh" "$@"
208
233
  ;;
209
234
  daemon)
210
- exec "$SCRIPT_DIR/cct-daemon.sh" "$@"
235
+ exec "$SCRIPT_DIR/sw-daemon.sh" "$@"
211
236
  ;;
212
237
  memory)
213
- exec "$SCRIPT_DIR/cct-memory.sh" "$@"
238
+ exec "$SCRIPT_DIR/sw-memory.sh" "$@"
214
239
  ;;
215
240
  cost)
216
- exec "$SCRIPT_DIR/cct-cost.sh" "$@"
241
+ exec "$SCRIPT_DIR/sw-cost.sh" "$@"
217
242
  ;;
218
243
  fleet)
219
- exec "$SCRIPT_DIR/cct-fleet.sh" "$@"
244
+ exec "$SCRIPT_DIR/sw-fleet.sh" "$@"
220
245
  ;;
221
246
  fix)
222
- exec "$SCRIPT_DIR/cct-fix.sh" "$@"
247
+ exec "$SCRIPT_DIR/sw-fix.sh" "$@"
223
248
  ;;
224
249
  init)
225
- exec "$SCRIPT_DIR/cct-init.sh" "$@"
250
+ exec "$SCRIPT_DIR/sw-init.sh" "$@"
251
+ ;;
252
+ setup)
253
+ exec "$SCRIPT_DIR/sw-setup.sh" "$@"
254
+ ;;
255
+ dashboard|dash)
256
+ exec "$SCRIPT_DIR/sw-dashboard.sh" "$@"
257
+ ;;
258
+ jira)
259
+ exec "$SCRIPT_DIR/sw-jira.sh" "$@"
260
+ ;;
261
+ linear)
262
+ exec "$SCRIPT_DIR/sw-linear.sh" "$@"
263
+ ;;
264
+ tracker)
265
+ exec "$SCRIPT_DIR/sw-tracker.sh" "$@"
266
+ ;;
267
+ heartbeat)
268
+ exec "$SCRIPT_DIR/sw-heartbeat.sh" "$@"
269
+ ;;
270
+ checkpoint)
271
+ exec "$SCRIPT_DIR/sw-checkpoint.sh" "$@"
272
+ ;;
273
+ connect)
274
+ exec "$SCRIPT_DIR/sw-connect.sh" "$@"
275
+ ;;
276
+ remote)
277
+ exec "$SCRIPT_DIR/sw-remote.sh" "$@"
278
+ ;;
279
+ launchd)
280
+ exec "$SCRIPT_DIR/sw-launchd.sh" "$@"
281
+ ;;
282
+ intelligence|intel)
283
+ exec "$SCRIPT_DIR/sw-intelligence.sh" "$@"
284
+ ;;
285
+ optimize)
286
+ exec "$SCRIPT_DIR/sw-self-optimize.sh" "$@"
287
+ ;;
288
+ predict)
289
+ exec "$SCRIPT_DIR/sw-predictive.sh" "$@"
290
+ ;;
291
+ adversarial)
292
+ exec "$SCRIPT_DIR/sw-adversarial.sh" "$@"
293
+ ;;
294
+ simulation)
295
+ exec "$SCRIPT_DIR/sw-developer-simulation.sh" "$@"
296
+ ;;
297
+ architecture)
298
+ exec "$SCRIPT_DIR/sw-architecture-enforcer.sh" "$@"
299
+ ;;
300
+ docs)
301
+ exec "$SCRIPT_DIR/sw-docs.sh" "$@"
302
+ ;;
303
+ tmux)
304
+ exec "$SCRIPT_DIR/sw-tmux.sh" "$@"
305
+ ;;
306
+ github|gh-context)
307
+ exec "$SCRIPT_DIR/sw-github-graphql.sh" "$@"
308
+ ;;
309
+ checks)
310
+ exec "$SCRIPT_DIR/sw-github-checks.sh" "$@"
311
+ ;;
312
+ deploys|deployments)
313
+ exec "$SCRIPT_DIR/sw-github-deploy.sh" "$@"
226
314
  ;;
227
315
  help|--help|-h)
228
316
  show_help