shipwright-cli 1.7.0 → 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 (106) 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/sw-init.sh +522 -0
  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 -328
  104. package/scripts/cct-init.sh +0 -282
  105. package/scripts/cct-session.sh +0 -284
  106. 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.9.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