shipwright-cli 2.0.0 → 2.1.1

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 (112) hide show
  1. package/README.md +160 -72
  2. package/completions/_shipwright +59 -7
  3. package/completions/shipwright.bash +24 -4
  4. package/completions/shipwright.fish +80 -2
  5. package/dashboard/server.ts +208 -0
  6. package/docs/tmux-research/TMUX-ARCHITECTURE.md +567 -0
  7. package/docs/tmux-research/TMUX-AUDIT.md +925 -0
  8. package/docs/tmux-research/TMUX-BEST-PRACTICES-2025-2026.md +829 -0
  9. package/docs/tmux-research/TMUX-QUICK-REFERENCE.md +543 -0
  10. package/docs/tmux-research/TMUX-RESEARCH-INDEX.md +438 -0
  11. package/package.json +2 -2
  12. package/scripts/lib/helpers.sh +7 -0
  13. package/scripts/sw +116 -2
  14. package/scripts/sw-activity.sh +1 -1
  15. package/scripts/sw-adaptive.sh +1 -1
  16. package/scripts/sw-adversarial.sh +1 -1
  17. package/scripts/sw-architecture-enforcer.sh +1 -1
  18. package/scripts/sw-auth.sh +1 -1
  19. package/scripts/sw-autonomous.sh +128 -38
  20. package/scripts/sw-changelog.sh +1 -1
  21. package/scripts/sw-checkpoint.sh +1 -1
  22. package/scripts/sw-ci.sh +1 -1
  23. package/scripts/sw-cleanup.sh +1 -1
  24. package/scripts/sw-code-review.sh +62 -1
  25. package/scripts/sw-connect.sh +1 -1
  26. package/scripts/sw-context.sh +1 -1
  27. package/scripts/sw-cost.sh +44 -3
  28. package/scripts/sw-daemon.sh +155 -27
  29. package/scripts/sw-dashboard.sh +1 -1
  30. package/scripts/sw-db.sh +958 -118
  31. package/scripts/sw-decompose.sh +1 -1
  32. package/scripts/sw-deps.sh +1 -1
  33. package/scripts/sw-developer-simulation.sh +1 -1
  34. package/scripts/sw-discovery.sh +1 -1
  35. package/scripts/sw-docs-agent.sh +1 -1
  36. package/scripts/sw-docs.sh +1 -1
  37. package/scripts/sw-doctor.sh +49 -1
  38. package/scripts/sw-dora.sh +1 -1
  39. package/scripts/sw-durable.sh +1 -1
  40. package/scripts/sw-e2e-orchestrator.sh +1 -1
  41. package/scripts/sw-eventbus.sh +1 -1
  42. package/scripts/sw-feedback.sh +23 -15
  43. package/scripts/sw-fix.sh +1 -1
  44. package/scripts/sw-fleet-discover.sh +1 -1
  45. package/scripts/sw-fleet-viz.sh +1 -1
  46. package/scripts/sw-fleet.sh +1 -1
  47. package/scripts/sw-github-app.sh +1 -1
  48. package/scripts/sw-github-checks.sh +4 -4
  49. package/scripts/sw-github-deploy.sh +1 -1
  50. package/scripts/sw-github-graphql.sh +1 -1
  51. package/scripts/sw-guild.sh +1 -1
  52. package/scripts/sw-heartbeat.sh +1 -1
  53. package/scripts/sw-hygiene.sh +1 -1
  54. package/scripts/sw-incident.sh +45 -6
  55. package/scripts/sw-init.sh +150 -24
  56. package/scripts/sw-instrument.sh +1 -1
  57. package/scripts/sw-intelligence.sh +1 -1
  58. package/scripts/sw-jira.sh +1 -1
  59. package/scripts/sw-launchd.sh +1 -1
  60. package/scripts/sw-linear.sh +1 -1
  61. package/scripts/sw-logs.sh +1 -1
  62. package/scripts/sw-loop.sh +204 -19
  63. package/scripts/sw-memory.sh +18 -1
  64. package/scripts/sw-mission-control.sh +1 -1
  65. package/scripts/sw-model-router.sh +1 -1
  66. package/scripts/sw-otel.sh +1 -1
  67. package/scripts/sw-oversight.sh +76 -1
  68. package/scripts/sw-pipeline-composer.sh +1 -1
  69. package/scripts/sw-pipeline-vitals.sh +1 -1
  70. package/scripts/sw-pipeline.sh +302 -18
  71. package/scripts/sw-pm.sh +70 -5
  72. package/scripts/sw-pr-lifecycle.sh +1 -1
  73. package/scripts/sw-predictive.sh +8 -1
  74. package/scripts/sw-prep.sh +1 -1
  75. package/scripts/sw-ps.sh +1 -1
  76. package/scripts/sw-public-dashboard.sh +1 -1
  77. package/scripts/sw-quality.sh +1 -1
  78. package/scripts/sw-reaper.sh +1 -1
  79. package/scripts/sw-recruit.sh +1853 -178
  80. package/scripts/sw-regression.sh +1 -1
  81. package/scripts/sw-release-manager.sh +1 -1
  82. package/scripts/sw-release.sh +1 -1
  83. package/scripts/sw-remote.sh +1 -1
  84. package/scripts/sw-replay.sh +1 -1
  85. package/scripts/sw-retro.sh +1 -1
  86. package/scripts/sw-scale.sh +1 -1
  87. package/scripts/sw-security-audit.sh +1 -1
  88. package/scripts/sw-self-optimize.sh +1 -1
  89. package/scripts/sw-session.sh +1 -1
  90. package/scripts/sw-setup.sh +263 -127
  91. package/scripts/sw-standup.sh +1 -1
  92. package/scripts/sw-status.sh +44 -2
  93. package/scripts/sw-strategic.sh +189 -41
  94. package/scripts/sw-stream.sh +1 -1
  95. package/scripts/sw-swarm.sh +42 -5
  96. package/scripts/sw-team-stages.sh +1 -1
  97. package/scripts/sw-templates.sh +4 -4
  98. package/scripts/sw-testgen.sh +66 -15
  99. package/scripts/sw-tmux-pipeline.sh +1 -1
  100. package/scripts/sw-tmux-role-color.sh +58 -0
  101. package/scripts/sw-tmux-status.sh +128 -0
  102. package/scripts/sw-tmux.sh +1 -1
  103. package/scripts/sw-trace.sh +1 -1
  104. package/scripts/sw-tracker.sh +1 -1
  105. package/scripts/sw-triage.sh +61 -37
  106. package/scripts/sw-upgrade.sh +1 -1
  107. package/scripts/sw-ux.sh +30 -2
  108. package/scripts/sw-webhook.sh +1 -1
  109. package/scripts/sw-widgets.sh +1 -1
  110. package/scripts/sw-worktree.sh +1 -1
  111. package/tmux/shipwright-overlay.conf +35 -17
  112. package/tmux/tmux.conf +26 -21
@@ -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.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -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.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
12
  # ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
@@ -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.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -7,7 +7,7 @@
7
7
  set -euo pipefail
8
8
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
9
9
 
10
- VERSION="2.0.0"
10
+ VERSION="2.1.1"
11
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
12
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
13
13
 
@@ -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.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -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.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -4,7 +4,7 @@
4
4
  # ║ ║
5
5
  # ║ Checks prerequisites, installed files, PATH, and common issues. ║
6
6
  # ╚═══════════════════════════════════════════════════════════════════════════╝
7
- VERSION="2.0.0"
7
+ VERSION="2.1.1"
8
8
  set -euo pipefail
9
9
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
10
10
 
@@ -943,6 +943,54 @@ else
943
943
  info " Port check skipped ${DIM}(lsof/ss not found)${RESET}"
944
944
  fi
945
945
 
946
+ # ═════════════════════════════════════════════════════════════════════════════
947
+ # 15. Database Health
948
+ # ═════════════════════════════════════════════════════════════════════════════
949
+ echo ""
950
+ echo -e "${PURPLE}${BOLD} DATABASE HEALTH${RESET}"
951
+ echo -e "${DIM} ──────────────────────────────────────────${RESET}"
952
+
953
+ if command -v sqlite3 &>/dev/null; then
954
+ _sqlite_ver="$(sqlite3 --version 2>/dev/null | cut -d' ' -f1 || echo "unknown")"
955
+ check_pass "sqlite3 ${_sqlite_ver}"
956
+
957
+ _db_file="${HOME}/.shipwright/shipwright.db"
958
+ if [[ -f "$_db_file" ]]; then
959
+ check_pass "Database exists: ${DIM}${_db_file}${RESET}"
960
+
961
+ # Check WAL mode
962
+ _wal_mode=$(sqlite3 "$_db_file" "PRAGMA journal_mode;" 2>/dev/null || echo "unknown")
963
+ if [[ "$_wal_mode" == "wal" ]]; then
964
+ check_pass "WAL mode enabled"
965
+ else
966
+ check_warn "WAL mode not enabled (current: ${_wal_mode})"
967
+ fi
968
+
969
+ # Check schema version
970
+ _schema_ver=$(sqlite3 "$_db_file" "SELECT MAX(version) FROM _schema;" 2>/dev/null || echo "0")
971
+ if [[ "${_schema_ver:-0}" -ge 2 ]]; then
972
+ check_pass "Schema version: ${_schema_ver}"
973
+ else
974
+ check_warn "Schema version ${_schema_ver:-0} — expected >= 2. Run: shipwright db init"
975
+ fi
976
+
977
+ # Check file size
978
+ _db_size=$(ls -l "$_db_file" 2>/dev/null | awk '{print $5}')
979
+ _db_size_mb=$(awk -v s="${_db_size:-0}" 'BEGIN { printf "%.1f", s / 1048576 }')
980
+ check_pass "Database size: ${_db_size_mb} MB"
981
+
982
+ # Check table counts
983
+ _event_count=$(sqlite3 "$_db_file" "SELECT COUNT(*) FROM events;" 2>/dev/null || echo "0")
984
+ _run_count=$(sqlite3 "$_db_file" "SELECT COUNT(*) FROM pipeline_runs;" 2>/dev/null || echo "0")
985
+ info " Tables: events=${_event_count} pipeline_runs=${_run_count}"
986
+ else
987
+ check_warn "Database not initialized — run: shipwright db init"
988
+ fi
989
+ else
990
+ check_warn "sqlite3 not installed — DB features disabled"
991
+ echo -e " ${DIM}Install: brew install sqlite (macOS) or apt install sqlite3 (Linux)${RESET}"
992
+ fi
993
+
946
994
  # ═════════════════════════════════════════════════════════════════════════════
947
995
  # Summary
948
996
  # ═════════════════════════════════════════════════════════════════════════════
@@ -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.0.0"
11
+ VERSION="2.1.1"
12
12
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13
13
 
14
14
  # ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
@@ -7,7 +7,7 @@
7
7
  set -euo pipefail
8
8
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
9
9
 
10
- VERSION="2.0.0"
10
+ VERSION="2.1.1"
11
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
12
 
13
13
  # ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
@@ -5,7 +5,7 @@
5
5
  # ╚═══════════════════════════════════════════════════════════════════════════╝
6
6
  set -euo pipefail
7
7
 
8
- VERSION="2.0.0"
8
+ VERSION="2.1.1"
9
9
 
10
10
  # ─── Script directory resolution ────────────────────────────────────────────
11
11
  SOURCE="${BASH_SOURCE[0]}"
@@ -7,7 +7,7 @@
7
7
  set -euo pipefail
8
8
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
9
9
 
10
- VERSION="2.0.0"
10
+ VERSION="2.1.1"
11
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
12
 
13
13
  # ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
@@ -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.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -59,7 +59,7 @@ emit_event() {
59
59
  INCIDENTS_FILE="${HOME}/.shipwright/incidents.jsonl"
60
60
  ERROR_THRESHOLD=5 # Create issue if error count >= threshold
61
61
  ERROR_LOG_DIR="${REPO_DIR}/.claude/pipeline-artifacts"
62
- ARTIFACTS_DIR="${REPO_DIR}/.claude/pipeline-artifacts"
62
+ ARTIFACTS_DIR="${ARTIFACTS_DIR:-${REPO_DIR}/.claude/pipeline-artifacts}"
63
63
 
64
64
  # ─── Initialize directories ────────────────────────────────────────────────
65
65
  ensure_dirs() {
@@ -220,6 +220,12 @@ cmd_create_issue() {
220
220
 
221
221
  info "Creating GitHub issue for regression..."
222
222
 
223
+ # Check if NO_GITHUB is set before attempting GitHub operations
224
+ if [[ "${NO_GITHUB:-}" == "true" || "${NO_GITHUB:-}" == "1" ]]; then
225
+ warn "NO_GITHUB set — skipping GitHub issue creation"
226
+ return 0
227
+ fi
228
+
223
229
  # Get repo info
224
230
  local owner_repo
225
231
  owner_repo=$(get_owner_repo) || {
@@ -267,12 +273,6 @@ git show $regression_commit
267
273
  EOF
268
274
  )
269
275
 
270
- # Check if gh is available and NO_GITHUB is not set
271
- if [[ "${NO_GITHUB:-}" == "true" || "${NO_GITHUB:-}" == "1" ]]; then
272
- warn "NO_GITHUB set — skipping GitHub issue creation"
273
- return 0
274
- fi
275
-
276
276
  if ! command -v gh &>/dev/null; then
277
277
  error "gh CLI not found — cannot create issue"
278
278
  return 1
@@ -319,20 +319,28 @@ cmd_rollback() {
319
319
  return 1
320
320
  }
321
321
 
322
- # For now, just log the rollback intent
323
- # Full implementation would call sw-github-deploy.sh and update deployment status
322
+ # Trigger real rollback via sw-github-deploy.sh (GitHub Deployments API)
323
+ local rollback_status="initiated"
324
+ local rollback_rc=0
325
+ bash "$SCRIPT_DIR/sw-github-deploy.sh" rollback "$environment" 2>&1 | tee -a "${ARTIFACTS_DIR}/rollback-output.log"
326
+ rollback_rc=${PIPESTATUS[0]:-$?}
327
+ if [[ "$rollback_rc" -eq 0 ]]; then
328
+ rollback_status="executed"
329
+ success "Rollback executed for $environment via GitHub Deployments API"
330
+ else
331
+ warn "GitHub Deployments rollback failed or unavailable (exit $rollback_rc, see rollback-output.log)"
332
+ fi
333
+
324
334
  local rollback_entry
325
335
  rollback_entry=$(jq -n \
326
336
  --arg ts "$(now_iso)" \
327
337
  --arg env "$environment" \
328
338
  --arg reason "$reason" \
329
- '{timestamp: $ts, environment: $env, reason: $reason, status: "initiated"}')
339
+ --arg status "$rollback_status" \
340
+ '{timestamp: $ts, environment: $env, reason: $reason, status: $status}')
330
341
 
331
342
  echo "$rollback_entry" >> "${ARTIFACTS_DIR}/rollbacks.jsonl"
332
-
333
- success "Rollback initiated for $environment"
334
- emit_event "feedback_rollback" "environment=$environment" "reason=$reason"
335
- info "Note: Full rollback requires manual GitHub Deployments API call"
343
+ emit_event "feedback_rollback" "environment=$environment" "reason=$reason" "status=$rollback_status"
336
344
  }
337
345
 
338
346
  # ─── Capture incident in memory system ───────────────────────────────────────
package/scripts/sw-fix.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.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
12
  # ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
@@ -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.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -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.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -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.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -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.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -6,9 +6,9 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="2.0.0"
10
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
- REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
9
+ VERSION="2.1.1"
10
+ SCRIPT_DIR="${SCRIPT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
11
+ REPO_DIR="${REPO_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
12
12
 
13
13
  # ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
14
14
  CYAN='\033[38;2;0;212;255m' # #00d4ff — primary accent
@@ -516,6 +516,6 @@ main() {
516
516
  }
517
517
 
518
518
  # Only run main if executed directly (not sourced)
519
- if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
519
+ if [[ "${BASH_SOURCE[0]:-}" == "$0" ]]; then
520
520
  main "$@"
521
521
  fi
@@ -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.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -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.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -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.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
12
  # ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
@@ -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.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
12
  # ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
@@ -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.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -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.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -252,12 +252,15 @@ See incident details: \`shipwright incident show $incident_id\`
252
252
  This issue was automatically created by the incident commander.
253
253
  "
254
254
 
255
+ # shipwright label so daemon picks up; hotfix for routing
255
256
  local issue_url
256
- issue_url=$(gh issue create --title "$title" --body "$body" --label "hotfix" 2>/dev/null || echo "")
257
+ issue_url=$(gh issue create --title "$title" --body "$body" --label "hotfix,shipwright" 2>/dev/null || echo "")
257
258
 
258
259
  if [[ -n "$issue_url" ]]; then
259
260
  success "Created hotfix issue: $issue_url"
260
- echo "$issue_url"
261
+ local issue_num
262
+ issue_num=$(echo "$issue_url" | sed -n 's|.*/issues/\([0-9]*\)|\1|p')
263
+ [[ -n "$issue_num" ]] && echo "$issue_num"
261
264
  return 0
262
265
  fi
263
266
 
@@ -265,6 +268,33 @@ This issue was automatically created by the incident commander.
265
268
  return 1
266
269
  }
267
270
 
271
+ # Trigger pipeline for P0/P1 hotfix issue (auto-remediation)
272
+ trigger_pipeline_for_incident() {
273
+ local issue_num="$1"
274
+ local incident_id="$2"
275
+ if [[ -z "$issue_num" || ! "$issue_num" =~ ^[0-9]+$ ]]; then
276
+ return 0
277
+ fi
278
+ if [[ ! -x "$SCRIPT_DIR/sw-pipeline.sh" ]]; then
279
+ return 0
280
+ fi
281
+ info "Auto-triggering pipeline for P0/P1 hotfix issue #${issue_num} (incident: $incident_id)"
282
+ (cd "$REPO_DIR" && export REPO_DIR SCRIPT_DIR && bash "$SCRIPT_DIR/sw-pipeline.sh" start --issue "$issue_num" --template hotfix 2>/dev/null) &
283
+ emit_event "incident.pipeline_triggered" "incident_id=$incident_id" "issue=$issue_num"
284
+ }
285
+
286
+ # Execute rollback when auto_rollback_enabled (wire to sw-feedback / sw-github-deploy)
287
+ trigger_rollback_for_incident() {
288
+ local incident_id="$1"
289
+ local reason="${2:-P0/P1 incident}"
290
+ if [[ ! -x "$SCRIPT_DIR/sw-feedback.sh" ]]; then
291
+ return 0
292
+ fi
293
+ info "Auto-rollback triggered for incident $incident_id: $reason"
294
+ (cd "$REPO_DIR" && bash "$SCRIPT_DIR/sw-feedback.sh" rollback production "$reason" 2>/dev/null) || true
295
+ emit_event "incident.rollback_triggered" "incident_id=$incident_id" "reason=$reason"
296
+ }
297
+
268
298
  # ─── Watch Command ─────────────────────────────────────────────────────────
269
299
 
270
300
  cmd_watch() {
@@ -284,7 +314,7 @@ cmd_watch() {
284
314
  # Background process
285
315
  (
286
316
  echo $$ > "$MONITOR_PID_FILE"
287
- trap "rm -f '$MONITOR_PID_FILE'" EXIT
317
+ trap 'rm -f "'"$MONITOR_PID_FILE"'"' EXIT
288
318
 
289
319
  while true; do
290
320
  sleep "$interval"
@@ -313,12 +343,21 @@ cmd_watch() {
313
343
  info "Incident $incident_id created (severity: $severity)"
314
344
  emit_event "incident.detected" "incident_id=$incident_id" "severity=$severity"
315
345
 
316
- # Auto-response for P0/P1
346
+ # Auto-response for P0/P1: hotfix issue, trigger pipeline, optional rollback
317
347
  if [[ "$severity" == "P0" ]] || [[ "$severity" == "P1" ]]; then
348
+ local auto_rollback
349
+ auto_rollback=$(jq -r '.auto_rollback_enabled // false' "$INCIDENT_CONFIG" 2>/dev/null || echo "false")
350
+ if [[ "$auto_rollback" == "true" ]]; then
351
+ trigger_rollback_for_incident "$incident_id" "P0/P1 incident: $root_cause"
352
+ fi
318
353
  local auto_hotfix
319
354
  auto_hotfix=$(jq -r '.p0_auto_hotfix // .p1_auto_hotfix' "$INCIDENT_CONFIG" 2>/dev/null || echo "false")
320
355
  if [[ "$auto_hotfix" == "true" ]]; then
321
- create_hotfix_issue "$incident_id" "$severity" "$root_cause"
356
+ local issue_num
357
+ issue_num=$(create_hotfix_issue "$incident_id" "$severity" "$root_cause")
358
+ if [[ -n "$issue_num" ]]; then
359
+ trigger_pipeline_for_incident "$issue_num" "$incident_id"
360
+ fi
322
361
  fi
323
362
  fi
324
363
  fi