shipwright-cli 2.3.1 → 3.0.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 (162) hide show
  1. package/README.md +95 -28
  2. package/completions/_shipwright +1 -1
  3. package/completions/shipwright.bash +3 -8
  4. package/completions/shipwright.fish +1 -1
  5. package/config/defaults.json +111 -0
  6. package/config/event-schema.json +81 -0
  7. package/config/policy.json +155 -2
  8. package/config/policy.schema.json +162 -1
  9. package/dashboard/coverage/coverage-summary.json +14 -0
  10. package/dashboard/public/index.html +1 -1
  11. package/dashboard/server.ts +306 -17
  12. package/dashboard/src/components/charts/bar.test.ts +79 -0
  13. package/dashboard/src/components/charts/donut.test.ts +68 -0
  14. package/dashboard/src/components/charts/pipeline-rail.test.ts +117 -0
  15. package/dashboard/src/components/charts/sparkline.test.ts +125 -0
  16. package/dashboard/src/core/api.test.ts +309 -0
  17. package/dashboard/src/core/helpers.test.ts +301 -0
  18. package/dashboard/src/core/router.test.ts +307 -0
  19. package/dashboard/src/core/router.ts +7 -0
  20. package/dashboard/src/core/sse.test.ts +144 -0
  21. package/dashboard/src/views/metrics.test.ts +186 -0
  22. package/dashboard/src/views/overview.test.ts +173 -0
  23. package/dashboard/src/views/pipelines.test.ts +183 -0
  24. package/dashboard/src/views/team.test.ts +253 -0
  25. package/dashboard/vitest.config.ts +14 -5
  26. package/docs/TIPS.md +1 -1
  27. package/docs/patterns/README.md +1 -1
  28. package/package.json +15 -5
  29. package/scripts/adapters/docker-deploy.sh +1 -1
  30. package/scripts/adapters/tmux-adapter.sh +11 -1
  31. package/scripts/adapters/wezterm-adapter.sh +1 -1
  32. package/scripts/check-version-consistency.sh +1 -1
  33. package/scripts/lib/architecture.sh +126 -0
  34. package/scripts/lib/bootstrap.sh +75 -0
  35. package/scripts/lib/compat.sh +89 -6
  36. package/scripts/lib/config.sh +91 -0
  37. package/scripts/lib/daemon-adaptive.sh +3 -3
  38. package/scripts/lib/daemon-dispatch.sh +39 -16
  39. package/scripts/lib/daemon-health.sh +1 -1
  40. package/scripts/lib/daemon-patrol.sh +24 -12
  41. package/scripts/lib/daemon-poll.sh +37 -25
  42. package/scripts/lib/daemon-state.sh +115 -23
  43. package/scripts/lib/daemon-triage.sh +30 -8
  44. package/scripts/lib/fleet-failover.sh +63 -0
  45. package/scripts/lib/helpers.sh +30 -6
  46. package/scripts/lib/pipeline-detection.sh +2 -2
  47. package/scripts/lib/pipeline-github.sh +9 -9
  48. package/scripts/lib/pipeline-intelligence.sh +85 -35
  49. package/scripts/lib/pipeline-quality-checks.sh +16 -16
  50. package/scripts/lib/pipeline-quality.sh +1 -1
  51. package/scripts/lib/pipeline-stages.sh +242 -28
  52. package/scripts/lib/pipeline-state.sh +40 -4
  53. package/scripts/lib/test-helpers.sh +247 -0
  54. package/scripts/postinstall.mjs +3 -11
  55. package/scripts/sw +10 -4
  56. package/scripts/sw-activity.sh +1 -11
  57. package/scripts/sw-adaptive.sh +109 -85
  58. package/scripts/sw-adversarial.sh +4 -14
  59. package/scripts/sw-architecture-enforcer.sh +1 -11
  60. package/scripts/sw-auth.sh +8 -17
  61. package/scripts/sw-autonomous.sh +111 -49
  62. package/scripts/sw-changelog.sh +1 -11
  63. package/scripts/sw-checkpoint.sh +144 -20
  64. package/scripts/sw-ci.sh +2 -12
  65. package/scripts/sw-cleanup.sh +13 -17
  66. package/scripts/sw-code-review.sh +16 -36
  67. package/scripts/sw-connect.sh +5 -12
  68. package/scripts/sw-context.sh +9 -26
  69. package/scripts/sw-cost.sh +6 -16
  70. package/scripts/sw-daemon.sh +75 -70
  71. package/scripts/sw-dashboard.sh +57 -17
  72. package/scripts/sw-db.sh +506 -15
  73. package/scripts/sw-decompose.sh +1 -11
  74. package/scripts/sw-deps.sh +15 -25
  75. package/scripts/sw-developer-simulation.sh +1 -11
  76. package/scripts/sw-discovery.sh +112 -30
  77. package/scripts/sw-doc-fleet.sh +7 -17
  78. package/scripts/sw-docs-agent.sh +6 -16
  79. package/scripts/sw-docs.sh +4 -12
  80. package/scripts/sw-doctor.sh +134 -43
  81. package/scripts/sw-dora.sh +11 -19
  82. package/scripts/sw-durable.sh +35 -52
  83. package/scripts/sw-e2e-orchestrator.sh +11 -27
  84. package/scripts/sw-eventbus.sh +115 -115
  85. package/scripts/sw-evidence.sh +748 -0
  86. package/scripts/sw-feedback.sh +3 -13
  87. package/scripts/sw-fix.sh +2 -20
  88. package/scripts/sw-fleet-discover.sh +1 -11
  89. package/scripts/sw-fleet-viz.sh +10 -18
  90. package/scripts/sw-fleet.sh +13 -17
  91. package/scripts/sw-github-app.sh +6 -16
  92. package/scripts/sw-github-checks.sh +1 -11
  93. package/scripts/sw-github-deploy.sh +1 -11
  94. package/scripts/sw-github-graphql.sh +2 -12
  95. package/scripts/sw-guild.sh +1 -11
  96. package/scripts/sw-heartbeat.sh +49 -12
  97. package/scripts/sw-hygiene.sh +45 -43
  98. package/scripts/sw-incident.sh +284 -67
  99. package/scripts/sw-init.sh +35 -37
  100. package/scripts/sw-instrument.sh +1 -11
  101. package/scripts/sw-intelligence.sh +362 -51
  102. package/scripts/sw-jira.sh +5 -14
  103. package/scripts/sw-launchd.sh +2 -12
  104. package/scripts/sw-linear.sh +8 -17
  105. package/scripts/sw-logs.sh +4 -12
  106. package/scripts/sw-loop.sh +641 -90
  107. package/scripts/sw-memory.sh +243 -17
  108. package/scripts/sw-mission-control.sh +2 -12
  109. package/scripts/sw-model-router.sh +73 -34
  110. package/scripts/sw-otel.sh +11 -21
  111. package/scripts/sw-oversight.sh +1 -11
  112. package/scripts/sw-patrol-meta.sh +5 -11
  113. package/scripts/sw-pipeline-composer.sh +7 -17
  114. package/scripts/sw-pipeline-vitals.sh +1 -11
  115. package/scripts/sw-pipeline.sh +478 -122
  116. package/scripts/sw-pm.sh +2 -12
  117. package/scripts/sw-pr-lifecycle.sh +203 -29
  118. package/scripts/sw-predictive.sh +16 -22
  119. package/scripts/sw-prep.sh +6 -16
  120. package/scripts/sw-ps.sh +1 -11
  121. package/scripts/sw-public-dashboard.sh +2 -12
  122. package/scripts/sw-quality.sh +77 -10
  123. package/scripts/sw-reaper.sh +1 -11
  124. package/scripts/sw-recruit.sh +15 -25
  125. package/scripts/sw-regression.sh +11 -21
  126. package/scripts/sw-release-manager.sh +19 -28
  127. package/scripts/sw-release.sh +8 -16
  128. package/scripts/sw-remote.sh +1 -11
  129. package/scripts/sw-replay.sh +48 -44
  130. package/scripts/sw-retro.sh +70 -92
  131. package/scripts/sw-review-rerun.sh +220 -0
  132. package/scripts/sw-scale.sh +109 -32
  133. package/scripts/sw-security-audit.sh +12 -22
  134. package/scripts/sw-self-optimize.sh +239 -23
  135. package/scripts/sw-session.sh +3 -13
  136. package/scripts/sw-setup.sh +8 -18
  137. package/scripts/sw-standup.sh +5 -15
  138. package/scripts/sw-status.sh +32 -23
  139. package/scripts/sw-strategic.sh +129 -13
  140. package/scripts/sw-stream.sh +1 -11
  141. package/scripts/sw-swarm.sh +76 -36
  142. package/scripts/sw-team-stages.sh +10 -20
  143. package/scripts/sw-templates.sh +4 -14
  144. package/scripts/sw-testgen.sh +3 -13
  145. package/scripts/sw-tmux-pipeline.sh +1 -19
  146. package/scripts/sw-tmux-role-color.sh +0 -10
  147. package/scripts/sw-tmux-status.sh +3 -11
  148. package/scripts/sw-tmux.sh +2 -20
  149. package/scripts/sw-trace.sh +1 -19
  150. package/scripts/sw-tracker-github.sh +0 -10
  151. package/scripts/sw-tracker-jira.sh +1 -11
  152. package/scripts/sw-tracker-linear.sh +1 -11
  153. package/scripts/sw-tracker.sh +7 -24
  154. package/scripts/sw-triage.sh +24 -34
  155. package/scripts/sw-upgrade.sh +5 -23
  156. package/scripts/sw-ux.sh +1 -19
  157. package/scripts/sw-webhook.sh +18 -32
  158. package/scripts/sw-widgets.sh +3 -21
  159. package/scripts/sw-worktree.sh +11 -27
  160. package/scripts/update-homebrew-sha.sh +67 -0
  161. package/templates/pipelines/tdd.json +72 -0
  162. package/scripts/sw-pipeline.sh.mock +0 -7
package/scripts/sw-ux.sh CHANGED
@@ -6,7 +6,7 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="2.3.1"
9
+ VERSION="3.0.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
12
  # ─── Cross-platform compatibility ──────────────────────────────────────────
@@ -26,24 +26,6 @@ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
26
26
  now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
27
27
  now_epoch() { date +%s; }
28
28
  fi
29
- if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
30
- emit_event() {
31
- local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
32
- local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
33
- while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
34
- echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
35
- }
36
- fi
37
- CYAN="${CYAN:-\033[38;2;0;212;255m}"
38
- PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
39
- BLUE="${BLUE:-\033[38;2;0;102;255m}"
40
- GREEN="${GREEN:-\033[38;2;74;222;128m}"
41
- YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
42
- RED="${RED:-\033[38;2;248;113;113m}"
43
- DIM="${DIM:-\033[2m}"
44
- BOLD="${BOLD:-\033[1m}"
45
- RESET="${RESET:-\033[0m}"
46
-
47
29
  # ─── Structured Event Log ──────────────────────────────────────────────────
48
30
  EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
49
31
 
@@ -6,7 +6,7 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="2.3.1"
9
+ VERSION="3.0.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
12
  # ─── Cross-platform compatibility ──────────────────────────────────────────
@@ -16,6 +16,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16
16
  # Canonical helpers (colors, output, events)
17
17
  # shellcheck source=lib/helpers.sh
18
18
  [[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh"
19
+ [[ -f "$SCRIPT_DIR/lib/config.sh" ]] && source "$SCRIPT_DIR/lib/config.sh"
19
20
  # Fallbacks when helpers not loaded (e.g. test env with overridden SCRIPT_DIR)
20
21
  [[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
21
22
  [[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
@@ -25,29 +26,11 @@ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
25
26
  now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
26
27
  now_epoch() { date +%s; }
27
28
  fi
28
- if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
29
- emit_event() {
30
- local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
31
- local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
32
- while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
33
- echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
34
- }
35
- fi
36
- CYAN="${CYAN:-\033[38;2;0;212;255m}"
37
- PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
38
- BLUE="${BLUE:-\033[38;2;0;102;255m}"
39
- GREEN="${GREEN:-\033[38;2;74;222;128m}"
40
- YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
41
- RED="${RED:-\033[38;2;248;113;113m}"
42
- DIM="${DIM:-\033[2m}"
43
- BOLD="${BOLD:-\033[1m}"
44
- RESET="${RESET:-\033[0m}"
45
-
46
29
  # ─── Constants ──────────────────────────────────────────────────────────────
47
30
  SHIPWRIGHT_DIR="$HOME/.shipwright"
48
31
  WEBHOOK_SECRET_FILE="$SHIPWRIGHT_DIR/webhook-secret"
49
32
  WEBHOOK_EVENTS_FILE="$SHIPWRIGHT_DIR/webhook-events.jsonl"
50
- WEBHOOK_PORT="${WEBHOOK_PORT:-8765}"
33
+ WEBHOOK_PORT="${WEBHOOK_PORT:-$(_config_get_int "webhook.port" 8765 2>/dev/null || echo 8765)}"
51
34
  WEBHOOK_PID_FILE="$SHIPWRIGHT_DIR/webhook.pid"
52
35
  WEBHOOK_LOG="$SHIPWRIGHT_DIR/webhook.log"
53
36
 
@@ -141,7 +124,7 @@ process_webhook_event() {
141
124
 
142
125
  # Check if nc (netcat) is available
143
126
  check_nc() {
144
- if ! command -v nc &>/dev/null; then
127
+ if ! command -v nc >/dev/null 2>&1; then
145
128
  error "netcat (nc) is required but not installed"
146
129
  echo -e " ${DIM}brew install netcat${RESET} (macOS)"
147
130
  echo -e " ${DIM}sudo apt install netcat-openbsd${RESET} (Ubuntu/Debian)"
@@ -254,17 +237,20 @@ webhook_server_bash() {
254
237
  local method path protocol
255
238
  read -r method path protocol <<< "$request_line"
256
239
 
257
- # Read headers until blank line
258
- local -A headers
240
+ # Read headers until blank line (Bash 3.2 compatible — no associative arrays)
259
241
  local header_line content_length=0
242
+ local hdr_signature="" hdr_event_type=""
260
243
  while read -r -u 3 -t 0.1 header_line; do
261
244
  [[ -z "$header_line" || "$header_line" == $'\r' ]] && break
262
245
  local key="${header_line%%:*}"
263
246
  local value="${header_line#*:}"
264
247
  value="${value#[[:space:]]}"
265
248
  value="${value%$'\r'}"
266
- headers["$key"]="$value"
267
- [[ "${key,,}" == "content-length" ]] && content_length="$value"
249
+ local key_lower
250
+ key_lower=$(printf '%s' "$key" | tr '[:upper:]' '[:lower:]')
251
+ [[ "$key_lower" == "content-length" ]] && content_length="$value"
252
+ [[ "$key_lower" == "x-hub-signature-256" ]] && hdr_signature="$value"
253
+ [[ "$key_lower" == "x-github-event" ]] && hdr_event_type="$value"
268
254
  done 2>/dev/null || true
269
255
 
270
256
  # Read body if content-length > 0
@@ -275,8 +261,8 @@ webhook_server_bash() {
275
261
 
276
262
  # Process webhook if method is POST
277
263
  if [[ "$method" == "POST" && "$path" == "/webhook" ]]; then
278
- local signature="${headers[X-Hub-Signature-256]:-}"
279
- local event_type="${headers[X-Github-Event]:-}"
264
+ local signature="$hdr_signature"
265
+ local event_type="$hdr_event_type"
280
266
 
281
267
  if validate_webhook_signature "$body" "$signature"; then
282
268
  if process_webhook_event "$body" "$event_type"; then
@@ -331,7 +317,7 @@ cmd_setup() {
331
317
  info "Webhook endpoint: http://localhost:${WEBHOOK_PORT}/webhook"
332
318
 
333
319
  # Check if gh CLI is available
334
- if ! command -v gh &>/dev/null; then
320
+ if ! command -v gh >/dev/null 2>&1; then
335
321
  error "GitHub CLI (gh) is required but not installed"
336
322
  return 1
337
323
  fi
@@ -345,7 +331,7 @@ cmd_setup() {
345
331
  -f "url=http://localhost:${WEBHOOK_PORT}/webhook" \
346
332
  -F "events=issues" \
347
333
  -f "config[content_type]=json" \
348
- -f "config[secret]=${secret}" 2>&1); then
334
+ -f "config[secret]=${secret}" --timeout 30 2>&1); then
349
335
 
350
336
  local hook_id
351
337
  hook_id=$(echo "$webhook_response" | jq -r '.id // empty' 2>/dev/null || true)
@@ -403,7 +389,7 @@ cmd_test() {
403
389
  return 1
404
390
  fi
405
391
 
406
- if ! command -v gh &>/dev/null; then
392
+ if ! command -v gh >/dev/null 2>&1; then
407
393
  error "GitHub CLI (gh) is required"
408
394
  return 1
409
395
  fi
@@ -440,7 +426,7 @@ cmd_test() {
440
426
  if gh api "repos/${org_repo}/hooks/tests" \
441
427
  -H "Accept: application/vnd.github+json" \
442
428
  -X POST \
443
- 2>&1 | grep -q "Test hook sent"; then
429
+ --timeout 30 2>&1 | grep -q "Test hook sent"; then
444
430
  success "Test ping sent to GitHub"
445
431
  else
446
432
  warn "Could not send test via GitHub API, but payload is valid:"
@@ -534,7 +520,7 @@ cmd_secret() {
534
520
  echo "$new_secret" > "$WEBHOOK_SECRET_FILE"
535
521
  chmod 600 "$WEBHOOK_SECRET_FILE"
536
522
  success "Webhook secret regenerated"
537
- info "New secret: ${new_secret}"
523
+ info "Secret: ${new_secret:0:8}... (full value in ${WEBHOOK_SECRET_FILE})"
538
524
  ;;
539
525
  *)
540
526
  error "Unknown secret action: $action"
@@ -8,7 +8,7 @@
8
8
  set -euo pipefail
9
9
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
10
10
 
11
- VERSION="2.3.1"
11
+ VERSION="3.0.0"
12
12
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13
13
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
14
14
 
@@ -29,24 +29,6 @@ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
29
29
  now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
30
30
  now_epoch() { date +%s; }
31
31
  fi
32
- if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
33
- emit_event() {
34
- local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
35
- local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
36
- while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
37
- echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
38
- }
39
- fi
40
- CYAN="${CYAN:-\033[38;2;0;212;255m}"
41
- PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
42
- BLUE="${BLUE:-\033[38;2;0;102;255m}"
43
- GREEN="${GREEN:-\033[38;2;74;222;128m}"
44
- YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
45
- RED="${RED:-\033[38;2;248;113;113m}"
46
- DIM="${DIM:-\033[2m}"
47
- BOLD="${BOLD:-\033[1m}"
48
- RESET="${RESET:-\033[0m}"
49
-
50
32
  # ─── Configuration ─────────────────────────────────────────────────────────
51
33
  CONFIG_DIR="${HOME}/.shipwright"
52
34
  CONFIG_FILE="${CONFIG_DIR}/widgets-config.json"
@@ -301,8 +283,8 @@ cmd_slack() {
301
283
  )
302
284
 
303
285
  # Send to webhook
304
- if command -v curl &>/dev/null; then
305
- response=$(curl -s -X POST "$webhook_url" \
286
+ if command -v curl >/dev/null 2>&1; then
287
+ response=$(curl -s --connect-timeout 10 --max-time 30 -X POST "$webhook_url" \
306
288
  -H 'Content-Type: application/json' \
307
289
  -d "$message_json" 2>&1)
308
290
 
@@ -5,7 +5,7 @@
5
5
  # ║ Each agent gets its own worktree so parallel agents don't clobber ║
6
6
  # ║ each other's files. Worktrees live in .worktrees/ relative to root. ║
7
7
  # ╚═══════════════════════════════════════════════════════════════════════════╝
8
- VERSION="2.3.1"
8
+ VERSION="3.0.0"
9
9
  set -euo pipefail
10
10
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
11
11
 
@@ -23,24 +23,6 @@ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
23
23
  now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
24
24
  now_epoch() { date +%s; }
25
25
  fi
26
- if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
27
- emit_event() {
28
- local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
29
- local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
30
- while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
31
- echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
32
- }
33
- fi
34
- CYAN="${CYAN:-\033[38;2;0;212;255m}"
35
- PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
36
- BLUE="${BLUE:-\033[38;2;0;102;255m}"
37
- GREEN="${GREEN:-\033[38;2;74;222;128m}"
38
- YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
39
- RED="${RED:-\033[38;2;248;113;113m}"
40
- DIM="${DIM:-\033[2m}"
41
- BOLD="${BOLD:-\033[1m}"
42
- RESET="${RESET:-\033[0m}"
43
-
44
26
  # ─── Repo root ─────────────────────────────────────────────────────────────
45
27
  REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || {
46
28
  error "Not inside a git repository."
@@ -122,7 +104,7 @@ worktree_list() {
122
104
 
123
105
  printf " ${CYAN}%-16s${RESET} ${PURPLE}%-22s${RESET} %b ${DIM}.worktrees/%s/${RESET}\n" \
124
106
  "$name" "$branch" "$status_str" "$name"
125
- ((found++))
107
+ found=$((found + 1))
126
108
  done
127
109
 
128
110
  if [[ $found -eq 0 ]]; then
@@ -167,8 +149,8 @@ worktree_sync_all() {
167
149
  [[ -d "$dir" ]] || continue
168
150
  local name
169
151
  name="$(basename "$dir")"
170
- worktree_sync "$name" || ((failed++))
171
- ((count++))
152
+ worktree_sync "$name" || failed=$((failed + 1))
153
+ count=$((count + 1))
172
154
  done
173
155
 
174
156
  echo ""
@@ -185,7 +167,7 @@ worktree_merge() {
185
167
  local current_branch
186
168
  current_branch="$(git branch --show-current)"
187
169
 
188
- if ! git rev-parse --verify "$branch" &>/dev/null; then
170
+ if ! git rev-parse --verify "$branch" >/dev/null 2>&1; then
189
171
  error "Branch '$branch' does not exist."
190
172
  return 1
191
173
  fi
@@ -219,7 +201,7 @@ worktree_merge_all() {
219
201
  echo -e " ${DIM}Resolve the conflict, then re-run: shipwright worktree merge-all${RESET}"
220
202
  return 1
221
203
  }
222
- ((count++))
204
+ count=$((count + 1))
223
205
  done
224
206
 
225
207
  echo ""
@@ -234,7 +216,9 @@ worktree_remove() {
234
216
  if [[ -d "$worktree_path" ]]; then
235
217
  git worktree remove "$worktree_path" --force 2>/dev/null || {
236
218
  warn "Could not cleanly remove worktree $name, forcing..."
237
- rm -rf "$worktree_path"
219
+ if [[ -n "$worktree_path" && "$worktree_path" == "$WORKTREE_DIR/"* ]]; then
220
+ rm -rf "$worktree_path"
221
+ fi
238
222
  git worktree prune 2>/dev/null || true
239
223
  }
240
224
  fi
@@ -257,7 +241,7 @@ worktree_cleanup() {
257
241
  local name
258
242
  name="$(basename "$dir")"
259
243
  worktree_remove "$name"
260
- ((count++))
244
+ count=$((count + 1))
261
245
  done
262
246
 
263
247
  # Prune stale worktree references
@@ -302,7 +286,7 @@ worktree_status() {
302
286
 
303
287
  printf " ${CYAN}%-16s${RESET} ${PURPLE}%-22s${RESET} ${GREEN}%s ahead${RESET}, ${YELLOW}%s behind${RESET}%b\n" \
304
288
  "$name" "$branch" "$ahead" "$behind" "$dirty"
305
- ((found++))
289
+ found=$((found + 1))
306
290
  done
307
291
 
308
292
  if [[ $found -eq 0 ]]; then
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env bash
2
+ # Updates homebrew/shipwright.rb with SHA256 hashes from the release artifacts.
3
+ # Downloads each tarball, computes SHA256, and updates the formula in-place.
4
+ #
5
+ # Usage: scripts/update-homebrew-sha.sh <version-tag>
6
+ # Example: scripts/update-homebrew-sha.sh v0.4.2
7
+ #
8
+ # Run after release artifacts are uploaded to GitHub Releases.
9
+ set -euo pipefail
10
+
11
+ VERSION="3.0.0"
12
+ VERSION_NUM="${VERSION#v}"
13
+ REPO="${SHIPWRIGHT_GITHUB_REPO:-sethdford/shipwright}"
14
+ REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
15
+ FORMULA="${REPO_ROOT}/homebrew/shipwright.rb"
16
+ BASE_URL="https://github.com/${REPO}/releases/download/${VERSION}"
17
+
18
+ TMPDIR="${TMPDIR:-/tmp}/shipwright-sha-$$"
19
+ mkdir -p "$TMPDIR"
20
+ trap 'rm -rf "$TMPDIR"' EXIT
21
+
22
+ # Download each artifact and compute SHA256
23
+ sha_darwin_arm64=""
24
+ sha_darwin_x86_64=""
25
+ sha_linux_x86_64=""
26
+
27
+ for platform in darwin-arm64 darwin-x86_64 linux-x86_64; do
28
+ filename="shipwright-${platform}.tar.gz"
29
+ url="${BASE_URL}/${filename}"
30
+ dest="${TMPDIR}/${filename}"
31
+ echo "Downloading ${url}..."
32
+ if ! curl -sfL -o "$dest" "$url"; then
33
+ echo "ERROR: Failed to download $url" >&2
34
+ exit 1
35
+ fi
36
+ if command -v shasum >/dev/null 2>&1; then
37
+ sha=$(shasum -a 256 "$dest" | awk '{print $1}')
38
+ else
39
+ sha=$(sha256sum "$dest" | awk '{print $1}')
40
+ fi
41
+ case "$platform" in
42
+ darwin-arm64) sha_darwin_arm64="$sha" ;;
43
+ darwin-x86_64) sha_darwin_x86_64="$sha" ;;
44
+ linux-x86_64) sha_linux_x86_64="$sha" ;;
45
+ esac
46
+ echo " ${platform}: ${sha}"
47
+ done
48
+
49
+ # Update formula: version and SHA256 values
50
+ # sed -i '' on macOS, sed -i on Linux
51
+ if [[ "$(uname -s)" == "Darwin" ]]; then
52
+ sed -i '' "s|version \"[^\"]*\"|version \"${VERSION_NUM}\"|g" "$FORMULA"
53
+ sed -i '' "s|sha256 \"PLACEHOLDER_DARWIN_ARM64_SHA256\"|sha256 \"${sha_darwin_arm64}\"|g" "$FORMULA"
54
+ sed -i '' "s|sha256 \"PLACEHOLDER_DARWIN_X86_64_SHA256\"|sha256 \"${sha_darwin_x86_64}\"|g" "$FORMULA"
55
+ sed -i '' "s|sha256 \"PLACEHOLDER_LINUX_X86_64_SHA256\"|sha256 \"${sha_linux_x86_64}\"|g" "$FORMULA"
56
+ else
57
+ sed -i "s|version \"[^\"]*\"|version \"${VERSION_NUM}\"|g" "$FORMULA"
58
+ sed -i "s|sha256 \"PLACEHOLDER_DARWIN_ARM64_SHA256\"|sha256 \"${sha_darwin_arm64}\"|g" "$FORMULA"
59
+ sed -i "s|sha256 \"PLACEHOLDER_DARWIN_X86_64_SHA256\"|sha256 \"${sha_darwin_x86_64}\"|g" "$FORMULA"
60
+ sed -i "s|sha256 \"PLACEHOLDER_LINUX_X86_64_SHA256\"|sha256 \"${sha_linux_x86_64}\"|g" "$FORMULA"
61
+ fi
62
+
63
+ echo ""
64
+ echo "Updated $FORMULA for v${VERSION_NUM}:"
65
+ echo " darwin-arm64: ${sha_darwin_arm64}"
66
+ echo " darwin-x86_64: ${sha_darwin_x86_64}"
67
+ echo " linux-x86_64: ${sha_linux_x86_64}"
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "tdd",
3
+ "description": "Test-first pipeline: plan → design → generate tests → build → test → review → PR",
4
+ "defaults": { "test_cmd": "npm test", "model": "sonnet", "agents": 1 },
5
+ "tdd": true,
6
+ "intelligence": {
7
+ "adversarial_enabled": true,
8
+ "architecture_enabled": true,
9
+ "simulation_enabled": true
10
+ },
11
+ "stages": [
12
+ { "id": "intake", "enabled": true, "gate": "auto", "config": {} },
13
+ {
14
+ "id": "plan",
15
+ "enabled": true,
16
+ "gate": "approve",
17
+ "config": { "model": "opus" }
18
+ },
19
+ {
20
+ "id": "design",
21
+ "enabled": true,
22
+ "gate": "approve",
23
+ "config": { "model": "opus" }
24
+ },
25
+ {
26
+ "id": "build",
27
+ "enabled": true,
28
+ "gate": "auto",
29
+ "config": { "max_iterations": 20, "audit": true, "quality_gates": true }
30
+ },
31
+ {
32
+ "id": "test",
33
+ "enabled": true,
34
+ "gate": "auto",
35
+ "config": { "coverage_min": 80 }
36
+ },
37
+ { "id": "review", "enabled": true, "gate": "approve", "config": {} },
38
+ {
39
+ "id": "compound_quality",
40
+ "enabled": true,
41
+ "gate": "auto",
42
+ "config": {
43
+ "adversarial": true,
44
+ "negative": true,
45
+ "e2e": true,
46
+ "dod_audit": true,
47
+ "max_cycles": 3,
48
+ "audit_intensity": "auto",
49
+ "compound_quality_blocking": true
50
+ }
51
+ },
52
+ {
53
+ "id": "pr",
54
+ "enabled": true,
55
+ "gate": "approve",
56
+ "config": { "wait_ci": false }
57
+ },
58
+ {
59
+ "id": "merge",
60
+ "enabled": true,
61
+ "gate": "approve",
62
+ "config": {
63
+ "merge_method": "squash",
64
+ "wait_ci_timeout_s": 600,
65
+ "auto_delete_branch": true,
66
+ "auto_merge": false,
67
+ "auto_approve": false
68
+ }
69
+ },
70
+ { "id": "deploy", "enabled": false, "gate": "approve", "config": {} }
71
+ ]
72
+ }
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env bash
2
- MOCK_LOG="${MOCK_PIPELINE_LOG:-/tmp/mock-pipeline.log}"
3
- echo "pipeline $*" >> "$MOCK_LOG"
4
- # Simulate quick pipeline run
5
- sleep 0.1
6
- echo "https://github.com/test/repo/pull/42"
7
- exit 0