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,252 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ╔═══════════════════════════════════════════════════════════════════════════╗
|
|
3
|
+
# ║ shipwright simulation — Multi-Persona Developer Simulation ║
|
|
4
|
+
# ║ Internal debate · PR quality gates · Automated reviewer personas ║
|
|
5
|
+
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
|
+
|
|
9
|
+
VERSION="1.10.0"
|
|
10
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
|
+
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
|
+
|
|
13
|
+
CYAN='\033[38;2;0;212;255m'
|
|
14
|
+
PURPLE='\033[38;2;124;58;237m'
|
|
15
|
+
BLUE='\033[38;2;0;102;255m'
|
|
16
|
+
GREEN='\033[38;2;74;222;128m'
|
|
17
|
+
YELLOW='\033[38;2;250;204;21m'
|
|
18
|
+
RED='\033[38;2;248;113;113m'
|
|
19
|
+
DIM='\033[2m'
|
|
20
|
+
BOLD='\033[1m'
|
|
21
|
+
RESET='\033[0m'
|
|
22
|
+
|
|
23
|
+
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
|
24
|
+
# shellcheck source=lib/compat.sh
|
|
25
|
+
[[ -f "$SCRIPT_DIR/lib/compat.sh" ]] && source "$SCRIPT_DIR/lib/compat.sh"
|
|
26
|
+
|
|
27
|
+
info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
|
|
28
|
+
success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
|
|
29
|
+
warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*"; }
|
|
30
|
+
error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
|
|
31
|
+
|
|
32
|
+
now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
|
|
33
|
+
now_epoch() { date +%s; }
|
|
34
|
+
|
|
35
|
+
# ─── Structured Event Log ────────────────────────────────────────────────
|
|
36
|
+
EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
|
|
37
|
+
|
|
38
|
+
emit_event() {
|
|
39
|
+
local event_type="$1"; shift
|
|
40
|
+
local json_fields=""
|
|
41
|
+
for kv in "$@"; do
|
|
42
|
+
local key="${kv%%=*}"; local val="${kv#*=}"
|
|
43
|
+
if [[ "$val" =~ ^-?[0-9]+\.?[0-9]*$ ]]; then
|
|
44
|
+
json_fields="${json_fields},\"${key}\":${val}"
|
|
45
|
+
else
|
|
46
|
+
val="${val//\"/\\\"}"; json_fields="${json_fields},\"${key}\":\"${val}\""
|
|
47
|
+
fi
|
|
48
|
+
done
|
|
49
|
+
mkdir -p "${HOME}/.shipwright"
|
|
50
|
+
echo "{\"ts\":\"$(now_iso)\",\"ts_epoch\":$(now_epoch),\"type\":\"${event_type}\"${json_fields}}" >> "$EVENTS_FILE"
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# ─── Source Intelligence Core ─────────────────────────────────────────────
|
|
54
|
+
if [[ -f "$SCRIPT_DIR/sw-intelligence.sh" ]]; then
|
|
55
|
+
source "$SCRIPT_DIR/sw-intelligence.sh"
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
# ─── Configuration ───────────────────────────────────────────────────────
|
|
59
|
+
MAX_SIMULATION_ROUNDS="${SIMULATION_MAX_ROUNDS:-3}"
|
|
60
|
+
|
|
61
|
+
_simulation_enabled() {
|
|
62
|
+
local config="${REPO_DIR}/.claude/daemon-config.json"
|
|
63
|
+
if [[ -f "$config" ]]; then
|
|
64
|
+
local enabled
|
|
65
|
+
enabled=$(jq -r '.intelligence.simulation_enabled // false' "$config" 2>/dev/null || echo "false")
|
|
66
|
+
[[ "$enabled" == "true" ]]
|
|
67
|
+
else
|
|
68
|
+
return 1
|
|
69
|
+
fi
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# ─── Persona Prompts ─────────────────────────────────────────────────────
|
|
73
|
+
|
|
74
|
+
_build_persona_prompt() {
|
|
75
|
+
local persona="$1"
|
|
76
|
+
local diff="$2"
|
|
77
|
+
local description="$3"
|
|
78
|
+
|
|
79
|
+
local role=""
|
|
80
|
+
case "$persona" in
|
|
81
|
+
security)
|
|
82
|
+
role="You are a senior security engineer reviewing a pull request. Focus on authentication issues, injection risks, data exposure, privilege escalation, and input validation. Be thorough and skeptical."
|
|
83
|
+
;;
|
|
84
|
+
performance)
|
|
85
|
+
role="You are a senior performance engineer reviewing a pull request. Focus on N+1 queries, unnecessary allocations, missing caching opportunities, algorithmic complexity, and resource leaks. Be precise."
|
|
86
|
+
;;
|
|
87
|
+
maintainability)
|
|
88
|
+
role="You are a senior software architect reviewing a pull request. Focus on code smells, missing tests, poor naming, unclear logic, coupling issues, and violations of established patterns. Be constructive."
|
|
89
|
+
;;
|
|
90
|
+
esac
|
|
91
|
+
|
|
92
|
+
jq -n --arg role "$role" --arg persona "$persona" --arg diff "$diff" --arg desc "$description" '{
|
|
93
|
+
role: $role,
|
|
94
|
+
instruction: "Review this PR diff and return a JSON array of concerns. Each concern must have: persona, concern (description), severity (critical|high|medium|low), and suggestion (specific fix).",
|
|
95
|
+
persona: $persona,
|
|
96
|
+
diff: $diff,
|
|
97
|
+
pr_description: $desc
|
|
98
|
+
}' | jq -r 'to_entries | map("\(.key): \(.value)") | join("\n\n")'
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
# ─── Simulation Review ───────────────────────────────────────────────────
|
|
102
|
+
|
|
103
|
+
simulation_review() {
|
|
104
|
+
local pr_diff="${1:-}"
|
|
105
|
+
local pr_description="${2:-}"
|
|
106
|
+
|
|
107
|
+
if ! _simulation_enabled; then
|
|
108
|
+
warn "Developer simulation disabled — enable intelligence.simulation_enabled" >&2
|
|
109
|
+
echo "[]"
|
|
110
|
+
return 0
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
if [[ -z "$pr_diff" ]]; then
|
|
114
|
+
error "Usage: simulation review <pr_diff> [pr_description]"
|
|
115
|
+
return 1
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
info "Running developer simulation (3 personas)..." >&2
|
|
119
|
+
|
|
120
|
+
local all_objections="[]"
|
|
121
|
+
local personas="security performance maintainability"
|
|
122
|
+
|
|
123
|
+
for persona in $personas; do
|
|
124
|
+
info " Persona: ${persona}..." >&2
|
|
125
|
+
|
|
126
|
+
local prompt
|
|
127
|
+
prompt=$(_build_persona_prompt "$persona" "$pr_diff" "$pr_description")
|
|
128
|
+
|
|
129
|
+
local cache_key="simulation_${persona}_$(echo -n "$pr_diff" | head -c 200 | _intelligence_md5)"
|
|
130
|
+
local result
|
|
131
|
+
if ! result=$(_intelligence_call_claude "$prompt" "$cache_key" 300); then
|
|
132
|
+
warn " ${persona} persona failed — skipping" >&2
|
|
133
|
+
continue
|
|
134
|
+
fi
|
|
135
|
+
|
|
136
|
+
# Ensure result is a JSON array
|
|
137
|
+
if ! echo "$result" | jq 'if type == "array" then . else empty end' >/dev/null 2>&1; then
|
|
138
|
+
result=$(echo "$result" | jq '.concerns // .objections // .findings // []' 2>/dev/null || echo "[]")
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
# Inject persona into each objection
|
|
142
|
+
result=$(echo "$result" | jq --arg p "$persona" '[.[] | . + {persona: $p}]' 2>/dev/null || echo "[]")
|
|
143
|
+
|
|
144
|
+
# Emit events
|
|
145
|
+
local count
|
|
146
|
+
count=$(echo "$result" | jq 'length' 2>/dev/null || echo "0")
|
|
147
|
+
local i=0
|
|
148
|
+
while [[ $i -lt $count ]]; do
|
|
149
|
+
local severity concern_text
|
|
150
|
+
severity=$(echo "$result" | jq -r ".[$i].severity // \"medium\"" 2>/dev/null || echo "medium")
|
|
151
|
+
concern_text=$(echo "$result" | jq -r ".[$i].concern // \"\"" 2>/dev/null | head -c 100)
|
|
152
|
+
emit_event "simulation.objection" "persona=$persona" "severity=$severity" "concern=$concern_text"
|
|
153
|
+
i=$((i + 1))
|
|
154
|
+
done
|
|
155
|
+
|
|
156
|
+
# Merge into all_objections
|
|
157
|
+
all_objections=$(jq -n --argjson existing "$all_objections" --argjson new "$result" '$existing + $new')
|
|
158
|
+
done
|
|
159
|
+
|
|
160
|
+
local total
|
|
161
|
+
total=$(echo "$all_objections" | jq 'length' 2>/dev/null || echo "0")
|
|
162
|
+
info "Simulation complete: $total total objections" >&2
|
|
163
|
+
|
|
164
|
+
echo "$all_objections"
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
# ─── Address Objections ──────────────────────────────────────────────────
|
|
168
|
+
|
|
169
|
+
simulation_address_objections() {
|
|
170
|
+
local objections_json="${1:-[]}"
|
|
171
|
+
local implementation_context="${2:-}"
|
|
172
|
+
|
|
173
|
+
local count
|
|
174
|
+
count=$(echo "$objections_json" | jq 'length' 2>/dev/null || echo "0")
|
|
175
|
+
|
|
176
|
+
if [[ "$count" -eq 0 ]]; then
|
|
177
|
+
success "No objections to address" >&2
|
|
178
|
+
emit_event "simulation.complete" "objections=0" "rounds=0"
|
|
179
|
+
echo "[]"
|
|
180
|
+
return 0
|
|
181
|
+
fi
|
|
182
|
+
|
|
183
|
+
info "Addressing $count objections..." >&2
|
|
184
|
+
|
|
185
|
+
local prompt
|
|
186
|
+
prompt=$(jq -n --arg objections "$objections_json" --arg ctx "$implementation_context" '{
|
|
187
|
+
instruction: "These concerns were raised about your PR by security, performance, and maintainability reviewers. Address each one. Return a JSON array with: concern (original), response (your explanation), action (will_fix|wont_fix|already_addressed), and code_change (if applicable).",
|
|
188
|
+
objections: $objections,
|
|
189
|
+
implementation_context: $ctx
|
|
190
|
+
}' | jq -r 'to_entries | map("\(.key): \(.value)") | join("\n\n")')
|
|
191
|
+
|
|
192
|
+
local result
|
|
193
|
+
if ! result=$(_intelligence_call_claude "$prompt" "simulation_address_$(echo -n "$objections_json" | head -c 200 | _intelligence_md5)" 300); then
|
|
194
|
+
warn "Claude call failed — returning unaddressed objections" >&2
|
|
195
|
+
echo "[]"
|
|
196
|
+
return 0
|
|
197
|
+
fi
|
|
198
|
+
|
|
199
|
+
# Ensure result is a JSON array
|
|
200
|
+
if ! echo "$result" | jq 'if type == "array" then . else empty end' >/dev/null 2>&1; then
|
|
201
|
+
result=$(echo "$result" | jq '.responses // .actions // []' 2>/dev/null || echo "[]")
|
|
202
|
+
fi
|
|
203
|
+
|
|
204
|
+
local addressed
|
|
205
|
+
addressed=$(echo "$result" | jq 'length' 2>/dev/null || echo "0")
|
|
206
|
+
emit_event "simulation.addressed" "count=$addressed"
|
|
207
|
+
emit_event "simulation.complete" "objections=$count" "addressed=$addressed"
|
|
208
|
+
|
|
209
|
+
success "Addressed $addressed of $count objections" >&2
|
|
210
|
+
echo "$result"
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
# ─── Help ─────────────────────────────────────────────────────────────────
|
|
214
|
+
|
|
215
|
+
show_help() {
|
|
216
|
+
echo ""
|
|
217
|
+
echo -e "${CYAN}${BOLD} Shipwright Simulation${RESET} ${DIM}v${VERSION}${RESET}"
|
|
218
|
+
echo -e "${DIM} ══════════════════════════════════════════${RESET}"
|
|
219
|
+
echo ""
|
|
220
|
+
echo -e " ${BOLD}USAGE${RESET}"
|
|
221
|
+
echo -e " shipwright simulation <command> [options]"
|
|
222
|
+
echo ""
|
|
223
|
+
echo -e " ${BOLD}COMMANDS${RESET}"
|
|
224
|
+
echo -e " ${CYAN}review${RESET} <diff> [description] Run multi-persona PR review"
|
|
225
|
+
echo -e " ${CYAN}address${RESET} <objections_json> [context] Address reviewer objections"
|
|
226
|
+
echo -e " ${CYAN}help${RESET} Show this help"
|
|
227
|
+
echo ""
|
|
228
|
+
echo -e " ${BOLD}PERSONAS${RESET}"
|
|
229
|
+
echo -e " ${CYAN}security${RESET} Auth, injection, data exposure"
|
|
230
|
+
echo -e " ${CYAN}performance${RESET} N+1 queries, allocations, caching"
|
|
231
|
+
echo -e " ${CYAN}maintainability${RESET} Code smells, naming, test coverage"
|
|
232
|
+
echo ""
|
|
233
|
+
echo -e " ${BOLD}CONFIGURATION${RESET}"
|
|
234
|
+
echo -e " Feature flag: ${DIM}intelligence.simulation_enabled${RESET} in daemon-config.json"
|
|
235
|
+
echo -e " Max rounds: ${DIM}SIMULATION_MAX_ROUNDS env var (default: 3)${RESET}"
|
|
236
|
+
echo ""
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
# ─── Command Router ──────────────────────────────────────────────────────
|
|
240
|
+
|
|
241
|
+
main() {
|
|
242
|
+
case "${1:-help}" in
|
|
243
|
+
review) shift; simulation_review "$@" ;;
|
|
244
|
+
address) shift; simulation_address_objections "$@" ;;
|
|
245
|
+
help|--help|-h) show_help ;;
|
|
246
|
+
*) error "Unknown: $1"; exit 1 ;;
|
|
247
|
+
esac
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
|
|
251
|
+
main "$@"
|
|
252
|
+
fi
|