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.
- package/.claude/agents/code-reviewer.md +90 -0
- package/.claude/agents/devops-engineer.md +142 -0
- package/.claude/agents/pipeline-agent.md +80 -0
- package/.claude/agents/shell-script-specialist.md +150 -0
- package/.claude/agents/test-specialist.md +196 -0
- package/.claude/hooks/post-tool-use.sh +38 -0
- package/.claude/hooks/pre-tool-use.sh +25 -0
- package/.claude/hooks/session-started.sh +37 -0
- package/README.md +212 -814
- package/claude-code/CLAUDE.md.shipwright +54 -0
- package/claude-code/hooks/notify-idle.sh +2 -2
- package/claude-code/hooks/session-start.sh +24 -0
- package/claude-code/hooks/task-completed.sh +6 -2
- package/claude-code/settings.json.template +12 -0
- package/dashboard/public/app.js +4422 -0
- package/dashboard/public/index.html +816 -0
- package/dashboard/public/styles.css +4755 -0
- package/dashboard/server.ts +4315 -0
- package/docs/KNOWN-ISSUES.md +18 -10
- package/docs/TIPS.md +38 -26
- package/docs/patterns/README.md +33 -23
- package/package.json +9 -5
- package/scripts/adapters/iterm2-adapter.sh +1 -1
- package/scripts/adapters/tmux-adapter.sh +52 -23
- package/scripts/adapters/wezterm-adapter.sh +26 -14
- package/scripts/lib/compat.sh +200 -0
- package/scripts/lib/helpers.sh +72 -0
- package/scripts/postinstall.mjs +72 -13
- package/scripts/{cct → sw} +109 -21
- package/scripts/sw-adversarial.sh +274 -0
- package/scripts/sw-architecture-enforcer.sh +330 -0
- package/scripts/sw-checkpoint.sh +390 -0
- package/scripts/{cct-cleanup.sh → sw-cleanup.sh} +3 -1
- package/scripts/sw-connect.sh +619 -0
- package/scripts/{cct-cost.sh → sw-cost.sh} +368 -34
- package/scripts/{cct-daemon.sh → sw-daemon.sh} +2217 -204
- package/scripts/sw-dashboard.sh +477 -0
- package/scripts/sw-developer-simulation.sh +252 -0
- package/scripts/sw-docs.sh +635 -0
- package/scripts/sw-doctor.sh +907 -0
- package/scripts/{cct-fix.sh → sw-fix.sh} +10 -6
- package/scripts/{cct-fleet.sh → sw-fleet.sh} +498 -22
- package/scripts/sw-github-checks.sh +521 -0
- package/scripts/sw-github-deploy.sh +533 -0
- package/scripts/sw-github-graphql.sh +972 -0
- package/scripts/sw-heartbeat.sh +293 -0
- package/scripts/{cct-init.sh → sw-init.sh} +144 -11
- package/scripts/sw-intelligence.sh +1196 -0
- package/scripts/sw-jira.sh +643 -0
- package/scripts/sw-launchd.sh +364 -0
- package/scripts/sw-linear.sh +648 -0
- package/scripts/{cct-logs.sh → sw-logs.sh} +72 -2
- package/scripts/{cct-loop.sh → sw-loop.sh} +534 -44
- package/scripts/{cct-memory.sh → sw-memory.sh} +321 -38
- package/scripts/sw-patrol-meta.sh +417 -0
- package/scripts/sw-pipeline-composer.sh +455 -0
- package/scripts/{cct-pipeline.sh → sw-pipeline.sh} +2319 -178
- package/scripts/sw-predictive.sh +820 -0
- package/scripts/{cct-prep.sh → sw-prep.sh} +339 -49
- package/scripts/{cct-ps.sh → sw-ps.sh} +6 -4
- package/scripts/{cct-reaper.sh → sw-reaper.sh} +6 -4
- package/scripts/sw-remote.sh +687 -0
- package/scripts/sw-self-optimize.sh +947 -0
- package/scripts/sw-session.sh +519 -0
- package/scripts/sw-setup.sh +234 -0
- package/scripts/sw-status.sh +605 -0
- package/scripts/{cct-templates.sh → sw-templates.sh} +9 -4
- package/scripts/sw-tmux.sh +591 -0
- package/scripts/sw-tracker-jira.sh +277 -0
- package/scripts/sw-tracker-linear.sh +292 -0
- package/scripts/sw-tracker.sh +409 -0
- package/scripts/{cct-upgrade.sh → sw-upgrade.sh} +103 -46
- package/scripts/{cct-worktree.sh → sw-worktree.sh} +3 -0
- package/templates/pipelines/autonomous.json +27 -5
- package/templates/pipelines/full.json +12 -0
- package/templates/pipelines/standard.json +12 -0
- package/tmux/{claude-teams-overlay.conf → shipwright-overlay.conf} +27 -9
- package/tmux/templates/accessibility.json +34 -0
- package/tmux/templates/api-design.json +35 -0
- package/tmux/templates/architecture.json +1 -0
- package/tmux/templates/bug-fix.json +9 -0
- package/tmux/templates/code-review.json +1 -0
- package/tmux/templates/compliance.json +36 -0
- package/tmux/templates/data-pipeline.json +36 -0
- package/tmux/templates/debt-paydown.json +34 -0
- package/tmux/templates/devops.json +1 -0
- package/tmux/templates/documentation.json +1 -0
- package/tmux/templates/exploration.json +1 -0
- package/tmux/templates/feature-dev.json +1 -0
- package/tmux/templates/full-stack.json +8 -0
- package/tmux/templates/i18n.json +34 -0
- package/tmux/templates/incident-response.json +36 -0
- package/tmux/templates/migration.json +1 -0
- package/tmux/templates/observability.json +35 -0
- package/tmux/templates/onboarding.json +33 -0
- package/tmux/templates/performance.json +35 -0
- package/tmux/templates/refactor.json +1 -0
- package/tmux/templates/release.json +35 -0
- package/tmux/templates/security-audit.json +8 -0
- package/tmux/templates/spike.json +34 -0
- package/tmux/templates/testing.json +1 -0
- package/tmux/tmux.conf +98 -9
- package/scripts/cct-doctor.sh +0 -414
- package/scripts/cct-session.sh +0 -284
- 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
|
+
}
|
package/scripts/postinstall.mjs
CHANGED
|
@@ -4,7 +4,14 @@
|
|
|
4
4
|
// ║ Copies templates and migrates legacy config directories ║
|
|
5
5
|
// ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
6
6
|
|
|
7
|
-
import {
|
|
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) {
|
|
24
|
-
|
|
25
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 (
|
|
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(
|
|
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(
|
|
89
|
-
|
|
90
|
-
|
|
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}`);
|
package/scripts/{cct → sw}
RENAMED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# ╔═══════════════════════════════════════════════════════════════════════════╗
|
|
3
|
-
# ║ Shipwright CLI (
|
|
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.
|
|
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/
|
|
192
|
+
exec "$SCRIPT_DIR/sw-session.sh" "$@"
|
|
168
193
|
;;
|
|
169
194
|
status)
|
|
170
195
|
check_tmux
|
|
171
|
-
exec "$SCRIPT_DIR/
|
|
196
|
+
exec "$SCRIPT_DIR/sw-status.sh" "$@"
|
|
172
197
|
;;
|
|
173
198
|
ps)
|
|
174
199
|
check_tmux
|
|
175
|
-
exec "$SCRIPT_DIR/
|
|
200
|
+
exec "$SCRIPT_DIR/sw-ps.sh" "$@"
|
|
176
201
|
;;
|
|
177
202
|
logs)
|
|
178
|
-
exec "$SCRIPT_DIR/
|
|
203
|
+
exec "$SCRIPT_DIR/sw-logs.sh" "$@"
|
|
179
204
|
;;
|
|
180
205
|
templates)
|
|
181
|
-
exec "$SCRIPT_DIR/
|
|
206
|
+
exec "$SCRIPT_DIR/sw-templates.sh" "$@"
|
|
182
207
|
;;
|
|
183
208
|
doctor)
|
|
184
|
-
exec "$SCRIPT_DIR/
|
|
209
|
+
exec "$SCRIPT_DIR/sw-doctor.sh" "$@"
|
|
185
210
|
;;
|
|
186
211
|
cleanup)
|
|
187
212
|
check_tmux
|
|
188
|
-
exec "$SCRIPT_DIR/
|
|
213
|
+
exec "$SCRIPT_DIR/sw-cleanup.sh" "$@"
|
|
189
214
|
;;
|
|
190
215
|
reaper)
|
|
191
216
|
check_tmux
|
|
192
|
-
exec "$SCRIPT_DIR/
|
|
217
|
+
exec "$SCRIPT_DIR/sw-reaper.sh" "$@"
|
|
193
218
|
;;
|
|
194
219
|
upgrade)
|
|
195
|
-
exec "$SCRIPT_DIR/
|
|
220
|
+
exec "$SCRIPT_DIR/sw-upgrade.sh" "$@"
|
|
196
221
|
;;
|
|
197
222
|
loop)
|
|
198
|
-
exec "$SCRIPT_DIR/
|
|
223
|
+
exec "$SCRIPT_DIR/sw-loop.sh" "$@"
|
|
199
224
|
;;
|
|
200
225
|
pipeline)
|
|
201
|
-
exec "$SCRIPT_DIR/
|
|
226
|
+
exec "$SCRIPT_DIR/sw-pipeline.sh" "$@"
|
|
202
227
|
;;
|
|
203
228
|
worktree)
|
|
204
|
-
exec "$SCRIPT_DIR/
|
|
229
|
+
exec "$SCRIPT_DIR/sw-worktree.sh" "$@"
|
|
205
230
|
;;
|
|
206
231
|
prep)
|
|
207
|
-
exec "$SCRIPT_DIR/
|
|
232
|
+
exec "$SCRIPT_DIR/sw-prep.sh" "$@"
|
|
208
233
|
;;
|
|
209
234
|
daemon)
|
|
210
|
-
exec "$SCRIPT_DIR/
|
|
235
|
+
exec "$SCRIPT_DIR/sw-daemon.sh" "$@"
|
|
211
236
|
;;
|
|
212
237
|
memory)
|
|
213
|
-
exec "$SCRIPT_DIR/
|
|
238
|
+
exec "$SCRIPT_DIR/sw-memory.sh" "$@"
|
|
214
239
|
;;
|
|
215
240
|
cost)
|
|
216
|
-
exec "$SCRIPT_DIR/
|
|
241
|
+
exec "$SCRIPT_DIR/sw-cost.sh" "$@"
|
|
217
242
|
;;
|
|
218
243
|
fleet)
|
|
219
|
-
exec "$SCRIPT_DIR/
|
|
244
|
+
exec "$SCRIPT_DIR/sw-fleet.sh" "$@"
|
|
220
245
|
;;
|
|
221
246
|
fix)
|
|
222
|
-
exec "$SCRIPT_DIR/
|
|
247
|
+
exec "$SCRIPT_DIR/sw-fix.sh" "$@"
|
|
223
248
|
;;
|
|
224
249
|
init)
|
|
225
|
-
exec "$SCRIPT_DIR/
|
|
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
|