@mmerterden/multi-agent-pipeline 12.7.0 → 12.9.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 (247) hide show
  1. package/CHANGELOG.md +207 -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/features/review-multi-repo.md +65 -0
  13. package/pipeline/multi-agent-refs/features/url-enrichment.md +93 -0
  14. package/pipeline/multi-agent-refs/phases/operations.md +28 -0
  15. package/pipeline/multi-agent-refs/phases/phase-0-init.md +3 -83
  16. package/pipeline/multi-agent-refs/phases/phase-2-planning.md +1 -1
  17. package/pipeline/multi-agent-refs/phases/phase-3-dev.md +1 -2
  18. package/pipeline/multi-agent-refs/phases/phase-4-review.md +50 -62
  19. package/pipeline/schemas/prefs.schema.json +6 -0
  20. package/pipeline/scripts/_smoke-root.sh +61 -0
  21. package/pipeline/scripts/agent-guard.py +57 -3
  22. package/pipeline/scripts/audit-log.sh +25 -0
  23. package/pipeline/scripts/smoke-cross-cli-behavior.sh +21 -7
  24. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-1-analysis.json +0 -25
  25. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-2-plan.json +0 -30
  26. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-4-review.json +0 -20
  27. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-4-triage.json +0 -15
  28. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/metadata.json +0 -14
  29. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/task.json +0 -12
  30. package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-1-analysis.json +0 -29
  31. package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-2-plan.json +0 -43
  32. package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-4-review.json +0 -35
  33. package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-4-triage.json +0 -35
  34. package/pipeline/eval/golden-tasks/02-android-feature-compose/metadata.json +0 -14
  35. package/pipeline/eval/golden-tasks/02-android-feature-compose/task.json +0 -12
  36. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-1-analysis.json +0 -29
  37. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-2-plan.json +0 -42
  38. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-4-review.json +0 -20
  39. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-4-triage.json +0 -15
  40. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/metadata.json +0 -14
  41. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/task.json +0 -12
  42. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-1-analysis.json +0 -29
  43. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-2-plan.json +0 -40
  44. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-4-review.json +0 -20
  45. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-4-triage.json +0 -15
  46. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/metadata.json +0 -14
  47. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/task.json +0 -12
  48. package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-1-analysis.json +0 -29
  49. package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-2-plan.json +0 -42
  50. package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-4-review.json +0 -28
  51. package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-4-triage.json +0 -27
  52. package/pipeline/eval/golden-tasks/05-ios-security-keychain/metadata.json +0 -14
  53. package/pipeline/eval/golden-tasks/05-ios-security-keychain/task.json +0 -12
  54. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-1-analysis.json +0 -29
  55. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-2-plan.json +0 -41
  56. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-4-review.json +0 -12
  57. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-4-triage.json +0 -6
  58. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/metadata.json +0 -14
  59. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/task.json +0 -12
  60. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-1-analysis.json +0 -29
  61. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-2-plan.json +0 -42
  62. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-4-review.json +0 -28
  63. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-4-triage.json +0 -27
  64. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/metadata.json +0 -14
  65. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/task.json +0 -12
  66. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-1-analysis.json +0 -25
  67. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-2-plan.json +0 -31
  68. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-4-review.json +0 -12
  69. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-4-triage.json +0 -18
  70. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/metadata.json +0 -14
  71. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/task.json +0 -12
  72. package/pipeline/eval/golden-tasks/README.md +0 -65
  73. package/pipeline/eval/intent-cases.json +0 -40
  74. package/pipeline/eval/run-metrics-fixture.json +0 -93
  75. package/pipeline/eval/triage/01-empty-findings/expected.json +0 -6
  76. package/pipeline/eval/triage/01-empty-findings/input.json +0 -5
  77. package/pipeline/eval/triage/01-empty-findings/notes.md +0 -7
  78. package/pipeline/eval/triage/02-real-blocker/expected.json +0 -15
  79. package/pipeline/eval/triage/02-real-blocker/input.json +0 -14
  80. package/pipeline/eval/triage/02-real-blocker/notes.md +0 -7
  81. package/pipeline/eval/triage/03-out-of-scope-defer/expected.json +0 -18
  82. package/pipeline/eval/triage/03-out-of-scope-defer/input.json +0 -14
  83. package/pipeline/eval/triage/03-out-of-scope-defer/notes.md +0 -10
  84. package/pipeline/eval/triage/04-false-positive-reject/expected.json +0 -18
  85. package/pipeline/eval/triage/04-false-positive-reject/input.json +0 -14
  86. package/pipeline/eval/triage/04-false-positive-reject/notes.md +0 -10
  87. package/pipeline/eval/triage/05-mixed-classification/expected.json +0 -43
  88. package/pipeline/eval/triage/05-mixed-classification/input.json +0 -38
  89. package/pipeline/eval/triage/05-mixed-classification/notes.md +0 -17
  90. package/pipeline/eval/triage/06-severity-mismatch/expected.json +0 -15
  91. package/pipeline/eval/triage/06-severity-mismatch/input.json +0 -14
  92. package/pipeline/eval/triage/06-severity-mismatch/notes.md +0 -9
  93. package/pipeline/eval/triage/07-duplicate-reviewers/expected.json +0 -27
  94. package/pipeline/eval/triage/07-duplicate-reviewers/input.json +0 -22
  95. package/pipeline/eval/triage/07-duplicate-reviewers/notes.md +0 -9
  96. package/pipeline/eval/triage/08-style-misclassified/expected.json +0 -18
  97. package/pipeline/eval/triage/08-style-misclassified/input.json +0 -14
  98. package/pipeline/eval/triage/08-style-misclassified/notes.md +0 -9
  99. package/pipeline/eval/triage/09-cascading-finding/expected.json +0 -23
  100. package/pipeline/eval/triage/09-cascading-finding/input.json +0 -22
  101. package/pipeline/eval/triage/09-cascading-finding/notes.md +0 -9
  102. package/pipeline/eval/triage/10-deferred-crossref/expected.json +0 -18
  103. package/pipeline/eval/triage/10-deferred-crossref/input.json +0 -14
  104. package/pipeline/eval/triage/10-deferred-crossref/notes.md +0 -9
  105. package/pipeline/eval/triage/11-vercel-token-leak-blocker/expected.json +0 -27
  106. package/pipeline/eval/triage/11-vercel-token-leak-blocker/input.json +0 -22
  107. package/pipeline/eval/triage/11-vercel-token-leak-blocker/notes.md +0 -14
  108. package/pipeline/eval/triage/README.md +0 -54
  109. package/pipeline/scripts/benchmark-phase-0.sh +0 -128
  110. package/pipeline/scripts/check-md-links.mjs +0 -88
  111. package/pipeline/scripts/eval-golden-tasks-live.mjs +0 -302
  112. package/pipeline/scripts/eval-golden-tasks.mjs +0 -224
  113. package/pipeline/scripts/eval-intent.mjs +0 -107
  114. package/pipeline/scripts/eval-mine-corpus.mjs +0 -211
  115. package/pipeline/scripts/eval-triage.mjs +0 -171
  116. package/pipeline/scripts/fixtures/diff-risk-android.diff +0 -40
  117. package/pipeline/scripts/fixtures/diff-risk-ios.diff +0 -48
  118. package/pipeline/scripts/fixtures/diff-risk-test-removal.diff +0 -40
  119. package/pipeline/scripts/fixtures/install-layout.tsv +0 -19
  120. package/pipeline/scripts/fixtures/pack-expected-count.txt +0 -1
  121. package/pipeline/scripts/fixtures/test-gap-node.diff +0 -30
  122. package/pipeline/scripts/fixtures/test-gap-python.diff +0 -32
  123. package/pipeline/scripts/lint-mcp-refs.mjs +0 -218
  124. package/pipeline/scripts/lint-skills.mjs +0 -154
  125. package/pipeline/scripts/run-smokes.mjs +0 -130
  126. package/pipeline/scripts/scorecard.mjs +0 -258
  127. package/pipeline/scripts/smoke-add-detail.sh +0 -137
  128. package/pipeline/scripts/smoke-agent-guard.sh +0 -74
  129. package/pipeline/scripts/smoke-agent-log-cost.sh +0 -262
  130. package/pipeline/scripts/smoke-agent-model-routing.sh +0 -87
  131. package/pipeline/scripts/smoke-ask-choice.sh +0 -42
  132. package/pipeline/scripts/smoke-autopilot-circuit-breaker.sh +0 -36
  133. package/pipeline/scripts/smoke-bitbucket-contract.sh +0 -255
  134. package/pipeline/scripts/smoke-changelog-version.sh +0 -47
  135. package/pipeline/scripts/smoke-channels-approval-gate.sh +0 -60
  136. package/pipeline/scripts/smoke-channels-flow.sh +0 -130
  137. package/pipeline/scripts/smoke-ci-workflows.sh +0 -88
  138. package/pipeline/scripts/smoke-clarify.sh +0 -148
  139. package/pipeline/scripts/smoke-command-inventory.sh +0 -81
  140. package/pipeline/scripts/smoke-commands-skills-parity.sh +0 -87
  141. package/pipeline/scripts/smoke-community-gates.sh +0 -75
  142. package/pipeline/scripts/smoke-compliance-skills.sh +0 -119
  143. package/pipeline/scripts/smoke-config-hygiene.sh +0 -58
  144. package/pipeline/scripts/smoke-context-budget.sh +0 -72
  145. package/pipeline/scripts/smoke-cost-budget.sh +0 -70
  146. package/pipeline/scripts/smoke-cost-summary.sh +0 -139
  147. package/pipeline/scripts/smoke-cross-phase-cohesion.sh +0 -128
  148. package/pipeline/scripts/smoke-description-tr.sh +0 -82
  149. package/pipeline/scripts/smoke-dev-critic.sh +0 -144
  150. package/pipeline/scripts/smoke-diff-explain.sh +0 -147
  151. package/pipeline/scripts/smoke-diff-risk.sh +0 -190
  152. package/pipeline/scripts/smoke-dynamic-skill-loading.sh +0 -160
  153. package/pipeline/scripts/smoke-eval-live.sh +0 -136
  154. package/pipeline/scripts/smoke-evidence-gate.sh +0 -93
  155. package/pipeline/scripts/smoke-extract-conventions.sh +0 -163
  156. package/pipeline/scripts/smoke-fetchers-offline.sh +0 -448
  157. package/pipeline/scripts/smoke-figma-dispatch.sh +0 -112
  158. package/pipeline/scripts/smoke-gate-hooks.sh +0 -74
  159. package/pipeline/scripts/smoke-gc-tmp.sh +0 -130
  160. package/pipeline/scripts/smoke-gc-worktrees.sh +0 -125
  161. package/pipeline/scripts/smoke-generate-issue.sh +0 -120
  162. package/pipeline/scripts/smoke-handoff-contract.sh +0 -92
  163. package/pipeline/scripts/smoke-identity-isolation.sh +0 -70
  164. package/pipeline/scripts/smoke-install-layout.sh +0 -248
  165. package/pipeline/scripts/smoke-intent-guard.sh +0 -86
  166. package/pipeline/scripts/smoke-issue-comment-template.sh +0 -86
  167. package/pipeline/scripts/smoke-issue-jira-triad.sh +0 -120
  168. package/pipeline/scripts/smoke-keychain.sh +0 -158
  169. package/pipeline/scripts/smoke-language-axis.sh +0 -109
  170. package/pipeline/scripts/smoke-learning-curve.sh +0 -61
  171. package/pipeline/scripts/smoke-learnings-ledger.sh +0 -86
  172. package/pipeline/scripts/smoke-lib-scripts.sh +0 -448
  173. package/pipeline/scripts/smoke-mcp-gate.sh +0 -68
  174. package/pipeline/scripts/smoke-md-links.sh +0 -8
  175. package/pipeline/scripts/smoke-md2confluence.sh +0 -126
  176. package/pipeline/scripts/smoke-metrics-cache-ratio.sh +0 -72
  177. package/pipeline/scripts/smoke-migrate-state.sh +0 -102
  178. package/pipeline/scripts/smoke-mode-dispatch-drift.sh +0 -161
  179. package/pipeline/scripts/smoke-model-fallback.sh +0 -89
  180. package/pipeline/scripts/smoke-multi-repo-integration.sh +0 -116
  181. package/pipeline/scripts/smoke-multi-repo-worktree.sh +0 -61
  182. package/pipeline/scripts/smoke-no-mcp-in-dev-phases.sh +0 -194
  183. package/pipeline/scripts/smoke-no-token-prompt.sh +0 -85
  184. package/pipeline/scripts/smoke-own-punctuation.sh +0 -103
  185. package/pipeline/scripts/smoke-pack-contents.sh +0 -140
  186. package/pipeline/scripts/smoke-pat-audit.sh +0 -128
  187. package/pipeline/scripts/smoke-per-repo-memory.sh +0 -156
  188. package/pipeline/scripts/smoke-phase-0-multi-repo.sh +0 -170
  189. package/pipeline/scripts/smoke-phase-6-multi.sh +0 -79
  190. package/pipeline/scripts/smoke-phase-banner.sh +0 -101
  191. package/pipeline/scripts/smoke-phase-tracker.sh +0 -324
  192. package/pipeline/scripts/smoke-phase0-bridge-contract.sh +0 -241
  193. package/pipeline/scripts/smoke-phase4-gates.sh +0 -45
  194. package/pipeline/scripts/smoke-phase4-triage.sh +0 -229
  195. package/pipeline/scripts/smoke-plan-approval-gate.sh +0 -71
  196. package/pipeline/scripts/smoke-plan-safety.sh +0 -139
  197. package/pipeline/scripts/smoke-plan-todos.sh +0 -196
  198. package/pipeline/scripts/smoke-pr-review-actions.sh +0 -152
  199. package/pipeline/scripts/smoke-pre-commit.sh +0 -170
  200. package/pipeline/scripts/smoke-pref-migration.sh +0 -226
  201. package/pipeline/scripts/smoke-prefs-language.sh +0 -134
  202. package/pipeline/scripts/smoke-progress-contract.sh +0 -127
  203. package/pipeline/scripts/smoke-prune-logs.sh +0 -137
  204. package/pipeline/scripts/smoke-purge.sh +0 -138
  205. package/pipeline/scripts/smoke-push-retry.sh +0 -75
  206. package/pipeline/scripts/smoke-repo-map.sh +0 -300
  207. package/pipeline/scripts/smoke-review-readiness.sh +0 -92
  208. package/pipeline/scripts/smoke-review-watch.sh +0 -146
  209. package/pipeline/scripts/smoke-routines.sh +0 -84
  210. package/pipeline/scripts/smoke-run-aggregator.sh +0 -216
  211. package/pipeline/scripts/smoke-run-metrics.sh +0 -50
  212. package/pipeline/scripts/smoke-search.sh +0 -187
  213. package/pipeline/scripts/smoke-shadow-git.sh +0 -224
  214. package/pipeline/scripts/smoke-skill-authoring.sh +0 -137
  215. package/pipeline/scripts/smoke-skill-language.sh +0 -83
  216. package/pipeline/scripts/smoke-skill-manifest.sh +0 -138
  217. package/pipeline/scripts/smoke-skill-scan.sh +0 -198
  218. package/pipeline/scripts/smoke-source-parity.sh +0 -85
  219. package/pipeline/scripts/smoke-subagent-validators.sh +0 -108
  220. package/pipeline/scripts/smoke-sync-parity.sh +0 -92
  221. package/pipeline/scripts/smoke-tasklist-ordering.sh +0 -112
  222. package/pipeline/scripts/smoke-telemetry.sh +0 -147
  223. package/pipeline/scripts/smoke-test-gap.sh +0 -183
  224. package/pipeline/scripts/smoke-token-budget.sh +0 -67
  225. package/pipeline/scripts/smoke-token-preflight.sh +0 -82
  226. package/pipeline/scripts/smoke-tracker-contract.sh +0 -191
  227. package/pipeline/scripts/smoke-tracker-tokens-invocation.sh +0 -73
  228. package/pipeline/scripts/smoke-triage-memory.sh +0 -174
  229. package/pipeline/scripts/smoke-update-check.sh +0 -135
  230. package/pipeline/scripts/smoke-url-enrichment.sh +0 -70
  231. package/pipeline/scripts/smoke-validate-analysis-doc.sh +0 -161
  232. package/pipeline/scripts/smoke-validator-contradiction.sh +0 -67
  233. package/pipeline/scripts/smoke-validator-gates.sh +0 -164
  234. package/pipeline/scripts/smoke-vercel-deploy-redact.sh +0 -129
  235. package/pipeline/scripts/smoke-verify-by-test.sh +0 -148
  236. package/pipeline/scripts/smoke-wiki-integration.sh +0 -122
  237. package/pipeline/scripts/smoke-work-summary.sh +0 -163
  238. package/pipeline/scripts/smoke-workflow-audit.sh +0 -101
  239. package/pipeline/scripts/smoke-worktree-path-convention.sh +0 -86
  240. package/pipeline/scripts/smoke-wrapper-preservation.sh +0 -68
  241. package/pipeline/scripts/smoke-write-state.sh +0 -159
  242. package/pipeline/scripts/sync-parity-check.sh +0 -135
  243. package/pipeline/scripts/test-gap-rules/android.json +0 -25
  244. package/pipeline/scripts/test-gap-rules/ios.json +0 -34
  245. package/pipeline/scripts/test-gap-rules/node.json +0 -29
  246. package/pipeline/scripts/test-gap-rules/python.json +0 -25
  247. 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 ]