shipwright-cli 3.2.0 → 3.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 (279) hide show
  1. package/.claude/agents/code-reviewer.md +2 -0
  2. package/.claude/agents/devops-engineer.md +2 -0
  3. package/.claude/agents/doc-fleet-agent.md +2 -0
  4. package/.claude/agents/pipeline-agent.md +2 -0
  5. package/.claude/agents/shell-script-specialist.md +2 -0
  6. package/.claude/agents/test-specialist.md +2 -0
  7. package/.claude/hooks/agent-crash-capture.sh +32 -0
  8. package/.claude/hooks/post-tool-use.sh +3 -2
  9. package/.claude/hooks/pre-tool-use.sh +35 -3
  10. package/README.md +4 -4
  11. package/claude-code/hooks/config-change.sh +18 -0
  12. package/claude-code/hooks/instructions-reloaded.sh +7 -0
  13. package/claude-code/hooks/worktree-create.sh +25 -0
  14. package/claude-code/hooks/worktree-remove.sh +20 -0
  15. package/config/code-constitution.json +130 -0
  16. package/dashboard/middleware/auth.ts +134 -0
  17. package/dashboard/middleware/constants.ts +21 -0
  18. package/dashboard/public/index.html +2 -6
  19. package/dashboard/public/styles.css +100 -97
  20. package/dashboard/routes/auth.ts +38 -0
  21. package/dashboard/server.ts +66 -25
  22. package/dashboard/services/config.ts +26 -0
  23. package/dashboard/services/db.ts +118 -0
  24. package/dashboard/src/canvas/pixel-agent.ts +298 -0
  25. package/dashboard/src/canvas/pixel-sprites.ts +440 -0
  26. package/dashboard/src/canvas/shipyard-effects.ts +367 -0
  27. package/dashboard/src/canvas/shipyard-scene.ts +616 -0
  28. package/dashboard/src/canvas/submarine-layout.ts +267 -0
  29. package/dashboard/src/components/header.ts +8 -7
  30. package/dashboard/src/core/router.ts +1 -0
  31. package/dashboard/src/design/submarine-theme.ts +253 -0
  32. package/dashboard/src/main.ts +2 -0
  33. package/dashboard/src/types/api.ts +2 -1
  34. package/dashboard/src/views/activity.ts +2 -1
  35. package/dashboard/src/views/shipyard.ts +39 -0
  36. package/dashboard/types/index.ts +166 -0
  37. package/docs/plans/2026-02-28-compound-audit-and-shipyard-design.md +186 -0
  38. package/docs/plans/2026-02-28-skipper-shipwright-implementation-plan.md +1182 -0
  39. package/docs/plans/2026-02-28-skipper-shipwright-integration-design.md +531 -0
  40. package/docs/plans/2026-03-01-ai-powered-skill-injection-design.md +298 -0
  41. package/docs/plans/2026-03-01-ai-powered-skill-injection-plan.md +1109 -0
  42. package/docs/plans/2026-03-01-capabilities-cleanup-plan.md +658 -0
  43. package/docs/plans/2026-03-01-clean-architecture-plan.md +924 -0
  44. package/docs/plans/2026-03-01-compound-audit-cascade-design.md +191 -0
  45. package/docs/plans/2026-03-01-compound-audit-cascade-plan.md +921 -0
  46. package/docs/plans/2026-03-01-deep-integration-plan.md +851 -0
  47. package/docs/plans/2026-03-01-pipeline-audit-trail-design.md +145 -0
  48. package/docs/plans/2026-03-01-pipeline-audit-trail-plan.md +770 -0
  49. package/docs/plans/2026-03-01-refined-depths-brand-design.md +382 -0
  50. package/docs/plans/2026-03-01-refined-depths-implementation.md +599 -0
  51. package/docs/plans/2026-03-01-skipper-kernel-integration-design.md +203 -0
  52. package/docs/plans/2026-03-01-unified-platform-design.md +272 -0
  53. package/docs/plans/2026-03-07-claude-code-feature-integration-design.md +189 -0
  54. package/docs/plans/2026-03-07-claude-code-feature-integration-plan.md +1165 -0
  55. package/docs/research/BACKLOG_QUICK_REFERENCE.md +352 -0
  56. package/docs/research/CUTTING_EDGE_RESEARCH_2026.md +546 -0
  57. package/docs/research/RESEARCH_INDEX.md +439 -0
  58. package/docs/research/RESEARCH_SOURCES.md +440 -0
  59. package/docs/research/RESEARCH_SUMMARY.txt +275 -0
  60. package/docs/superpowers/specs/2026-03-10-pipeline-quality-revolution-design.md +341 -0
  61. package/package.json +2 -2
  62. package/scripts/lib/adaptive-model.sh +427 -0
  63. package/scripts/lib/adaptive-timeout.sh +316 -0
  64. package/scripts/lib/audit-trail.sh +309 -0
  65. package/scripts/lib/auto-recovery.sh +471 -0
  66. package/scripts/lib/bandit-selector.sh +431 -0
  67. package/scripts/lib/bootstrap.sh +104 -2
  68. package/scripts/lib/causal-graph.sh +455 -0
  69. package/scripts/lib/compat.sh +126 -0
  70. package/scripts/lib/compound-audit.sh +337 -0
  71. package/scripts/lib/constitutional.sh +454 -0
  72. package/scripts/lib/context-budget.sh +359 -0
  73. package/scripts/lib/convergence.sh +594 -0
  74. package/scripts/lib/cost-optimizer.sh +634 -0
  75. package/scripts/lib/daemon-adaptive.sh +10 -0
  76. package/scripts/lib/daemon-dispatch.sh +106 -17
  77. package/scripts/lib/daemon-failure.sh +34 -4
  78. package/scripts/lib/daemon-patrol.sh +23 -2
  79. package/scripts/lib/daemon-poll-github.sh +361 -0
  80. package/scripts/lib/daemon-poll-health.sh +299 -0
  81. package/scripts/lib/daemon-poll.sh +27 -611
  82. package/scripts/lib/daemon-state.sh +112 -66
  83. package/scripts/lib/daemon-triage.sh +10 -0
  84. package/scripts/lib/dod-scorecard.sh +442 -0
  85. package/scripts/lib/error-actionability.sh +300 -0
  86. package/scripts/lib/formal-spec.sh +461 -0
  87. package/scripts/lib/helpers.sh +177 -4
  88. package/scripts/lib/intent-analysis.sh +409 -0
  89. package/scripts/lib/loop-convergence.sh +350 -0
  90. package/scripts/lib/loop-iteration.sh +682 -0
  91. package/scripts/lib/loop-progress.sh +48 -0
  92. package/scripts/lib/loop-restart.sh +185 -0
  93. package/scripts/lib/memory-effectiveness.sh +506 -0
  94. package/scripts/lib/mutation-executor.sh +352 -0
  95. package/scripts/lib/outcome-feedback.sh +521 -0
  96. package/scripts/lib/pipeline-cli.sh +336 -0
  97. package/scripts/lib/pipeline-commands.sh +1216 -0
  98. package/scripts/lib/pipeline-detection.sh +100 -2
  99. package/scripts/lib/pipeline-execution.sh +897 -0
  100. package/scripts/lib/pipeline-github.sh +28 -3
  101. package/scripts/lib/pipeline-intelligence-compound.sh +431 -0
  102. package/scripts/lib/pipeline-intelligence-scoring.sh +407 -0
  103. package/scripts/lib/pipeline-intelligence-skip.sh +181 -0
  104. package/scripts/lib/pipeline-intelligence.sh +100 -1136
  105. package/scripts/lib/pipeline-quality-bash-compat.sh +182 -0
  106. package/scripts/lib/pipeline-quality-checks.sh +17 -715
  107. package/scripts/lib/pipeline-quality-gates.sh +563 -0
  108. package/scripts/lib/pipeline-stages-build.sh +730 -0
  109. package/scripts/lib/pipeline-stages-delivery.sh +965 -0
  110. package/scripts/lib/pipeline-stages-intake.sh +1133 -0
  111. package/scripts/lib/pipeline-stages-monitor.sh +407 -0
  112. package/scripts/lib/pipeline-stages-review.sh +1022 -0
  113. package/scripts/lib/pipeline-stages.sh +59 -2929
  114. package/scripts/lib/pipeline-state.sh +36 -5
  115. package/scripts/lib/pipeline-util.sh +487 -0
  116. package/scripts/lib/policy-learner.sh +438 -0
  117. package/scripts/lib/process-reward.sh +493 -0
  118. package/scripts/lib/project-detect.sh +649 -0
  119. package/scripts/lib/quality-profile.sh +334 -0
  120. package/scripts/lib/recruit-commands.sh +885 -0
  121. package/scripts/lib/recruit-learning.sh +739 -0
  122. package/scripts/lib/recruit-roles.sh +648 -0
  123. package/scripts/lib/reward-aggregator.sh +458 -0
  124. package/scripts/lib/rl-optimizer.sh +362 -0
  125. package/scripts/lib/root-cause.sh +427 -0
  126. package/scripts/lib/scope-enforcement.sh +445 -0
  127. package/scripts/lib/session-restart.sh +493 -0
  128. package/scripts/lib/skill-memory.sh +300 -0
  129. package/scripts/lib/skill-registry.sh +775 -0
  130. package/scripts/lib/spec-driven.sh +476 -0
  131. package/scripts/lib/test-helpers.sh +18 -7
  132. package/scripts/lib/test-holdout.sh +429 -0
  133. package/scripts/lib/test-optimizer.sh +511 -0
  134. package/scripts/shipwright-file-suggest.sh +45 -0
  135. package/scripts/skills/adversarial-quality.md +61 -0
  136. package/scripts/skills/api-design.md +44 -0
  137. package/scripts/skills/architecture-design.md +50 -0
  138. package/scripts/skills/brainstorming.md +43 -0
  139. package/scripts/skills/data-pipeline.md +44 -0
  140. package/scripts/skills/deploy-safety.md +64 -0
  141. package/scripts/skills/documentation.md +38 -0
  142. package/scripts/skills/frontend-design.md +45 -0
  143. package/scripts/skills/generated/.gitkeep +0 -0
  144. package/scripts/skills/generated/_refinements/.gitkeep +0 -0
  145. package/scripts/skills/generated/_refinements/adversarial-quality.patch.md +3 -0
  146. package/scripts/skills/generated/_refinements/architecture-design.patch.md +3 -0
  147. package/scripts/skills/generated/_refinements/brainstorming.patch.md +3 -0
  148. package/scripts/skills/generated/cli-version-management.md +29 -0
  149. package/scripts/skills/generated/collection-system-validation.md +99 -0
  150. package/scripts/skills/generated/large-scale-c-refactoring-coordination.md +97 -0
  151. package/scripts/skills/generated/pattern-matching-similarity-scoring.md +195 -0
  152. package/scripts/skills/generated/test-parallelization-detection.md +65 -0
  153. package/scripts/skills/observability.md +79 -0
  154. package/scripts/skills/performance.md +48 -0
  155. package/scripts/skills/pr-quality.md +49 -0
  156. package/scripts/skills/product-thinking.md +43 -0
  157. package/scripts/skills/security-audit.md +49 -0
  158. package/scripts/skills/systematic-debugging.md +40 -0
  159. package/scripts/skills/testing-strategy.md +47 -0
  160. package/scripts/skills/two-stage-review.md +52 -0
  161. package/scripts/skills/validation-thoroughness.md +55 -0
  162. package/scripts/sw +9 -3
  163. package/scripts/sw-activity.sh +9 -2
  164. package/scripts/sw-adaptive.sh +2 -1
  165. package/scripts/sw-adversarial.sh +2 -1
  166. package/scripts/sw-architecture-enforcer.sh +3 -1
  167. package/scripts/sw-auth.sh +12 -2
  168. package/scripts/sw-autonomous.sh +5 -1
  169. package/scripts/sw-changelog.sh +4 -1
  170. package/scripts/sw-checkpoint.sh +2 -1
  171. package/scripts/sw-ci.sh +5 -1
  172. package/scripts/sw-cleanup.sh +4 -26
  173. package/scripts/sw-code-review.sh +10 -4
  174. package/scripts/sw-connect.sh +2 -1
  175. package/scripts/sw-context.sh +2 -1
  176. package/scripts/sw-cost.sh +48 -3
  177. package/scripts/sw-daemon.sh +66 -9
  178. package/scripts/sw-dashboard.sh +3 -1
  179. package/scripts/sw-db.sh +59 -16
  180. package/scripts/sw-decide.sh +8 -2
  181. package/scripts/sw-decompose.sh +360 -17
  182. package/scripts/sw-deps.sh +4 -1
  183. package/scripts/sw-developer-simulation.sh +4 -1
  184. package/scripts/sw-discovery.sh +325 -2
  185. package/scripts/sw-doc-fleet.sh +4 -1
  186. package/scripts/sw-docs-agent.sh +3 -1
  187. package/scripts/sw-docs.sh +2 -1
  188. package/scripts/sw-doctor.sh +453 -2
  189. package/scripts/sw-dora.sh +4 -1
  190. package/scripts/sw-durable.sh +4 -3
  191. package/scripts/sw-e2e-orchestrator.sh +17 -16
  192. package/scripts/sw-eventbus.sh +7 -1
  193. package/scripts/sw-evidence.sh +364 -12
  194. package/scripts/sw-feedback.sh +550 -9
  195. package/scripts/sw-fix.sh +20 -1
  196. package/scripts/sw-fleet-discover.sh +6 -2
  197. package/scripts/sw-fleet-viz.sh +4 -1
  198. package/scripts/sw-fleet.sh +5 -1
  199. package/scripts/sw-github-app.sh +16 -3
  200. package/scripts/sw-github-checks.sh +3 -2
  201. package/scripts/sw-github-deploy.sh +3 -2
  202. package/scripts/sw-github-graphql.sh +18 -7
  203. package/scripts/sw-guild.sh +5 -1
  204. package/scripts/sw-heartbeat.sh +5 -30
  205. package/scripts/sw-hello.sh +67 -0
  206. package/scripts/sw-hygiene.sh +6 -1
  207. package/scripts/sw-incident.sh +265 -1
  208. package/scripts/sw-init.sh +18 -2
  209. package/scripts/sw-instrument.sh +10 -2
  210. package/scripts/sw-intelligence.sh +42 -6
  211. package/scripts/sw-jira.sh +5 -1
  212. package/scripts/sw-launchd.sh +2 -1
  213. package/scripts/sw-linear.sh +4 -1
  214. package/scripts/sw-logs.sh +4 -1
  215. package/scripts/sw-loop.sh +432 -1128
  216. package/scripts/sw-memory.sh +356 -2
  217. package/scripts/sw-mission-control.sh +6 -1
  218. package/scripts/sw-model-router.sh +481 -26
  219. package/scripts/sw-otel.sh +13 -4
  220. package/scripts/sw-oversight.sh +14 -5
  221. package/scripts/sw-patrol-meta.sh +334 -0
  222. package/scripts/sw-pipeline-composer.sh +5 -1
  223. package/scripts/sw-pipeline-vitals.sh +2 -1
  224. package/scripts/sw-pipeline.sh +53 -2664
  225. package/scripts/sw-pm.sh +12 -5
  226. package/scripts/sw-pr-lifecycle.sh +2 -1
  227. package/scripts/sw-predictive.sh +7 -1
  228. package/scripts/sw-prep.sh +185 -2
  229. package/scripts/sw-ps.sh +5 -25
  230. package/scripts/sw-public-dashboard.sh +15 -3
  231. package/scripts/sw-quality.sh +2 -1
  232. package/scripts/sw-reaper.sh +8 -25
  233. package/scripts/sw-recruit.sh +156 -2303
  234. package/scripts/sw-regression.sh +19 -12
  235. package/scripts/sw-release-manager.sh +3 -1
  236. package/scripts/sw-release.sh +4 -1
  237. package/scripts/sw-remote.sh +3 -1
  238. package/scripts/sw-replay.sh +7 -1
  239. package/scripts/sw-retro.sh +158 -1
  240. package/scripts/sw-review-rerun.sh +3 -1
  241. package/scripts/sw-scale.sh +10 -3
  242. package/scripts/sw-security-audit.sh +6 -1
  243. package/scripts/sw-self-optimize.sh +6 -3
  244. package/scripts/sw-session.sh +9 -3
  245. package/scripts/sw-setup.sh +3 -1
  246. package/scripts/sw-stall-detector.sh +406 -0
  247. package/scripts/sw-standup.sh +15 -7
  248. package/scripts/sw-status.sh +3 -1
  249. package/scripts/sw-strategic.sh +4 -1
  250. package/scripts/sw-stream.sh +7 -1
  251. package/scripts/sw-swarm.sh +18 -6
  252. package/scripts/sw-team-stages.sh +13 -6
  253. package/scripts/sw-templates.sh +5 -29
  254. package/scripts/sw-testgen.sh +7 -1
  255. package/scripts/sw-tmux-pipeline.sh +4 -1
  256. package/scripts/sw-tmux-role-color.sh +2 -0
  257. package/scripts/sw-tmux-status.sh +1 -1
  258. package/scripts/sw-tmux.sh +3 -1
  259. package/scripts/sw-trace.sh +3 -1
  260. package/scripts/sw-tracker-github.sh +3 -0
  261. package/scripts/sw-tracker-jira.sh +3 -0
  262. package/scripts/sw-tracker-linear.sh +3 -0
  263. package/scripts/sw-tracker.sh +3 -1
  264. package/scripts/sw-triage.sh +2 -1
  265. package/scripts/sw-upgrade.sh +3 -1
  266. package/scripts/sw-ux.sh +5 -2
  267. package/scripts/sw-webhook.sh +3 -1
  268. package/scripts/sw-widgets.sh +3 -1
  269. package/scripts/sw-worktree.sh +15 -3
  270. package/scripts/test-skill-injection.sh +1233 -0
  271. package/templates/pipelines/autonomous.json +27 -3
  272. package/templates/pipelines/cost-aware.json +34 -8
  273. package/templates/pipelines/deployed.json +12 -0
  274. package/templates/pipelines/enterprise.json +12 -0
  275. package/templates/pipelines/fast.json +6 -0
  276. package/templates/pipelines/full.json +27 -3
  277. package/templates/pipelines/hotfix.json +6 -0
  278. package/templates/pipelines/standard.json +12 -0
  279. package/templates/pipelines/tdd.json +12 -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="3.2.0"
9
+ VERSION="3.3.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
12
  # ─── Cross-platform compatibility ──────────────────────────────────────────
@@ -26,18 +26,20 @@ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
26
26
  fi
27
27
  if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
28
28
  emit_event() {
29
- local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
29
+ local event_type="$1"; shift; mkdir -p "${PM_STATE_DIR:=${HOME}/.shipwright}"
30
+ # shellcheck disable=SC2155
30
31
  local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
31
32
  while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
32
- echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
33
+ echo "${payload}}" >> "${PM_STATE_DIR:=${HOME}/.shipwright}/events.jsonl"
33
34
  }
34
35
  fi
35
36
  # ─── PM History Storage ──────────────────────────────────────────────────────
36
- PM_HISTORY="${HOME}/.shipwright/pm-history.json"
37
+ PM_STATE_DIR="${PM_STATE_DIR:-${HOME}/.shipwright}"
38
+ PM_HISTORY="${PM_STATE_DIR}/pm-history.json"
37
39
 
38
40
  # ─── Ensure PM history file exists ───────────────────────────────────────────
39
41
  ensure_pm_history() {
40
- mkdir -p "${HOME}/.shipwright"
42
+ mkdir -p "${PM_STATE_DIR}"
41
43
  if [[ ! -f "$PM_HISTORY" ]]; then
42
44
  echo '{"decisions":[],"outcomes":[]}' > "$PM_HISTORY"
43
45
  fi
@@ -495,6 +497,7 @@ cmd_recommend() {
495
497
 
496
498
  # Combine into comprehensive recommendation
497
499
  local recommendation
500
+ # shellcheck disable=SC2046
498
501
  recommendation=$(jq -n \
499
502
  --argjson analysis "$analysis" \
500
503
  --argjson team "$team_rec" \
@@ -513,6 +516,7 @@ cmd_recommend() {
513
516
  ensure_pm_history
514
517
  local tmp_hist
515
518
  tmp_hist=$(mktemp)
519
+ # shellcheck disable=SC2064
516
520
  trap "rm -f '$tmp_hist'" RETURN
517
521
  jq --argjson rec "$recommendation" '.decisions += [$rec]' "$PM_HISTORY" > "$tmp_hist" && mv "$tmp_hist" "$PM_HISTORY"
518
522
  emit_event "pm.recommend" "issue=${issue_num}"
@@ -541,6 +545,7 @@ cmd_recommend() {
541
545
  ensure_pm_history
542
546
  local tmp_hist
543
547
  tmp_hist=$(mktemp)
548
+ # shellcheck disable=SC2064
544
549
  trap "rm -f '$tmp_hist'" RETURN
545
550
  jq --argjson rec "$recommendation" '.decisions += [$rec]' "$PM_HISTORY" > "$tmp_hist" && mv "$tmp_hist" "$PM_HISTORY"
546
551
 
@@ -605,6 +610,7 @@ cmd_learn() {
605
610
  # Save to history
606
611
  local tmp_hist
607
612
  tmp_hist=$(mktemp)
613
+ # shellcheck disable=SC2064
608
614
  trap "rm -f '$tmp_hist'" RETURN
609
615
  jq --argjson outcome "$outcome_record" '.outcomes += [$outcome]' "$PM_HISTORY" > "$tmp_hist" && mv "$tmp_hist" "$PM_HISTORY"
610
616
 
@@ -630,6 +636,7 @@ cmd_history() {
630
636
  local total_decisions success_count fail_count
631
637
  total_decisions=$(jq '.outcomes | length' "$PM_HISTORY")
632
638
  success_count=$(jq '[.outcomes[] | select(.outcome == "success")] | length' "$PM_HISTORY")
639
+ # shellcheck disable=SC2034
633
640
  fail_count=$(jq '[.outcomes[] | select(.outcome == "failure")] | length' "$PM_HISTORY")
634
641
 
635
642
  if [[ "$total_decisions" -gt 0 ]]; then
@@ -6,7 +6,8 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="3.2.0"
9
+ # shellcheck disable=SC2034
10
+ VERSION="3.3.0"
10
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
12
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
13
 
@@ -6,7 +6,8 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="3.2.0"
9
+ # shellcheck disable=SC2034
10
+ VERSION="3.3.0"
10
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
12
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
13
 
@@ -31,12 +32,14 @@ fi
31
32
  if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
32
33
  emit_event() {
33
34
  local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
35
+ # shellcheck disable=SC2155
34
36
  local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
35
37
  while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
36
38
  echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
37
39
  }
38
40
  fi
39
41
  # ─── Structured Event Log ──────────────────────────────────────────────────
42
+ # shellcheck disable=SC2034
40
43
  EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
41
44
 
42
45
  # ─── Intelligence Engine (optional) ────────────────────────────────────────
@@ -180,6 +183,7 @@ predictive_confirm_anomaly() {
180
183
  # Find the most recent unconfirmed anomaly for this stage+metric
181
184
  local tmp_file
182
185
  tmp_file=$(mktemp "${TMPDIR:-/tmp}/sw-anomaly-confirm.XXXXXX")
186
+ # shellcheck disable=SC2064
183
187
  trap "rm -f '$tmp_file'" RETURN
184
188
  local found=false
185
189
 
@@ -276,6 +280,7 @@ _predictive_update_alarm_rates() {
276
280
  # Atomic write
277
281
  local tmp_file
278
282
  tmp_file=$(mktemp "${TMPDIR:-/tmp}/sw-anomaly-thresh.XXXXXX")
283
+ # shellcheck disable=SC2064
279
284
  trap "rm -f '$tmp_file'" RETURN
280
285
  jq --arg m "$metric_name" \
281
286
  --argjson crit "$new_critical" \
@@ -757,6 +762,7 @@ predict_update_baseline() {
757
762
  # Atomic write
758
763
  local tmp_file
759
764
  tmp_file=$(mktemp)
765
+ # shellcheck disable=SC2064
760
766
  trap "rm -f '$tmp_file'" RETURN
761
767
  jq --arg key "$key" \
762
768
  --argjson val "$new_value" \
@@ -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="3.2.0"
9
+ VERSION="3.3.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
12
  # ─── Handle subcommands ───────────────────────────────────────────────────────
@@ -33,7 +33,8 @@ fi
33
33
  if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
34
34
  emit_event() {
35
35
  local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
36
- local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
36
+ local payload
37
+ payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
37
38
  while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
38
39
  echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
39
40
  }
@@ -43,6 +44,7 @@ FORCE=false
43
44
  CHECK_ONLY=false
44
45
  UPDATE_MODE=false
45
46
  WITH_CLAUDE=false
47
+ INTERACTIVE=false
46
48
  PROJECT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
47
49
 
48
50
  # Detection results
@@ -99,6 +101,7 @@ show_help() {
99
101
  echo -e " ${CYAN}--force${RESET} Overwrite existing files"
100
102
  echo -e " ${CYAN}--check${RESET} Audit existing prep (dry run)"
101
103
  echo -e " ${CYAN}--update${RESET} Refresh auto-generated sections only"
104
+ echo -e " ${CYAN}--interactive${RESET} Interactive quality profile dialogue"
102
105
  echo -e " ${CYAN}--with-claude${RESET} Deep analysis using Claude Code (slower, richer)"
103
106
  echo -e " ${CYAN}--help, -h${RESET} Show this help message"
104
107
  echo ""
@@ -129,6 +132,7 @@ for arg in "$@"; do
129
132
  --force) FORCE=true ;;
130
133
  --check) CHECK_ONLY=true ;;
131
134
  --update) UPDATE_MODE=true ;;
135
+ --interactive) INTERACTIVE=true ;;
132
136
  --with-claude) WITH_CLAUDE=true ;;
133
137
  --help|-h) show_help; exit 0 ;;
134
138
  *)
@@ -459,6 +463,7 @@ prep_scan_structure() {
459
463
  for d in docs doc documentation wiki; do
460
464
  [[ -d "$root/$d" ]] && ddirs+=("$d")
461
465
  done
466
+ # shellcheck disable=SC2034
462
467
  DOC_DIRS="${ddirs[*]:-}"
463
468
 
464
469
  # Config files
@@ -499,6 +504,7 @@ prep_scan_structure() {
499
504
  -not -path "*/node_modules/*" -not -path "*/.git/*" 2>/dev/null | wc -l | tr -d ' ')
500
505
 
501
506
  # Total lines (approximation from source files)
507
+ # shellcheck disable=SC2227,SC2261
502
508
  TOTAL_LINES=$(find "$root" \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" \
503
509
  -o -name "*.py" -o -name "*.rb" -o -name "*.go" -o -name "*.rs" -o -name "*.java" \) \
504
510
  -not -path "*/node_modules/*" -not -path "*/.git/*" -not -path "*/vendor/*" \
@@ -572,6 +578,7 @@ prep_extract_patterns() {
572
578
 
573
579
  # ── Middleware ──
574
580
  if grep -rq "app\.use(" "$root/src" "$root/app" "$root/lib" 2>/dev/null; then
581
+ # shellcheck disable=SC2034
575
582
  HAS_MIDDLEWARE=true
576
583
  fi
577
584
 
@@ -767,8 +774,11 @@ ${style_samples}"
767
774
  DB_PATTERNS="$smart_val"
768
775
  fi
769
776
 
777
+ # shellcheck disable=SC2034
770
778
  SEMICOLONS=$(echo "$analysis" | grep "^SEMICOLONS:" | sed 's/^SEMICOLONS:[[:space:]]*//' | head -1)
779
+ # shellcheck disable=SC2034
771
780
  QUOTE_STYLE=$(echo "$analysis" | grep "^QUOTE_STYLE:" | sed 's/^QUOTE_STYLE:[[:space:]]*//' | head -1)
781
+ # shellcheck disable=SC2034
772
782
  INDENT_STYLE=$(echo "$analysis" | grep "^INDENT:" | sed 's/^INDENT:[[:space:]]*//' | head -1)
773
783
 
774
784
  success "Smart detection: ${ARCHITECTURE_PATTERN:-unknown} architecture${FRAMEWORK:+, ${FRAMEWORK}}"
@@ -818,6 +828,7 @@ prep_learn_patterns() {
818
828
  # Write patterns file atomically
819
829
  local tmp_patterns
820
830
  tmp_patterns=$(mktemp)
831
+ # shellcheck disable=SC2064
821
832
  trap "rm -f '$tmp_patterns'" RETURN
822
833
  jq -n \
823
834
  --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
@@ -947,6 +958,24 @@ prep_generate_settings() {
947
958
  success "Generated .claude/settings.json"
948
959
  }
949
960
 
961
+ # ─── prep_generate_managed_mcp ────────────────────────────────────────────────
962
+
963
+ prep_generate_managed_mcp() {
964
+ local filepath="$PROJECT_ROOT/.claude/managed-mcp.json"
965
+ if ! should_write "$filepath"; then return; fi
966
+
967
+ info "Generating .claude/managed-mcp.json..."
968
+
969
+ jq -n '{
970
+ "allowedMcpServers": ["*"],
971
+ "deniedMcpServers": [],
972
+ "note": "Configure MCP server access policies for pipeline agents"
973
+ }' > "$filepath"
974
+
975
+ track_file "$filepath"
976
+ success "Generated .claude/managed-mcp.json"
977
+ }
978
+
950
979
  # ─── prep_generate_hooks ────────────────────────────────────────────────────
951
980
 
952
981
  prep_generate_hooks() {
@@ -1572,6 +1601,156 @@ prep_check() {
1572
1601
  echo ""
1573
1602
  }
1574
1603
 
1604
+ # ─── generate_quality_profile — Interactive quality profile dialogue ────────
1605
+
1606
+ generate_quality_profile() {
1607
+ local profile_path="$PROJECT_ROOT/.claude/quality-profile.json"
1608
+
1609
+ # Load quality-profile library
1610
+ if [[ -f "$SCRIPT_DIR/lib/quality-profile.sh" ]]; then
1611
+ source "$SCRIPT_DIR/lib/quality-profile.sh"
1612
+ else
1613
+ warn "quality-profile.sh library not found"
1614
+ return 1
1615
+ fi
1616
+
1617
+ info "Generating quality profile..."
1618
+
1619
+ # Start with inferred values
1620
+ local inferred
1621
+ inferred=$(qp_infer_from_repo)
1622
+
1623
+ # Generate base profile
1624
+ local base_profile
1625
+ base_profile=$(generate_default_profile)
1626
+
1627
+ # In interactive mode, ask refinement questions
1628
+ if $INTERACTIVE; then
1629
+ echo ""
1630
+ echo -e "${CYAN}${BOLD}Quality Profile Setup${RESET}"
1631
+ echo -e "${DIM}Answer these questions to calibrate quality standards:${RESET}"
1632
+ echo ""
1633
+
1634
+ # Q1: Max PR size
1635
+ local max_pr_lines
1636
+ read -p "Max PR size in lines (default 500): " max_pr_lines
1637
+ max_pr_lines="${max_pr_lines:-500}"
1638
+
1639
+ # Q2: Max files per PR
1640
+ local max_files
1641
+ read -p "Max files per PR (default 15): " max_files
1642
+ max_files="${max_files:-15}"
1643
+
1644
+ # Q3: Test philosophy
1645
+ echo ""
1646
+ echo -e "${DIM}Test philosophy:${RESET}"
1647
+ echo " 1. test_after (default)"
1648
+ echo " 2. tdd"
1649
+ echo " 3. coverage_target"
1650
+ echo " 4. manual"
1651
+ read -p "Choose [1-4]: " test_choice
1652
+
1653
+ local philosophy="test_after"
1654
+ case "$test_choice" in
1655
+ 2) philosophy="tdd" ;;
1656
+ 3) philosophy="coverage_target" ;;
1657
+ 4) philosophy="manual" ;;
1658
+ esac
1659
+
1660
+ # Q4: Architecture pattern
1661
+ echo ""
1662
+ echo -e "${DIM}Architecture pattern:${RESET}"
1663
+ echo " 1. monolith (default)"
1664
+ echo " 2. modular_monolith"
1665
+ echo " 3. microservices"
1666
+ echo " 4. serverless"
1667
+ echo " 5. library"
1668
+ read -p "Choose [1-5]: " arch_choice
1669
+
1670
+ local arch_pattern="monolith"
1671
+ case "$arch_choice" in
1672
+ 2) arch_pattern="modular_monolith" ;;
1673
+ 3) arch_pattern="microservices" ;;
1674
+ 4) arch_pattern="serverless" ;;
1675
+ 5) arch_pattern="library" ;;
1676
+ esac
1677
+
1678
+ # Q5: Never ship rules
1679
+ echo ""
1680
+ read -p "Critical rules to never ship (comma-separated, or press Enter to skip): " never_ship
1681
+
1682
+ # Q6: Focus areas for code review
1683
+ echo ""
1684
+ read -p "Focus areas for review (comma-separated, e.g., 'performance,security'): " focus_areas
1685
+
1686
+ # Q7: Deployment strategy
1687
+ echo ""
1688
+ echo -e "${DIM}Deployment strategy:${RESET}"
1689
+ echo " 1. direct (default)"
1690
+ echo " 2. preview_then_production"
1691
+ echo " 3. staged_rollout"
1692
+ read -p "Choose [1-3]: " deploy_choice
1693
+
1694
+ local deploy_strategy="direct"
1695
+ case "$deploy_choice" in
1696
+ 2) deploy_strategy="preview_then_production" ;;
1697
+ 3) deploy_strategy="staged_rollout" ;;
1698
+ esac
1699
+
1700
+ # Build the updated profile
1701
+ local never_ship_array="[]"
1702
+ if [[ -n "$never_ship" ]]; then
1703
+ never_ship_array=$(echo "$never_ship" | jq -R 'split(",") | map(ltrimstr(" ") | rtrimstr(" "))')
1704
+ fi
1705
+
1706
+ local focus_areas_array="[]"
1707
+ if [[ -n "$focus_areas" ]]; then
1708
+ focus_areas_array=$(echo "$focus_areas" | jq -R 'split(",") | map(ltrimstr(" ") | rtrimstr(" "))')
1709
+ fi
1710
+
1711
+ # Merge updates into base profile
1712
+ base_profile=$(echo "$base_profile" | jq \
1713
+ --arg max_pr "$max_pr_lines" \
1714
+ --arg max_f "$max_files" \
1715
+ --arg phil "$philosophy" \
1716
+ --arg arch "$arch_pattern" \
1717
+ --arg deploy "$deploy_strategy" \
1718
+ --argjson never_ship "$never_ship_array" \
1719
+ --argjson focus "$focus_areas_array" \
1720
+ '.quality.max_pr_lines = ($max_pr | tonumber) |
1721
+ .quality.max_files_per_pr = ($max_f | tonumber) |
1722
+ .quality.never_ship = $never_ship |
1723
+ .testing.philosophy = $phil |
1724
+ .architecture.pattern = $arch |
1725
+ .deployment.strategy = $deploy |
1726
+ .review.focus_areas = $focus'
1727
+ )
1728
+ else
1729
+ # Non-interactive: apply inferred values
1730
+ local test_cmd focus_areas arch_pattern
1731
+ test_cmd=$(echo "$inferred" | jq -r '.test_cmd')
1732
+ arch_pattern=$(echo "$inferred" | jq -r '.framework')
1733
+
1734
+ # Merge inferred test command and architecture
1735
+ if [[ -n "$test_cmd" && "$test_cmd" != "null" && "$test_cmd" != "" ]]; then
1736
+ base_profile=$(echo "$base_profile" | jq --arg cmd "$test_cmd" '.testing.test_cmd = $cmd')
1737
+ fi
1738
+ if [[ -n "$arch_pattern" && "$arch_pattern" != "null" && "$arch_pattern" != "" ]]; then
1739
+ base_profile=$(echo "$base_profile" | jq --arg arch "$arch_pattern" '.architecture.pattern = $arch')
1740
+ fi
1741
+ fi
1742
+
1743
+ # Save the profile
1744
+ if qp_save "$base_profile"; then
1745
+ success "Quality profile saved to .claude/quality-profile.json"
1746
+ track_file ".claude/quality-profile.json"
1747
+ return 0
1748
+ else
1749
+ error "Failed to save quality profile"
1750
+ return 1
1751
+ fi
1752
+ }
1753
+
1575
1754
  # ─── prep_report — Summary output ──────────────────────────────────────────
1576
1755
 
1577
1756
  prep_report() {
@@ -1627,6 +1806,7 @@ main() {
1627
1806
  # Generation
1628
1807
  prep_generate_claude_md
1629
1808
  prep_generate_settings
1809
+ prep_generate_managed_mcp
1630
1810
  prep_generate_hooks
1631
1811
  prep_generate_agents
1632
1812
  prep_generate_architecture
@@ -1634,6 +1814,9 @@ main() {
1634
1814
  prep_generate_dod
1635
1815
  prep_generate_issue_templates
1636
1816
 
1817
+ # Quality profile (auto or interactive)
1818
+ generate_quality_profile
1819
+
1637
1820
  # Deep analysis (optional)
1638
1821
  prep_with_claude
1639
1822
 
package/scripts/sw-ps.sh CHANGED
@@ -5,32 +5,12 @@
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="3.2.0"
8
+ # shellcheck disable=SC2034
9
+ VERSION="3.3.0"
9
10
  set -euo pipefail
10
- trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
11
-
12
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13
-
14
- # Canonical helpers (colors, output, events)
15
- # shellcheck source=lib/helpers.sh
16
- [[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh"
17
- # Fallbacks when helpers not loaded (e.g. test env with overridden SCRIPT_DIR)
18
- [[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
19
- [[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
20
- [[ "$(type -t warn 2>/dev/null)" == "function" ]] || warn() { echo -e "\033[38;2;250;204;21m\033[1m⚠\033[0m $*"; }
21
- [[ "$(type -t error 2>/dev/null)" == "function" ]] || error() { echo -e "\033[38;2;248;113;113m\033[1m✗\033[0m $*" >&2; }
22
- if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
23
- now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
24
- now_epoch() { date +%s; }
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
11
+
12
+ # shellcheck source=lib/bootstrap.sh
13
+ source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib/bootstrap.sh"
34
14
  # ─── Format idle time ───────────────────────────────────────────────────────
35
15
  format_idle() {
36
16
  local seconds="$1"
@@ -6,7 +6,8 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="3.2.0"
9
+ # shellcheck disable=SC2034
10
+ VERSION="3.3.0"
10
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
12
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
13
 
@@ -29,7 +30,8 @@ fi
29
30
  if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
30
31
  emit_event() {
31
32
  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
+ local payload
34
+ payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
33
35
  while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
34
36
  echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
35
37
  }
@@ -79,11 +81,13 @@ sanitize_for_privacy() {
79
81
  gather_pipeline_state() {
80
82
  local privacy="${1:-stages_only}"
81
83
 
84
+ # shellcheck disable=SC2034
82
85
  local state_file="${REPO_DIR}/.claude/pipeline-state.md"
83
86
  local daemon_state="${HOME}/.shipwright/daemon-state.json"
84
87
  local pipeline_artifacts="${REPO_DIR}/.claude/pipeline-artifacts"
85
88
 
86
- local pipeline_data='{
89
+ local pipeline_data
90
+ pipeline_data='{
87
91
  "status":"unknown",
88
92
  "stages":[],
89
93
  "agents":[],
@@ -140,6 +144,7 @@ generate_html() {
140
144
 
141
145
  # Escape JSON for embedding in HTML
142
146
  local json_escaped
147
+ # shellcheck disable=SC2034
143
148
  json_escaped=$(echo "$data_json" | sed 's/"/\\"/g' | tr '\n' ' ')
144
149
 
145
150
  cat <<'EOF'
@@ -418,6 +423,7 @@ cmd_export() {
418
423
  # Atomic write
419
424
  local tmp_file
420
425
  tmp_file=$(mktemp)
426
+ # shellcheck disable=SC2064
421
427
  trap "rm -f '$tmp_file'" EXIT
422
428
  echo "$html" > "$tmp_file"
423
429
  mv "$tmp_file" "$output_file"
@@ -453,6 +459,7 @@ cmd_share() {
453
459
  # Append to share links file (atomic)
454
460
  local tmp_file
455
461
  tmp_file=$(mktemp)
462
+ # shellcheck disable=SC2064
456
463
  trap "rm -f '$tmp_file'" EXIT
457
464
  jq ".links += [$link_entry]" "$SHARE_LINKS_FILE" > "$tmp_file"
458
465
  mv "$tmp_file" "$SHARE_LINKS_FILE"
@@ -480,6 +487,7 @@ cmd_revoke() {
480
487
 
481
488
  local tmp_file
482
489
  tmp_file=$(mktemp)
490
+ # shellcheck disable=SC2064
483
491
  trap "rm -f '$tmp_file'" EXIT
484
492
 
485
493
  if jq ".links |= map(select(.token != \"$token\"))" "$SHARE_LINKS_FILE" > "$tmp_file"; then
@@ -545,6 +553,7 @@ cmd_config() {
545
553
  [[ -z "$value" ]] && error "Value required for privacy" && return 1
546
554
  local tmp_file
547
555
  tmp_file=$(mktemp)
556
+ # shellcheck disable=SC2064
548
557
  trap "rm -f '$tmp_file'" EXIT
549
558
  jq ".privacy = \"$value\"" "$SHARE_CONFIG_FILE" > "$tmp_file"
550
559
  mv "$tmp_file" "$SHARE_CONFIG_FILE"
@@ -554,6 +563,7 @@ cmd_config() {
554
563
  [[ -z "$value" ]] && error "Value required for expiry (hours)" && return 1
555
564
  local tmp_file
556
565
  tmp_file=$(mktemp)
566
+ # shellcheck disable=SC2064
557
567
  trap "rm -f '$tmp_file'" EXIT
558
568
  jq ".expiry_hours = $value" "$SHARE_CONFIG_FILE" > "$tmp_file"
559
569
  mv "$tmp_file" "$SHARE_CONFIG_FILE"
@@ -563,6 +573,7 @@ cmd_config() {
563
573
  [[ -z "$value" ]] && error "Value required for domain" && return 1
564
574
  local tmp_file
565
575
  tmp_file=$(mktemp)
576
+ # shellcheck disable=SC2064
566
577
  trap "rm -f '$tmp_file'" EXIT
567
578
  jq ".custom_domain = \"$value\"" "$SHARE_CONFIG_FILE" > "$tmp_file"
568
579
  mv "$tmp_file" "$SHARE_CONFIG_FILE"
@@ -642,6 +653,7 @@ cmd_cleanup() {
642
653
 
643
654
  local tmp_file
644
655
  tmp_file=$(mktemp)
656
+ # shellcheck disable=SC2064
645
657
  trap "rm -f '$tmp_file'" EXIT
646
658
 
647
659
  jq ".links |= map(select((.expires | fromdateiso8601) > $now_epoch_val))" "$SHARE_LINKS_FILE" > "$tmp_file"
@@ -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="3.2.0"
9
+ VERSION="3.3.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -30,6 +30,7 @@ fi
30
30
  if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
31
31
  emit_event() {
32
32
  local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
33
+ # shellcheck disable=SC2155
33
34
  local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
34
35
  while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
35
36
  echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
@@ -11,32 +11,12 @@
11
11
  # ║ shipwright reaper --watch Continuous loop (default: 5s) ║
12
12
  # ║ shipwright reaper --dry-run Preview what would be reaped ║
13
13
  # ╚═══════════════════════════════════════════════════════════════════════════╝
14
- VERSION="3.2.0"
14
+ # shellcheck disable=SC2034
15
+ VERSION="3.3.0"
15
16
  set -euo pipefail
16
- trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
17
-
18
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
19
-
20
- # Canonical helpers (colors, output, events)
21
- # shellcheck source=lib/helpers.sh
22
- [[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh"
23
- # Fallbacks when helpers not loaded (e.g. test env with overridden SCRIPT_DIR)
24
- [[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
25
- [[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
26
- [[ "$(type -t warn 2>/dev/null)" == "function" ]] || warn() { echo -e "\033[38;2;250;204;21m\033[1m⚠\033[0m $*"; }
27
- [[ "$(type -t error 2>/dev/null)" == "function" ]] || error() { echo -e "\033[38;2;248;113;113m\033[1m✗\033[0m $*" >&2; }
28
- if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
29
- now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
30
- now_epoch() { date +%s; }
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
17
+
18
+ # shellcheck source=lib/bootstrap.sh
19
+ source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib/bootstrap.sh"
40
20
  # ─── Defaults ──────────────────────────────────────────────────────────────
41
21
  WATCH=false
42
22
  DRY_RUN=false
@@ -193,6 +173,8 @@ scan_and_reap() {
193
173
  local skipped=0
194
174
  local scanned=0
195
175
 
176
+ # shellcheck disable=SC2034
177
+ # shellcheck disable=SC2034
196
178
  while IFS='|' read -r window_name pane_title pane_pid cmd pane_active pane_idle pane_dead pane_ref; do
197
179
  [[ -z "$window_name" ]] && continue
198
180
 
@@ -291,6 +273,7 @@ cleanup_team_dirs() {
291
273
  cleaned=$((cleaned + 1))
292
274
  }
293
275
  if [[ -d "${tasks_dir}/${team_name}" ]]; then
276
+ # shellcheck disable=SC2115
294
277
  rm -rf "${tasks_dir}/${team_name}" && {
295
278
  echo -e " ${RED}✗${RESET} Removed task dir: ${BOLD}${team_name}/${RESET}"
296
279
  log "CLEAN_TASKS team=${team_name}"