shipwright-cli 2.2.1 → 2.3.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 (156) hide show
  1. package/README.md +19 -19
  2. package/dashboard/public/index.html +224 -8
  3. package/dashboard/public/styles.css +1078 -4
  4. package/dashboard/server.ts +1100 -15
  5. package/dashboard/src/canvas/interactions.ts +74 -0
  6. package/dashboard/src/canvas/layout.ts +85 -0
  7. package/dashboard/src/canvas/overlays.ts +117 -0
  8. package/dashboard/src/canvas/particles.ts +105 -0
  9. package/dashboard/src/canvas/renderer.ts +191 -0
  10. package/dashboard/src/components/charts/bar.ts +54 -0
  11. package/dashboard/src/components/charts/donut.ts +25 -0
  12. package/dashboard/src/components/charts/pipeline-rail.ts +105 -0
  13. package/dashboard/src/components/charts/sparkline.ts +82 -0
  14. package/dashboard/src/components/header.ts +616 -0
  15. package/dashboard/src/components/modal.ts +413 -0
  16. package/dashboard/src/components/terminal.ts +144 -0
  17. package/dashboard/src/core/api.ts +381 -0
  18. package/dashboard/src/core/helpers.ts +118 -0
  19. package/dashboard/src/core/router.ts +190 -0
  20. package/dashboard/src/core/sse.ts +38 -0
  21. package/dashboard/src/core/state.ts +150 -0
  22. package/dashboard/src/core/ws.ts +143 -0
  23. package/dashboard/src/design/icons.ts +131 -0
  24. package/dashboard/src/design/tokens.ts +160 -0
  25. package/dashboard/src/main.ts +68 -0
  26. package/dashboard/src/types/api.ts +337 -0
  27. package/dashboard/src/views/activity.ts +185 -0
  28. package/dashboard/src/views/agent-cockpit.ts +236 -0
  29. package/dashboard/src/views/agents.ts +72 -0
  30. package/dashboard/src/views/fleet-map.ts +299 -0
  31. package/dashboard/src/views/insights.ts +298 -0
  32. package/dashboard/src/views/machines.ts +162 -0
  33. package/dashboard/src/views/metrics.ts +420 -0
  34. package/dashboard/src/views/overview.ts +409 -0
  35. package/dashboard/src/views/pipeline-theater.ts +219 -0
  36. package/dashboard/src/views/pipelines.ts +595 -0
  37. package/dashboard/src/views/team.ts +362 -0
  38. package/dashboard/src/views/timeline.ts +389 -0
  39. package/dashboard/tsconfig.json +21 -0
  40. package/docs/AGI-PLATFORM-PLAN.md +5 -5
  41. package/docs/AGI-WHATS-NEXT.md +19 -16
  42. package/docs/README.md +2 -0
  43. package/package.json +8 -1
  44. package/scripts/check-version-consistency.sh +72 -0
  45. package/scripts/lib/daemon-adaptive.sh +610 -0
  46. package/scripts/lib/daemon-dispatch.sh +489 -0
  47. package/scripts/lib/daemon-failure.sh +387 -0
  48. package/scripts/lib/daemon-patrol.sh +1113 -0
  49. package/scripts/lib/daemon-poll.sh +1202 -0
  50. package/scripts/lib/daemon-state.sh +550 -0
  51. package/scripts/lib/daemon-triage.sh +490 -0
  52. package/scripts/lib/helpers.sh +81 -0
  53. package/scripts/lib/pipeline-intelligence.sh +0 -6
  54. package/scripts/lib/pipeline-quality-checks.sh +3 -1
  55. package/scripts/lib/pipeline-stages.sh +20 -0
  56. package/scripts/sw +109 -168
  57. package/scripts/sw-activity.sh +1 -1
  58. package/scripts/sw-adaptive.sh +2 -2
  59. package/scripts/sw-adversarial.sh +1 -1
  60. package/scripts/sw-architecture-enforcer.sh +1 -1
  61. package/scripts/sw-auth.sh +14 -6
  62. package/scripts/sw-autonomous.sh +1 -1
  63. package/scripts/sw-changelog.sh +2 -2
  64. package/scripts/sw-checkpoint.sh +1 -1
  65. package/scripts/sw-ci.sh +1 -1
  66. package/scripts/sw-cleanup.sh +1 -1
  67. package/scripts/sw-code-review.sh +1 -1
  68. package/scripts/sw-connect.sh +1 -1
  69. package/scripts/sw-context.sh +1 -1
  70. package/scripts/sw-cost.sh +1 -1
  71. package/scripts/sw-daemon.sh +53 -4817
  72. package/scripts/sw-dashboard.sh +1 -1
  73. package/scripts/sw-db.sh +1 -1
  74. package/scripts/sw-decompose.sh +1 -1
  75. package/scripts/sw-deps.sh +1 -1
  76. package/scripts/sw-developer-simulation.sh +1 -1
  77. package/scripts/sw-discovery.sh +1 -1
  78. package/scripts/sw-doc-fleet.sh +1 -1
  79. package/scripts/sw-docs-agent.sh +1 -1
  80. package/scripts/sw-docs.sh +1 -1
  81. package/scripts/sw-doctor.sh +49 -1
  82. package/scripts/sw-dora.sh +1 -1
  83. package/scripts/sw-durable.sh +1 -1
  84. package/scripts/sw-e2e-orchestrator.sh +1 -1
  85. package/scripts/sw-eventbus.sh +1 -1
  86. package/scripts/sw-feedback.sh +1 -1
  87. package/scripts/sw-fix.sh +6 -5
  88. package/scripts/sw-fleet-discover.sh +1 -1
  89. package/scripts/sw-fleet-viz.sh +3 -3
  90. package/scripts/sw-fleet.sh +1 -1
  91. package/scripts/sw-github-app.sh +5 -2
  92. package/scripts/sw-github-checks.sh +1 -1
  93. package/scripts/sw-github-deploy.sh +1 -1
  94. package/scripts/sw-github-graphql.sh +1 -1
  95. package/scripts/sw-guild.sh +1 -1
  96. package/scripts/sw-heartbeat.sh +1 -1
  97. package/scripts/sw-hygiene.sh +1 -1
  98. package/scripts/sw-incident.sh +1 -1
  99. package/scripts/sw-init.sh +112 -9
  100. package/scripts/sw-instrument.sh +6 -1
  101. package/scripts/sw-intelligence.sh +5 -1
  102. package/scripts/sw-jira.sh +1 -1
  103. package/scripts/sw-launchd.sh +1 -1
  104. package/scripts/sw-linear.sh +20 -9
  105. package/scripts/sw-logs.sh +1 -1
  106. package/scripts/sw-loop.sh +2 -1
  107. package/scripts/sw-memory.sh +10 -1
  108. package/scripts/sw-mission-control.sh +1 -1
  109. package/scripts/sw-model-router.sh +4 -1
  110. package/scripts/sw-otel.sh +4 -4
  111. package/scripts/sw-oversight.sh +1 -1
  112. package/scripts/sw-pipeline-composer.sh +3 -1
  113. package/scripts/sw-pipeline-vitals.sh +4 -6
  114. package/scripts/sw-pipeline.sh +19 -56
  115. package/scripts/sw-pipeline.sh.mock +7 -0
  116. package/scripts/sw-pm.sh +5 -2
  117. package/scripts/sw-pr-lifecycle.sh +1 -1
  118. package/scripts/sw-predictive.sh +4 -1
  119. package/scripts/sw-prep.sh +3 -2
  120. package/scripts/sw-ps.sh +1 -1
  121. package/scripts/sw-public-dashboard.sh +10 -4
  122. package/scripts/sw-quality.sh +1 -1
  123. package/scripts/sw-reaper.sh +1 -1
  124. package/scripts/sw-recruit.sh +25 -1
  125. package/scripts/sw-regression.sh +2 -1
  126. package/scripts/sw-release-manager.sh +1 -1
  127. package/scripts/sw-release.sh +7 -5
  128. package/scripts/sw-remote.sh +1 -1
  129. package/scripts/sw-replay.sh +1 -1
  130. package/scripts/sw-retro.sh +1 -1
  131. package/scripts/sw-scale.sh +11 -5
  132. package/scripts/sw-security-audit.sh +1 -1
  133. package/scripts/sw-self-optimize.sh +172 -7
  134. package/scripts/sw-session.sh +1 -1
  135. package/scripts/sw-setup.sh +1 -1
  136. package/scripts/sw-standup.sh +4 -3
  137. package/scripts/sw-status.sh +1 -1
  138. package/scripts/sw-strategic.sh +2 -1
  139. package/scripts/sw-stream.sh +8 -2
  140. package/scripts/sw-swarm.sh +12 -10
  141. package/scripts/sw-team-stages.sh +1 -1
  142. package/scripts/sw-templates.sh +1 -1
  143. package/scripts/sw-testgen.sh +3 -2
  144. package/scripts/sw-tmux-pipeline.sh +2 -1
  145. package/scripts/sw-tmux.sh +1 -1
  146. package/scripts/sw-trace.sh +1 -1
  147. package/scripts/sw-tracker-jira.sh +1 -0
  148. package/scripts/sw-tracker-linear.sh +1 -0
  149. package/scripts/sw-tracker.sh +24 -6
  150. package/scripts/sw-triage.sh +1 -1
  151. package/scripts/sw-upgrade.sh +1 -1
  152. package/scripts/sw-ux.sh +1 -1
  153. package/scripts/sw-webhook.sh +1 -1
  154. package/scripts/sw-widgets.sh +2 -2
  155. package/scripts/sw-worktree.sh +1 -1
  156. package/dashboard/public/app.js +0 -4422
@@ -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.2.1"
9
+ VERSION="2.3.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
12
  # ─── Cross-platform compatibility ──────────────────────────────────────────
package/scripts/sw-db.sh CHANGED
@@ -14,7 +14,7 @@ if [[ -n "${_SW_DB_LOADED:-}" ]] && [[ "${BASH_SOURCE[0]}" != "$0" ]]; then
14
14
  fi
15
15
  _SW_DB_LOADED=1
16
16
 
17
- VERSION="2.2.1"
17
+ VERSION="2.3.0"
18
18
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
19
19
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
20
20
 
@@ -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.2.1"
9
+ VERSION="2.3.0"
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.2.1"
9
+ VERSION="2.3.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
12
  # ─── Cross-platform compatibility ──────────────────────────────────────────
@@ -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.2.1"
9
+ VERSION="2.3.0"
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.2.1"
10
+ VERSION="2.3.0"
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.2.1"
9
+ VERSION="2.3.0"
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.2.1"
9
+ VERSION="2.3.0"
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.2.1"
9
+ VERSION="2.3.0"
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.2.1"
7
+ VERSION="2.3.0"
8
8
  set -euo pipefail
9
9
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
10
10
 
@@ -45,6 +45,15 @@ RESET="${RESET:-\033[0m}"
45
45
  PASS=0
46
46
  WARN=0
47
47
  FAIL=0
48
+ SKIP_PLATFORM_SCAN=false
49
+
50
+ # Parse doctor flags
51
+ for _arg in "$@"; do
52
+ case "$_arg" in
53
+ --skip-platform-scan) SKIP_PLATFORM_SCAN=true ;;
54
+ --version|-V) echo "sw-doctor $VERSION"; exit 0 ;;
55
+ esac
56
+ done
48
57
 
49
58
  check_pass() { success "$*"; PASS=$((PASS + 1)); }
50
59
  check_warn() { warn "$*"; WARN=$((WARN + 1)); }
@@ -332,6 +341,13 @@ fi
332
341
  # Check sw subcommands are installed alongside the router
333
342
  if command -v sw &>/dev/null; then
334
343
  SW_DIR="$(dirname "$(command -v sw)")"
344
+ # Follow symlinks to find the actual scripts directory
345
+ _sw_path="$(command -v sw)"
346
+ if [[ -L "$_sw_path" ]]; then
347
+ _sw_real="$(readlink "$_sw_path")"
348
+ [[ "$_sw_real" != /* ]] && _sw_real="$(cd "$(dirname "$_sw_path")" && cd "$(dirname "$_sw_real")" && pwd)/$(basename "$_sw_real")"
349
+ SW_DIR="$(dirname "$_sw_real")"
350
+ fi
335
351
  check_pass "shipwright router found at ${SW_DIR}/sw"
336
352
 
337
353
  missing_subs=()
@@ -352,6 +368,29 @@ else
352
368
  echo -e " ${DIM}Re-run install.sh to install the CLI${RESET}"
353
369
  fi
354
370
 
371
+ # ═════════════════════════════════════════════════════════════════════════════
372
+ # 4b. Version consistency (Shipwright repo only)
373
+ # ═════════════════════════════════════════════════════════════════════════════
374
+ REPO_ROOT_DOC="$(cd "$SCRIPT_DIR/.." 2>/dev/null && pwd)"
375
+ if [[ -n "$REPO_ROOT_DOC" && -f "$REPO_ROOT_DOC/package.json" ]] && \
376
+ command -v jq &>/dev/null && \
377
+ [[ "$(jq -r '.name // ""' "$REPO_ROOT_DOC/package.json" 2>/dev/null)" == "shipwright-cli" ]]; then
378
+ echo ""
379
+ echo -e "${PURPLE}${BOLD} VERSION CONSISTENCY${RESET} ${DIM}(Shipwright repo)${RESET}"
380
+ echo -e "${DIM} ──────────────────────────────────────────${RESET}"
381
+ if [[ -x "$SCRIPT_DIR/check-version-consistency.sh" ]]; then
382
+ if bash "$SCRIPT_DIR/check-version-consistency.sh" 2>/dev/null; then
383
+ check_pass "Version consistent (package.json, README, scripts)"
384
+ else
385
+ check_warn "Version drift — package.json, README, or scripts out of sync"
386
+ echo -e " ${DIM}Run: shipwright version check${RESET}"
387
+ echo -e " ${DIM}Fix: shipwright version bump <x.y.z>${RESET}"
388
+ fi
389
+ else
390
+ check_warn "check-version-consistency.sh not found"
391
+ fi
392
+ fi
393
+
355
394
  # ═════════════════════════════════════════════════════════════════════════════
356
395
  # 5. Pane Display
357
396
  # ═════════════════════════════════════════════════════════════════════════════
@@ -1011,6 +1050,13 @@ echo -e "${DIM} ─────────────────────
1011
1050
  SCRIPT_DIR_DOC="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
1012
1051
  REPO_DIR_DOC="$(cd "$SCRIPT_DIR_DOC/.." && pwd)"
1013
1052
  PH_FILE="$REPO_DIR_DOC/.claude/platform-hygiene.json"
1053
+ # Auto-run platform-refactor scan if report is missing (unless --skip-platform-scan)
1054
+ if [[ ! -f "$PH_FILE" ]] && [[ "$SKIP_PLATFORM_SCAN" != "true" ]]; then
1055
+ if [[ -f "$SCRIPT_DIR_DOC/sw-hygiene.sh" ]]; then
1056
+ info " Platform hygiene report not found — running scan..."
1057
+ bash "$SCRIPT_DIR_DOC/sw-hygiene.sh" platform-refactor >/dev/null 2>&1 || true
1058
+ fi
1059
+ fi
1014
1060
  if [[ -f "$PH_FILE" ]] && command -v jq &>/dev/null; then
1015
1061
  hc=$(jq -r '.counts.hardcoded // 0' "$PH_FILE" 2>/dev/null || echo "0")
1016
1062
  fb=$(jq -r '.counts.fallback // 0' "$PH_FILE" 2>/dev/null || echo "0")
@@ -1019,6 +1065,8 @@ if [[ -f "$PH_FILE" ]] && command -v jq &>/dev/null; then
1019
1065
  hack=$(jq -r '.counts.hack // 0' "$PH_FILE" 2>/dev/null || echo "0")
1020
1066
  check_pass "Platform hygiene: hardcoded=$hc fallback=$fb TODO=$todo FIXME=$fixme HACK=$hack"
1021
1067
  info " Refresh: shipwright hygiene platform-refactor"
1068
+ elif [[ "$SKIP_PLATFORM_SCAN" == "true" ]]; then
1069
+ info " Platform hygiene skipped (--skip-platform-scan)"
1022
1070
  else
1023
1071
  check_warn "Platform hygiene not run — run: shipwright hygiene platform-refactor"
1024
1072
  fi
@@ -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.2.1"
11
+ VERSION="2.3.0"
12
12
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13
13
 
14
14
  # ─── Cross-platform compatibility ──────────────────────────────────────────
@@ -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.2.1"
10
+ VERSION="2.3.0"
11
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
12
 
13
13
  # ─── Cross-platform compatibility ──────────────────────────────────────────
@@ -5,7 +5,7 @@
5
5
  # ╚═══════════════════════════════════════════════════════════════════════════╝
6
6
  set -euo pipefail
7
7
 
8
- VERSION="2.2.1"
8
+ VERSION="2.3.0"
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.2.1"
10
+ VERSION="2.3.0"
11
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
12
 
13
13
  # ─── Cross-platform compatibility ──────────────────────────────────────────
@@ -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.2.1"
9
+ VERSION="2.3.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
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.2.1"
9
+ VERSION="2.3.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
12
  # ─── Cross-platform compatibility ──────────────────────────────────────────
@@ -227,7 +227,7 @@ fix_start() {
227
227
  # Validate repos exist
228
228
  for repo in "${REPOS[@]}"; do
229
229
  local expanded
230
- expanded=$(eval echo "$repo")
230
+ expanded="${repo/#\~/$HOME}"
231
231
  if [[ ! -d "$expanded" ]]; then
232
232
  error "Repo directory not found: $expanded"
233
233
  exit 1
@@ -267,7 +267,7 @@ fix_start() {
267
267
  info "Dry run — would execute:"
268
268
  for repo in "${REPOS[@]}"; do
269
269
  local expanded
270
- expanded=$(eval echo "$repo")
270
+ expanded="${repo/#\~/$HOME}"
271
271
  local rname
272
272
  rname=$(basename "$expanded")
273
273
  echo -e " ${DIM}cd $expanded && git checkout -b $branch_name${RESET}"
@@ -281,7 +281,7 @@ fix_start() {
281
281
  local repos_json="[]"
282
282
  for repo in "${REPOS[@]}"; do
283
283
  local expanded
284
- expanded=$(eval echo "$repo")
284
+ expanded="${repo/#\~/$HOME}"
285
285
  local rname
286
286
  rname=$(basename "$expanded")
287
287
  repos_json=$(echo "$repos_json" | jq --arg name "$rname" --arg path "$expanded" \
@@ -291,6 +291,7 @@ fix_start() {
291
291
  # Atomic write initial state
292
292
  local tmp_state
293
293
  tmp_state=$(mktemp)
294
+ trap 'rm -f "$tmp_state"' RETURN
294
295
  jq -n \
295
296
  --arg goal "$GOAL" \
296
297
  --arg branch "$branch_name" \
@@ -311,7 +312,7 @@ fix_start() {
311
312
 
312
313
  for repo in "${REPOS[@]}"; do
313
314
  local expanded
314
- expanded=$(eval echo "$repo")
315
+ expanded="${repo/#\~/$HOME}"
315
316
  local rname
316
317
  rname=$(basename "$expanded")
317
318
 
@@ -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.2.1"
9
+ VERSION="2.3.0"
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.2.1"
9
+ VERSION="2.3.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -213,8 +213,8 @@ show_insights() {
213
213
 
214
214
  # Fleet-wide success rate (last 30 days)
215
215
  local total_pipelines successful_pipelines
216
- total_pipelines=$(grep '"type":"pipeline_complete"' "$EVENTS_FILE" 2>/dev/null | tail -5000 | wc -l || echo "0")
217
- successful_pipelines=$(grep '"type":"pipeline_complete".*"status":"success"' "$EVENTS_FILE" 2>/dev/null | tail -5000 | wc -l || echo "0")
216
+ total_pipelines=$(grep '"type":"pipeline.completed"' "$EVENTS_FILE" 2>/dev/null | tail -5000 | wc -l || echo "0")
217
+ successful_pipelines=$(grep '"type":"pipeline.completed".*"status":"success"' "$EVENTS_FILE" 2>/dev/null | tail -5000 | wc -l || echo "0")
218
218
 
219
219
  local success_rate=0
220
220
  if [[ "$total_pipelines" -gt 0 ]]; then
@@ -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.2.1"
9
+ VERSION="2.3.0"
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.2.1"
9
+ VERSION="2.3.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -90,6 +90,7 @@ cmd_setup() {
90
90
  # Create config atomically
91
91
  local tmp_config
92
92
  tmp_config=$(mktemp)
93
+ trap "rm -f '$tmp_config'" RETURN
93
94
  jq -n \
94
95
  --arg app_id "$app_id" \
95
96
  --arg key_path "$key_path" \
@@ -194,6 +195,7 @@ _cache_token() {
194
195
 
195
196
  local tmp_tokens
196
197
  tmp_tokens=$(mktemp)
198
+ trap "rm -f '$tmp_tokens'" RETURN
197
199
 
198
200
  if [[ -f "$TOKENS_FILE" ]]; then
199
201
  jq ".tokens += [{\"installation_id\":$installation_id,\"token\":\"$token\",\"expires_at\":\"$expires_at\"}]" \
@@ -399,9 +401,10 @@ cmd_manifest() {
399
401
  manifest=$(jq -n \
400
402
  --arg name "$app_name" \
401
403
  --arg webhook_url "$webhook_url" \
404
+ --arg github_url "$(_sw_github_url)" \
402
405
  '{
403
406
  name: $name,
404
- url: "https://github.com/sethdford/shipwright",
407
+ url: $github_url,
405
408
  hook_attributes: {
406
409
  url: $webhook_url
407
410
  },
@@ -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.2.1"
9
+ VERSION="2.3.0"
10
10
  SCRIPT_DIR="${SCRIPT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
11
11
  REPO_DIR="${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.2.1"
9
+ VERSION="2.3.0"
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.2.1"
9
+ VERSION="2.3.0"
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.2.1"
9
+ VERSION="2.3.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
12
  # ─── Cross-platform compatibility ──────────────────────────────────────────
@@ -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.2.1"
9
+ VERSION="2.3.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
12
  # ─── Cross-platform compatibility ──────────────────────────────────────────
@@ -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.2.1"
9
+ VERSION="2.3.0"
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.2.1"
9
+ VERSION="2.3.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -8,9 +8,10 @@
8
8
  # ║ ║
9
9
  # ║ --deploy Detect platform and generate deployed.json template ║
10
10
  # ╚═══════════════════════════════════════════════════════════════════════════╝
11
- VERSION="2.2.1"
11
+ VERSION="2.3.0"
12
12
  set -euo pipefail
13
13
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
14
+ trap 'rm -f "${tmp:-}"' EXIT
14
15
 
15
16
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16
17
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
@@ -305,6 +306,59 @@ if [[ $_verify_fail -eq 0 ]]; then
305
306
  success "Verified: tmux config, overlay, TPM, and plugins all deployed"
306
307
  fi
307
308
 
309
+ # ─── CLI Bootstrap (symlinks + PATH) ─────────────────────────────────────────
310
+ # Install sw/shipwright/cct symlinks so the CLI works from anywhere
311
+ BIN_DIR="$HOME/.local/bin"
312
+ mkdir -p "$BIN_DIR"
313
+
314
+ SW_SRC="$SCRIPT_DIR/sw"
315
+ if [[ -f "$SW_SRC" ]]; then
316
+ _cli_changed=false
317
+ for _cmd in sw shipwright cct; do
318
+ _dest="$BIN_DIR/$_cmd"
319
+ if [[ -L "$_dest" ]] && [[ "$(readlink "$_dest")" == "$SW_SRC" ]]; then
320
+ continue
321
+ fi
322
+ ln -sf "$SW_SRC" "$_dest"
323
+ _cli_changed=true
324
+ done
325
+ if [[ "$_cli_changed" == "true" ]]; then
326
+ success "CLI symlinks: sw, shipwright, cct → $BIN_DIR"
327
+ else
328
+ success "CLI symlinks already correct"
329
+ fi
330
+ fi
331
+
332
+ # Ensure ~/.local/bin is in PATH via shell profile
333
+ if ! echo "$PATH" | tr ':' '\n' | grep -qxF "$BIN_DIR"; then
334
+ _login_shell="$(basename "${SHELL:-/bin/zsh}")"
335
+ case "$_login_shell" in
336
+ zsh) _rc="$HOME/.zshrc" ;;
337
+ bash)
338
+ if [[ -f "$HOME/.bash_profile" ]]; then _rc="$HOME/.bash_profile"
339
+ else _rc="$HOME/.bashrc"; fi
340
+ ;;
341
+ *) _rc="$HOME/.profile" ;;
342
+ esac
343
+
344
+ _marker="# Added by Shipwright"
345
+ _line='export PATH="$HOME/.local/bin:$PATH"'
346
+
347
+ if [[ -f "$_rc" ]] && grep -qF "$_marker" "$_rc" 2>/dev/null; then
348
+ info "PATH already configured in $_rc"
349
+ else
350
+ if [[ -f "$_rc" ]]; then
351
+ printf '\n%s\n%s\n' "$_marker" "$_line" >> "$_rc"
352
+ else
353
+ printf '%s\n%s\n' "$_marker" "$_line" > "$_rc"
354
+ fi
355
+ success "Added ~/.local/bin to PATH in $_rc"
356
+ fi
357
+ export PATH="$BIN_DIR:$PATH"
358
+ else
359
+ success "~/.local/bin already in PATH"
360
+ fi
361
+
308
362
  # ─── Team Templates ──────────────────────────────────────────────────────────
309
363
  SHIPWRIGHT_DIR="$HOME/.shipwright"
310
364
  TEMPLATES_SRC="$REPO_DIR/tmux/templates"
@@ -338,18 +392,17 @@ fi
338
392
 
339
393
  # ─── Shell Completions ────────────────────────────────────────────────────────
340
394
  # Detect shell type and install completions to the correct location
395
+ # Detect the user's login shell (not the script's running shell).
396
+ # This script runs in bash, so $BASH_VERSION is always set — check $SHELL first.
341
397
  SHELL_TYPE=""
342
- if [[ -n "${ZSH_VERSION:-}" ]]; then
398
+ if [[ "${SHELL:-}" == *"zsh"* ]]; then
399
+ SHELL_TYPE="zsh"
400
+ elif [[ "${SHELL:-}" == *"bash"* ]]; then
401
+ SHELL_TYPE="bash"
402
+ elif [[ -n "${ZSH_VERSION:-}" ]]; then
343
403
  SHELL_TYPE="zsh"
344
404
  elif [[ -n "${BASH_VERSION:-}" ]]; then
345
405
  SHELL_TYPE="bash"
346
- else
347
- # Try to detect from $SHELL env var
348
- if [[ "$SHELL" == *"zsh"* ]]; then
349
- SHELL_TYPE="zsh"
350
- elif [[ "$SHELL" == *"bash"* ]]; then
351
- SHELL_TYPE="bash"
352
- fi
353
406
  fi
354
407
 
355
408
  COMPLETIONS_SRC="$REPO_DIR/completions"
@@ -375,6 +428,10 @@ elif [[ "$SHELL_TYPE" == "zsh" ]]; then
375
428
  } >> "$HOME/.zshrc"
376
429
  info "Added ~/.zsh/completions to fpath in ~/.zshrc"
377
430
  fi
431
+ # Ensure compinit is present (needed for completions to work)
432
+ if ! grep -q "compinit" "$HOME/.zshrc" 2>/dev/null; then
433
+ echo "autoload -Uz compinit && compinit" >> "$HOME/.zshrc"
434
+ fi
378
435
  else
379
436
  # Create minimal .zshrc with fpath
380
437
  {
@@ -585,6 +642,22 @@ if [[ "$SKIP_CLAUDE_MD" == "false" && -f "$CLAUDE_MD_SRC" ]]; then
585
642
  fi
586
643
  fi
587
644
 
645
+ # ─── GitHub CLI Authentication ────────────────────────────────────────────────
646
+ # gh auth is required for daemon, pipeline, PR creation, and issue management
647
+ if command -v gh &>/dev/null; then
648
+ if gh auth status &>/dev/null 2>&1; then
649
+ success "GitHub CLI authenticated"
650
+ else
651
+ warn "GitHub CLI installed but not authenticated"
652
+ echo -e " ${DIM}Required for: daemon, pipeline, PR creation, issue management${RESET}"
653
+ echo -e " ${DIM}Run: ${RESET}${BOLD}gh auth login${RESET}"
654
+ fi
655
+ else
656
+ warn "GitHub CLI (gh) not installed"
657
+ echo -e " ${DIM}Required for: daemon, pipeline, PR creation, issue management${RESET}"
658
+ echo -e " ${DIM}Install: ${RESET}${BOLD}brew install gh && gh auth login${RESET}"
659
+ fi
660
+
588
661
  # ─── Reload tmux if inside a session ──────────────────────────────────────────
589
662
  if [[ -n "${TMUX:-}" ]]; then
590
663
  if tmux source-file "$HOME/.tmux.conf" 2>/dev/null; then
@@ -595,6 +668,36 @@ if [[ -n "${TMUX:-}" ]]; then
595
668
  fi
596
669
  fi
597
670
 
671
+ # ─── Bun (required for dashboard) ──────────────────────────────────────────
672
+ if command -v bun &>/dev/null || [[ -x "$HOME/.bun/bin/bun" ]]; then
673
+ _bun_cmd="bun"
674
+ [[ -x "$HOME/.bun/bin/bun" ]] && _bun_cmd="$HOME/.bun/bin/bun"
675
+ success "Bun $($_bun_cmd --version 2>/dev/null || echo "installed") — dashboard ready"
676
+ else
677
+ info "Installing Bun (required for ${BOLD}shipwright dashboard${RESET})..."
678
+ if curl -fsSL https://bun.sh/install | bash 2>/dev/null; then
679
+ export PATH="$HOME/.bun/bin:$PATH"
680
+ success "Bun installed — dashboard ready"
681
+ else
682
+ warn "Could not install Bun automatically"
683
+ echo -e " ${DIM}Install manually: curl -fsSL https://bun.sh/install | bash${RESET}"
684
+ echo -e " ${DIM}The dashboard requires Bun to run: shipwright dashboard${RESET}"
685
+ fi
686
+ fi
687
+
688
+ # ─── Dashboard Files ──────────────────────────────────────────────────────
689
+ # Copy dashboard files to the install location for non-source installs
690
+ DASHBOARD_SRC="$REPO_DIR/dashboard"
691
+ DASHBOARD_DEST="$HOME/.local/share/shipwright/dashboard"
692
+ if [[ -f "$DASHBOARD_SRC/server.ts" ]]; then
693
+ mkdir -p "$DASHBOARD_DEST/public"
694
+ cp "$DASHBOARD_SRC/server.ts" "$DASHBOARD_DEST/server.ts"
695
+ for _f in "$DASHBOARD_SRC/public"/*; do
696
+ [[ -f "$_f" ]] && cp "$_f" "$DASHBOARD_DEST/public/$(basename "$_f")"
697
+ done
698
+ success "Dashboard files installed → ~/.local/share/shipwright/dashboard/"
699
+ fi
700
+
598
701
  # ─── Validation ───────────────────────────────────────────────────────────────
599
702
  echo ""
600
703
  echo -e "${CYAN}${BOLD}Running doctor...${RESET}"
@@ -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.2.1"
9
+ VERSION="2.3.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -200,6 +200,7 @@ cmd_start() {
200
200
  local run_file="${INSTRUMENT_ACTIVE}/${run_id}.json"
201
201
  local tmp_file
202
202
  tmp_file="$(mktemp "${INSTRUMENT_ACTIVE}/.tmp.XXXXXX")"
203
+ trap "rm -f '$tmp_file'" RETURN
203
204
 
204
205
  # Get repo info if not provided
205
206
  if [[ "$repo" == "." ]]; then
@@ -266,6 +267,7 @@ cmd_record() {
266
267
 
267
268
  local tmp_file
268
269
  tmp_file="$(mktemp "${INSTRUMENT_ACTIVE}/.tmp.XXXXXX")"
270
+ trap "rm -f '$tmp_file'" RETURN
269
271
 
270
272
  # Parse value as number if it's numeric
271
273
  local value_json
@@ -328,6 +330,7 @@ cmd_stage_start() {
328
330
 
329
331
  local tmp_file
330
332
  tmp_file="$(mktemp "${INSTRUMENT_ACTIVE}/.tmp.XXXXXX")"
333
+ trap "rm -f '$tmp_file'" RETURN
331
334
 
332
335
  jq \
333
336
  --arg stage "$stage" \
@@ -373,6 +376,7 @@ cmd_stage_end() {
373
376
 
374
377
  local tmp_file
375
378
  tmp_file="$(mktemp "${INSTRUMENT_ACTIVE}/.tmp.XXXXXX")"
379
+ trap "rm -f '$tmp_file'" RETURN
376
380
 
377
381
  jq \
378
382
  --arg stage "$stage" \
@@ -422,6 +426,7 @@ cmd_finish() {
422
426
 
423
427
  local tmp_file
424
428
  tmp_file="$(mktemp "${INSTRUMENT_ACTIVE}/.tmp.XXXXXX")"
429
+ trap "rm -f '$tmp_file'" RETURN
425
430
 
426
431
  # Update run record with finish data
427
432
  jq \