shipwright-cli 1.7.1 → 1.10.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 +45 -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} +118 -22
- package/scripts/sw-adversarial.sh +274 -0
- package/scripts/sw-architecture-enforcer.sh +330 -0
- package/scripts/sw-checkpoint.sh +468 -0
- package/scripts/sw-cleanup.sh +359 -0
- package/scripts/sw-connect.sh +619 -0
- package/scripts/{cct-cost.sh → sw-cost.sh} +368 -34
- package/scripts/sw-daemon.sh +5574 -0
- 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/sw-loop.sh +2217 -0
- package/scripts/{cct-memory.sh → sw-memory.sh} +514 -36
- package/scripts/sw-patrol-meta.sh +417 -0
- package/scripts/sw-pipeline-composer.sh +455 -0
- package/scripts/sw-pipeline-vitals.sh +1096 -0
- package/scripts/sw-pipeline.sh +7593 -0
- 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} +9 -6
- package/scripts/{cct-reaper.sh → sw-reaper.sh} +10 -6
- package/scripts/sw-remote.sh +687 -0
- package/scripts/sw-self-optimize.sh +1048 -0
- package/scripts/sw-session.sh +541 -0
- package/scripts/sw-setup.sh +234 -0
- package/scripts/sw-status.sh +796 -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 +35 -6
- package/templates/pipelines/cost-aware.json +21 -0
- package/templates/pipelines/deployed.json +40 -6
- package/templates/pipelines/enterprise.json +16 -2
- package/templates/pipelines/fast.json +19 -0
- package/templates/pipelines/full.json +28 -2
- package/templates/pipelines/hotfix.json +19 -0
- package/templates/pipelines/standard.json +31 -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-cleanup.sh +0 -172
- package/scripts/cct-daemon.sh +0 -3189
- package/scripts/cct-doctor.sh +0 -414
- package/scripts/cct-loop.sh +0 -1332
- package/scripts/cct-pipeline.sh +0 -3844
- 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} $*"; }
|
|
@@ -64,7 +67,7 @@ show_help() {
|
|
|
64
67
|
echo ""
|
|
65
68
|
echo -e "${BOLD}COMMANDS${RESET}"
|
|
66
69
|
echo -e " ${CYAN}session${RESET} [name] Create a new tmux window for a Claude team"
|
|
67
|
-
echo -e " ${CYAN}status${RESET}
|
|
70
|
+
echo -e " ${CYAN}status${RESET} [--json] Show dashboard of running teams and agents"
|
|
68
71
|
echo -e " ${CYAN}ps${RESET} Show running agent processes and status"
|
|
69
72
|
echo -e " ${CYAN}logs${RESET} [team] [opts] View and search agent pane logs"
|
|
70
73
|
echo -e " ${CYAN}templates${RESET} [list|show] Manage team composition templates"
|
|
@@ -81,9 +84,26 @@ 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}vitals${RESET} ${BOLD}Pipeline vitals${RESET} — real-time health scoring and dashboard"
|
|
99
|
+
echo -e " ${CYAN}github${RESET} ${BOLD}GitHub context${RESET} — repo metadata, security, blame"
|
|
100
|
+
echo -e " ${CYAN}checks${RESET} ${BOLD}GitHub checks${RESET} — CI check runs and status"
|
|
101
|
+
echo -e " ${CYAN}deploys${RESET} ${BOLD}Deployments${RESET} — deployment history and environments"
|
|
84
102
|
echo -e " ${CYAN}init${RESET} ${BOLD}Quick tmux setup${RESET} — one command, no prompts"
|
|
103
|
+
echo -e " ${CYAN}setup${RESET} ${BOLD}Guided setup${RESET} — prerequisites, init, doctor, quick start"
|
|
85
104
|
echo -e " ${CYAN}help${RESET} Show this help message"
|
|
86
105
|
echo -e " ${CYAN}version${RESET} Show version"
|
|
106
|
+
echo -e " ${CYAN}hello${RESET} Say hello world"
|
|
87
107
|
echo ""
|
|
88
108
|
echo -e "${BOLD}CONTINUOUS LOOP${RESET} ${DIM}(autonomous agent operation)${RESET}"
|
|
89
109
|
echo -e " ${DIM}shipwright loop \"Build auth\" --test-cmd \"npm test\"${RESET}"
|
|
@@ -123,6 +143,13 @@ show_help() {
|
|
|
123
143
|
echo -e " ${DIM}shipwright prep --check${RESET} # Audit existing prep quality"
|
|
124
144
|
echo -e " ${DIM}shipwright prep --with-claude${RESET} # Deep analysis using Claude Code"
|
|
125
145
|
echo ""
|
|
146
|
+
echo -e "${BOLD}GITHUB INTEGRATION${RESET} ${DIM}(repo context, checks, deployments)${RESET}"
|
|
147
|
+
echo -e " ${DIM}shipwright github context${RESET} # Show repo GitHub context"
|
|
148
|
+
echo -e " ${DIM}shipwright github security${RESET} # Show security alerts"
|
|
149
|
+
echo -e " ${DIM}shipwright github blame <path>${RESET} # Show file ownership"
|
|
150
|
+
echo -e " ${DIM}shipwright checks list${RESET} # Show check runs"
|
|
151
|
+
echo -e " ${DIM}shipwright deploys list${RESET} # Show deployment history"
|
|
152
|
+
echo ""
|
|
126
153
|
echo -e "${BOLD}TEST SUITES${RESET} ${DIM}(validate shipwright components)${RESET}"
|
|
127
154
|
echo -e " ${DIM}shipwright daemon test${RESET} # Run daemon test suite"
|
|
128
155
|
echo -e " ${DIM}shipwright prep test${RESET} # Run prep test suite"
|
|
@@ -164,65 +191,131 @@ main() {
|
|
|
164
191
|
session)
|
|
165
192
|
check_tmux
|
|
166
193
|
check_in_tmux
|
|
167
|
-
exec "$SCRIPT_DIR/
|
|
194
|
+
exec "$SCRIPT_DIR/sw-session.sh" "$@"
|
|
168
195
|
;;
|
|
169
196
|
status)
|
|
170
197
|
check_tmux
|
|
171
|
-
exec "$SCRIPT_DIR/
|
|
198
|
+
exec "$SCRIPT_DIR/sw-status.sh" "$@"
|
|
172
199
|
;;
|
|
173
200
|
ps)
|
|
174
201
|
check_tmux
|
|
175
|
-
exec "$SCRIPT_DIR/
|
|
202
|
+
exec "$SCRIPT_DIR/sw-ps.sh" "$@"
|
|
176
203
|
;;
|
|
177
204
|
logs)
|
|
178
|
-
exec "$SCRIPT_DIR/
|
|
205
|
+
exec "$SCRIPT_DIR/sw-logs.sh" "$@"
|
|
179
206
|
;;
|
|
180
207
|
templates)
|
|
181
|
-
exec "$SCRIPT_DIR/
|
|
208
|
+
exec "$SCRIPT_DIR/sw-templates.sh" "$@"
|
|
182
209
|
;;
|
|
183
210
|
doctor)
|
|
184
|
-
exec "$SCRIPT_DIR/
|
|
211
|
+
exec "$SCRIPT_DIR/sw-doctor.sh" "$@"
|
|
185
212
|
;;
|
|
186
213
|
cleanup)
|
|
187
214
|
check_tmux
|
|
188
|
-
exec "$SCRIPT_DIR/
|
|
215
|
+
exec "$SCRIPT_DIR/sw-cleanup.sh" "$@"
|
|
189
216
|
;;
|
|
190
217
|
reaper)
|
|
191
218
|
check_tmux
|
|
192
|
-
exec "$SCRIPT_DIR/
|
|
219
|
+
exec "$SCRIPT_DIR/sw-reaper.sh" "$@"
|
|
193
220
|
;;
|
|
194
221
|
upgrade)
|
|
195
|
-
exec "$SCRIPT_DIR/
|
|
222
|
+
exec "$SCRIPT_DIR/sw-upgrade.sh" "$@"
|
|
196
223
|
;;
|
|
197
224
|
loop)
|
|
198
|
-
exec "$SCRIPT_DIR/
|
|
225
|
+
exec "$SCRIPT_DIR/sw-loop.sh" "$@"
|
|
199
226
|
;;
|
|
200
227
|
pipeline)
|
|
201
|
-
exec "$SCRIPT_DIR/
|
|
228
|
+
exec "$SCRIPT_DIR/sw-pipeline.sh" "$@"
|
|
202
229
|
;;
|
|
203
230
|
worktree)
|
|
204
|
-
exec "$SCRIPT_DIR/
|
|
231
|
+
exec "$SCRIPT_DIR/sw-worktree.sh" "$@"
|
|
205
232
|
;;
|
|
206
233
|
prep)
|
|
207
|
-
exec "$SCRIPT_DIR/
|
|
234
|
+
exec "$SCRIPT_DIR/sw-prep.sh" "$@"
|
|
208
235
|
;;
|
|
209
236
|
daemon)
|
|
210
|
-
exec "$SCRIPT_DIR/
|
|
237
|
+
exec "$SCRIPT_DIR/sw-daemon.sh" "$@"
|
|
211
238
|
;;
|
|
212
239
|
memory)
|
|
213
|
-
exec "$SCRIPT_DIR/
|
|
240
|
+
exec "$SCRIPT_DIR/sw-memory.sh" "$@"
|
|
214
241
|
;;
|
|
215
242
|
cost)
|
|
216
|
-
exec "$SCRIPT_DIR/
|
|
243
|
+
exec "$SCRIPT_DIR/sw-cost.sh" "$@"
|
|
217
244
|
;;
|
|
218
245
|
fleet)
|
|
219
|
-
exec "$SCRIPT_DIR/
|
|
246
|
+
exec "$SCRIPT_DIR/sw-fleet.sh" "$@"
|
|
220
247
|
;;
|
|
221
248
|
fix)
|
|
222
|
-
exec "$SCRIPT_DIR/
|
|
249
|
+
exec "$SCRIPT_DIR/sw-fix.sh" "$@"
|
|
223
250
|
;;
|
|
224
251
|
init)
|
|
225
|
-
exec "$SCRIPT_DIR/
|
|
252
|
+
exec "$SCRIPT_DIR/sw-init.sh" "$@"
|
|
253
|
+
;;
|
|
254
|
+
setup)
|
|
255
|
+
exec "$SCRIPT_DIR/sw-setup.sh" "$@"
|
|
256
|
+
;;
|
|
257
|
+
dashboard|dash)
|
|
258
|
+
exec "$SCRIPT_DIR/sw-dashboard.sh" "$@"
|
|
259
|
+
;;
|
|
260
|
+
jira)
|
|
261
|
+
exec "$SCRIPT_DIR/sw-jira.sh" "$@"
|
|
262
|
+
;;
|
|
263
|
+
linear)
|
|
264
|
+
exec "$SCRIPT_DIR/sw-linear.sh" "$@"
|
|
265
|
+
;;
|
|
266
|
+
tracker)
|
|
267
|
+
exec "$SCRIPT_DIR/sw-tracker.sh" "$@"
|
|
268
|
+
;;
|
|
269
|
+
heartbeat)
|
|
270
|
+
exec "$SCRIPT_DIR/sw-heartbeat.sh" "$@"
|
|
271
|
+
;;
|
|
272
|
+
checkpoint)
|
|
273
|
+
exec "$SCRIPT_DIR/sw-checkpoint.sh" "$@"
|
|
274
|
+
;;
|
|
275
|
+
connect)
|
|
276
|
+
exec "$SCRIPT_DIR/sw-connect.sh" "$@"
|
|
277
|
+
;;
|
|
278
|
+
remote)
|
|
279
|
+
exec "$SCRIPT_DIR/sw-remote.sh" "$@"
|
|
280
|
+
;;
|
|
281
|
+
launchd)
|
|
282
|
+
exec "$SCRIPT_DIR/sw-launchd.sh" "$@"
|
|
283
|
+
;;
|
|
284
|
+
intelligence|intel)
|
|
285
|
+
exec "$SCRIPT_DIR/sw-intelligence.sh" "$@"
|
|
286
|
+
;;
|
|
287
|
+
optimize)
|
|
288
|
+
exec "$SCRIPT_DIR/sw-self-optimize.sh" "$@"
|
|
289
|
+
;;
|
|
290
|
+
predict)
|
|
291
|
+
exec "$SCRIPT_DIR/sw-predictive.sh" "$@"
|
|
292
|
+
;;
|
|
293
|
+
adversarial)
|
|
294
|
+
exec "$SCRIPT_DIR/sw-adversarial.sh" "$@"
|
|
295
|
+
;;
|
|
296
|
+
simulation)
|
|
297
|
+
exec "$SCRIPT_DIR/sw-developer-simulation.sh" "$@"
|
|
298
|
+
;;
|
|
299
|
+
architecture)
|
|
300
|
+
exec "$SCRIPT_DIR/sw-architecture-enforcer.sh" "$@"
|
|
301
|
+
;;
|
|
302
|
+
vitals)
|
|
303
|
+
exec "$SCRIPT_DIR/sw-pipeline-vitals.sh" "$@"
|
|
304
|
+
;;
|
|
305
|
+
docs)
|
|
306
|
+
exec "$SCRIPT_DIR/sw-docs.sh" "$@"
|
|
307
|
+
;;
|
|
308
|
+
tmux)
|
|
309
|
+
exec "$SCRIPT_DIR/sw-tmux.sh" "$@"
|
|
310
|
+
;;
|
|
311
|
+
github|gh-context)
|
|
312
|
+
exec "$SCRIPT_DIR/sw-github-graphql.sh" "$@"
|
|
313
|
+
;;
|
|
314
|
+
checks)
|
|
315
|
+
exec "$SCRIPT_DIR/sw-github-checks.sh" "$@"
|
|
316
|
+
;;
|
|
317
|
+
deploys|deployments)
|
|
318
|
+
exec "$SCRIPT_DIR/sw-github-deploy.sh" "$@"
|
|
226
319
|
;;
|
|
227
320
|
help|--help|-h)
|
|
228
321
|
show_help
|
|
@@ -230,6 +323,9 @@ main() {
|
|
|
230
323
|
version|--version|-v)
|
|
231
324
|
show_version
|
|
232
325
|
;;
|
|
326
|
+
hello)
|
|
327
|
+
echo "hello world"
|
|
328
|
+
;;
|
|
233
329
|
*)
|
|
234
330
|
error "Unknown command: ${cmd}"
|
|
235
331
|
echo ""
|