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,334 @@
1
+ #!/usr/bin/env bash
2
+ # ╔═══════════════════════════════════════════════════════════════════════════╗
3
+ # ║ lib/quality-profile.sh — Quality Profile Management ║
4
+ # ║ Load, validate, and manage project quality standards (quality-profile.json) ║
5
+ # ╚═══════════════════════════════════════════════════════════════════════════╝
6
+
7
+ # Source guard — prevent double-loading
8
+ [[ -n "${_QUALITY_PROFILE_LOADED:-}" ]] && return 0
9
+ _QUALITY_PROFILE_LOADED=1
10
+
11
+ set -euo pipefail
12
+
13
+ SCRIPT_DIR="${SCRIPT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
14
+ REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
15
+ QUALITY_PROFILE_PATH="${REPO_ROOT}/.claude/quality-profile.json"
16
+
17
+ # Default schema version
18
+ QP_SCHEMA_VERSION=1
19
+
20
+ # Cache the loaded profile (Bash 3.2 compatible — no declare -g)
21
+ _QP_CACHE=""
22
+ _QP_LOADED=0
23
+
24
+ # ─────────────────────────────────────────────────────────────────────────────
25
+ # load_quality_profile
26
+ # Load quality profile from .claude/quality-profile.json or create defaults
27
+ # Returns 0 on success, 1 on validation failure
28
+ # ─────────────────────────────────────────────────────────────────────────────
29
+ load_quality_profile() {
30
+ # Return cached copy if already loaded
31
+ if [[ "$_QP_LOADED" == "1" ]] && [[ -n "$_QP_CACHE" ]]; then
32
+ echo "$_QP_CACHE"
33
+ return 0
34
+ fi
35
+
36
+ if [[ -f "$QUALITY_PROFILE_PATH" ]]; then
37
+ _QP_CACHE=$(cat "$QUALITY_PROFILE_PATH")
38
+ else
39
+ # Generate default profile
40
+ _QP_CACHE=$(generate_default_profile)
41
+ fi
42
+
43
+ # Validate the profile
44
+ if ! validate_quality_profile "$_QP_CACHE"; then
45
+ return 1
46
+ fi
47
+
48
+ _QP_LOADED=1
49
+ echo "$_QP_CACHE"
50
+ return 0
51
+ }
52
+
53
+ # ─────────────────────────────────────────────────────────────────────────────
54
+ # validate_quality_profile <profile_json>
55
+ # Validate profile against schema (version, required fields)
56
+ # Returns 0 if valid, 1 if invalid
57
+ # ─────────────────────────────────────────────────────────────────────────────
58
+ validate_quality_profile() {
59
+ local profile_json="$1"
60
+
61
+ # Check if it's valid JSON
62
+ if ! echo "$profile_json" | jq empty 2>/dev/null; then
63
+ return 1
64
+ fi
65
+
66
+ # Check version field
67
+ local version
68
+ version=$(echo "$profile_json" | jq -r '.version // ""' 2>/dev/null)
69
+ if [[ "$version" != "$QP_SCHEMA_VERSION" ]]; then
70
+ return 1
71
+ fi
72
+
73
+ # Check required top-level fields
74
+ local required_fields=("architecture" "testing" "quality" "review" "scope" "deployment")
75
+ for field in "${required_fields[@]}"; do
76
+ local value
77
+ value=$(echo "$profile_json" | jq -r ".${field} // \"\"" 2>/dev/null)
78
+ if [[ -z "$value" ]] || [[ "$value" == "null" ]]; then
79
+ return 1
80
+ fi
81
+ done
82
+
83
+ return 0
84
+ }
85
+
86
+ # ─────────────────────────────────────────────────────────────────────────────
87
+ # qp_get <jq_path> [default]
88
+ # Get a specific value from the profile with optional default
89
+ # Usage: qp_get ".quality.max_pr_lines" "500"
90
+ # ─────────────────────────────────────────────────────────────────────────────
91
+ qp_get() {
92
+ local jq_path="$1"
93
+ local default="${2:-}"
94
+
95
+ local profile
96
+ profile=$(load_quality_profile) || return 1
97
+
98
+ local value
99
+ value=$(echo "$profile" | jq -r "${jq_path} // \"\"" 2>/dev/null || echo "")
100
+
101
+ if [[ -z "$value" ]] || [[ "$value" == "null" ]]; then
102
+ echo "$default"
103
+ else
104
+ echo "$value"
105
+ fi
106
+ }
107
+
108
+ # ─────────────────────────────────────────────────────────────────────────────
109
+ # qp_get_array <jq_path>
110
+ # Get array values as newline-separated list
111
+ # Usage: qp_get_array ".quality.never_ship"
112
+ # ─────────────────────────────────────────────────────────────────────────────
113
+ qp_get_array() {
114
+ local jq_path="$1"
115
+
116
+ local profile
117
+ profile=$(load_quality_profile) || return 1
118
+
119
+ # Convert array to newline-separated strings
120
+ echo "$profile" | jq -r "${jq_path}[]? // empty" 2>/dev/null || return 1
121
+ }
122
+
123
+ # ─────────────────────────────────────────────────────────────────────────────
124
+ # qp_add_learned_rule <rule> <source> <confidence> <inject_at_stages>
125
+ # Add a learned quality rule from outcome feedback
126
+ # Usage: qp_add_learned_rule "Always validate input" "3 PRs got review comments" 0.85 "plan,build,review"
127
+ # ─────────────────────────────────────────────────────────────────────────────
128
+ qp_add_learned_rule() {
129
+ local rule="$1"
130
+ local source="$2"
131
+ local confidence="$3"
132
+ local inject_at="$4"
133
+
134
+ if [[ ! -f "$QUALITY_PROFILE_PATH" ]]; then
135
+ return 1
136
+ fi
137
+
138
+ local created_at
139
+ created_at=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
140
+
141
+ # Convert inject_at comma-separated to array
142
+ local inject_array
143
+ inject_array=$(echo "$inject_at" | jq -R 'split(",") | map(ltrimstr(" ") | rtrimstr(" "))')
144
+
145
+ # Build the new rule as JSON object
146
+ local new_rule
147
+ new_rule=$(jq -n \
148
+ --arg r "$rule" \
149
+ --arg s "$source" \
150
+ --arg c "$confidence" \
151
+ --argjson i "$inject_array" \
152
+ --arg dt "$created_at" \
153
+ '{rule: $r, source: $s, confidence: $c, inject_at: $i, created_at: $dt}')
154
+
155
+ # Atomic write: read, modify, write
156
+ local tmp_file
157
+ tmp_file=$(mktemp)
158
+ trap "rm -f '$tmp_file'" RETURN
159
+
160
+ # Add rule to learned_rules array
161
+ if ! jq ".quality.learned_rules += [$new_rule]" "$QUALITY_PROFILE_PATH" > "$tmp_file" 2>/dev/null; then
162
+ return 1
163
+ fi
164
+
165
+ mv "$tmp_file" "$QUALITY_PROFILE_PATH"
166
+ _QP_LOADED=0 # Invalidate cache
167
+ return 0
168
+ }
169
+
170
+ # ─────────────────────────────────────────────────────────────────────────────
171
+ # qp_get_rules_for_stage <stage_name>
172
+ # Get all learned rules for a specific stage (plan, build, review, etc)
173
+ # Usage: qp_get_rules_for_stage "build"
174
+ # ─────────────────────────────────────────────────────────────────────────────
175
+ qp_get_rules_for_stage() {
176
+ local stage="$1"
177
+
178
+ local profile
179
+ profile=$(load_quality_profile) || return 1
180
+
181
+ # Filter rules where inject_at contains the stage
182
+ echo "$profile" | jq -r ".quality.learned_rules[]? | select(.inject_at[]? == \"$stage\") | .rule" 2>/dev/null || return 0
183
+ }
184
+
185
+ # ─────────────────────────────────────────────────────────────────────────────
186
+ # generate_default_profile
187
+ # Generate a minimal default quality profile (non-interactive)
188
+ # Returns the profile JSON to stdout
189
+ # ─────────────────────────────────────────────────────────────────────────────
190
+ generate_default_profile() {
191
+ local now
192
+ now=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
193
+
194
+ local project_name
195
+ project_name=$(basename "$REPO_ROOT")
196
+
197
+ cat <<EOF
198
+ {
199
+ "version": $QP_SCHEMA_VERSION,
200
+ "project_name": "$project_name",
201
+ "generated_at": "$now",
202
+ "architecture": {
203
+ "pattern": "monolith",
204
+ "layers": [],
205
+ "dependency_direction": "none",
206
+ "rules": []
207
+ },
208
+ "testing": {
209
+ "philosophy": "test_after",
210
+ "min_coverage_delta": 0,
211
+ "required_test_types": ["unit"],
212
+ "test_cmd": "",
213
+ "fast_test_cmd": ""
214
+ },
215
+ "quality": {
216
+ "max_pr_lines": 500,
217
+ "max_files_per_pr": 15,
218
+ "never_ship": [],
219
+ "always_require": [],
220
+ "learned_rules": []
221
+ },
222
+ "review": {
223
+ "focus_areas": [],
224
+ "blocking_severities": ["critical", "bug", "security"],
225
+ "min_issues_to_find": 3
226
+ },
227
+ "scope": {
228
+ "unplanned_files_block": false,
229
+ "decomposition_threshold_lines": 500
230
+ },
231
+ "deployment": {
232
+ "strategy": "direct",
233
+ "rollback_plan": "revert_commit",
234
+ "monitoring_window_minutes": 30
235
+ }
236
+ }
237
+ EOF
238
+ }
239
+
240
+ # ─────────────────────────────────────────────────────────────────────────────
241
+ # qp_save <profile_json>
242
+ # Save a quality profile to disk (atomic write)
243
+ # ─────────────────────────────────────────────────────────────────────────────
244
+ qp_save() {
245
+ local profile_json="$1"
246
+
247
+ # Validate before saving
248
+ if ! validate_quality_profile "$profile_json"; then
249
+ return 1
250
+ fi
251
+
252
+ local tmp_file
253
+ tmp_file=$(mktemp)
254
+ trap "rm -f '$tmp_file'" RETURN
255
+
256
+ # Pretty-print and write atomically
257
+ if ! echo "$profile_json" | jq '.' > "$tmp_file" 2>/dev/null; then
258
+ return 1
259
+ fi
260
+
261
+ mkdir -p "$(dirname "$QUALITY_PROFILE_PATH")"
262
+ mv "$tmp_file" "$QUALITY_PROFILE_PATH"
263
+ _QP_LOADED=0 # Invalidate cache
264
+ return 0
265
+ }
266
+
267
+ # ─────────────────────────────────────────────────────────────────────────────
268
+ # qp_merge <base_profile> <updates>
269
+ # Deep merge two profile objects (updates override base)
270
+ # ─────────────────────────────────────────────────────────────────────────────
271
+ qp_merge() {
272
+ local base="$1"
273
+ local updates="$2"
274
+
275
+ # Use jq's * operator for recursive merge
276
+ echo "$base" | jq --argjson u "$updates" '. * $u' 2>/dev/null || return 1
277
+ }
278
+
279
+ # ─────────────────────────────────────────────────────────────────────────────
280
+ # qp_infer_from_repo
281
+ # Analyze the repo to infer quality profile settings
282
+ # Returns JSON with inferred values
283
+ # ─────────────────────────────────────────────────────────────────────────────
284
+ qp_infer_from_repo() {
285
+ local test_cmd=""
286
+ local fast_test_cmd=""
287
+ local philosophy="test_after"
288
+ local framework="monolith"
289
+
290
+ # Infer test command from package.json
291
+ if [[ -f "$REPO_ROOT/package.json" ]]; then
292
+ if jq -e '.scripts.test' "$REPO_ROOT/package.json" >/dev/null 2>&1; then
293
+ test_cmd="npm test"
294
+ fi
295
+ elif [[ -f "$REPO_ROOT/go.mod" ]]; then
296
+ test_cmd="go test ./..."
297
+ elif [[ -f "$REPO_ROOT/Cargo.toml" ]]; then
298
+ test_cmd="cargo test"
299
+ elif [[ -f "$REPO_ROOT/pyproject.toml" ]] || [[ -f "$REPO_ROOT/setup.py" ]]; then
300
+ test_cmd="pytest"
301
+ fi
302
+
303
+ # Infer architecture from repo structure
304
+ if [[ -d "$REPO_ROOT/services" ]] || [[ -d "$REPO_ROOT/microservices" ]]; then
305
+ framework="microservices"
306
+ elif [[ -d "$REPO_ROOT/packages" ]] && [[ -d "$REPO_ROOT/apps" ]]; then
307
+ framework="modular_monolith"
308
+ fi
309
+
310
+ # Output as JSON fragment
311
+ jq -n \
312
+ --arg test_cmd "$test_cmd" \
313
+ --arg framework "$framework" \
314
+ '{test_cmd: $test_cmd, framework: $framework}'
315
+ }
316
+
317
+ # ─────────────────────────────────────────────────────────────────────────────
318
+ # qp_get_version
319
+ # Get the schema version of the profile
320
+ # ─────────────────────────────────────────────────────────────────────────────
321
+ qp_get_version() {
322
+ local profile
323
+ profile=$(load_quality_profile) || return 1
324
+ echo "$profile" | jq -r '.version // ""' 2>/dev/null
325
+ }
326
+
327
+ # ─────────────────────────────────────────────────────────────────────────────
328
+ # qp_clear_cache
329
+ # Clear the in-memory cache (used before reload)
330
+ # ─────────────────────────────────────────────────────────────────────────────
331
+ qp_clear_cache() {
332
+ _QP_CACHE=""
333
+ _QP_LOADED=0
334
+ }