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
@@ -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
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
13
 
@@ -72,7 +73,8 @@ detect_code_smells() {
72
73
 
73
74
  # Check 1: Long functions (>60 lines in bash)
74
75
  local func_count
75
- func_count=$(grep -c "^[a-zA-Z_][a-zA-Z0-9_]*().*{" "$target_file" 2>/dev/null || echo "0")
76
+ func_count=$(grep -c "^[a-zA-Z_][a-zA-Z0-9_]*().*{" "$target_file" 2>/dev/null || true)
77
+ func_count="${func_count:-0}"
76
78
  if [[ "$func_count" -gt 0 ]]; then
77
79
  while IFS= read -r line; do
78
80
  if [[ "$line" =~ ^[a-zA-Z_][a-zA-Z0-9_]*\(\).*\{ ]]; then
@@ -106,7 +108,8 @@ detect_code_smells() {
106
108
 
107
109
  # Check 3: Duplicate code patterns (repeated >3 times)
108
110
  local dup_count=0
109
- dup_count=$(grep -c '^\s*\(cd\|cd\|mkdir\|rm\|echo\)' "$target_file" 2>/dev/null || echo "0")
111
+ dup_count=$(grep -c '^\s*\(cd\|cd\|mkdir\|rm\|echo\)' "$target_file" 2>/dev/null || true)
112
+ dup_count="${dup_count:-0}"
110
113
  if [[ $dup_count -gt 3 ]]; then
111
114
  issues+=("REPEATED_PATTERNS: Common operations appear $dup_count times (consider helper functions)")
112
115
  fi
@@ -139,7 +142,8 @@ check_solid_principles() {
139
142
 
140
143
  # Single Responsibility: Check if scripts do multiple unrelated things
141
144
  local sourced_count
142
- sourced_count=$(grep -c '^\s*source\|^\s*\.\s' "$target_file" 2>/dev/null || echo "0")
145
+ sourced_count=$(grep -c '^\s*source\|^\s*\.\s' "$target_file" 2>/dev/null || true)
146
+ sourced_count="${sourced_count:-0}"
143
147
  if [[ $sourced_count -gt 3 ]]; then
144
148
  violations+=("SRP_VIOLATION: Script sources $sourced_count modules (too many responsibilities)")
145
149
  fi
@@ -159,7 +163,8 @@ check_solid_principles() {
159
163
  if [[ "$line" =~ ^[a-zA-Z_][a-zA-Z0-9_]*\(\) ]]; then
160
164
  local func_name="${line%%(*}"
161
165
  local body
162
- body=$(awk "/^${func_name}\\(\\)/,/^}/" "$target_file" | grep -c '\$[0-9]' || echo "0")
166
+ body=$(awk "/^${func_name}\\(\\)/,/^}/" "$target_file" | grep -c '\$[0-9]' || true)
167
+ body="${body:-0}"
163
168
  if [[ $body -gt 5 ]]; then
164
169
  violations+=("ISP_VIOLATION: Function $func_name uses >5 parameters")
165
170
  fi
@@ -227,7 +232,9 @@ analyze_complexity() {
227
232
 
228
233
  # Cyclomatic complexity: count decision points (if, elif, case, &&, ||)
229
234
  local cc=1
230
- cc=$((cc + $(sed -n "${start_line},${end_line}p" "$target_file" | grep -cE '\s(if|elif|case|&&|\|\|)' || echo 0)))
235
+ local _cc_count
236
+ _cc_count=$(sed -n "${start_line},${end_line}p" "$target_file" | grep -cE '\s(if|elif|case|&&|\|\|)' || true)
237
+ cc=$((cc + ${_cc_count:-0}))
231
238
 
232
239
  # Lines of code
233
240
  local loc=$((end_line - start_line))
@@ -266,8 +273,12 @@ check_style_consistency() {
266
273
  local has_trap=false
267
274
  local has_set_e=false
268
275
 
269
- [[ $(grep -c 'trap.*ERR' "$target_file" 2>/dev/null || echo 0) -gt 0 ]] && has_trap=true
270
- [[ $(grep -c 'set -e' "$target_file" 2>/dev/null || echo 0) -gt 0 ]] && has_set_e=true
276
+ local _trap_count
277
+ _trap_count=$(grep -c 'trap.*ERR' "$target_file" 2>/dev/null || true)
278
+ [[ "${_trap_count:-0}" -gt 0 ]] && has_trap=true
279
+ local _set_e_count
280
+ _set_e_count=$(grep -c 'set -e' "$target_file" 2>/dev/null || true)
281
+ [[ "${_set_e_count:-0}" -gt 0 ]] && has_set_e=true
271
282
 
272
283
  if [[ "$has_set_e" == "true" ]] && [[ "$has_trap" == "false" ]]; then
273
284
  issues+=("STYLE: Missing ERR trap despite 'set -e' (inconsistent error handling)")
@@ -276,8 +287,10 @@ check_style_consistency() {
276
287
  # Check for inconsistent quote usage
277
288
  local single_quotes
278
289
  local double_quotes
279
- single_quotes=$(grep -o "'" "$target_file" 2>/dev/null | wc -l || echo 0)
280
- double_quotes=$(grep -o '"' "$target_file" 2>/dev/null | wc -l || echo 0)
290
+ single_quotes=$(grep -o "'" "$target_file" 2>/dev/null | wc -l || true)
291
+ single_quotes="${single_quotes:-0}"
292
+ double_quotes=$(grep -o '"' "$target_file" 2>/dev/null | wc -l || true)
293
+ double_quotes="${double_quotes:-0}"
281
294
  if [[ $single_quotes -gt $((double_quotes * 3)) ]] || [[ $double_quotes -gt $((single_quotes * 3)) ]]; then
282
295
  issues+=("STYLE: Inconsistent quote style (mix of single and double quotes)")
283
296
  fi
@@ -285,8 +298,10 @@ check_style_consistency() {
285
298
  # Check for inconsistent spacing/indentation
286
299
  local tab_count
287
300
  local space_count
288
- tab_count=$(grep -c $'^\t' "$target_file" 2>/dev/null || echo 0)
289
- space_count=$(grep -c '^ ' "$target_file" 2>/dev/null || echo 0)
301
+ tab_count=$(grep -c $'^\t' "$target_file" 2>/dev/null || true)
302
+ tab_count="${tab_count:-0}"
303
+ space_count=$(grep -c '^ ' "$target_file" 2>/dev/null || true)
304
+ space_count="${space_count:-0}"
290
305
  if [[ $tab_count -gt 0 ]] && [[ $space_count -gt 0 ]]; then
291
306
  issues+=("STYLE: Mixed tabs and spaces")
292
307
  fi
@@ -333,7 +348,8 @@ auto_fix() {
333
348
 
334
349
  # Fix 2: Trailing whitespace
335
350
  local trailing_ws
336
- trailing_ws=$(grep -c '[[:space:]]$' "$target_file" 2>/dev/null || echo "0")
351
+ trailing_ws=$(grep -c '[[:space:]]$' "$target_file" 2>/dev/null || true)
352
+ trailing_ws="${trailing_ws:-0}"
337
353
  if [[ $trailing_ws -gt 0 ]]; then
338
354
  sed -i '' 's/[[:space:]]*$//' "$target_file"
339
355
  info "Removed $trailing_ws lines of trailing whitespace"
@@ -349,7 +365,8 @@ auto_fix() {
349
365
 
350
366
  # Fix 4: Consistent spacing around operators (simple cases)
351
367
  local spacing_fixes=0
352
- spacing_fixes=$(grep -c '==' "$target_file" 2>/dev/null || echo "0")
368
+ spacing_fixes=$(grep -c '==' "$target_file" 2>/dev/null || true)
369
+ spacing_fixes="${spacing_fixes:-0}"
353
370
  if [[ $spacing_fixes -gt 0 ]]; then
354
371
  info "Flagged $spacing_fixes operator spacing cases (manual review recommended)"
355
372
  fi
@@ -415,7 +432,8 @@ review_changes() {
415
432
 
416
433
  mkdir -p "${REPO_DIR}/.claude/pipeline-artifacts"
417
434
 
418
- 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\":{}}"
419
437
  local total_issues=0
420
438
 
421
439
  # Get changed files (Bash 3.2 compatible — no mapfile)
@@ -498,18 +516,24 @@ review_changes() {
498
516
  scan_codebase() {
499
517
  info "Running full codebase quality scan..."
500
518
 
501
- 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\":[]}"
502
522
  local total_issues=0
503
523
 
524
+ # shellcheck disable=SC2178,SC2128
504
525
  find "$REPO_DIR/scripts" -name "*.sh" -type f 2>/dev/null | while read -r file; do
505
526
  local file_rel="${file#$REPO_DIR/}"
506
527
  local smells=0
507
528
  local solids=0
508
529
  local arch_issues=0
509
530
 
510
- smells=$(detect_code_smells "$file" 2>/dev/null | wc -l || echo 0)
511
- solids=$(check_solid_principles "$file" 2>/dev/null | wc -l || echo 0)
512
- arch_issues=$(check_architecture_boundaries "$file" 2>/dev/null | wc -l || echo 0)
531
+ smells=$(detect_code_smells "$file" 2>/dev/null | wc -l || true)
532
+ smells="${smells:-0}"
533
+ solids=$(check_solid_principles "$file" 2>/dev/null | wc -l || true)
534
+ solids="${solids:-0}"
535
+ arch_issues=$(check_architecture_boundaries "$file" 2>/dev/null | wc -l || true)
536
+ arch_issues="${arch_issues:-0}"
513
537
 
514
538
  local file_issues=$((smells + solids + arch_issues))
515
539
  total_issues=$((total_issues + file_issues))
@@ -528,7 +552,8 @@ scan_codebase() {
528
552
  complexity_report() {
529
553
  info "Analyzing code complexity metrics..."
530
554
 
531
- 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\":[]}"
532
557
 
533
558
  find "$REPO_DIR/scripts" -name "*.sh" -type f 2>/dev/null | while read -r file; do
534
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.1.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.1.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.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"
@@ -150,11 +152,11 @@ 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")
157
- jq --argjson input "$input_tokens" \
158
+ tmp_file=$(mktemp "${COST_FILE}.tmp.XXXXXX") || { error "mktemp failed for cost record"; exit 1; }
159
+ if ! jq --argjson input "$input_tokens" \
158
160
  --argjson output "$output_tokens" \
159
161
  --arg model "$model" \
160
162
  --arg stage "$stage" \
@@ -172,7 +174,16 @@ cost_record() {
172
174
  ts: $ts,
173
175
  ts_epoch: $epoch
174
176
  }] | .entries = (.entries | .[-1000:])' \
175
- "$COST_FILE" > "$tmp_file" && mv "$tmp_file" "$COST_FILE" || rm -f "$tmp_file"
177
+ "$COST_FILE" > "$tmp_file" 2>/dev/null; then
178
+ error "Cost jq transformation failed — entry may be lost"
179
+ rm -f "$tmp_file"
180
+ # Continue without updating cost file
181
+ else
182
+ mv "$tmp_file" "$COST_FILE" || {
183
+ error "Failed to update cost file"
184
+ rm -f "$tmp_file"
185
+ }
186
+ fi
176
187
  ) 200>"${COST_FILE}.lock"
177
188
 
178
189
  emit_event "cost.record" \
@@ -602,6 +613,49 @@ cost_dashboard() {
602
613
 
603
614
  if [[ "$entry_count" -eq 0 ]]; then
604
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
605
659
  return 0
606
660
  fi
607
661
 
@@ -790,6 +844,54 @@ cost_dashboard() {
790
844
  fi
791
845
  fi
792
846
 
847
+ # Context efficiency (from loop.context_efficiency events)
848
+ local events_file="${HOME}/.shipwright/events.jsonl"
849
+ if [[ -f "$events_file" ]]; then
850
+ local ctx_events
851
+ ctx_events=$(grep '"type":"loop.context_efficiency"' "$events_file" 2>/dev/null | tail -200 || true)
852
+ local ctx_count
853
+ ctx_count=$(echo "$ctx_events" | grep -c '"loop.context_efficiency"' 2>/dev/null || echo "0")
854
+ ctx_count="${ctx_count:-0}"
855
+
856
+ if [[ "$ctx_count" -gt 0 ]]; then
857
+ # Parse metrics using awk (Bash 3.2 safe — no arrays needed)
858
+ local avg_utilization avg_trim_ratio total_raw total_trimmed trim_count
859
+ eval "$(echo "$ctx_events" | awk -F'"' '
860
+ /"loop.context_efficiency"/ {
861
+ for (i=1; i<=NF; i++) {
862
+ if ($i == "budget_utilization") util = $(i+2)
863
+ if ($i == "trim_ratio") ratio = $(i+2)
864
+ if ($i == "raw_prompt_chars") raw = $(i+2)
865
+ if ($i == "trimmed_prompt_chars") trimmed = $(i+2)
866
+ }
867
+ total_util += util; total_ratio += ratio
868
+ total_raw += raw; total_trimmed += trimmed
869
+ if (ratio + 0 > 0) trim_events++
870
+ n++
871
+ }
872
+ END {
873
+ if (n > 0) {
874
+ printf "avg_utilization=%.1f\n", total_util / n
875
+ printf "avg_trim_ratio=%.1f\n", total_ratio / n
876
+ } else {
877
+ printf "avg_utilization=0\navg_trim_ratio=0\n"
878
+ }
879
+ printf "total_raw=%d\ntotal_trimmed=%d\ntrim_count=%d\n", total_raw, total_trimmed, (trim_events+0)
880
+ }
881
+ ')"
882
+
883
+ local total_discarded=$(( total_raw - total_trimmed ))
884
+
885
+ echo -e "${BOLD} CONTEXT EFFICIENCY${RESET}"
886
+ echo -e " Avg budget used ${avg_utilization}%"
887
+ echo -e " Avg trim ratio ${avg_trim_ratio}%"
888
+ echo -e " Chars generated $(printf "%'d" "$total_raw")"
889
+ echo -e " Chars discarded $(printf "%'d" "$total_discarded")"
890
+ echo -e " Trim events ${trim_count} / ${ctx_count} iterations"
891
+ echo ""
892
+ fi
893
+ fi
894
+
793
895
  echo -e "${PURPLE}${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
794
896
  echo ""
795
897
  }
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env bash
2
+ # shellcheck disable=SC2034 # config vars used by sourced scripts and subshells
2
3
  # ╔═══════════════════════════════════════════════════════════════════════════╗
3
4
  # ║ shipwright daemon — Autonomous GitHub Issue Watcher ║
4
5
  # ║ Polls for labeled issues · Spawns pipelines · Manages worktrees ║
@@ -8,8 +9,11 @@ trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
9
 
9
10
  # Allow spawning Claude CLI from within a Claude Code session (daemon, fleet, etc.)
10
11
  unset CLAUDECODE 2>/dev/null || true
12
+ # Ignore SIGHUP so daemon survives tmux attach/detach
13
+ trap '' HUP
14
+ trap '' SIGPIPE
11
15
 
12
- VERSION="3.1.0"
16
+ VERSION="3.3.0"
13
17
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
14
18
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
15
19
 
@@ -199,6 +203,8 @@ ISSUE_LIMIT=$(_config_get_int "daemon.issue_limit" 100 2>/dev/null || echo 100)
199
203
  PIPELINE_TEMPLATE="autonomous"
200
204
  SKIP_GATES=true
201
205
  MODEL="opus"
206
+ EFFORT_LEVEL=""
207
+ FALLBACK_MODEL="sonnet"
202
208
  BASE_BRANCH="main"
203
209
  ON_SUCCESS_REMOVE_LABEL="shipwright"
204
210
  ON_SUCCESS_ADD_LABEL="pipeline/complete"
@@ -381,6 +387,8 @@ load_config() {
381
387
  PIPELINE_TEMPLATE=$(jq -r '.pipeline_template // "autonomous"' "$config_file")
382
388
  SKIP_GATES=$(jq -r '.skip_gates // true' "$config_file")
383
389
  MODEL=$(jq -r '.model // "opus"' "$config_file")
390
+ EFFORT_LEVEL=$(jq -r '.effort_level // ""' "$config_file")
391
+ FALLBACK_MODEL=$(jq -r '.fallback_model // "sonnet"' "$config_file")
384
392
  BASE_BRANCH=$(jq -r '.base_branch // "main"' "$config_file")
385
393
 
386
394
  # on_success settings
@@ -441,6 +449,7 @@ load_config() {
441
449
  # intelligence engine settings (default "auto" = enable when Claude CLI available)
442
450
  INTELLIGENCE_ENABLED=$(jq -r '.intelligence.enabled // "auto"' "$config_file")
443
451
  INTELLIGENCE_CACHE_TTL=$(jq -r '.intelligence.cache_ttl_seconds // 3600' "$config_file")
452
+ INTELLIGENCE_MODEL=$(jq -r '.intelligence.model // "haiku"' "$config_file")
444
453
  COMPOSER_ENABLED=$(jq -r '.intelligence.composer_enabled // "auto"' "$config_file")
445
454
 
446
455
  # Auto-enable intelligence when Claude is available (unless explicitly disabled)
@@ -471,14 +480,27 @@ load_config() {
471
480
  COMPOSER_ENABLED=false
472
481
  fi
473
482
  fi
474
- OPTIMIZATION_ENABLED=$(jq -r '.intelligence.optimization_enabled // false' "$config_file")
475
- PREDICTION_ENABLED=$(jq -r '.intelligence.prediction_enabled // false' "$config_file")
483
+ OPTIMIZATION_ENABLED=$(jq -r '.intelligence.optimization_enabled // "auto"' "$config_file")
484
+ PREDICTION_ENABLED=$(jq -r '.intelligence.prediction_enabled // "auto"' "$config_file")
476
485
  ANOMALY_THRESHOLD=$(jq -r '.intelligence.anomaly_threshold // 3.0' "$config_file")
477
486
 
478
487
  # adaptive thresholds (intelligence-driven operational tuning)
479
- ADAPTIVE_THRESHOLDS_ENABLED=$(jq -r '.intelligence.adaptive_enabled // false' "$config_file")
488
+ ADAPTIVE_THRESHOLDS_ENABLED=$(jq -r '.intelligence.adaptive_enabled // "auto"' "$config_file")
480
489
  PRIORITY_STRATEGY=$(jq -r '.intelligence.priority_strategy // "quick-wins-first"' "$config_file")
481
490
 
491
+ # Auto-resolve "auto" for prediction, optimization, adaptive (same pattern as intelligence/composer)
492
+ local _flag_val=""
493
+ for _flag_var in OPTIMIZATION_ENABLED PREDICTION_ENABLED ADAPTIVE_THRESHOLDS_ENABLED; do
494
+ eval "_flag_val=\"\${${_flag_var}}\""
495
+ if [[ "$_flag_val" == "auto" ]]; then
496
+ if command -v claude &>/dev/null; then
497
+ eval "${_flag_var}=true"
498
+ else
499
+ eval "${_flag_var}=false"
500
+ fi
501
+ fi
502
+ done
503
+
482
504
  # gh_retry: enable retry wrapper on critical GitHub API calls
483
505
  GH_RETRY_ENABLED=$(jq -r '.gh_retry // true' "$config_file")
484
506
 
@@ -544,19 +566,45 @@ setup_dirs() {
544
566
  STATE_FILE="$DAEMON_DIR/daemon-state.json"
545
567
  LOG_FILE="$DAEMON_DIR/daemon.log"
546
568
  LOG_DIR="$DAEMON_DIR/logs"
547
- WORKTREE_DIR=".worktrees"
569
+
570
+ # ── Worktree Directory (must be absolute for security) ──
571
+ # Always use repo-level .claude/worktrees (self-healing: create .claude if missing)
572
+ local _abs_cwd
573
+ _abs_cwd="$(cd "$(pwd)" && pwd)"
574
+ WORKTREE_DIR="${_abs_cwd}/.claude/worktrees"
575
+
548
576
  PAUSE_FLAG="${HOME}/.shipwright/daemon-pause.flag"
549
577
 
550
578
  mkdir -p "$LOG_DIR"
551
579
  mkdir -p "$HOME/.shipwright/progress"
580
+ mkdir -p "$WORKTREE_DIR"
581
+
582
+ # Ensure worktrees are gitignored
583
+ local _gitignore="${_abs_cwd}/.gitignore"
584
+ if [[ -f "$_gitignore" ]] && ! grep -q '\.claude/worktrees' "$_gitignore" 2>/dev/null; then
585
+ echo ".claude/worktrees/" >> "$_gitignore"
586
+ fi
552
587
  }
553
588
 
554
589
  # ─── Adaptive Threshold Helpers ──────────────────────────────────────────────
555
590
  # When intelligence.adaptive_enabled=true, operational thresholds are learned
556
591
  # from historical data instead of using fixed defaults.
557
- # Every function falls back to the current hardcoded value when no data exists.
558
-
559
- ADAPTIVE_THRESHOLDS_ENABLED="${ADAPTIVE_THRESHOLDS_ENABLED:-false}"
592
+ # Every function falls back to the config default when no data exists.
593
+
594
+ # Auto-resolve intelligence defaults when no config file is loaded.
595
+ # All three default to "auto" → true when Claude CLI is available.
596
+ _auto_resolve_intelligence() {
597
+ local val="${1:-auto}"
598
+ if [[ "$val" == "auto" ]]; then
599
+ command -v claude &>/dev/null && echo "true" || echo "false"
600
+ else
601
+ echo "$val"
602
+ fi
603
+ }
604
+ INTELLIGENCE_MODEL="${INTELLIGENCE_MODEL:-haiku}"
605
+ OPTIMIZATION_ENABLED=$(_auto_resolve_intelligence "${OPTIMIZATION_ENABLED:-auto}")
606
+ PREDICTION_ENABLED=$(_auto_resolve_intelligence "${PREDICTION_ENABLED:-auto}")
607
+ ADAPTIVE_THRESHOLDS_ENABLED=$(_auto_resolve_intelligence "${ADAPTIVE_THRESHOLDS_ENABLED:-auto}")
560
608
  PRIORITY_STRATEGY="${PRIORITY_STRATEGY:-quick-wins-first}"
561
609
  EMPTY_QUEUE_CYCLES=0
562
610
 
@@ -669,7 +717,8 @@ daemon_start() {
669
717
  fi
670
718
 
671
719
  # Export current PATH so detached session finds claude, gh, etc.
672
- local tmux_cmd="export PATH='${PATH}'; ${cmd_args[*]}"
720
+ # Unset CLAUDECODE so daemon works when started from inside Claude Code
721
+ local tmux_cmd="unset CLAUDECODE 2>/dev/null; export PATH='${PATH}'; ${cmd_args[*]}"
673
722
  tmux new-session -d -s "sw-daemon" "$tmux_cmd" 2>/dev/null || {
674
723
  # Session may already exist — try killing and recreating
675
724
  tmux kill-session -t "sw-daemon" 2>/dev/null || true
@@ -934,6 +983,11 @@ daemon_init() {
934
983
 
935
984
  mkdir -p "$config_dir"
936
985
 
986
+ # Set restrictive umask for sensitive files (owner-only: 600)
987
+ local _old_umask
988
+ _old_umask=$(umask)
989
+ umask 0077
990
+
937
991
  cat > "$config_file" << 'CONFIGEOF'
938
992
  {
939
993
  "watch_label": "shipwright",
@@ -999,10 +1053,12 @@ daemon_init() {
999
1053
  "estimated_cost_per_job_usd": 5.0,
1000
1054
  "intelligence": {
1001
1055
  "enabled": "auto",
1056
+ "model": "haiku",
1002
1057
  "cache_ttl_seconds": 3600,
1003
1058
  "composer_enabled": "auto",
1004
- "optimization_enabled": true,
1005
- "prediction_enabled": true,
1059
+ "optimization_enabled": "auto",
1060
+ "prediction_enabled": "auto",
1061
+ "adaptive_enabled": "auto",
1006
1062
  "adversarial_enabled": false,
1007
1063
  "simulation_enabled": false,
1008
1064
  "architecture_enabled": false,
@@ -1012,6 +1068,10 @@ daemon_init() {
1012
1068
  }
1013
1069
  CONFIGEOF
1014
1070
 
1071
+ # Restore umask and ensure file has restricted permissions
1072
+ umask "$_old_umask"
1073
+ chmod 600 "$config_file"
1074
+
1015
1075
  success "Generated config: ${config_file}"
1016
1076
  echo ""
1017
1077
  echo -e "${DIM}Edit this file to customize the daemon behavior, then run:${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
 
12
12
  # ─── Cross-platform compatibility ──────────────────────────────────────────
@@ -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"
@@ -41,6 +42,7 @@ TEAMS_DIR="${HOME}/.shipwright"
41
42
  PID_FILE="${TEAMS_DIR}/dashboard.pid"
42
43
  LOG_DIR="${TEAMS_DIR}/logs"
43
44
  LOG_FILE="${LOG_DIR}/dashboard.log"
45
+ # shellcheck disable=SC2034
44
46
  EVENTS_FILE="${TEAMS_DIR}/events.jsonl"
45
47
  DEFAULT_PORT=$(_config_get_int "dashboard.port" 8767 2>/dev/null || echo 8767)
46
48