shipwright-cli 3.1.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 (283) 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 +22 -8
  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/config/defaults.json +25 -2
  17. package/config/policy.json +1 -1
  18. package/dashboard/middleware/auth.ts +134 -0
  19. package/dashboard/middleware/constants.ts +21 -0
  20. package/dashboard/public/index.html +8 -6
  21. package/dashboard/public/styles.css +176 -97
  22. package/dashboard/routes/auth.ts +38 -0
  23. package/dashboard/server.ts +117 -25
  24. package/dashboard/services/config.ts +26 -0
  25. package/dashboard/services/db.ts +118 -0
  26. package/dashboard/src/canvas/pixel-agent.ts +298 -0
  27. package/dashboard/src/canvas/pixel-sprites.ts +440 -0
  28. package/dashboard/src/canvas/shipyard-effects.ts +367 -0
  29. package/dashboard/src/canvas/shipyard-scene.ts +616 -0
  30. package/dashboard/src/canvas/submarine-layout.ts +267 -0
  31. package/dashboard/src/components/header.ts +8 -7
  32. package/dashboard/src/core/api.ts +5 -0
  33. package/dashboard/src/core/router.ts +1 -0
  34. package/dashboard/src/design/submarine-theme.ts +253 -0
  35. package/dashboard/src/main.ts +2 -0
  36. package/dashboard/src/types/api.ts +12 -1
  37. package/dashboard/src/views/activity.ts +2 -1
  38. package/dashboard/src/views/metrics.ts +69 -1
  39. package/dashboard/src/views/shipyard.ts +39 -0
  40. package/dashboard/types/index.ts +166 -0
  41. package/docs/plans/2026-02-28-compound-audit-and-shipyard-design.md +186 -0
  42. package/docs/plans/2026-02-28-skipper-shipwright-implementation-plan.md +1182 -0
  43. package/docs/plans/2026-02-28-skipper-shipwright-integration-design.md +531 -0
  44. package/docs/plans/2026-03-01-ai-powered-skill-injection-design.md +298 -0
  45. package/docs/plans/2026-03-01-ai-powered-skill-injection-plan.md +1109 -0
  46. package/docs/plans/2026-03-01-capabilities-cleanup-plan.md +658 -0
  47. package/docs/plans/2026-03-01-clean-architecture-plan.md +924 -0
  48. package/docs/plans/2026-03-01-compound-audit-cascade-design.md +191 -0
  49. package/docs/plans/2026-03-01-compound-audit-cascade-plan.md +921 -0
  50. package/docs/plans/2026-03-01-deep-integration-plan.md +851 -0
  51. package/docs/plans/2026-03-01-pipeline-audit-trail-design.md +145 -0
  52. package/docs/plans/2026-03-01-pipeline-audit-trail-plan.md +770 -0
  53. package/docs/plans/2026-03-01-refined-depths-brand-design.md +382 -0
  54. package/docs/plans/2026-03-01-refined-depths-implementation.md +599 -0
  55. package/docs/plans/2026-03-01-skipper-kernel-integration-design.md +203 -0
  56. package/docs/plans/2026-03-01-unified-platform-design.md +272 -0
  57. package/docs/plans/2026-03-07-claude-code-feature-integration-design.md +189 -0
  58. package/docs/plans/2026-03-07-claude-code-feature-integration-plan.md +1165 -0
  59. package/docs/research/BACKLOG_QUICK_REFERENCE.md +352 -0
  60. package/docs/research/CUTTING_EDGE_RESEARCH_2026.md +546 -0
  61. package/docs/research/RESEARCH_INDEX.md +439 -0
  62. package/docs/research/RESEARCH_SOURCES.md +440 -0
  63. package/docs/research/RESEARCH_SUMMARY.txt +275 -0
  64. package/docs/superpowers/specs/2026-03-10-pipeline-quality-revolution-design.md +341 -0
  65. package/package.json +2 -2
  66. package/scripts/lib/adaptive-model.sh +427 -0
  67. package/scripts/lib/adaptive-timeout.sh +316 -0
  68. package/scripts/lib/audit-trail.sh +309 -0
  69. package/scripts/lib/auto-recovery.sh +471 -0
  70. package/scripts/lib/bandit-selector.sh +431 -0
  71. package/scripts/lib/bootstrap.sh +104 -2
  72. package/scripts/lib/causal-graph.sh +455 -0
  73. package/scripts/lib/compat.sh +126 -0
  74. package/scripts/lib/compound-audit.sh +337 -0
  75. package/scripts/lib/constitutional.sh +454 -0
  76. package/scripts/lib/context-budget.sh +359 -0
  77. package/scripts/lib/convergence.sh +594 -0
  78. package/scripts/lib/cost-optimizer.sh +634 -0
  79. package/scripts/lib/daemon-adaptive.sh +14 -2
  80. package/scripts/lib/daemon-dispatch.sh +106 -17
  81. package/scripts/lib/daemon-failure.sh +34 -4
  82. package/scripts/lib/daemon-patrol.sh +25 -4
  83. package/scripts/lib/daemon-poll-github.sh +361 -0
  84. package/scripts/lib/daemon-poll-health.sh +299 -0
  85. package/scripts/lib/daemon-poll.sh +27 -611
  86. package/scripts/lib/daemon-state.sh +119 -66
  87. package/scripts/lib/daemon-triage.sh +10 -0
  88. package/scripts/lib/dod-scorecard.sh +442 -0
  89. package/scripts/lib/error-actionability.sh +300 -0
  90. package/scripts/lib/formal-spec.sh +461 -0
  91. package/scripts/lib/helpers.sh +180 -5
  92. package/scripts/lib/intent-analysis.sh +409 -0
  93. package/scripts/lib/loop-convergence.sh +350 -0
  94. package/scripts/lib/loop-iteration.sh +682 -0
  95. package/scripts/lib/loop-progress.sh +48 -0
  96. package/scripts/lib/loop-restart.sh +185 -0
  97. package/scripts/lib/memory-effectiveness.sh +506 -0
  98. package/scripts/lib/mutation-executor.sh +352 -0
  99. package/scripts/lib/outcome-feedback.sh +521 -0
  100. package/scripts/lib/pipeline-cli.sh +336 -0
  101. package/scripts/lib/pipeline-commands.sh +1216 -0
  102. package/scripts/lib/pipeline-detection.sh +101 -3
  103. package/scripts/lib/pipeline-execution.sh +897 -0
  104. package/scripts/lib/pipeline-github.sh +28 -3
  105. package/scripts/lib/pipeline-intelligence-compound.sh +431 -0
  106. package/scripts/lib/pipeline-intelligence-scoring.sh +407 -0
  107. package/scripts/lib/pipeline-intelligence-skip.sh +181 -0
  108. package/scripts/lib/pipeline-intelligence.sh +104 -1138
  109. package/scripts/lib/pipeline-quality-bash-compat.sh +182 -0
  110. package/scripts/lib/pipeline-quality-checks.sh +17 -711
  111. package/scripts/lib/pipeline-quality-gates.sh +563 -0
  112. package/scripts/lib/pipeline-stages-build.sh +730 -0
  113. package/scripts/lib/pipeline-stages-delivery.sh +965 -0
  114. package/scripts/lib/pipeline-stages-intake.sh +1133 -0
  115. package/scripts/lib/pipeline-stages-monitor.sh +407 -0
  116. package/scripts/lib/pipeline-stages-review.sh +1022 -0
  117. package/scripts/lib/pipeline-stages.sh +161 -2901
  118. package/scripts/lib/pipeline-state.sh +36 -5
  119. package/scripts/lib/pipeline-util.sh +487 -0
  120. package/scripts/lib/policy-learner.sh +438 -0
  121. package/scripts/lib/process-reward.sh +493 -0
  122. package/scripts/lib/project-detect.sh +649 -0
  123. package/scripts/lib/quality-profile.sh +334 -0
  124. package/scripts/lib/recruit-commands.sh +885 -0
  125. package/scripts/lib/recruit-learning.sh +739 -0
  126. package/scripts/lib/recruit-roles.sh +648 -0
  127. package/scripts/lib/reward-aggregator.sh +458 -0
  128. package/scripts/lib/rl-optimizer.sh +362 -0
  129. package/scripts/lib/root-cause.sh +427 -0
  130. package/scripts/lib/scope-enforcement.sh +445 -0
  131. package/scripts/lib/session-restart.sh +493 -0
  132. package/scripts/lib/skill-memory.sh +300 -0
  133. package/scripts/lib/skill-registry.sh +775 -0
  134. package/scripts/lib/spec-driven.sh +476 -0
  135. package/scripts/lib/test-helpers.sh +18 -7
  136. package/scripts/lib/test-holdout.sh +429 -0
  137. package/scripts/lib/test-optimizer.sh +511 -0
  138. package/scripts/shipwright-file-suggest.sh +45 -0
  139. package/scripts/skills/adversarial-quality.md +61 -0
  140. package/scripts/skills/api-design.md +44 -0
  141. package/scripts/skills/architecture-design.md +50 -0
  142. package/scripts/skills/brainstorming.md +43 -0
  143. package/scripts/skills/data-pipeline.md +44 -0
  144. package/scripts/skills/deploy-safety.md +64 -0
  145. package/scripts/skills/documentation.md +38 -0
  146. package/scripts/skills/frontend-design.md +45 -0
  147. package/scripts/skills/generated/.gitkeep +0 -0
  148. package/scripts/skills/generated/_refinements/.gitkeep +0 -0
  149. package/scripts/skills/generated/_refinements/adversarial-quality.patch.md +3 -0
  150. package/scripts/skills/generated/_refinements/architecture-design.patch.md +3 -0
  151. package/scripts/skills/generated/_refinements/brainstorming.patch.md +3 -0
  152. package/scripts/skills/generated/cli-version-management.md +29 -0
  153. package/scripts/skills/generated/collection-system-validation.md +99 -0
  154. package/scripts/skills/generated/large-scale-c-refactoring-coordination.md +97 -0
  155. package/scripts/skills/generated/pattern-matching-similarity-scoring.md +195 -0
  156. package/scripts/skills/generated/test-parallelization-detection.md +65 -0
  157. package/scripts/skills/observability.md +79 -0
  158. package/scripts/skills/performance.md +48 -0
  159. package/scripts/skills/pr-quality.md +49 -0
  160. package/scripts/skills/product-thinking.md +43 -0
  161. package/scripts/skills/security-audit.md +49 -0
  162. package/scripts/skills/systematic-debugging.md +40 -0
  163. package/scripts/skills/testing-strategy.md +47 -0
  164. package/scripts/skills/two-stage-review.md +52 -0
  165. package/scripts/skills/validation-thoroughness.md +55 -0
  166. package/scripts/sw +9 -3
  167. package/scripts/sw-activity.sh +9 -8
  168. package/scripts/sw-adaptive.sh +8 -7
  169. package/scripts/sw-adversarial.sh +2 -1
  170. package/scripts/sw-architecture-enforcer.sh +3 -1
  171. package/scripts/sw-auth.sh +12 -2
  172. package/scripts/sw-autonomous.sh +5 -1
  173. package/scripts/sw-changelog.sh +4 -1
  174. package/scripts/sw-checkpoint.sh +2 -1
  175. package/scripts/sw-ci.sh +15 -6
  176. package/scripts/sw-cleanup.sh +4 -26
  177. package/scripts/sw-code-review.sh +45 -20
  178. package/scripts/sw-connect.sh +2 -1
  179. package/scripts/sw-context.sh +2 -1
  180. package/scripts/sw-cost.sh +107 -5
  181. package/scripts/sw-daemon.sh +71 -11
  182. package/scripts/sw-dashboard.sh +3 -1
  183. package/scripts/sw-db.sh +71 -20
  184. package/scripts/sw-decide.sh +8 -2
  185. package/scripts/sw-decompose.sh +360 -17
  186. package/scripts/sw-deps.sh +4 -1
  187. package/scripts/sw-developer-simulation.sh +4 -1
  188. package/scripts/sw-discovery.sh +378 -5
  189. package/scripts/sw-doc-fleet.sh +4 -1
  190. package/scripts/sw-docs-agent.sh +3 -1
  191. package/scripts/sw-docs.sh +2 -1
  192. package/scripts/sw-doctor.sh +453 -2
  193. package/scripts/sw-dora.sh +4 -1
  194. package/scripts/sw-durable.sh +12 -7
  195. package/scripts/sw-e2e-orchestrator.sh +17 -16
  196. package/scripts/sw-eventbus.sh +13 -4
  197. package/scripts/sw-evidence.sh +364 -12
  198. package/scripts/sw-feedback.sh +550 -9
  199. package/scripts/sw-fix.sh +20 -1
  200. package/scripts/sw-fleet-discover.sh +6 -2
  201. package/scripts/sw-fleet-viz.sh +9 -4
  202. package/scripts/sw-fleet.sh +5 -1
  203. package/scripts/sw-github-app.sh +18 -4
  204. package/scripts/sw-github-checks.sh +3 -2
  205. package/scripts/sw-github-deploy.sh +3 -2
  206. package/scripts/sw-github-graphql.sh +18 -7
  207. package/scripts/sw-guild.sh +5 -1
  208. package/scripts/sw-heartbeat.sh +5 -30
  209. package/scripts/sw-hello.sh +67 -0
  210. package/scripts/sw-hygiene.sh +10 -3
  211. package/scripts/sw-incident.sh +273 -5
  212. package/scripts/sw-init.sh +18 -2
  213. package/scripts/sw-instrument.sh +10 -2
  214. package/scripts/sw-intelligence.sh +44 -7
  215. package/scripts/sw-jira.sh +5 -1
  216. package/scripts/sw-launchd.sh +2 -1
  217. package/scripts/sw-linear.sh +4 -1
  218. package/scripts/sw-logs.sh +4 -1
  219. package/scripts/sw-loop.sh +436 -1076
  220. package/scripts/sw-memory.sh +357 -3
  221. package/scripts/sw-mission-control.sh +6 -1
  222. package/scripts/sw-model-router.sh +483 -27
  223. package/scripts/sw-otel.sh +15 -4
  224. package/scripts/sw-oversight.sh +14 -5
  225. package/scripts/sw-patrol-meta.sh +334 -0
  226. package/scripts/sw-pipeline-composer.sh +7 -1
  227. package/scripts/sw-pipeline-vitals.sh +12 -6
  228. package/scripts/sw-pipeline.sh +54 -2653
  229. package/scripts/sw-pm.sh +16 -8
  230. package/scripts/sw-pr-lifecycle.sh +2 -1
  231. package/scripts/sw-predictive.sh +17 -5
  232. package/scripts/sw-prep.sh +185 -2
  233. package/scripts/sw-ps.sh +5 -25
  234. package/scripts/sw-public-dashboard.sh +17 -4
  235. package/scripts/sw-quality.sh +14 -6
  236. package/scripts/sw-reaper.sh +8 -25
  237. package/scripts/sw-recruit.sh +156 -2303
  238. package/scripts/sw-regression.sh +19 -12
  239. package/scripts/sw-release-manager.sh +3 -1
  240. package/scripts/sw-release.sh +4 -1
  241. package/scripts/sw-remote.sh +3 -1
  242. package/scripts/sw-replay.sh +7 -1
  243. package/scripts/sw-retro.sh +158 -1
  244. package/scripts/sw-review-rerun.sh +3 -1
  245. package/scripts/sw-scale.sh +14 -5
  246. package/scripts/sw-security-audit.sh +6 -1
  247. package/scripts/sw-self-optimize.sh +173 -6
  248. package/scripts/sw-session.sh +9 -3
  249. package/scripts/sw-setup.sh +3 -1
  250. package/scripts/sw-stall-detector.sh +406 -0
  251. package/scripts/sw-standup.sh +15 -7
  252. package/scripts/sw-status.sh +3 -1
  253. package/scripts/sw-strategic.sh +14 -6
  254. package/scripts/sw-stream.sh +13 -4
  255. package/scripts/sw-swarm.sh +20 -7
  256. package/scripts/sw-team-stages.sh +13 -6
  257. package/scripts/sw-templates.sh +7 -31
  258. package/scripts/sw-testgen.sh +17 -6
  259. package/scripts/sw-tmux-pipeline.sh +4 -1
  260. package/scripts/sw-tmux-role-color.sh +2 -0
  261. package/scripts/sw-tmux-status.sh +1 -1
  262. package/scripts/sw-tmux.sh +37 -1
  263. package/scripts/sw-trace.sh +3 -1
  264. package/scripts/sw-tracker-github.sh +3 -0
  265. package/scripts/sw-tracker-jira.sh +3 -0
  266. package/scripts/sw-tracker-linear.sh +3 -0
  267. package/scripts/sw-tracker.sh +3 -1
  268. package/scripts/sw-triage.sh +3 -2
  269. package/scripts/sw-upgrade.sh +3 -1
  270. package/scripts/sw-ux.sh +5 -2
  271. package/scripts/sw-webhook.sh +5 -2
  272. package/scripts/sw-widgets.sh +9 -4
  273. package/scripts/sw-worktree.sh +15 -3
  274. package/scripts/test-skill-injection.sh +1233 -0
  275. package/templates/pipelines/autonomous.json +27 -3
  276. package/templates/pipelines/cost-aware.json +34 -8
  277. package/templates/pipelines/deployed.json +12 -0
  278. package/templates/pipelines/enterprise.json +12 -0
  279. package/templates/pipelines/fast.json +6 -0
  280. package/templates/pipelines/full.json +27 -3
  281. package/templates/pipelines/hotfix.json +6 -0
  282. package/templates/pipelines/standard.json +12 -0
  283. package/templates/pipelines/tdd.json +12 -0
@@ -0,0 +1,55 @@
1
+ ## Validation Thoroughness: Prove It Works in Production
2
+
3
+ Smoke tests are necessary but not sufficient. Validate the actual user experience.
4
+
5
+ ### Smoke Test Design
6
+ - Test the critical user path end-to-end (not just health endpoints)
7
+ - Verify the SPECIFIC functionality from this issue works
8
+ - Include authentication flow if the feature requires auth
9
+ - Test with realistic data, not just empty/default states
10
+
11
+ ### Health Check Layers
12
+ 1. **Liveness** — Is the process running? (HTTP 200 on /health)
13
+ 2. **Readiness** — Can it serve traffic? (dependencies connected, workers initialized)
14
+ 3. **Functional** — Does the new feature actually work? (feature-specific endpoint test)
15
+
16
+ ### Regression Detection
17
+ - Run the full test suite against the deployed environment (not just smoke)
18
+ - Compare response times to baseline — >20% regression is a red flag
19
+ - Verify existing features still work (not just the new one)
20
+ - Check error rates in logs for the first 100 requests
21
+
22
+ ### Production Readiness Checklist
23
+ - [ ] Health endpoint returns 200
24
+ - [ ] Key feature endpoint returns expected response
25
+ - [ ] Error rate is below baseline threshold
26
+ - [ ] Response latency is within acceptable range (p95 < SLO)
27
+ - [ ] No new error patterns in logs
28
+ - [ ] Database connections are healthy
29
+ - [ ] External service integrations are working
30
+
31
+ ### Issue Closure Criteria
32
+ Before automatically closing the issue:
33
+ 1. Smoke tests pass
34
+ 2. Health checks pass (5 consecutive successes)
35
+ 3. No error rate spike in first 5 minutes
36
+ 4. Feature-specific validation passes
37
+ 5. PR is merged and deployed
38
+
39
+ ### Failure Response
40
+ If validation fails:
41
+ 1. Do NOT close the issue
42
+ 2. Create an incident issue with validation failure details
43
+ 3. Trigger rollback if auto-rollback is configured
44
+ 4. Preserve deploy logs and smoke test output for debugging
45
+
46
+ ### Required Output (Mandatory)
47
+
48
+ Your output MUST include these sections when this skill is active:
49
+
50
+ 1. **Smoke Test Specification**: Explicit test cases covering the critical user path with realistic data (not just health endpoints)
51
+ 2. **Health Check Results**: Liveness check (process running), Readiness check (dependencies connected), Functional check (feature works)
52
+ 3. **Regression Detection**: Comparison of response times to baseline, error rate against baseline threshold, log analysis for new error patterns
53
+ 4. **Issue Closure Decision**: PASS/FAIL verdict with supporting evidence (all health checks passed, no error rate spike, feature-specific validation passed)
54
+
55
+ If any section is not applicable, explicitly state why it's skipped.
package/scripts/sw CHANGED
@@ -5,7 +5,7 @@
5
5
  # ╚═══════════════════════════════════════════════════════════════════════════╝
6
6
  set -euo pipefail
7
7
 
8
- VERSION="3.1.0"
8
+ VERSION="3.3.0"
9
9
 
10
10
  # Resolve symlinks (required for npm global install where bin/ symlinks to node_modules/)
11
11
  SOURCE="${BASH_SOURCE[0]}"
@@ -19,6 +19,7 @@ SCRIPT_DIR="$(cd "$(dirname "$SOURCE")" && pwd)"
19
19
  # ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
20
20
  CYAN='\033[38;2;0;212;255m' # #00d4ff — primary accent
21
21
  PURPLE='\033[38;2;124;58;237m' # #7c3aed — secondary
22
+ # shellcheck disable=SC2034
22
23
  BLUE='\033[38;2;0;102;255m' # #0066ff — tertiary
23
24
  GREEN='\033[38;2;74;222;128m' # success
24
25
  YELLOW='\033[38;2;250;204;21m' # warning
@@ -36,6 +37,7 @@ _sw_github_repo() {
36
37
  echo "${SHIPWRIGHT_GITHUB_REPO:-sethdford/shipwright}"
37
38
  fi
38
39
  }
40
+ # shellcheck disable=SC2155
39
41
  _sw_github_owner() { local r="$(_sw_github_repo)"; echo "${r%%/*}"; }
40
42
  _sw_docs_url() { echo "${SHIPWRIGHT_DOCS_URL:-https://$(_sw_github_owner).github.io/shipwright}"; }
41
43
  _sw_github_url() { echo "https://github.com/$(_sw_github_repo)"; }
@@ -162,7 +164,7 @@ show_help_all() {
162
164
  echo -e " ${CYAN}auth${RESET} ${CYAN}webhook${RESET} ${CYAN}eventbus${RESET} ${CYAN}otel${RESET} ${CYAN}context${RESET}"
163
165
  echo -e " ${CYAN}trace${RESET} ${CYAN}widgets${RESET} ${CYAN}connect${RESET} ${CYAN}remote${RESET} ${CYAN}launchd${RESET}"
164
166
  echo -e " ${CYAN}jira${RESET} ${CYAN}linear${RESET} ${CYAN}tracker${RESET} ${CYAN}heartbeat${RESET} ${CYAN}checkpoint${RESET}"
165
- echo -e " ${CYAN}durable${RESET} ${CYAN}autonomous${RESET} ${CYAN}pm${RESET} ${CYAN}strategic${RESET} ${CYAN}team-stages${RESET}"
167
+ echo -e " ${CYAN}stall-detector${RESET} ${CYAN}durable${RESET} ${CYAN}autonomous${RESET} ${CYAN}pm${RESET} ${CYAN}strategic${RESET}"
166
168
  echo -e " ${CYAN}ux${RESET} ${CYAN}mission-control${RESET} ${CYAN}tmux${RESET} ${CYAN}reaper${RESET} ${CYAN}e2e${RESET}"
167
169
  echo -e " ${CYAN}init${RESET} ${CYAN}setup${RESET} ${CYAN}doctor${RESET} ${CYAN}cleanup${RESET} ${CYAN}upgrade${RESET}"
168
170
  echo -e " ${CYAN}templates${RESET} ${CYAN}version${RESET}"
@@ -265,6 +267,7 @@ main() {
265
267
 
266
268
  shift 2>/dev/null || true
267
269
 
270
+ # shellcheck disable=SC2221,SC2222
268
271
  case "$cmd" in
269
272
  # Command groups
270
273
  agent) route_agent "$@" ;;
@@ -402,6 +405,9 @@ main() {
402
405
  checkpoint)
403
406
  exec "$SCRIPT_DIR/sw-checkpoint.sh" "$@"
404
407
  ;;
408
+ stall-detector)
409
+ exec "$SCRIPT_DIR/sw-stall-detector.sh" "$@"
410
+ ;;
405
411
  durable)
406
412
  exec "$SCRIPT_DIR/sw-durable.sh" "$@"
407
413
  ;;
@@ -600,7 +606,7 @@ main() {
600
606
  show_version
601
607
  ;;
602
608
  hello)
603
- echo "hello world"
609
+ exec "$SCRIPT_DIR/sw-hello.sh" "$@"
604
610
  ;;
605
611
  *)
606
612
  error "Unknown command: ${cmd}"
@@ -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.1.0"
9
+ # shellcheck disable=SC2034
10
+ VERSION="3.3.0"
10
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
12
 
12
13
  # ─── Cross-platform compatibility ──────────────────────────────────────────
@@ -28,7 +29,8 @@ fi
28
29
  if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
29
30
  emit_event() {
30
31
  local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
31
- local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
32
+ local payload
33
+ payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
32
34
  while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
33
35
  echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
34
36
  }
@@ -39,7 +41,9 @@ FILTER_TYPE=""
39
41
  FILTER_AGENT=""
40
42
  FILTER_TEAM=""
41
43
  FILTER_STAGE=""
44
+ # shellcheck disable=SC2034
42
45
  FILTER_START=""
46
+ # shellcheck disable=SC2034
43
47
  FILTER_END=""
44
48
 
45
49
  # Event type icons for terminal display (bash 3.2 compatible)
@@ -223,7 +227,9 @@ cmd_snapshot() {
223
227
 
224
228
  # Group by agent, show last event for each
225
229
  local last_agent=""
230
+ # shellcheck disable=SC2034
226
231
  local last_time=""
232
+ # shellcheck disable=SC2034
227
233
  local last_event=""
228
234
 
229
235
  tac "$EVENTS_FILE" 2>/dev/null | while IFS= read -r line; do
@@ -332,7 +338,6 @@ cmd_stats() {
332
338
  local end_time=""
333
339
 
334
340
  # Read directly to avoid subshell issues
335
- echo "DEBUG: Starting read loop..." >&2
336
341
  while IFS= read -r line; do
337
342
  [ -z "$line" ] && continue
338
343
 
@@ -363,14 +368,9 @@ cmd_stats() {
363
368
  end_time="$ts"
364
369
  done < <(grep -v '^$' "$EVENTS_FILE" 2>/dev/null)
365
370
 
366
- echo "DEBUG: Read complete, total=$total_events" >&2
367
- echo "DEBUG: agents_seen length: ${#agents_seen}" >&2
368
371
  local unique_agents
369
- echo "DEBUG: About to compute unique..." >&2
370
372
  unique_agents=$(sort -u <<< "$agents_seen" | grep -v '^$' | wc -l | tr -d ' ')
371
- echo "DEBUG: unique_agents=$unique_agents" >&2
372
373
 
373
- echo "DEBUG: About to print results..." >&2
374
374
  printf "${BOLD}Total Events:${RESET} %d\n" "$total_events"
375
375
  printf "${BOLD}Commits:${RESET} %d\n" "$commits"
376
376
  printf "${BOLD}Tests:${RESET} %d\n" "$tests"
@@ -449,6 +449,7 @@ main() {
449
449
  shift 2>/dev/null || true
450
450
 
451
451
  # Parse global options
452
+ # shellcheck disable=SC2034
452
453
  while [ $# -gt 0 ]; do
453
454
  case "$1" in
454
455
  --type) FILTER_TYPE="$2"; shift 2 ;;
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env bash
2
2
  # ╔═══════════════════════════════════════════════════════════════════════════╗
3
3
  # ║ shipwright adaptive — data-driven pipeline tuning ║
4
- # ║ Replace 83+ hardcoded values with learned defaults from historical runs
4
+ # ║ Replace static defaults with learned values from historical runs
5
5
  # ╚═══════════════════════════════════════════════════════════════════════════╝
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="3.1.0"
9
+ VERSION="3.3.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
12
  # ─── Cross-platform compatibility ──────────────────────────────────────────
@@ -31,6 +31,7 @@ fi
31
31
  if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
32
32
  emit_event() {
33
33
  local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
34
+ # shellcheck disable=SC2155
34
35
  local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
35
36
  while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
36
37
  echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
@@ -712,10 +713,10 @@ cmd_compare() {
712
713
  esac
713
714
  done
714
715
 
715
- info "Learned vs Hardcoded Values for ${CYAN}${repo}${RESET}"
716
+ info "Learned vs Default Values for ${CYAN}${repo}${RESET}"
716
717
  echo ""
717
718
 
718
- printf "%-25s %-15s %-15s %-15s\n" "Metric" "Hardcoded" "Learned" "Difference"
719
+ printf "%-25s %-15s %-15s %-15s\n" "Metric" "Default" "Learned" "Difference"
719
720
  printf "%s\n" "$(printf '%.0s─' {1..70})"
720
721
 
721
722
  # Timeout
@@ -841,7 +842,7 @@ ${BOLD}USAGE${RESET}
841
842
 
842
843
  ${BOLD}SUBCOMMANDS${RESET}
843
844
  ${CYAN}get${RESET} <metric> [--stage S] [--repo R] [--complexity C] [--default V]
844
- Return adaptive value for a metric (replaces hardcoded defaults)
845
+ Return adaptive value for a metric (replaces static defaults)
845
846
  Metrics: timeout, iterations, model, team_size, template, poll_interval,
846
847
  retry_limit, quality_threshold, coverage_min
847
848
 
@@ -852,7 +853,7 @@ ${BOLD}SUBCOMMANDS${RESET}
852
853
  Rebuild models from events.jsonl (run after significant pipeline activity)
853
854
 
854
855
  ${CYAN}compare${RESET} [--repo REPO]
855
- Side-by-side table: learned vs hardcoded values
856
+ Side-by-side table: learned vs default values
856
857
 
857
858
  ${CYAN}recommend${RESET} --issue N [--repo REPO]
858
859
  Full JSON recommendation for an issue (template, model, team_size, etc.)
@@ -876,7 +877,7 @@ ${BOLD}EXAMPLES${RESET}
876
877
  # Get complete recommendation for issue #42
877
878
  sw adaptive recommend --issue 42
878
879
 
879
- # Compare learned vs hardcoded
880
+ # Compare learned vs defaults
880
881
  sw adaptive compare
881
882
 
882
883
  ${BOLD}STORAGE${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="3.1.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
 
@@ -29,6 +29,7 @@ fi
29
29
  if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
30
30
  emit_event() {
31
31
  local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
32
+ # shellcheck disable=SC2155
32
33
  local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
33
34
  while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
34
35
  echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
@@ -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.1.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
 
@@ -29,12 +29,14 @@ fi
29
29
  if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
30
30
  emit_event() {
31
31
  local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
32
+ # shellcheck disable=SC2155
32
33
  local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
33
34
  while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
34
35
  echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
35
36
  }
36
37
  fi
37
38
  # ─── Structured Event Log ────────────────────────────────────────────────
39
+ # shellcheck disable=SC2034
38
40
  EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
39
41
 
40
42
  # ─── Source Intelligence Core ─────────────────────────────────────────────
@@ -6,8 +6,10 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="3.1.0"
9
+ # shellcheck disable=SC2034
10
+ VERSION="3.3.0"
10
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
+ # shellcheck disable=SC2034
11
13
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
14
 
13
15
  # ─── Cross-platform compatibility ──────────────────────────────────────────
@@ -30,7 +32,8 @@ fi
30
32
  if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
31
33
  emit_event() {
32
34
  local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
33
- local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
35
+ local payload
36
+ payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
34
37
  while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
35
38
  echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
36
39
  }
@@ -40,6 +43,7 @@ AUTH_FILE="${HOME}/.shipwright/auth.json"
40
43
  DEVICE_FLOW_ENDPOINT="$(_config_get "urls.github_device_login" "https://github.com/login/device")"
41
44
  API_ENDPOINT="$(_config_get "urls.github_api" "https://api.github.com")"
42
45
  OAUTH_CLIENT_ID="${GITHUB_OAUTH_CLIENT_ID:-Iv1.d3f6a7e8c9b2a1d4}" # Shipwright app ID
46
+ # shellcheck disable=SC2034
43
47
  OAUTH_TIMEOUT=900 # 15 minutes
44
48
 
45
49
  # Ensure auth storage directory exists
@@ -202,6 +206,8 @@ store_user() {
202
206
 
203
207
  local temp_file
204
208
  temp_file=$(mktemp)
209
+ # shellcheck disable=SC2064
210
+ # shellcheck disable=SC2064
205
211
  trap "rm -f '$temp_file'" RETURN
206
212
 
207
213
  local updated
@@ -246,6 +252,8 @@ switch_user() {
246
252
 
247
253
  local temp_file
248
254
  temp_file=$(mktemp)
255
+ # shellcheck disable=SC2064
256
+ # shellcheck disable=SC2064
249
257
  trap "rm -f '$temp_file'" RETURN
250
258
 
251
259
  jq --arg login "$login" '.active_user = $login' "$AUTH_FILE" > "$temp_file"
@@ -261,6 +269,8 @@ remove_user() {
261
269
 
262
270
  local temp_file
263
271
  temp_file=$(mktemp)
272
+ # shellcheck disable=SC2064
273
+ # shellcheck disable=SC2064
264
274
  trap "rm -f '$temp_file'" RETURN
265
275
 
266
276
  jq --arg login "$login" \
@@ -7,7 +7,8 @@
7
7
  set -euo pipefail
8
8
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
9
9
 
10
- VERSION="3.1.0"
10
+ # shellcheck disable=SC2034
11
+ VERSION="3.3.0"
11
12
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
13
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
13
14
 
@@ -29,6 +30,7 @@ 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"
33
+ # shellcheck disable=SC2155
32
34
  local 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"
@@ -53,6 +55,7 @@ STATE_DIR="${HOME}/.shipwright/autonomous"
53
55
  STATE_FILE="${STATE_DIR}/state.json"
54
56
  HISTORY_FILE="${STATE_DIR}/history.jsonl"
55
57
  CONFIG_FILE="${STATE_DIR}/config.json"
58
+ # shellcheck disable=SC2034
56
59
  CYCLE_COUNTER="${STATE_DIR}/cycle-counter.txt"
57
60
  AUTONOMOUS_OVERLAP_FILE="${HOME}/.shipwright/autonomous-state.json"
58
61
 
@@ -581,6 +584,7 @@ record_finding_pending() {
581
584
  local issue_num="$1"
582
585
  local finding_title="$2"
583
586
  ensure_state_dir
587
+ # shellcheck disable=SC2034
584
588
  local state_file="${STATE_DIR}/state.json"
585
589
  local pending_file="${STATE_DIR}/pending_findings.jsonl"
586
590
  [[ ! -f "$pending_file" ]] && touch "$pending_file"
@@ -7,7 +7,8 @@
7
7
  set -euo pipefail
8
8
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
9
9
 
10
- VERSION="3.1.0"
10
+ # shellcheck disable=SC2034
11
+ VERSION="3.3.0"
11
12
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
13
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
13
14
 
@@ -29,6 +30,7 @@ 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"
33
+ # shellcheck disable=SC2155
32
34
  local 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"
@@ -109,6 +111,7 @@ parse_commits() {
109
111
  docs_changes=""
110
112
  chores=""
111
113
  local contributors=""
114
+ # shellcheck disable=SC2034
112
115
  local pr_links=""
113
116
 
114
117
  while IFS='|' read -r hash author email date subject body; do
@@ -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="3.1.0"
11
+ VERSION="3.3.0"
12
12
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
13
13
 
14
14
  # ─── Cross-platform compatibility ──────────────────────────────────────────
@@ -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"
package/scripts/sw-ci.sh CHANGED
@@ -6,8 +6,9 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="3.1.0"
9
+ VERSION="3.3.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
+ # shellcheck disable=SC2034
11
12
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
13
 
13
14
  # ─── Cross-platform compatibility ──────────────────────────────────────────
@@ -29,6 +30,7 @@ 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"
33
+ # shellcheck disable=SC2155
32
34
  local 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"
@@ -77,6 +79,7 @@ jobs:
77
79
  stage_config=$(jq ".stages[] | select(.id==\"$stage_id\")" "$pipeline_config" 2>/dev/null || echo "{}")
78
80
 
79
81
  local gate
82
+ # shellcheck disable=SC2034
80
83
  gate=$(jq -r '.gate // "auto"' <<< "$stage_config")
81
84
 
82
85
  yaml_content+=" ${stage_id}:
@@ -227,15 +230,20 @@ cmd_analyze() {
227
230
  info "Analyzing workflow efficiency"
228
231
 
229
232
  local job_count step_count matrix_enabled
230
- job_count=$(grep -c "^ [a-z_-]*:" "$workflow_file" 2>/dev/null || echo "0")
231
- step_count=$(grep -c " - name:" "$workflow_file" 2>/dev/null || echo "0")
232
- matrix_enabled=$(grep -c "matrix:" "$workflow_file" 2>/dev/null || echo "0")
233
+ job_count=$(grep -c "^ [a-z_-]*:" "$workflow_file" 2>/dev/null || true)
234
+ job_count="${job_count:-0}"
235
+ step_count=$(grep -c " - name:" "$workflow_file" 2>/dev/null || true)
236
+ step_count="${step_count:-0}"
237
+ matrix_enabled=$(grep -c "matrix:" "$workflow_file" 2>/dev/null || true)
238
+ matrix_enabled="${matrix_enabled:-0}"
233
239
 
234
240
  local has_cache
235
- has_cache=$(grep -c "actions/cache" "$workflow_file" 2>/dev/null || echo "0")
241
+ has_cache=$(grep -c "actions/cache" "$workflow_file" 2>/dev/null || true)
242
+ has_cache="${has_cache:-0}"
236
243
 
237
244
  local has_timeout
238
- has_timeout=$(grep -c "timeout-minutes:" "$workflow_file" 2>/dev/null || echo "0")
245
+ has_timeout=$(grep -c "timeout-minutes:" "$workflow_file" 2>/dev/null || true)
246
+ has_timeout="${has_timeout:-0}"
239
247
 
240
248
  echo ""
241
249
  echo -e "${BOLD}Workflow Analysis: $(basename "$workflow_file")${RESET}"
@@ -296,6 +304,7 @@ cmd_secrets() {
296
304
  info "Checking secret availability in GitHub"
297
305
 
298
306
  local repo="${2:-.}"
307
+ # shellcheck disable=SC2034
299
308
  local owner org_name
300
309
 
301
310
  # Parse owner from git remote
@@ -5,38 +5,16 @@
5
5
  # ║ Default: dry-run (shows what would be cleaned). ║
6
6
  # ║ Use --force to actually kill sessions and remove files. ║
7
7
  # ╚═══════════════════════════════════════════════════════════════════════════╝
8
- VERSION="3.1.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
11
 
12
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
+ # shellcheck source=lib/bootstrap.sh
13
+ source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib/bootstrap.sh"
13
14
 
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
- # shellcheck source=lib/compat.sh
18
- [[ -f "$SCRIPT_DIR/lib/compat.sh" ]] && source "$SCRIPT_DIR/lib/compat.sh"
19
15
  [[ -f "$SCRIPT_DIR/lib/config.sh" ]] && source "$SCRIPT_DIR/lib/config.sh"
20
16
 
21
17
  PROJECT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
22
-
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
40
18
  # ─── Parse Args ──────────────────────────────────────────────────────────────
41
19
 
42
20
  FORCE=false