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
  REPO_DIR="${REPO_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
12
12
 
@@ -75,6 +75,7 @@ _intelligence_track_cache_access() {
75
75
 
76
76
  local tmp_file
77
77
  tmp_file=$(mktemp "${TMPDIR:-/tmp}/sw-cache-stats.XXXXXX")
78
+ trap "rm -f '$tmp_file'" RETURN
78
79
  if [[ "$hit_or_miss" == "hit" ]]; then
79
80
  jq '.hits += 1 | .total += 1' "$CACHE_STATS_FILE" > "$tmp_file" && mv "$tmp_file" "$CACHE_STATS_FILE" || rm -f "$tmp_file"
80
81
  else
@@ -118,6 +119,7 @@ _intelligence_adjust_cache_ttl() {
118
119
  if [[ "$new_ttl" != "$current_ttl" ]]; then
119
120
  local tmp_file
120
121
  tmp_file=$(mktemp "${TMPDIR:-/tmp}/sw-cache-ttl.XXXXXX")
122
+ trap "rm -f '$tmp_file'" RETURN
121
123
  jq -n \
122
124
  --argjson ttl "$new_ttl" \
123
125
  --argjson miss_rate "$miss_rate" \
@@ -134,6 +136,7 @@ _intelligence_adjust_cache_ttl() {
134
136
  # Reset stats for next window
135
137
  local tmp_reset
136
138
  tmp_reset=$(mktemp "${TMPDIR:-/tmp}/sw-cache-reset.XXXXXX")
139
+ trap "rm -f '$tmp_reset'" RETURN
137
140
  echo '{"hits":0,"misses":0,"total":0}' > "$tmp_reset" && mv "$tmp_reset" "$CACHE_STATS_FILE" || rm -f "$tmp_reset"
138
141
  }
139
142
 
@@ -212,6 +215,7 @@ _intelligence_cache_set() {
212
215
 
213
216
  local tmp_file
214
217
  tmp_file=$(mktemp "${TMPDIR:-/tmp}/sw-intel-cache.XXXXXX")
218
+ trap "rm -f '$tmp_file'" RETURN
215
219
  jq --arg h "$hash" \
216
220
  --argjson result "$result" \
217
221
  --argjson ts "$now" \
@@ -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
 
@@ -48,12 +48,14 @@ RESET="${RESET:-\033[0m}"
48
48
  CONFIG_DIR="${HOME}/.shipwright"
49
49
  LINEAR_CONFIG="${CONFIG_DIR}/linear-config.json"
50
50
 
51
- # Linear Status IDs (Sethdford team)
52
- STATUS_BACKLOG="147eb91d-0428-457b-bdcb-0875b847b061"
53
- STATUS_TODO="f89d423b-9cad-4e60-aec9-422b64b78a4b"
54
- STATUS_IN_PROGRESS="7ed39c42-434d-4239-86f3-ffa24dbf1275"
55
- STATUS_IN_REVIEW="ea38a4f2-f0ee-4e0b-ae45-7e5aad45ef53"
56
- STATUS_DONE="dc2430cf-0713-40c9-a8c6-889413b626e7"
51
+ # Linear Status IDs loaded from config, with env var overrides
52
+ # Configure via: shipwright tracker init --provider linear
53
+ # Or set env vars: LINEAR_STATUS_BACKLOG, LINEAR_STATUS_TODO, etc.
54
+ STATUS_BACKLOG="${LINEAR_STATUS_BACKLOG:-}"
55
+ STATUS_TODO="${LINEAR_STATUS_TODO:-}"
56
+ STATUS_IN_PROGRESS="${LINEAR_STATUS_IN_PROGRESS:-}"
57
+ STATUS_IN_REVIEW="${LINEAR_STATUS_IN_REVIEW:-}"
58
+ STATUS_DONE="${LINEAR_STATUS_DONE:-}"
57
59
 
58
60
  LINEAR_API="https://api.linear.app/graphql"
59
61
 
@@ -65,8 +67,17 @@ load_config() {
65
67
  fi
66
68
 
67
69
  LINEAR_API_KEY="${LINEAR_API_KEY:-}"
68
- LINEAR_TEAM_ID="${LINEAR_TEAM_ID:-83deb533-69d2-43ef-bc58-eadb6e72a8f2}"
69
- LINEAR_PROJECT_ID="${LINEAR_PROJECT_ID:-b262d625-5bbe-47bd-9f89-df27c45eba8b}"
70
+ LINEAR_TEAM_ID="${LINEAR_TEAM_ID:-$(jq -r '.team_id // empty' "$LINEAR_CONFIG" 2>/dev/null || true)}"
71
+ LINEAR_PROJECT_ID="${LINEAR_PROJECT_ID:-$(jq -r '.project_id // empty' "$LINEAR_CONFIG" 2>/dev/null || true)}"
72
+
73
+ # Load status IDs from config if not set via env
74
+ if [[ -f "$LINEAR_CONFIG" ]]; then
75
+ STATUS_BACKLOG="${STATUS_BACKLOG:-$(jq -r '.status_ids.backlog // empty' "$LINEAR_CONFIG" 2>/dev/null || true)}"
76
+ STATUS_TODO="${STATUS_TODO:-$(jq -r '.status_ids.todo // empty' "$LINEAR_CONFIG" 2>/dev/null || true)}"
77
+ STATUS_IN_PROGRESS="${STATUS_IN_PROGRESS:-$(jq -r '.status_ids.in_progress // empty' "$LINEAR_CONFIG" 2>/dev/null || true)}"
78
+ STATUS_IN_REVIEW="${STATUS_IN_REVIEW:-$(jq -r '.status_ids.in_review // empty' "$LINEAR_CONFIG" 2>/dev/null || true)}"
79
+ STATUS_DONE="${STATUS_DONE:-$(jq -r '.status_ids.done // empty' "$LINEAR_CONFIG" 2>/dev/null || true)}"
80
+ fi
70
81
  }
71
82
 
72
83
  check_api_key() {
@@ -4,7 +4,7 @@
4
4
  # ║ ║
5
5
  # ║ Captures tmux pane scrollback and provides log browsing/search. ║
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
 
@@ -71,7 +71,7 @@ MAX_RESTARTS=0
71
71
  SESSION_RESTART=false
72
72
  RESTART_COUNT=0
73
73
  REPO_OVERRIDE=""
74
- VERSION="2.2.1"
74
+ VERSION="2.3.0"
75
75
 
76
76
  # ─── Token Tracking ─────────────────────────────────────────────────────────
77
77
  LOOP_INPUT_TOKENS=0
@@ -531,6 +531,7 @@ write_loop_tokens() {
531
531
  fi
532
532
  local tmp_file
533
533
  tmp_file=$(mktemp "${token_file}.XXXXXX" 2>/dev/null || mktemp)
534
+ trap "rm -f '$tmp_file'" RETURN
534
535
  cat > "$tmp_file" <<TOKJSON
535
536
  {"input_tokens":${LOOP_INPUT_TOKENS},"output_tokens":${LOOP_OUTPUT_TOKENS},"cost_usd":${cost_usd},"iterations":${ITERATION:-0}}
536
537
  TOKJSON
@@ -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="${REPO_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
12
12
 
@@ -150,6 +150,7 @@ memory_capture_pipeline() {
150
150
  # Record review patterns to global memory for cross-repo learning
151
151
  local tmp_global
152
152
  tmp_global=$(mktemp)
153
+ trap "rm -f '$tmp_global'" RETURN
153
154
  jq --arg repo "$repo" \
154
155
  --arg ts "$captured_at" \
155
156
  --argjson bugs "${bug_count:-0}" \
@@ -211,6 +212,7 @@ memory_capture_failure() {
211
212
  fi
212
213
  local tmp_file
213
214
  tmp_file=$(mktemp "${failures_file}.tmp.XXXXXX")
215
+ trap "rm -f '$tmp_file'" EXIT
214
216
 
215
217
  if [[ "$existing_idx" != "-1" && "$existing_idx" != "null" ]]; then
216
218
  # Update existing entry
@@ -277,6 +279,7 @@ memory_record_fix_outcome() {
277
279
  fi
278
280
  local tmp_file
279
281
  tmp_file=$(mktemp "${failures_file}.tmp.XXXXXX")
282
+ trap "rm -f '$tmp_file'" EXIT
280
283
 
281
284
  jq --argjson idx "$match_idx" \
282
285
  --argjson app "$applied_inc" \
@@ -442,6 +445,7 @@ _memory_aggregate_global() {
442
445
  # Add to global, cap at 100 entries
443
446
  local tmp_global
444
447
  tmp_global=$(mktemp "${global_file}.tmp.XXXXXX")
448
+ trap "rm -f '$tmp_global'" RETURN
445
449
  jq --arg p "$pattern" \
446
450
  --arg ts "$(now_iso)" \
447
451
  --arg cat "general" \
@@ -593,6 +597,7 @@ Return JSON only, no markdown fences, no explanation."
593
597
  # Update the most recent failure entry with root_cause, fix, category
594
598
  local tmp_file
595
599
  tmp_file=$(mktemp)
600
+ trap "rm -f '$tmp_file'" RETURN
596
601
  jq --arg rc "$root_cause" \
597
602
  --arg fix "$fix" \
598
603
  --arg cat "$category" \
@@ -622,6 +627,7 @@ memory_capture_pattern() {
622
627
 
623
628
  local tmp_file
624
629
  tmp_file=$(mktemp)
630
+ trap "rm -f '$tmp_file'" RETURN
625
631
 
626
632
  case "$pattern_type" in
627
633
  project)
@@ -1112,6 +1118,7 @@ memory_update_metrics() {
1112
1118
  # Update baseline using atomic write
1113
1119
  local tmp_file
1114
1120
  tmp_file=$(mktemp)
1121
+ trap "rm -f '$tmp_file'" RETURN
1115
1122
  jq --arg m "$metric_name" \
1116
1123
  --argjson v "$value" \
1117
1124
  --arg ts "$(now_iso)" \
@@ -1135,6 +1142,7 @@ memory_capture_decision() {
1135
1142
 
1136
1143
  local tmp_file
1137
1144
  tmp_file=$(mktemp)
1145
+ trap "rm -f '$tmp_file'" RETURN
1138
1146
  jq --arg type "$dec_type" \
1139
1147
  --arg summary "$summary" \
1140
1148
  --arg detail "$detail" \
@@ -1454,6 +1462,7 @@ memory_import() {
1454
1462
  # Extract and write each section
1455
1463
  local tmp_file
1456
1464
  tmp_file=$(mktemp)
1465
+ trap "rm -f '$tmp_file'" RETURN
1457
1466
 
1458
1467
  jq '.patterns // {}' "$import_file" > "$tmp_file" && mv "$tmp_file" "$mem_dir/patterns.json"
1459
1468
  jq '.failures // {"failures":[]}' "$import_file" > "$tmp_file" && mv "$tmp_file" "$mem_dir/failures.json"
@@ -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
 
@@ -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
 
@@ -204,6 +204,7 @@ set_config() {
204
204
  # Use jq to safely update the config
205
205
  local tmp_config
206
206
  tmp_config=$(mktemp)
207
+ trap "rm -f '$tmp_config'" RETURN
207
208
 
208
209
  if [[ "$value" == "true" ]] || [[ "$value" == "false" ]]; then
209
210
  jq ".${key} = ${value}" "$MODEL_ROUTING_CONFIG" > "$tmp_config"
@@ -336,6 +337,7 @@ configure_ab_test() {
336
337
 
337
338
  local tmp_config
338
339
  tmp_config=$(mktemp)
340
+ trap "rm -f '$tmp_config'" RETURN
339
341
 
340
342
  jq ".a_b_test = {\"enabled\": true, \"percentage\": $percentage, \"variant\": \"$variant\"}" \
341
343
  "$MODEL_ROUTING_CONFIG" > "$tmp_config"
@@ -521,6 +523,7 @@ main() {
521
523
  if command -v jq &>/dev/null; then
522
524
  local tmp_config
523
525
  tmp_config=$(mktemp)
526
+ trap "rm -f '$tmp_config'" RETURN
524
527
  jq ".a_b_test.enabled = false" "$MODEL_ROUTING_CONFIG" > "$tmp_config"
525
528
  mv "$tmp_config" "$MODEL_ROUTING_CONFIG"
526
529
  success "Disabled A/B testing"
@@ -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
 
@@ -94,16 +94,16 @@ cmd_metrics() {
94
94
  event_type=$(echo "$line" | jq -r '.type // empty' 2>/dev/null || true)
95
95
 
96
96
  case "$event_type" in
97
- pipeline_start)
97
+ pipeline_start|pipeline.started)
98
98
  ((total_pipelines++))
99
99
  ((active_pipelines++))
100
100
  ;;
101
- pipeline_complete)
101
+ pipeline_complete|pipeline.completed)
102
102
  ((active_pipelines--))
103
103
  ((succeeded_pipelines++))
104
104
  ((status_success++))
105
105
  ;;
106
- pipeline_failed)
106
+ pipeline_failed|pipeline.failed)
107
107
  ((active_pipelines--))
108
108
  ((failed_pipelines++))
109
109
  ((status_failed++))
@@ -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
 
@@ -124,6 +124,7 @@ composer_create_pipeline() {
124
124
  # Atomic write
125
125
  local tmp_file
126
126
  tmp_file=$(mktemp "${output_file}.XXXXXX")
127
+ trap "rm -f '$tmp_file'" RETURN
127
128
  echo "$composed" | jq '.' > "$tmp_file"
128
129
  mv "$tmp_file" "$output_file"
129
130
 
@@ -152,6 +153,7 @@ composer_create_pipeline() {
152
153
  info "Using fallback template: standard" >&2
153
154
  local tmp_file
154
155
  tmp_file=$(mktemp "${output_file}.XXXXXX")
156
+ trap "rm -f '$tmp_file'" RETURN
155
157
  cp "$fallback_template" "$tmp_file"
156
158
  mv "$tmp_file" "$output_file"
157
159
 
@@ -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
 
@@ -316,13 +316,11 @@ _compute_error_maturity() {
316
316
  # ─── File Locking Helpers ──────────────────────────────────────────────────
317
317
  _vitals_acquire_lock() {
318
318
  local lockfile="$1.lock"
319
- local fd=200
320
- eval "exec $fd>\"$lockfile\""
321
- flock -w 5 "$fd" || { warn "Vitals lock timeout"; return 1; }
319
+ exec 200>"$lockfile"
320
+ flock -w 5 200 || { warn "Vitals lock timeout"; return 1; }
322
321
  }
323
322
  _vitals_release_lock() {
324
- local fd=200
325
- flock -u "$fd" 2>/dev/null || true
323
+ flock -u 200 2>/dev/null || true
326
324
  }
327
325
 
328
326
  # ═══════════════════════════════════════════════════════════════════════════
@@ -11,7 +11,7 @@ unset CLAUDECODE 2>/dev/null || true
11
11
  # Ignore SIGHUP so tmux attach/detach doesn't kill long-running plan/design/review stages
12
12
  trap '' HUP
13
13
 
14
- VERSION="2.2.1"
14
+ VERSION="2.3.0"
15
15
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16
16
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
17
17
 
@@ -49,6 +49,18 @@ BOLD="${BOLD:-\033[1m}"
49
49
  RESET="${RESET:-\033[0m}"
50
50
  # Policy + pipeline quality thresholds (config/policy.json via lib/pipeline-quality.sh)
51
51
  [[ -f "$SCRIPT_DIR/lib/pipeline-quality.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-quality.sh"
52
+ # shellcheck source=lib/pipeline-state.sh
53
+ [[ -f "$SCRIPT_DIR/lib/pipeline-state.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-state.sh"
54
+ # shellcheck source=lib/pipeline-github.sh
55
+ [[ -f "$SCRIPT_DIR/lib/pipeline-github.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-github.sh"
56
+ # shellcheck source=lib/pipeline-detection.sh
57
+ [[ -f "$SCRIPT_DIR/lib/pipeline-detection.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-detection.sh"
58
+ # shellcheck source=lib/pipeline-quality-checks.sh
59
+ [[ -f "$SCRIPT_DIR/lib/pipeline-quality-checks.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-quality-checks.sh"
60
+ # shellcheck source=lib/pipeline-intelligence.sh
61
+ [[ -f "$SCRIPT_DIR/lib/pipeline-intelligence.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-intelligence.sh"
62
+ # shellcheck source=lib/pipeline-stages.sh
63
+ [[ -f "$SCRIPT_DIR/lib/pipeline-stages.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-stages.sh"
52
64
  PIPELINE_COVERAGE_THRESHOLD="${PIPELINE_COVERAGE_THRESHOLD:-60}"
53
65
  PIPELINE_QUALITY_GATE_THRESHOLD="${PIPELINE_QUALITY_GATE_THRESHOLD:-70}"
54
66
 
@@ -760,55 +772,7 @@ notify() {
760
772
  fi
761
773
  }
762
774
 
763
- # ─── GitHub Integration Helpers ─────────────────────────────────────────────
764
-
765
-
766
- # ─── Pipeline libs (extracted for decomposition) ─────────────────────────
767
- # shellcheck source=lib/pipeline-github.sh
768
- [[ -f "$SCRIPT_DIR/lib/pipeline-github.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-github.sh"
769
- # shellcheck source=lib/pipeline-detection.sh
770
- [[ -f "$SCRIPT_DIR/lib/pipeline-detection.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-detection.sh"
771
-
772
- PIPELINE_STATUS="pending"
773
- CURRENT_STAGE=""
774
- STARTED_AT=""
775
- UPDATED_AT=""
776
- STAGE_STATUSES=""
777
- LOG_ENTRIES=""
778
-
779
- # shellcheck source=lib/pipeline-state.sh
780
- [[ -f "$SCRIPT_DIR/lib/pipeline-state.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-state.sh"
781
-
782
- show_stage_preview() {
783
- local stage_id="$1"
784
- echo ""
785
- echo -e "${PURPLE}${BOLD}━━━ Stage: ${stage_id} ━━━${RESET}"
786
- case "$stage_id" in
787
- intake) echo -e " Fetch issue, detect task type, create branch, self-assign" ;;
788
- plan) echo -e " Generate plan via Claude, post task checklist to issue" ;;
789
- design) echo -e " Generate Architecture Decision Record (ADR), evaluate alternatives" ;;
790
- build) echo -e " Delegate to ${CYAN}shipwright loop${RESET} for autonomous building" ;;
791
- test) echo -e " Run test suite and check coverage" ;;
792
- review) echo -e " AI code review on the diff, post findings" ;;
793
- pr) echo -e " Create GitHub PR with labels, reviewers, milestone" ;;
794
- merge) echo -e " Wait for CI checks, merge PR, optionally delete branch" ;;
795
- deploy) echo -e " Deploy to staging/production with rollback" ;;
796
- validate) echo -e " Smoke tests, health checks, close issue" ;;
797
- monitor) echo -e " Post-deploy monitoring, health checks, auto-rollback" ;;
798
- esac
799
- echo ""
800
- }
801
-
802
- # ─── Stage Functions ────────────────────────────────────────────────────────
803
-
804
-
805
- # shellcheck source=lib/pipeline-stages.sh
806
- [[ -f "$SCRIPT_DIR/lib/pipeline-stages.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-stages.sh"
807
- # shellcheck source=lib/pipeline-quality-checks.sh
808
- [[ -f "$SCRIPT_DIR/lib/pipeline-quality-checks.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-quality-checks.sh"
809
- # shellcheck source=lib/pipeline-intelligence.sh
810
- [[ -f "$SCRIPT_DIR/lib/pipeline-intelligence.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-intelligence.sh"
811
-
775
+ # ─── Error Classification ──────────────────────────────────────────────────
812
776
  # Classifies errors to determine whether retrying makes sense.
813
777
  # Returns: "infrastructure", "logic", "configuration", or "unknown"
814
778
 
@@ -886,6 +850,7 @@ Reply with ONLY the classification word, nothing else." --model haiku < /dev/nul
886
850
  mkdir -p "$class_dir" 2>/dev/null || true
887
851
  local tmp_class
888
852
  tmp_class="$(mktemp)"
853
+ trap "rm -f '$tmp_class'" RETURN
889
854
  if [[ -f "$class_history" ]]; then
890
855
  jq --arg sig "$error_sig" --arg cls "$classification" --arg canon "$canonical_category" --arg stage "$stage_id" \
891
856
  '.[$sig] = {"classification": $cls, "canonical": $canon, "stage": $stage, "recorded_at": now}' \
@@ -1305,6 +1270,7 @@ run_pipeline() {
1305
1270
  # Remove this stage from the skip file
1306
1271
  local tmp_skip
1307
1272
  tmp_skip="$(mktemp)"
1273
+ trap "rm -f '$tmp_skip'" RETURN
1308
1274
  grep -vx "$id" "$ARTIFACTS_DIR/skip-stage.txt" > "$tmp_skip" 2>/dev/null || true
1309
1275
  mv "$tmp_skip" "$ARTIFACTS_DIR/skip-stage.txt"
1310
1276
  continue
@@ -1636,12 +1602,9 @@ pipeline_post_completion_cleanup() {
1636
1602
  # Reset status to idle (preserves the file for reference but unblocks new runs)
1637
1603
  local tmp_state
1638
1604
  tmp_state=$(mktemp)
1639
- if sed 's/^status: .*/status: idle/' "$STATE_FILE" > "$tmp_state" 2>/dev/null && [[ -s "$tmp_state" ]]; then
1640
- mv "$tmp_state" "$STATE_FILE"
1641
- else
1642
- rm -f "$tmp_state"
1643
- warn "Failed to reset state file status to idle" 2>/dev/null || true
1644
- fi
1605
+ trap "rm -f '$tmp_state'" RETURN
1606
+ sed 's/^status: .*/status: idle/' "$STATE_FILE" > "$tmp_state" 2>/dev/null || true
1607
+ mv "$tmp_state" "$STATE_FILE"
1645
1608
  fi
1646
1609
 
1647
1610
  if [[ "$cleaned" -gt 0 ]]; then
@@ -0,0 +1,7 @@
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
package/scripts/sw-pm.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 ──────────────────────────────────────────
@@ -77,7 +77,7 @@ show_help() {
77
77
  echo -e " ${DIM}shipwright pm history${RESET} # Show past decisions"
78
78
  echo -e " ${DIM}shipwright pm history --pattern${RESET} # Show success patterns"
79
79
  echo ""
80
- echo -e "${DIM}Docs: https://sethdford.github.io/shipwright | GitHub: https://github.com/sethdford/shipwright${RESET}"
80
+ echo -e "${DIM}Docs: $(_sw_docs_url) | GitHub: $(_sw_github_url)${RESET}"
81
81
  }
82
82
 
83
83
  # ─── analyze_issue <issue_num> ───────────────────────────────────────────────
@@ -522,6 +522,7 @@ cmd_recommend() {
522
522
  ensure_pm_history
523
523
  local tmp_hist
524
524
  tmp_hist=$(mktemp)
525
+ trap "rm -f '$tmp_hist'" RETURN
525
526
  jq --argjson rec "$recommendation" '.decisions += [$rec]' "$PM_HISTORY" > "$tmp_hist" && mv "$tmp_hist" "$PM_HISTORY"
526
527
  emit_event "pm.recommend" "issue=${issue_num}"
527
528
  return 0
@@ -549,6 +550,7 @@ cmd_recommend() {
549
550
  ensure_pm_history
550
551
  local tmp_hist
551
552
  tmp_hist=$(mktemp)
553
+ trap "rm -f '$tmp_hist'" RETURN
552
554
  jq --argjson rec "$recommendation" '.decisions += [$rec]' "$PM_HISTORY" > "$tmp_hist" && mv "$tmp_hist" "$PM_HISTORY"
553
555
 
554
556
  success "Recommendation saved to history"
@@ -612,6 +614,7 @@ cmd_learn() {
612
614
  # Save to history
613
615
  local tmp_hist
614
616
  tmp_hist=$(mktemp)
617
+ trap "rm -f '$tmp_hist'" RETURN
615
618
  jq --argjson outcome "$outcome_record" '.outcomes += [$outcome]' "$PM_HISTORY" > "$tmp_hist" && mv "$tmp_hist" "$PM_HISTORY"
616
619
 
617
620
  success "Recorded ${outcome} outcome for issue #${issue_num}"
@@ -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
 
@@ -188,6 +188,7 @@ predictive_confirm_anomaly() {
188
188
  # Find the most recent unconfirmed anomaly for this stage+metric
189
189
  local tmp_file
190
190
  tmp_file=$(mktemp "${TMPDIR:-/tmp}/sw-anomaly-confirm.XXXXXX")
191
+ trap "rm -f '$tmp_file'" RETURN
191
192
  local found=false
192
193
 
193
194
  # Process file in reverse to find most recent unconfirmed
@@ -283,6 +284,7 @@ _predictive_update_alarm_rates() {
283
284
  # Atomic write
284
285
  local tmp_file
285
286
  tmp_file=$(mktemp "${TMPDIR:-/tmp}/sw-anomaly-thresh.XXXXXX")
287
+ trap "rm -f '$tmp_file'" RETURN
286
288
  jq --arg m "$metric_name" \
287
289
  --argjson crit "$new_critical" \
288
290
  --argjson warn "$new_warning" \
@@ -755,6 +757,7 @@ predict_update_baseline() {
755
757
  # Atomic write
756
758
  local tmp_file
757
759
  tmp_file=$(mktemp)
760
+ trap "rm -f '$tmp_file'" RETURN
758
761
  jq --arg key "$key" \
759
762
  --argjson val "$new_value" \
760
763
  --argjson cnt "$new_count" \
@@ -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
  # ─── Handle subcommands ───────────────────────────────────────────────────────
@@ -129,7 +129,7 @@ show_help() {
129
129
  echo -e " ${DIM}.claude/hooks/*.sh${RESET} Pre/post action hooks"
130
130
  echo -e " ${DIM}.github/ISSUE_TEMPLATE/agent-task.md${RESET} Agent task template"
131
131
  echo ""
132
- echo -e "${DIM}Docs: https://sethdford.github.io/shipwright | GitHub: https://github.com/sethdford/shipwright${RESET}"
132
+ echo -e "${DIM}Docs: $(_sw_docs_url) | GitHub: $(_sw_github_url)${RESET}"
133
133
  }
134
134
 
135
135
  # ─── CLI Argument Parsing ───────────────────────────────────────────────────
@@ -828,6 +828,7 @@ prep_learn_patterns() {
828
828
  # Write patterns file atomically
829
829
  local tmp_patterns
830
830
  tmp_patterns=$(mktemp)
831
+ trap "rm -f '$tmp_patterns'" RETURN
831
832
  jq -n \
832
833
  --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
833
834
  --arg lang "${LANG_DETECTED:-}" \
package/scripts/sw-ps.sh CHANGED
@@ -5,7 +5,7 @@
5
5
  # ║ Displays a table of agents running in claude-* tmux windows with ║
6
6
  # ║ PID, status, idle time, and pane references. ║
7
7
  # ╚═══════════════════════════════════════════════════════════════════════════╝
8
- VERSION="2.2.1"
8
+ VERSION="2.3.0"
9
9
  set -euo pipefail
10
10
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
11
11
 
@@ -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
 
@@ -323,7 +323,7 @@ generate_html() {
323
323
  </div>
324
324
 
325
325
  <div class="footer">
326
- <p>Generated by <a href="https://github.com/sethdford/shipwright">Shipwright</a> v1.13.0</p>
326
+ <p>Generated by <a href="GITHUB_URL_PLACEHOLDER">Shipwright</a> v1.13.0</p>
327
327
  <p style="margin-top: 8px; color: #555;">Dashboard auto-refreshes every 30s when served from dashboard server</p>
328
328
  <p style="margin-top: 8px;" id="footer-timestamp">Generated: —</p>
329
329
  </div>
@@ -384,7 +384,12 @@ generate_html() {
384
384
  const newDoc = parser.parseFromString(html, 'text/html');
385
385
  const newScript = newDoc.querySelector('script');
386
386
  if (newScript) {
387
- eval(newScript.textContent);
387
+ // Use DOM script insertion instead of eval: script comes from same-origin
388
+ // fetch of this page; DOM insertion executes in global scope without eval
389
+ const s = document.createElement('script');
390
+ s.textContent = newScript.textContent;
391
+ document.body.appendChild(s);
392
+ s.remove();
388
393
  renderDashboard();
389
394
  }
390
395
  })
@@ -417,6 +422,7 @@ cmd_export() {
417
422
  html="${html//TITLE_PLACEHOLDER/$title}"
418
423
  html="${html//PRIVACY_PLACEHOLDER/$privacy}"
419
424
  html="${html//\{DATA_PLACEHOLDER\}/$state_data}"
425
+ html="${html//GITHUB_URL_PLACEHOLDER/$(_sw_github_url)}"
420
426
 
421
427
  # Atomic write
422
428
  local tmp_file
@@ -736,7 +742,7 @@ ${BOLD}SHARE LINKS${RESET}
736
742
  Share links require a running dashboard server to serve the public endpoint.
737
743
  By default, requires dashboard to serve at: https://your-domain.com/public-dashboard/<token>
738
744
 
739
- ${DIM}Docs: https://sethdford.github.io/shipwright${RESET}
745
+ ${DIM}Docs: $(_sw_docs_url)${RESET}
740
746
  EOF
741
747
  }
742
748