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
@@ -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.2.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.2.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
@@ -443,6 +449,7 @@ main() {
443
449
  shift 2>/dev/null || true
444
450
 
445
451
  # Parse global options
452
+ # shellcheck disable=SC2034
446
453
  while [ $# -gt 0 ]; do
447
454
  case "$1" in
448
455
  --type) FILTER_TYPE="$2"; shift 2 ;;
@@ -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 ──────────────────────────────────────────
@@ -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"
@@ -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
 
@@ -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.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
 
@@ -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.2.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.2.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.2.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.2.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.2.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}:
@@ -301,6 +304,7 @@ cmd_secrets() {
301
304
  info "Checking secret availability in GitHub"
302
305
 
303
306
  local repo="${2:-.}"
307
+ # shellcheck disable=SC2034
304
308
  local owner org_name
305
309
 
306
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.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
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
@@ -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
 
@@ -431,7 +432,8 @@ review_changes() {
431
432
 
432
433
  mkdir -p "${REPO_DIR}/.claude/pipeline-artifacts"
433
434
 
434
- local review_output="{\"timestamp\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"scope\":\"$review_scope\",\"findings\":{}}"
435
+ local review_output
436
+ review_output="{\"timestamp\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"scope\":\"$review_scope\",\"findings\":{}}"
435
437
  local total_issues=0
436
438
 
437
439
  # Get changed files (Bash 3.2 compatible — no mapfile)
@@ -514,9 +516,12 @@ review_changes() {
514
516
  scan_codebase() {
515
517
  info "Running full codebase quality scan..."
516
518
 
517
- local scan_output="{\"timestamp\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"files\":[]}"
519
+ local scan_output
520
+ # shellcheck disable=SC2034
521
+ scan_output="{\"timestamp\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"files\":[]}"
518
522
  local total_issues=0
519
523
 
524
+ # shellcheck disable=SC2178,SC2128
520
525
  find "$REPO_DIR/scripts" -name "*.sh" -type f 2>/dev/null | while read -r file; do
521
526
  local file_rel="${file#$REPO_DIR/}"
522
527
  local smells=0
@@ -547,7 +552,8 @@ scan_codebase() {
547
552
  complexity_report() {
548
553
  info "Analyzing code complexity metrics..."
549
554
 
550
- local complexity_data="{\"timestamp\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"files\":[]}"
555
+ local complexity_data
556
+ complexity_data="{\"timestamp\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"files\":[]}"
551
557
 
552
558
  find "$REPO_DIR/scripts" -name "*.sh" -type f 2>/dev/null | while read -r file; do
553
559
  local file_metrics
@@ -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.2.0"
11
+ VERSION="3.3.0"
12
12
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13
13
 
14
14
  # ─── Cross-platform compatibility ──────────────────────────────────────────
@@ -33,6 +33,7 @@ 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
+ # shellcheck disable=SC2155
36
37
  local 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"
@@ -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="${SHIPWRIGHT_REPO_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
12
12
 
@@ -387,6 +387,7 @@ gather_context() {
387
387
 
388
388
  local tmp_file
389
389
  tmp_file=$(mktemp "${TMPDIR:-/tmp}/sw-context-bundle.XXXXXX")
390
+ # shellcheck disable=SC2064
390
391
  trap "rm -f '$tmp_file'" RETURN
391
392
 
392
393
  # Write bundle header
@@ -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.2.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"
@@ -150,10 +152,10 @@ cost_record() {
150
152
  # Always write to JSON (dual-write period)
151
153
  (
152
154
  if command -v flock >/dev/null 2>&1; then
153
- flock -w 10 200 2>/dev/null || { warn "Cost lock timeout"; }
155
+ flock -w 10 200 2>/dev/null || { warn "Cost lock timeout — proceeding without lock"; }
154
156
  fi
155
157
  local tmp_file
156
- tmp_file=$(mktemp "${COST_FILE}.tmp.XXXXXX")
158
+ tmp_file=$(mktemp "${COST_FILE}.tmp.XXXXXX") || { error "mktemp failed for cost record"; exit 1; }
157
159
  if ! jq --argjson input "$input_tokens" \
158
160
  --argjson output "$output_tokens" \
159
161
  --arg model "$model" \
@@ -611,6 +613,49 @@ cost_dashboard() {
611
613
 
612
614
  if [[ "$entry_count" -eq 0 ]]; then
613
615
  warn "No cost entries in the last ${period_days} day(s)."
616
+ # Still show context efficiency data if available
617
+ local events_file="${HOME}/.shipwright/events.jsonl"
618
+ if [[ -f "$events_file" ]]; then
619
+ local ctx_events
620
+ ctx_events=$(grep '"type":"loop.context_efficiency"' "$events_file" 2>/dev/null | tail -200 || true)
621
+ local ctx_count
622
+ ctx_count=$(echo "$ctx_events" | grep -c '"loop.context_efficiency"' 2>/dev/null || echo "0")
623
+ ctx_count="${ctx_count:-0}"
624
+ if [[ "$ctx_count" -gt 0 ]]; then
625
+ local avg_utilization avg_trim_ratio total_raw total_trimmed trim_count
626
+ eval "$(echo "$ctx_events" | awk -F'"' '
627
+ /"loop.context_efficiency"/ {
628
+ for (i=1; i<=NF; i++) {
629
+ if ($i == "budget_utilization") util = $(i+2)
630
+ if ($i == "trim_ratio") ratio = $(i+2)
631
+ if ($i == "raw_prompt_chars") raw = $(i+2)
632
+ if ($i == "trimmed_prompt_chars") trimmed = $(i+2)
633
+ }
634
+ total_util += util; total_ratio += ratio
635
+ total_raw += raw; total_trimmed += trimmed
636
+ if (ratio + 0 > 0) trim_events++
637
+ n++
638
+ }
639
+ END {
640
+ if (n > 0) {
641
+ printf "avg_utilization=%.1f\n", total_util / n
642
+ printf "avg_trim_ratio=%.1f\n", total_ratio / n
643
+ } else {
644
+ printf "avg_utilization=0\navg_trim_ratio=0\n"
645
+ }
646
+ printf "total_raw=%d\ntotal_trimmed=%d\ntrim_count=%d\n", total_raw, total_trimmed, (trim_events+0)
647
+ }
648
+ ')"
649
+ local total_discarded=$(( total_raw - total_trimmed ))
650
+ echo -e "${BOLD} CONTEXT EFFICIENCY${RESET}"
651
+ echo -e " Avg budget used ${avg_utilization}%"
652
+ echo -e " Avg trim ratio ${avg_trim_ratio}%"
653
+ echo -e " Chars generated $(printf "%'d" "$total_raw")"
654
+ echo -e " Chars discarded $(printf "%'d" "$total_discarded")"
655
+ echo -e " Trim events ${trim_count} / ${ctx_count} iterations"
656
+ echo ""
657
+ fi
658
+ fi
614
659
  return 0
615
660
  fi
616
661