@mmerterden/multi-agent-pipeline 12.7.0 → 12.8.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 (244) hide show
  1. package/CHANGELOG.md +126 -0
  2. package/install/_common.mjs +48 -0
  3. package/install/_dev-only-files.mjs +125 -5
  4. package/install/claude.mjs +14 -8
  5. package/install/copilot.mjs +5 -8
  6. package/package.json +17 -2
  7. package/pipeline/commands/multi-agent/analysis/SKILL.md +1 -1
  8. package/pipeline/lib/credential-store.sh +20 -0
  9. package/pipeline/multi-agent-refs/_account-picker.md +1 -1
  10. package/pipeline/multi-agent-refs/_dev-context.md +1 -1
  11. package/pipeline/multi-agent-refs/_repo-picker.md +1 -1
  12. package/pipeline/multi-agent-refs/phases/operations.md +28 -0
  13. package/pipeline/multi-agent-refs/phases/phase-0-init.md +1 -0
  14. package/pipeline/multi-agent-refs/phases/phase-2-planning.md +1 -1
  15. package/pipeline/multi-agent-refs/phases/phase-3-dev.md +1 -2
  16. package/pipeline/multi-agent-refs/phases/phase-4-review.md +49 -4
  17. package/pipeline/schemas/prefs.schema.json +6 -0
  18. package/pipeline/scripts/_smoke-root.sh +61 -0
  19. package/pipeline/scripts/audit-log.sh +25 -0
  20. package/pipeline/scripts/smoke-cross-cli-behavior.sh +21 -7
  21. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-1-analysis.json +0 -25
  22. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-2-plan.json +0 -30
  23. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-4-review.json +0 -20
  24. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-4-triage.json +0 -15
  25. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/metadata.json +0 -14
  26. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/task.json +0 -12
  27. package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-1-analysis.json +0 -29
  28. package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-2-plan.json +0 -43
  29. package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-4-review.json +0 -35
  30. package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-4-triage.json +0 -35
  31. package/pipeline/eval/golden-tasks/02-android-feature-compose/metadata.json +0 -14
  32. package/pipeline/eval/golden-tasks/02-android-feature-compose/task.json +0 -12
  33. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-1-analysis.json +0 -29
  34. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-2-plan.json +0 -42
  35. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-4-review.json +0 -20
  36. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-4-triage.json +0 -15
  37. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/metadata.json +0 -14
  38. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/task.json +0 -12
  39. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-1-analysis.json +0 -29
  40. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-2-plan.json +0 -40
  41. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-4-review.json +0 -20
  42. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-4-triage.json +0 -15
  43. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/metadata.json +0 -14
  44. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/task.json +0 -12
  45. package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-1-analysis.json +0 -29
  46. package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-2-plan.json +0 -42
  47. package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-4-review.json +0 -28
  48. package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-4-triage.json +0 -27
  49. package/pipeline/eval/golden-tasks/05-ios-security-keychain/metadata.json +0 -14
  50. package/pipeline/eval/golden-tasks/05-ios-security-keychain/task.json +0 -12
  51. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-1-analysis.json +0 -29
  52. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-2-plan.json +0 -41
  53. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-4-review.json +0 -12
  54. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-4-triage.json +0 -6
  55. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/metadata.json +0 -14
  56. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/task.json +0 -12
  57. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-1-analysis.json +0 -29
  58. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-2-plan.json +0 -42
  59. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-4-review.json +0 -28
  60. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-4-triage.json +0 -27
  61. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/metadata.json +0 -14
  62. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/task.json +0 -12
  63. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-1-analysis.json +0 -25
  64. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-2-plan.json +0 -31
  65. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-4-review.json +0 -12
  66. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-4-triage.json +0 -18
  67. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/metadata.json +0 -14
  68. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/task.json +0 -12
  69. package/pipeline/eval/golden-tasks/README.md +0 -65
  70. package/pipeline/eval/intent-cases.json +0 -40
  71. package/pipeline/eval/run-metrics-fixture.json +0 -93
  72. package/pipeline/eval/triage/01-empty-findings/expected.json +0 -6
  73. package/pipeline/eval/triage/01-empty-findings/input.json +0 -5
  74. package/pipeline/eval/triage/01-empty-findings/notes.md +0 -7
  75. package/pipeline/eval/triage/02-real-blocker/expected.json +0 -15
  76. package/pipeline/eval/triage/02-real-blocker/input.json +0 -14
  77. package/pipeline/eval/triage/02-real-blocker/notes.md +0 -7
  78. package/pipeline/eval/triage/03-out-of-scope-defer/expected.json +0 -18
  79. package/pipeline/eval/triage/03-out-of-scope-defer/input.json +0 -14
  80. package/pipeline/eval/triage/03-out-of-scope-defer/notes.md +0 -10
  81. package/pipeline/eval/triage/04-false-positive-reject/expected.json +0 -18
  82. package/pipeline/eval/triage/04-false-positive-reject/input.json +0 -14
  83. package/pipeline/eval/triage/04-false-positive-reject/notes.md +0 -10
  84. package/pipeline/eval/triage/05-mixed-classification/expected.json +0 -43
  85. package/pipeline/eval/triage/05-mixed-classification/input.json +0 -38
  86. package/pipeline/eval/triage/05-mixed-classification/notes.md +0 -17
  87. package/pipeline/eval/triage/06-severity-mismatch/expected.json +0 -15
  88. package/pipeline/eval/triage/06-severity-mismatch/input.json +0 -14
  89. package/pipeline/eval/triage/06-severity-mismatch/notes.md +0 -9
  90. package/pipeline/eval/triage/07-duplicate-reviewers/expected.json +0 -27
  91. package/pipeline/eval/triage/07-duplicate-reviewers/input.json +0 -22
  92. package/pipeline/eval/triage/07-duplicate-reviewers/notes.md +0 -9
  93. package/pipeline/eval/triage/08-style-misclassified/expected.json +0 -18
  94. package/pipeline/eval/triage/08-style-misclassified/input.json +0 -14
  95. package/pipeline/eval/triage/08-style-misclassified/notes.md +0 -9
  96. package/pipeline/eval/triage/09-cascading-finding/expected.json +0 -23
  97. package/pipeline/eval/triage/09-cascading-finding/input.json +0 -22
  98. package/pipeline/eval/triage/09-cascading-finding/notes.md +0 -9
  99. package/pipeline/eval/triage/10-deferred-crossref/expected.json +0 -18
  100. package/pipeline/eval/triage/10-deferred-crossref/input.json +0 -14
  101. package/pipeline/eval/triage/10-deferred-crossref/notes.md +0 -9
  102. package/pipeline/eval/triage/11-vercel-token-leak-blocker/expected.json +0 -27
  103. package/pipeline/eval/triage/11-vercel-token-leak-blocker/input.json +0 -22
  104. package/pipeline/eval/triage/11-vercel-token-leak-blocker/notes.md +0 -14
  105. package/pipeline/eval/triage/README.md +0 -54
  106. package/pipeline/scripts/benchmark-phase-0.sh +0 -128
  107. package/pipeline/scripts/check-md-links.mjs +0 -88
  108. package/pipeline/scripts/eval-golden-tasks-live.mjs +0 -302
  109. package/pipeline/scripts/eval-golden-tasks.mjs +0 -224
  110. package/pipeline/scripts/eval-intent.mjs +0 -107
  111. package/pipeline/scripts/eval-mine-corpus.mjs +0 -211
  112. package/pipeline/scripts/eval-triage.mjs +0 -171
  113. package/pipeline/scripts/fixtures/diff-risk-android.diff +0 -40
  114. package/pipeline/scripts/fixtures/diff-risk-ios.diff +0 -48
  115. package/pipeline/scripts/fixtures/diff-risk-test-removal.diff +0 -40
  116. package/pipeline/scripts/fixtures/install-layout.tsv +0 -19
  117. package/pipeline/scripts/fixtures/pack-expected-count.txt +0 -1
  118. package/pipeline/scripts/fixtures/test-gap-node.diff +0 -30
  119. package/pipeline/scripts/fixtures/test-gap-python.diff +0 -32
  120. package/pipeline/scripts/lint-mcp-refs.mjs +0 -218
  121. package/pipeline/scripts/lint-skills.mjs +0 -154
  122. package/pipeline/scripts/run-smokes.mjs +0 -130
  123. package/pipeline/scripts/scorecard.mjs +0 -258
  124. package/pipeline/scripts/smoke-add-detail.sh +0 -137
  125. package/pipeline/scripts/smoke-agent-guard.sh +0 -74
  126. package/pipeline/scripts/smoke-agent-log-cost.sh +0 -262
  127. package/pipeline/scripts/smoke-agent-model-routing.sh +0 -87
  128. package/pipeline/scripts/smoke-ask-choice.sh +0 -42
  129. package/pipeline/scripts/smoke-autopilot-circuit-breaker.sh +0 -36
  130. package/pipeline/scripts/smoke-bitbucket-contract.sh +0 -255
  131. package/pipeline/scripts/smoke-changelog-version.sh +0 -47
  132. package/pipeline/scripts/smoke-channels-approval-gate.sh +0 -60
  133. package/pipeline/scripts/smoke-channels-flow.sh +0 -130
  134. package/pipeline/scripts/smoke-ci-workflows.sh +0 -88
  135. package/pipeline/scripts/smoke-clarify.sh +0 -148
  136. package/pipeline/scripts/smoke-command-inventory.sh +0 -81
  137. package/pipeline/scripts/smoke-commands-skills-parity.sh +0 -87
  138. package/pipeline/scripts/smoke-community-gates.sh +0 -75
  139. package/pipeline/scripts/smoke-compliance-skills.sh +0 -119
  140. package/pipeline/scripts/smoke-config-hygiene.sh +0 -58
  141. package/pipeline/scripts/smoke-context-budget.sh +0 -72
  142. package/pipeline/scripts/smoke-cost-budget.sh +0 -70
  143. package/pipeline/scripts/smoke-cost-summary.sh +0 -139
  144. package/pipeline/scripts/smoke-cross-phase-cohesion.sh +0 -128
  145. package/pipeline/scripts/smoke-description-tr.sh +0 -82
  146. package/pipeline/scripts/smoke-dev-critic.sh +0 -144
  147. package/pipeline/scripts/smoke-diff-explain.sh +0 -147
  148. package/pipeline/scripts/smoke-diff-risk.sh +0 -190
  149. package/pipeline/scripts/smoke-dynamic-skill-loading.sh +0 -160
  150. package/pipeline/scripts/smoke-eval-live.sh +0 -136
  151. package/pipeline/scripts/smoke-evidence-gate.sh +0 -93
  152. package/pipeline/scripts/smoke-extract-conventions.sh +0 -163
  153. package/pipeline/scripts/smoke-fetchers-offline.sh +0 -448
  154. package/pipeline/scripts/smoke-figma-dispatch.sh +0 -112
  155. package/pipeline/scripts/smoke-gate-hooks.sh +0 -74
  156. package/pipeline/scripts/smoke-gc-tmp.sh +0 -130
  157. package/pipeline/scripts/smoke-gc-worktrees.sh +0 -125
  158. package/pipeline/scripts/smoke-generate-issue.sh +0 -120
  159. package/pipeline/scripts/smoke-handoff-contract.sh +0 -92
  160. package/pipeline/scripts/smoke-identity-isolation.sh +0 -70
  161. package/pipeline/scripts/smoke-install-layout.sh +0 -248
  162. package/pipeline/scripts/smoke-intent-guard.sh +0 -86
  163. package/pipeline/scripts/smoke-issue-comment-template.sh +0 -86
  164. package/pipeline/scripts/smoke-issue-jira-triad.sh +0 -120
  165. package/pipeline/scripts/smoke-keychain.sh +0 -158
  166. package/pipeline/scripts/smoke-language-axis.sh +0 -109
  167. package/pipeline/scripts/smoke-learning-curve.sh +0 -61
  168. package/pipeline/scripts/smoke-learnings-ledger.sh +0 -86
  169. package/pipeline/scripts/smoke-lib-scripts.sh +0 -448
  170. package/pipeline/scripts/smoke-mcp-gate.sh +0 -68
  171. package/pipeline/scripts/smoke-md-links.sh +0 -8
  172. package/pipeline/scripts/smoke-md2confluence.sh +0 -126
  173. package/pipeline/scripts/smoke-metrics-cache-ratio.sh +0 -72
  174. package/pipeline/scripts/smoke-migrate-state.sh +0 -102
  175. package/pipeline/scripts/smoke-mode-dispatch-drift.sh +0 -161
  176. package/pipeline/scripts/smoke-model-fallback.sh +0 -89
  177. package/pipeline/scripts/smoke-multi-repo-integration.sh +0 -116
  178. package/pipeline/scripts/smoke-multi-repo-worktree.sh +0 -61
  179. package/pipeline/scripts/smoke-no-mcp-in-dev-phases.sh +0 -194
  180. package/pipeline/scripts/smoke-no-token-prompt.sh +0 -85
  181. package/pipeline/scripts/smoke-own-punctuation.sh +0 -103
  182. package/pipeline/scripts/smoke-pack-contents.sh +0 -140
  183. package/pipeline/scripts/smoke-pat-audit.sh +0 -128
  184. package/pipeline/scripts/smoke-per-repo-memory.sh +0 -156
  185. package/pipeline/scripts/smoke-phase-0-multi-repo.sh +0 -170
  186. package/pipeline/scripts/smoke-phase-6-multi.sh +0 -79
  187. package/pipeline/scripts/smoke-phase-banner.sh +0 -101
  188. package/pipeline/scripts/smoke-phase-tracker.sh +0 -324
  189. package/pipeline/scripts/smoke-phase0-bridge-contract.sh +0 -241
  190. package/pipeline/scripts/smoke-phase4-gates.sh +0 -45
  191. package/pipeline/scripts/smoke-phase4-triage.sh +0 -229
  192. package/pipeline/scripts/smoke-plan-approval-gate.sh +0 -71
  193. package/pipeline/scripts/smoke-plan-safety.sh +0 -139
  194. package/pipeline/scripts/smoke-plan-todos.sh +0 -196
  195. package/pipeline/scripts/smoke-pr-review-actions.sh +0 -152
  196. package/pipeline/scripts/smoke-pre-commit.sh +0 -170
  197. package/pipeline/scripts/smoke-pref-migration.sh +0 -226
  198. package/pipeline/scripts/smoke-prefs-language.sh +0 -134
  199. package/pipeline/scripts/smoke-progress-contract.sh +0 -127
  200. package/pipeline/scripts/smoke-prune-logs.sh +0 -137
  201. package/pipeline/scripts/smoke-purge.sh +0 -138
  202. package/pipeline/scripts/smoke-push-retry.sh +0 -75
  203. package/pipeline/scripts/smoke-repo-map.sh +0 -300
  204. package/pipeline/scripts/smoke-review-readiness.sh +0 -92
  205. package/pipeline/scripts/smoke-review-watch.sh +0 -146
  206. package/pipeline/scripts/smoke-routines.sh +0 -84
  207. package/pipeline/scripts/smoke-run-aggregator.sh +0 -216
  208. package/pipeline/scripts/smoke-run-metrics.sh +0 -50
  209. package/pipeline/scripts/smoke-search.sh +0 -187
  210. package/pipeline/scripts/smoke-shadow-git.sh +0 -224
  211. package/pipeline/scripts/smoke-skill-authoring.sh +0 -137
  212. package/pipeline/scripts/smoke-skill-language.sh +0 -83
  213. package/pipeline/scripts/smoke-skill-manifest.sh +0 -138
  214. package/pipeline/scripts/smoke-skill-scan.sh +0 -198
  215. package/pipeline/scripts/smoke-source-parity.sh +0 -85
  216. package/pipeline/scripts/smoke-subagent-validators.sh +0 -108
  217. package/pipeline/scripts/smoke-sync-parity.sh +0 -92
  218. package/pipeline/scripts/smoke-tasklist-ordering.sh +0 -112
  219. package/pipeline/scripts/smoke-telemetry.sh +0 -147
  220. package/pipeline/scripts/smoke-test-gap.sh +0 -183
  221. package/pipeline/scripts/smoke-token-budget.sh +0 -67
  222. package/pipeline/scripts/smoke-token-preflight.sh +0 -82
  223. package/pipeline/scripts/smoke-tracker-contract.sh +0 -191
  224. package/pipeline/scripts/smoke-tracker-tokens-invocation.sh +0 -73
  225. package/pipeline/scripts/smoke-triage-memory.sh +0 -174
  226. package/pipeline/scripts/smoke-update-check.sh +0 -135
  227. package/pipeline/scripts/smoke-url-enrichment.sh +0 -70
  228. package/pipeline/scripts/smoke-validate-analysis-doc.sh +0 -161
  229. package/pipeline/scripts/smoke-validator-contradiction.sh +0 -67
  230. package/pipeline/scripts/smoke-validator-gates.sh +0 -164
  231. package/pipeline/scripts/smoke-vercel-deploy-redact.sh +0 -129
  232. package/pipeline/scripts/smoke-verify-by-test.sh +0 -148
  233. package/pipeline/scripts/smoke-wiki-integration.sh +0 -122
  234. package/pipeline/scripts/smoke-work-summary.sh +0 -163
  235. package/pipeline/scripts/smoke-workflow-audit.sh +0 -101
  236. package/pipeline/scripts/smoke-worktree-path-convention.sh +0 -86
  237. package/pipeline/scripts/smoke-wrapper-preservation.sh +0 -68
  238. package/pipeline/scripts/smoke-write-state.sh +0 -159
  239. package/pipeline/scripts/sync-parity-check.sh +0 -135
  240. package/pipeline/scripts/test-gap-rules/android.json +0 -25
  241. package/pipeline/scripts/test-gap-rules/ios.json +0 -34
  242. package/pipeline/scripts/test-gap-rules/node.json +0 -29
  243. package/pipeline/scripts/test-gap-rules/python.json +0 -25
  244. package/pipeline/scripts/validate-schemas.mjs +0 -88
@@ -1,152 +0,0 @@
1
- #!/usr/bin/env bash
2
- #
3
- # smoke-pr-review-actions.sh
4
- #
5
- # Asserts the review-actions contract is wired correctly: the new channel
6
- # doc, the orchestrator, the decision rule, both languages, the github +
7
- # bitbucket-server provider switch, and the absence of the legacy monolith
8
- # comment artifacts.
9
- #
10
- # This is a lint, not a behavioural test. Behavioural drift is caught at
11
- # runtime by the chat summary + the actual PR state on the provider.
12
-
13
- set -euo pipefail
14
-
15
- SELF_DIR=$(cd "$(dirname "$0")" && pwd)
16
- PIPELINE_ROOT=$(cd "$SELF_DIR/.." && pwd)
17
-
18
- cd "$PIPELINE_ROOT"
19
-
20
- FAIL=0
21
-
22
- CHANNEL="multi-agent-refs/channels/pr-review-actions.md"
23
- REVIEW="commands/multi-agent/review/SKILL.md"
24
- POSTER="lib/post-pr-review.sh"
25
-
26
- # 1. New canonical template + new poster exist.
27
- if [ ! -f "$CHANNEL" ]; then
28
- echo "FAIL [smoke-pr-review-actions]: $CHANNEL missing"
29
- exit 1
30
- fi
31
- if [ ! -x "$POSTER" ]; then
32
- echo "FAIL [smoke-pr-review-actions]: $POSTER missing or not executable"
33
- FAIL=$((FAIL + 1))
34
- fi
35
-
36
- # 2. Legacy monolith artifacts must not exist or be referenced.
37
- LEGACY_TEMPLATE="multi-agent-refs/channels/pr-review-comment.md"
38
- LEGACY_RENDERER="lib/render-pr-review-body.sh"
39
- if [ -e "$LEGACY_TEMPLATE" ]; then
40
- echo "FAIL [smoke-pr-review-actions]: $LEGACY_TEMPLATE must not exist (monolith comment template forbidden)"
41
- FAIL=$((FAIL + 1))
42
- fi
43
- if [ -e "$LEGACY_RENDERER" ]; then
44
- echo "FAIL [smoke-pr-review-actions]: $LEGACY_RENDERER must not exist (monolith comment renderer forbidden)"
45
- FAIL=$((FAIL + 1))
46
- fi
47
- # Reference scan - no spec files should still WIRE the legacy artifacts.
48
- # Match only call-site patterns (bash <path>, --body-file <path>), NOT prose
49
- # references. Migration notes like "render-pr-review-body.sh is GONE" are
50
- # allowed; an actual `bash render-pr-review-body.sh` call is not.
51
- LEAK=$(grep -rEl '(bash|sh|source) [^ ]*render-pr-review-body\.sh|--body-file [^ ]*pr-review-comment\.md' \
52
- commands/ lib/ scripts/ 2>/dev/null \
53
- | grep -v "$(basename "$0")" \
54
- | grep -v "CHANGELOG\." \
55
- | head -1 || true)
56
- if [ -n "$LEAK" ]; then
57
- echo "FAIL [smoke-pr-review-actions]: stale call-site to legacy artifact in: $LEAK"
58
- FAIL=$((FAIL + 1))
59
- fi
60
-
61
- # 3. Decision rule is documented verbatim in the channel doc.
62
- declare -a DECISION_ANCHORS=(
63
- "0 accepted blocking AND 0 accepted important"
64
- "≥1 accepted blocking OR ≥1 accepted important"
65
- "Suggestions never block"
66
- "APPROVE"
67
- "NEEDS_WORK"
68
- )
69
- for a in "${DECISION_ANCHORS[@]}"; do
70
- if ! grep -qF "$a" "$CHANNEL" "$REVIEW"; then
71
- echo "FAIL [smoke-pr-review-actions]: decision rule anchor missing across $CHANNEL + $REVIEW: $a"
72
- FAIL=$((FAIL + 1))
73
- fi
74
- done
75
-
76
- # 4. Both languages render - the template documents tr + en shapes.
77
- if ! grep -qE 'outputLanguage *= *"tr"|Turkish \(outputLanguage' "$CHANNEL"; then
78
- echo "FAIL [smoke-pr-review-actions]: $CHANNEL must document the tr inline-comment shape"
79
- FAIL=$((FAIL + 1))
80
- fi
81
- if ! grep -qE 'outputLanguage *= *"en"|English \(outputLanguage' "$CHANNEL"; then
82
- echo "FAIL [smoke-pr-review-actions]: $CHANNEL must document the en inline-comment shape"
83
- FAIL=$((FAIL + 1))
84
- fi
85
-
86
- # 5. Provider switch covers github + bitbucket-server explicitly.
87
- declare -a PROVIDER_HINTS=(
88
- "github"
89
- "bitbucket-server"
90
- )
91
- for p in "${PROVIDER_HINTS[@]}"; do
92
- if ! grep -qF "$p" "$REVIEW" "$CHANNEL" "$POSTER"; then
93
- echo "FAIL [smoke-pr-review-actions]: provider '$p' missing across review.md + channel + poster"
94
- FAIL=$((FAIL + 1))
95
- fi
96
- done
97
-
98
- # 6. review.md wires post-pr-review.sh and references the new channel doc.
99
- if ! grep -qF "post-pr-review.sh" "$REVIEW"; then
100
- echo "FAIL [smoke-pr-review-actions]: $REVIEW must wire post-pr-review.sh"
101
- FAIL=$((FAIL + 1))
102
- fi
103
- if ! grep -qF "refs/channels/pr-review-actions.md" "$REVIEW"; then
104
- echo "FAIL [smoke-pr-review-actions]: $REVIEW must reference refs/channels/pr-review-actions.md"
105
- FAIL=$((FAIL + 1))
106
- fi
107
-
108
- # 7. post-pr-review.sh enforces the decision rule and the language axis.
109
- if ! grep -qF "outputLanguage" "$POSTER"; then
110
- echo "FAIL [smoke-pr-review-actions]: $POSTER must read prefs.global.outputLanguage"
111
- FAIL=$((FAIL + 1))
112
- fi
113
- if ! grep -qE 'DECISION=approve|DECISION=needs_work' "$POSTER"; then
114
- echo "FAIL [smoke-pr-review-actions]: $POSTER must compute DECISION=approve|needs_work"
115
- FAIL=$((FAIL + 1))
116
- fi
117
- if ! grep -qE '"status":"APPROVED"' "$POSTER"; then
118
- echo "FAIL [smoke-pr-review-actions]: $POSTER must include the Bitbucket APPROVED participant payload"
119
- FAIL=$((FAIL + 1))
120
- fi
121
- if ! grep -qE '"status":"NEEDS_WORK"' "$POSTER"; then
122
- echo "FAIL [smoke-pr-review-actions]: $POSTER must include the Bitbucket NEEDS_WORK participant payload"
123
- FAIL=$((FAIL + 1))
124
- fi
125
-
126
- # 8. No suggestion severity ever posts inline (hard prohibition in template).
127
- if ! grep -qE 'No suggestion-severity inline comments|Suggestions are chat-only|never get inline comments by default' "$CHANNEL"; then
128
- echo "FAIL [smoke-pr-review-actions]: $CHANNEL must declare suggestions are chat-only (never inline)"
129
- FAIL=$((FAIL + 1))
130
- fi
131
- if grep -qE 'severity.*suggestion.*inline' "$POSTER"; then
132
- echo "FAIL [smoke-pr-review-actions]: $POSTER must NOT post suggestion-severity findings inline"
133
- FAIL=$((FAIL + 1))
134
- fi
135
-
136
- # 9. Bitbucket URL parser is wired into review.md Step 1.
137
- if ! grep -qE 'bitbucket\.\*/projects/\*/repos/\*/pull-requests/\*' "$REVIEW"; then
138
- echo "FAIL [smoke-pr-review-actions]: $REVIEW must parse bitbucket.* PR URLs in Step 1"
139
- FAIL=$((FAIL + 1))
140
- fi
141
- if ! grep -qF "bbProjectKey" "$REVIEW"; then
142
- echo "FAIL [smoke-pr-review-actions]: $REVIEW must persist bbProjectKey in agent-state.review.input"
143
- FAIL=$((FAIL + 1))
144
- fi
145
-
146
- if [ "$FAIL" -gt 0 ]; then
147
- echo ""
148
- echo "smoke-pr-review-actions: $FAIL violation(s)."
149
- exit 1
150
- fi
151
-
152
- echo "smoke-pr-review-actions: ok"
@@ -1,170 +0,0 @@
1
- #!/usr/bin/env bash
2
- # smoke-pre-commit.sh - verify pre-commit-check.sh catches all secret patterns.
3
- # Uses a real temp git repo to test the actual hook behavior end-to-end.
4
- # No mocks, no test-only flags - tests exactly what runs in production.
5
-
6
- set -uo pipefail
7
-
8
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
9
- HOOK="$SCRIPT_DIR/pre-commit-check.sh"
10
-
11
- if [ ! -f "$HOOK" ]; then
12
- echo "FAIL: pre-commit-check.sh not found at $HOOK" >&2
13
- exit 1
14
- fi
15
-
16
- PASS=0
17
- FAIL=0
18
-
19
- pass() { PASS=$((PASS+1)); echo " ✓ $1"; }
20
- fail() { FAIL=$((FAIL+1)); echo " ✗ $1"; }
21
-
22
- TMPDIR=$(mktemp -d) || { echo "FAIL: mktemp" >&2; exit 1; }
23
- trap 'rm -rf "$TMPDIR"' EXIT
24
-
25
- # Bootstrap a real git repo with an initial commit
26
- git -C "$TMPDIR" init -q
27
- git -C "$TMPDIR" config user.email "test@test.com"
28
- git -C "$TMPDIR" config user.name "Test"
29
- echo "init" > "$TMPDIR/init.txt"
30
- git -C "$TMPDIR" add init.txt
31
- git -C "$TMPDIR" commit -q -m "init"
32
-
33
- # Stage a file with content and run the hook inside the temp repo
34
- stage_and_check() {
35
- local filename="$1" content="$2"
36
- echo "$content" > "$TMPDIR/$filename"
37
- git -C "$TMPDIR" add "$filename"
38
- }
39
-
40
- reset_stage() {
41
- git -C "$TMPDIR" reset -q HEAD -- . 2>/dev/null
42
- git -C "$TMPDIR" checkout -q -- . 2>/dev/null
43
- rm -f "$TMPDIR"/test-* "$TMPDIR"/.env* 2>/dev/null
44
- }
45
-
46
- run_hook() {
47
- (cd "$TMPDIR" && bash "$HOOK") >/dev/null 2>&1
48
- return $?
49
- }
50
-
51
- check_detects() {
52
- local desc="$1" filename="$2" content="$3"
53
- reset_stage
54
- stage_and_check "$filename" "$content"
55
- if run_hook; then
56
- fail "$desc (hook passed, expected block)"
57
- else
58
- pass "$desc"
59
- fi
60
- }
61
-
62
- check_passes() {
63
- local desc="$1" filename="$2" content="$3"
64
- reset_stage
65
- stage_and_check "$filename" "$content"
66
- if run_hook; then
67
- pass "$desc"
68
- else
69
- fail "$desc (hook blocked, expected pass)"
70
- fi
71
- }
72
-
73
- echo "→ 1. Secret pattern detection"
74
-
75
- check_detects "API key (api_key=long_string)" \
76
- "test-file.swift" \
77
- 'let api_key = "ghp_aBcDeFgHiJkLmNoPqRsT1234567890"'
78
-
79
- check_detects "AWS access key (AKIA prefix)" \
80
- "test-file.py" \
81
- 'aws_key = "AKIAIOSFODNN7EXAMPLE"'
82
-
83
- check_detects "RSA private key header" \
84
- "test-file.pem" \
85
- '-----BEGIN RSA PRIVATE KEY-----'
86
-
87
- check_detects "Generic private key header" \
88
- "test-file.key" \
89
- '-----BEGIN PRIVATE KEY-----'
90
-
91
- check_detects "EC private key header" \
92
- "test-file.key" \
93
- '-----BEGIN EC PRIVATE KEY-----'
94
-
95
- check_detects "GCP service account JSON" \
96
- "test-file.json" \
97
- '{"type": "service_account", "project_id": "my-project"}'
98
-
99
- check_detects "GitHub PAT (ghp_ 36 chars)" \
100
- "test-file.txt" \
101
- 'token: ghp_aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789'
102
-
103
- check_detects "Slack token (xoxb-)" \
104
- "test-file.txt" \
105
- 'slack = "xoxb-123456789012-abcdefghijklmnop"'
106
-
107
- check_detects "Google API key (AIza)" \
108
- "test-file.txt" \
109
- 'gmaps = "AIzaSyA1234567890abcdefghijklmnopqrstuv"'
110
-
111
- check_detects "JWT three-segment token" \
112
- "test-file.txt" \
113
- 'auth = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N"'
114
-
115
- check_detects "High-entropy custom secret (no known prefix)" \
116
- "test-file.txt" \
117
- 'session = "Zx9Kq2Lm7Pw4Nv8Rt3Yb6Hc1Df5Gj0Sa2Wd7Qe4Uo9Ik"'
118
-
119
- check_detects "Secret in a filename WITH SPACES (no false-negative)" \
120
- "test secret file.txt" \
121
- 'token: ghp_aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789'
122
-
123
- echo ""
124
- echo "→ 2. File-name based detection"
125
-
126
- check_detects ".env file blocked by name" \
127
- ".env" \
128
- "DATABASE_URL=postgres://localhost/db"
129
-
130
- check_detects ".env.local blocked by name" \
131
- ".env.local" \
132
- "SECRET=foo"
133
-
134
- check_detects "Credentials JSON blocked by name" \
135
- "credentials.json" \
136
- '{"user": "admin"}'
137
-
138
- echo ""
139
- echo "→ 3. Clean files pass"
140
-
141
- check_passes "Normal Swift code" \
142
- "test-file.swift" \
143
- 'import Foundation
144
- let greeting = "Hello, World!"
145
- func add(_ a: Int, _ b: Int) -> Int { a + b }'
146
-
147
- check_passes "Empty file" \
148
- "test-file.txt" \
149
- ""
150
-
151
- check_passes "Git SHA / hex hash is not flagged as high-entropy" \
152
- "test-file.txt" \
153
- 'commit a1b2c3d4e5f6789012345678901234567890abcd resolved'
154
-
155
- check_passes "Lockfile integrity hash is exempt" \
156
- "test-yarn.lock" \
157
- 'resolved "https://r.npm/x" integrity sha512-Zx9Kq2Lm7Pw4Nv8Rt3Yb6Hc1Df5Gj0Sa2Wd7Qe4Uo9IkLp=='
158
-
159
- echo ""
160
- echo "→ 4. No staged files = clean exit"
161
- reset_stage
162
- if run_hook; then
163
- pass "No staged files exits 0"
164
- else
165
- fail "No staged files exits 0"
166
- fi
167
-
168
- echo ""
169
- echo "══ pre-commit smoke: $PASS passed, $FAIL failed ══"
170
- [ "$FAIL" -eq 0 ]
@@ -1,226 +0,0 @@
1
- #!/usr/bin/env bash
2
- # smoke-pref-migration.sh - exercises migrate-prefs.mjs against representative
3
- # v2.0.0 and pre-2.0.0 fixtures, asserts the output is v2.1.0-shaped.
4
- #
5
- # Fixtures are synthesized inline (no external files) to keep the test self-contained.
6
- # Run after any change to migrate-prefs.mjs or prefs.schema.json.
7
-
8
- set -uo pipefail
9
-
10
- HERE="$(cd "$(dirname "$0")" && pwd)"
11
- MIGRATE="$HERE/migrate-prefs.mjs"
12
- TMP="$(mktemp -d -t ma-smoke-migration-XXXX)"
13
- trap 'rm -rf "$TMP"' EXIT
14
-
15
- PASS=0
16
- FAIL=0
17
- pass() { PASS=$((PASS + 1)); echo " ✓ $1"; }
18
- fail() { FAIL=$((FAIL + 1)); echo " ✗ $1"; }
19
-
20
- if [ ! -f "$MIGRATE" ]; then
21
- fail "migrate-prefs.mjs not found at $MIGRATE"
22
- echo "══ pref-migration smoke: aborted ══"
23
- exit 2
24
- fi
25
-
26
- # Helper: write fixture to $TMP/<name>.json, run migration, read back
27
- run_fixture() {
28
- local name="$1"
29
- local content="$2"
30
- local file="$TMP/$name.json"
31
- printf '%s' "$content" > "$file"
32
- node "$MIGRATE" --file "$file" >/dev/null 2>&1
33
- cat "$file"
34
- }
35
-
36
- assert_json_has() {
37
- local name="$1"
38
- local json="$2"
39
- local path="$3" # e.g. .schemaVersion or .global.identities
40
- local expected="$4"
41
- local actual
42
- actual=$(echo "$json" | node -e "
43
- const j = JSON.parse(require('fs').readFileSync(0, 'utf8'));
44
- const p = '$path'.split('.').filter(Boolean);
45
- let v = j; for (const k of p) v = v?.[k];
46
- if (Array.isArray(v)) console.log('array:' + v.length);
47
- else if (typeof v === 'object' && v !== null) console.log('object:' + Object.keys(v).length);
48
- else console.log(String(v));
49
- " 2>/dev/null)
50
- if [ "$actual" = "$expected" ]; then
51
- pass "$name: $path == $expected"
52
- else
53
- fail "$name: $path expected '$expected', got '$actual'"
54
- fi
55
- }
56
-
57
- # ──────────────────────────────────────────────────────────────────────────
58
- echo "→ Fixture 1: v2.0.0 with gitIdentities (legacy)"
59
- F1=$(run_fixture "f1-v2.0.0-legacy" '{
60
- "schemaVersion": "2.0.0",
61
- "global": {
62
- "gitIdentities": [{"name": "Test User", "email": "test@example.com"}],
63
- "keychainMapping": {"jira": "user_Jira_Access_Token"}
64
- },
65
- "projects": {}
66
- }')
67
- assert_json_has "f1" "$F1" ".schemaVersion" "2.4.0"
68
- assert_json_has "f1" "$F1" ".global.identities" "array:1"
69
- assert_json_has "f1" "$F1" ".global.gitIdentities" "undefined"
70
- assert_json_has "f1" "$F1" ".global.settings" "object:8"
71
- assert_json_has "f1" "$F1" ".global.keychainMapping" "object:10"
72
- assert_json_has "f1" "$F1" ".global.platformIdentityRouting" "object:0"
73
- assert_json_has "f1" "$F1" ".global.recentGroups" "array:0"
74
- assert_json_has "f1" "$F1" ".global.recentAccounts" "array:0"
75
- assert_json_has "f1" "$F1" ".global.accounts" "array:0"
76
- assert_json_has "f1" "$F1" ".global.routines" "array:0"
77
-
78
- echo ""
79
- echo "→ Fixture 2: no schemaVersion (pre-2.0.0 fossil)"
80
- F2=$(run_fixture "f2-no-version" '{
81
- "global": {"gitIdentities": []},
82
- "projects": {}
83
- }')
84
- assert_json_has "f2" "$F2" ".schemaVersion" "2.4.0"
85
- assert_json_has "f2" "$F2" ".global.identities" "array:0"
86
-
87
- echo ""
88
- echo "→ Fixture 3: v2.4.0 already (no-op)"
89
- F3_FILE="$TMP/f3-v2.4.0.json"
90
- cat > "$F3_FILE" <<'EOF'
91
- {
92
- "schemaVersion": "2.4.0",
93
- "global": {
94
- "identities": [],
95
- "keychainMapping": {
96
- "jira": null, "bitbucket_token": null, "bitbucket_user": null,
97
- "github": null, "confluence": null, "figma": null,
98
- "figma_mcp": null, "fortify": null,
99
- "firebase": null, "jenkins": null
100
- },
101
- "platformIdentityRouting": {},
102
- "recentProjects": [],
103
- "recentBranches": {},
104
- "recentGroups": [],
105
- "serviceStatus": {},
106
- "settings": {
107
- "branchTtlDays": 15, "pushRetryMax": 5, "buildRetryMax": 3,
108
- "serviceStatusCacheSeconds": 300, "repoScanDays": 90,
109
- "identityRoutingEnabled": false, "multiRepoEnabled": false,
110
- "pushMustSucceed": true
111
- },
112
- "triageCrossCheck": {
113
- "enabled": false, "samplePct": 10, "model": "sonnet", "blockOnDisagreement": false
114
- },
115
- "promptLanguage": "en",
116
- "reportChannels": {"pr": true, "jira": true, "confluence": false, "wiki": false},
117
- "reportContent": {"normalAnalysis": true, "technicalAnalysis": false, "testScenarios": true, "autoDiff": false, "manualNote": false},
118
- "wikiScope": ["main", "ios", "screenshots", "index"],
119
- "autopilotReportTimeoutSeconds": 1800,
120
- "recentAccounts": [],
121
- "accounts": [],
122
- "routines": []
123
- },
124
- "projects": {}
125
- }
126
- EOF
127
- # Hash before
128
- BEFORE=$(shasum -a 256 "$F3_FILE" | awk '{print $1}')
129
- node "$MIGRATE" --file "$F3_FILE" >/dev/null 2>&1
130
- AFTER=$(shasum -a 256 "$F3_FILE" | awk '{print $1}')
131
- if [ "$BEFORE" = "$AFTER" ]; then
132
- pass "f3: idempotent (v2.3.0 unchanged by re-run)"
133
- else
134
- fail "f3: v2.3.0 file mutated by re-run (hash changed)"
135
- fi
136
-
137
- echo ""
138
- echo "→ Fixture 4: obsolete fields pruned"
139
- F4=$(run_fixture "f4-obsolete" '{
140
- "global": {
141
- "defaultPriority": "Medium",
142
- "defaultIssueType": "Story",
143
- "gitIdentities": []
144
- },
145
- "projects": {}
146
- }')
147
- assert_json_has "f4" "$F4" ".global.defaultPriority" "undefined"
148
- assert_json_has "f4" "$F4" ".global.defaultIssueType" "undefined"
149
-
150
- echo ""
151
- echo "→ Fixture 5: keychainMapping values preserved"
152
- F5=$(run_fixture "f5-km-preserve" '{
153
- "global": {
154
- "gitIdentities": [],
155
- "keychainMapping": {
156
- "jira": "user_Jira_Access_Token",
157
- "github": "user_Github_Access_Token"
158
- }
159
- },
160
- "projects": {}
161
- }')
162
- # Parse and inspect specific keychain values
163
- JIRA_VAL=$(echo "$F5" | node -e "const j=JSON.parse(require('fs').readFileSync(0,'utf8')); console.log(j.global.keychainMapping.jira)")
164
- if [ "$JIRA_VAL" = "user_Jira_Access_Token" ]; then
165
- pass "f5: existing keychainMapping.jira value preserved"
166
- else
167
- fail "f5: keychainMapping.jira lost or changed: got '$JIRA_VAL'"
168
- fi
169
-
170
- echo ""
171
- echo "→ Fixture 6: v2.1.0 firebase_sa + firebase_project → firebase (consolidation)"
172
- F6=$(run_fixture "f6-firebase-consolidate" '{
173
- "schemaVersion": "2.1.0",
174
- "global": {
175
- "identities": [{
176
- "name": "corporate",
177
- "email": "x@y.com",
178
- "servicePatMap": {
179
- "firebase_sa": "user_Firebase_Access_Json",
180
- "firebase_project": "user_Firebase_Project_Id"
181
- }
182
- }],
183
- "keychainMapping": {
184
- "jira": null, "bitbucket_token": null, "bitbucket_user": null,
185
- "github": null, "confluence": null, "figma_pat": "user_Figma_Access_Token",
186
- "figma_user": "user_figma_email", "figma_mcp": null, "fortify": null,
187
- "firebase_sa": "user_Firebase_Access_Json",
188
- "firebase_project": "user_Firebase_Project_Id",
189
- "jenkins": null
190
- },
191
- "platformIdentityRouting": {},
192
- "recentProjects": [], "recentBranches": {}, "recentGroups": [],
193
- "serviceStatus": {},
194
- "settings": {
195
- "branchTtlDays": 15, "pushRetryMax": 5, "buildRetryMax": 3,
196
- "serviceStatusCacheSeconds": 300, "repoScanDays": 90,
197
- "identityRoutingEnabled": false, "multiRepoEnabled": false,
198
- "pushMustSucceed": true
199
- }
200
- },
201
- "projects": {}
202
- }')
203
- # keychainMapping.firebase_sa must be gone, firebase_project must be gone, firebase must carry the old firebase_sa value
204
- FB_SA=$(echo "$F6" | node -e "const j=JSON.parse(require('fs').readFileSync(0,'utf8')); console.log(j.global.keychainMapping.firebase_sa === undefined ? 'absent' : 'present')")
205
- FB_PROJ=$(echo "$F6" | node -e "const j=JSON.parse(require('fs').readFileSync(0,'utf8')); console.log(j.global.keychainMapping.firebase_project === undefined ? 'absent' : 'present')")
206
- FB=$(echo "$F6" | node -e "const j=JSON.parse(require('fs').readFileSync(0,'utf8')); console.log(j.global.keychainMapping.firebase)")
207
- SPM_SA=$(echo "$F6" | node -e "const j=JSON.parse(require('fs').readFileSync(0,'utf8')); console.log(j.global.identities[0].servicePatMap.firebase_sa === undefined ? 'absent' : 'present')")
208
- SPM_PROJ=$(echo "$F6" | node -e "const j=JSON.parse(require('fs').readFileSync(0,'utf8')); console.log(j.global.identities[0].servicePatMap.firebase_project === undefined ? 'absent' : 'present')")
209
- SPM_FB=$(echo "$F6" | node -e "const j=JSON.parse(require('fs').readFileSync(0,'utf8')); console.log(j.global.identities[0].servicePatMap.firebase)")
210
- [ "$FB_SA" = "absent" ] && pass "f6: keychainMapping.firebase_sa removed" || fail "f6: keychainMapping.firebase_sa still present"
211
- [ "$FB_PROJ" = "absent" ] && pass "f6: keychainMapping.firebase_project removed" || fail "f6: keychainMapping.firebase_project still present"
212
- [ "$FB" = "user_Firebase_Access_Json" ] && pass "f6: keychainMapping.firebase carries old firebase_sa value" || fail "f6: keychainMapping.firebase wrong value: '$FB'"
213
- [ "$SPM_SA" = "absent" ] && pass "f6: servicePatMap.firebase_sa removed" || fail "f6: servicePatMap.firebase_sa still present"
214
- [ "$SPM_PROJ" = "absent" ] && pass "f6: servicePatMap.firebase_project removed" || fail "f6: servicePatMap.firebase_project still present"
215
- [ "$SPM_FB" = "user_Firebase_Access_Json" ] && pass "f6: servicePatMap.firebase carries old value" || fail "f6: servicePatMap.firebase wrong value: '$SPM_FB'"
216
- # figma consolidation: figma_pat → figma, figma_user removed
217
- FIG_PAT=$(echo "$F6" | node -e "const j=JSON.parse(require('fs').readFileSync(0,'utf8')); console.log(j.global.keychainMapping.figma_pat === undefined ? 'absent' : 'present')")
218
- FIG_USER=$(echo "$F6" | node -e "const j=JSON.parse(require('fs').readFileSync(0,'utf8')); console.log(j.global.keychainMapping.figma_user === undefined ? 'absent' : 'present')")
219
- FIG=$(echo "$F6" | node -e "const j=JSON.parse(require('fs').readFileSync(0,'utf8')); console.log(j.global.keychainMapping.figma)")
220
- [ "$FIG_PAT" = "absent" ] && pass "f6: keychainMapping.figma_pat removed" || fail "f6: keychainMapping.figma_pat still present"
221
- [ "$FIG_USER" = "absent" ] && pass "f6: keychainMapping.figma_user removed" || fail "f6: keychainMapping.figma_user still present"
222
- [ "$FIG" = "user_Figma_Access_Token" ] && pass "f6: keychainMapping.figma carries old figma_pat value" || fail "f6: keychainMapping.figma wrong value: '$FIG'"
223
-
224
- echo ""
225
- echo "══ pref-migration smoke: $PASS passed, $FAIL failed ══"
226
- [ "$FAIL" -eq 0 ]
@@ -1,134 +0,0 @@
1
- #!/usr/bin/env bash
2
- # smoke-prefs-language.sh - contract check for `/multi-agent language`.
3
- #
4
- # Does NOT touch the user's real $HOME/.claude/multi-agent-preferences.json.
5
- # Uses a throwaway tempfile + node shim that applies the documented write
6
- # rules (atomic rename, schema validation, enum check).
7
- #
8
- # Verifies:
9
- # 1. promptLanguage is part of the prefs schema and enum is {en, tr}.
10
- # 2. "en" and "tr" round-trip cleanly.
11
- # 3. Unknown values ("de", "xx") are rejected.
12
- # 4. Missing promptLanguage in prefs is valid (field is optional).
13
- # 5. Schema file is structurally valid.
14
-
15
- set -euo pipefail
16
-
17
- HERE="$(cd "$(dirname "$0")" && pwd)"
18
- ROOT="$(cd "$HERE/../.." && pwd)"
19
- SCHEMA="$ROOT/pipeline/schemas/prefs.schema.json"
20
- TMP="$(mktemp -d -t multi-agent-smoke-XXXX)"
21
- trap 'rm -rf "$TMP"' EXIT
22
-
23
- PASS=0
24
- FAIL=0
25
- pass() { PASS=$((PASS+1)); echo " ✓ $1"; }
26
- fail() { FAIL=$((FAIL+1)); echo " ✗ $1"; }
27
-
28
- need() { command -v "$1" >/dev/null 2>&1 || { echo "error: $1 is required" >&2; exit 127; }; }
29
- need node
30
- need jq
31
-
32
- [ -f "$SCHEMA" ] || { echo "error: schema not found at $SCHEMA" >&2; exit 1; }
33
-
34
- echo "→ schema declares promptLanguage with enum {en, tr}"
35
- ENUM_JSON=$(jq '.properties.global.properties.promptLanguage.enum' "$SCHEMA")
36
- if [ "$ENUM_JSON" = '[
37
- "en",
38
- "tr"
39
- ]' ] || [ "$(echo "$ENUM_JSON" | jq -c '.')" = '["en","tr"]' ]; then
40
- pass "promptLanguage.enum is exactly [en, tr]"
41
- else
42
- fail "promptLanguage.enum unexpected: $ENUM_JSON"
43
- fi
44
-
45
- DEFAULT=$(jq -r '.properties.global.properties.promptLanguage.default' "$SCHEMA")
46
- if [ "$DEFAULT" = "en" ]; then
47
- pass "default promptLanguage is 'en' (safe for open-source)"
48
- else
49
- fail "default promptLanguage is '$DEFAULT' (expected 'en')"
50
- fi
51
-
52
- echo ""
53
- echo "→ prefs with promptLanguage=en round-trips"
54
- cat > "$TMP/prefs-en.json" <<'EOF'
55
- {
56
- "schemaVersion": "2.0.0",
57
- "global": {
58
- "promptLanguage": "en"
59
- },
60
- "projects": {}
61
- }
62
- EOF
63
- node -e "
64
- const s = JSON.parse(require('fs').readFileSync('$TMP/prefs-en.json','utf-8'));
65
- if (s.global.promptLanguage !== 'en') process.exit(1);
66
- " && pass "en value parses" || fail "en value failed"
67
-
68
- echo ""
69
- echo "→ prefs with promptLanguage=tr round-trips"
70
- cat > "$TMP/prefs-tr.json" <<'EOF'
71
- {
72
- "schemaVersion": "2.0.0",
73
- "global": {
74
- "promptLanguage": "tr"
75
- },
76
- "projects": {}
77
- }
78
- EOF
79
- node -e "
80
- const s = JSON.parse(require('fs').readFileSync('$TMP/prefs-tr.json','utf-8'));
81
- if (s.global.promptLanguage !== 'tr') process.exit(1);
82
- " && pass "tr value parses" || fail "tr value failed"
83
-
84
- echo ""
85
- echo "→ unknown language 'de' is not in enum"
86
- if ! echo "$ENUM_JSON" | jq -e '. | index("de")' >/dev/null 2>&1; then
87
- pass "'de' correctly absent from enum"
88
- else
89
- fail "'de' should not be in enum yet"
90
- fi
91
-
92
- echo ""
93
- echo "→ prefs without promptLanguage is valid (optional field)"
94
- cat > "$TMP/prefs-missing.json" <<'EOF'
95
- {
96
- "schemaVersion": "2.0.0",
97
- "global": {},
98
- "projects": {}
99
- }
100
- EOF
101
- node -e "
102
- const s = JSON.parse(require('fs').readFileSync('$TMP/prefs-missing.json','utf-8'));
103
- if ('promptLanguage' in s.global) process.exit(1);
104
- " && pass "missing promptLanguage is tolerated" || fail "missing field check failed"
105
-
106
- echo ""
107
- echo "→ 5. triageCrossCheck schema is well-formed"
108
- TCC_DEFAULT=$(jq -r '.properties.global.properties.triageCrossCheck.properties.enabled.default' "$SCHEMA")
109
- [ "$TCC_DEFAULT" = "false" ] && pass "triageCrossCheck.enabled defaults to false (opt-in)" || fail "expected false, got $TCC_DEFAULT"
110
- TCC_PCT_DEFAULT=$(jq -r '.properties.global.properties.triageCrossCheck.properties.samplePct.default' "$SCHEMA")
111
- [ "$TCC_PCT_DEFAULT" = "10" ] && pass "samplePct defaults to 10" || fail "expected 10, got $TCC_PCT_DEFAULT"
112
- TCC_MODEL_ENUM=$(jq -c '.properties.global.properties.triageCrossCheck.properties.model.enum' "$SCHEMA")
113
- [ "$TCC_MODEL_ENUM" = '["sonnet"]' ] && pass "model enum locked to [sonnet]" || fail "expected [sonnet], got $TCC_MODEL_ENUM"
114
- TCC_PCT_MIN=$(jq -r '.properties.global.properties.triageCrossCheck.properties.samplePct.minimum' "$SCHEMA")
115
- TCC_PCT_MAX=$(jq -r '.properties.global.properties.triageCrossCheck.properties.samplePct.maximum' "$SCHEMA")
116
- [ "$TCC_PCT_MIN" = "1" ] && [ "$TCC_PCT_MAX" = "100" ] && pass "samplePct bounded [1,100]" || fail "samplePct bounds wrong"
117
-
118
- echo ""
119
- echo "→ setup.md documents Step 0 - Language Selection"
120
- SETUP_DOC="$ROOT/pipeline/commands/multi-agent/setup/SKILL.md"
121
- if [ -f "$SETUP_DOC" ] && grep -q "^### Step 0 - Language Selection" "$SETUP_DOC"; then
122
- pass "setup.md has Step 0 - Language Selection"
123
- else
124
- fail "setup.md missing Step 0 - Language Selection heading"
125
- fi
126
- if [ -f "$SETUP_DOC" ] && grep -q "promptLanguage" "$SETUP_DOC"; then
127
- pass "setup.md references promptLanguage"
128
- else
129
- fail "setup.md never mentions promptLanguage"
130
- fi
131
-
132
- echo ""
133
- echo "══ prefs-language smoke: $PASS passed, $FAIL failed ══"
134
- [ "$FAIL" -eq 0 ]