@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,448 +0,0 @@
1
- #!/usr/bin/env bash
2
- #
3
- # smoke-fetchers-offline.sh - offline invocation tests for the pipeline/lib
4
- # fetchers. No network, no real tokens.
5
- #
6
- # Asserts, per fetcher:
7
- # 1. usage / arg-validation paths exit with the documented code
8
- # 2. URL/host parsing succeeds for a representative URL. This is the
9
- # permanent regression guard for the env-prefix bug where
10
- # `VAR=x PARSED=$(python3 ...)` never exported VAR to the child, so
11
- # fetch-confluence always failed with "could not determine Confluence
12
- # host" before reaching the credential stage.
13
- # 3. with stub credentials (fake credential-store in a temp HOME, fake curl
14
- # on PATH) the failure moves past parsing to the documented
15
- # credential/network exit code
16
- # 4. static source checks: no bash-4-only constructs (macOS /bin/bash is
17
- # 3.2) and no secret-bearing argv patterns (curl -H auth headers,
18
- # --data-urlencode secrets, security add-generic-password -w on argv)
19
- #
20
- # Fetchers run under /bin/bash when available so bash-4-isms fail loudly on
21
- # macOS instead of passing under a newer Homebrew bash.
22
- #
23
- # Exit codes: 0=pass, 1=failure
24
-
25
- set -euo pipefail
26
-
27
- REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
28
- LIB="$REPO_ROOT/pipeline/lib"
29
- SCRIPTS="$REPO_ROOT/pipeline/scripts"
30
-
31
- # Prefer the system bash (3.2 on macOS) so bash-4-isms regress loudly here.
32
- SH="/bin/bash"
33
- [ -x "$SH" ] || SH="$(command -v bash)"
34
-
35
- PASS=0
36
- FAIL=0
37
- note() { echo " -> $*"; }
38
- pass() { echo " ok $*"; PASS=$((PASS + 1)); }
39
- fail() { echo " FAIL $*"; FAIL=$((FAIL + 1)); }
40
-
41
- WORK=$(mktemp -d "${TMPDIR:-/tmp}/smoke-fetchers.XXXXXX")
42
- trap 'rm -rf "$WORK"' EXIT
43
-
44
- OUT="$WORK/out.log"
45
- ERR="$WORK/err.log"
46
-
47
- # expect_rc <expected-rc> <label> <cmd...>
48
- # Runs cmd, captures stdout/stderr to $OUT/$ERR, asserts the exit code.
49
- expect_rc() {
50
- local expected="$1" label="$2"
51
- shift 2
52
- local rc=0
53
- "$@" >"$OUT" 2>"$ERR" || rc=$?
54
- if [ "$rc" -eq "$expected" ]; then
55
- pass "$label (rc=$rc)"
56
- else
57
- fail "$label (rc=$rc, expected $expected)"
58
- tail -5 "$ERR" | sed 's/^/ /'
59
- fi
60
- }
61
-
62
- assert_in_file() {
63
- local needle="$1" file="$2" label="$3"
64
- if grep -q -e "$needle" "$file" 2>/dev/null; then
65
- pass "$label"
66
- else
67
- fail "$label (pattern '$needle' not found)"
68
- fi
69
- }
70
-
71
- assert_not_in_file() {
72
- local needle="$1" file="$2" label="$3"
73
- if grep -q -e "$needle" "$file" 2>/dev/null; then
74
- fail "$label (pattern '$needle' present)"
75
- else
76
- pass "$label"
77
- fi
78
- }
79
-
80
- # -----------------------------------------------------------------------------
81
- note "0. fixtures: temp HOME with resolver + fake credential store, fake curls"
82
- # -----------------------------------------------------------------------------
83
- FAKE_HOME="$WORK/home"
84
- mkdir -p "$FAKE_HOME/.claude/lib"
85
- cp "$LIB/credential-store-resolver.sh" "$FAKE_HOME/.claude/lib/credential-store-resolver.sh"
86
-
87
- # Fake credential store: empty by default, returns FAKE_CRED_VALUE when set.
88
- cat > "$FAKE_HOME/.claude/lib/credential-store.sh" <<'FAKE'
89
- #!/bin/bash
90
- case "${1:-}" in
91
- get)
92
- if [ -n "${FAKE_CRED_VALUE:-}" ]; then printf '%s' "$FAKE_CRED_VALUE"; exit 0; fi
93
- exit 1 ;;
94
- platform) echo "fake" ;;
95
- *) exit 3 ;;
96
- esac
97
- FAKE
98
- chmod +x "$FAKE_HOME/.claude/lib/credential-store.sh"
99
-
100
- # Fake curl variants, each in its own PATH-prepend dir.
101
- BIN_CURL_FAIL="$WORK/bin-curl-fail"
102
- mkdir -p "$BIN_CURL_FAIL"
103
- cat > "$BIN_CURL_FAIL/curl" <<'FAKE'
104
- #!/bin/bash
105
- echo "curl: (7) offline stub - connection refused" >&2
106
- exit 7
107
- FAKE
108
- chmod +x "$BIN_CURL_FAIL/curl"
109
-
110
- # Swagger meta stub: honours --output, emits the --write-out triple with a
111
- # content type that matches neither json nor yaml, forcing the URL-suffix
112
- # lowercase path (the former bash-4 ${URL,,} site).
113
- BIN_CURL_META="$WORK/bin-curl-meta"
114
- mkdir -p "$BIN_CURL_META"
115
- cat > "$BIN_CURL_META/curl" <<'FAKE'
116
- #!/bin/bash
117
- out=""
118
- prev=""
119
- for a in "$@"; do
120
- if [ "$prev" = "--output" ]; then out="$a"; fi
121
- prev="$a"
122
- done
123
- if [ -n "$out" ]; then printf '{}' > "$out"; fi
124
- printf '200\napplication/octet-stream\n2\n'
125
- exit 0
126
- FAKE
127
- chmod +x "$BIN_CURL_META/curl"
128
-
129
- # 401 stub: honours -o, prints the HTTP code the way curl -w '%{http_code}' does.
130
- BIN_CURL_401="$WORK/bin-curl-401"
131
- mkdir -p "$BIN_CURL_401"
132
- cat > "$BIN_CURL_401/curl" <<'FAKE'
133
- #!/bin/bash
134
- out=""
135
- prev=""
136
- for a in "$@"; do
137
- if [ "$prev" = "-o" ] || [ "$prev" = "--output" ]; then out="$a"; fi
138
- prev="$a"
139
- done
140
- if [ -n "$out" ]; then printf '{}' > "$out"; fi
141
- printf '401'
142
- exit 0
143
- FAKE
144
- chmod +x "$BIN_CURL_401/curl"
145
-
146
- # Fake security + uname (forces the macOS branch of credential-store.sh) so
147
- # the no-secret-on-argv property of `security -i` writes can be asserted on
148
- # any platform without touching a real keychain.
149
- BIN_DARWIN="$WORK/bin-darwin"
150
- mkdir -p "$BIN_DARWIN"
151
- cat > "$BIN_DARWIN/uname" <<'FAKE'
152
- #!/bin/bash
153
- echo "Darwin"
154
- FAKE
155
- cat > "$BIN_DARWIN/security" <<'FAKE'
156
- #!/bin/bash
157
- printf '%s\n' "$*" >> "$SMOKE_CAPTURE_DIR/security-argv.log"
158
- if [ "${1:-}" = "-i" ]; then
159
- cat >> "$SMOKE_CAPTURE_DIR/security-stdin.log"
160
- fi
161
- exit 0
162
- FAKE
163
- chmod +x "$BIN_DARWIN/uname" "$BIN_DARWIN/security"
164
-
165
- # -----------------------------------------------------------------------------
166
- note "1. fetch-confluence.sh"
167
- # -----------------------------------------------------------------------------
168
- expect_rc 4 "no args exits 4 (usage)" \
169
- "$SH" "$LIB/fetch-confluence.sh"
170
- expect_rc 4 "--help exits 4 (usage)" \
171
- "$SH" "$LIB/fetch-confluence.sh" --help
172
-
173
- # Regression guard for the env-prefix parse bug: a plain page URL must get
174
- # past host/pageId resolution and fail at the credential stage (exit 2),
175
- # never with the parse error.
176
- expect_rc 2 "URL parse reaches credential stage (viewpage.action?pageId)" \
177
- env HOME="$FAKE_HOME" USER=smoke \
178
- "$SH" "$LIB/fetch-confluence.sh" \
179
- "https://confluence.example.com/pages/viewpage.action?pageId=12345"
180
- assert_in_file "missing-token" "$ERR" "blocked JSON names missing-token"
181
- assert_not_in_file "could not determine Confluence host" "$ERR" \
182
- "no host-parse error (env-prefix regression)"
183
-
184
- expect_rc 2 "URL parse reaches credential stage (cloud /wiki/spaces form)" \
185
- env HOME="$FAKE_HOME" USER=smoke \
186
- "$SH" "$LIB/fetch-confluence.sh" \
187
- "https://tenant.atlassian.net/wiki/spaces/ENG/pages/99887/Some+Page"
188
- assert_in_file "missing-token" "$ERR" "cloud form also blocked on token only"
189
-
190
- # With a stub token and a failing curl, the failure must be the documented
191
- # network error (3), proving parsing and auth wiring are past.
192
- expect_rc 3 "stub token + offline curl exits 3 (network stage)" \
193
- env HOME="$FAKE_HOME" USER=smoke FAKE_CRED_VALUE=fake-token \
194
- PATH="$BIN_CURL_FAIL:$PATH" \
195
- "$SH" "$LIB/fetch-confluence.sh" \
196
- "https://confluence.example.com/pages/viewpage.action?pageId=12345"
197
- assert_in_file "Confluence GET failed" "$ERR" "network-stage error message"
198
-
199
- # -----------------------------------------------------------------------------
200
- note "2. fetch-crashlytics.sh"
201
- # -----------------------------------------------------------------------------
202
- expect_rc 4 "no args exits 4 (usage)" \
203
- "$SH" "$LIB/fetch-crashlytics.sh"
204
- expect_rc 4 "--help exits 4 (usage)" \
205
- "$SH" "$LIB/fetch-crashlytics.sh" --help
206
-
207
- CRASH_URL="https://console.firebase.google.com/project/my-proj/crashlytics/app/ios:com.example.app/issues/abc123"
208
- expect_rc 2 "URL parse reaches credential stage" \
209
- env HOME="$FAKE_HOME" USER=smoke \
210
- "$SH" "$LIB/fetch-crashlytics.sh" "$CRASH_URL"
211
- assert_in_file "missing-token" "$ERR" "blocked JSON names missing-token"
212
-
213
- # Stub SA JSON whose project_id mismatches the URL: proves parse + credential
214
- # read + base64 decode + JSON validation all pass, fully offline (exit 5).
215
- MISMATCH_SA_B64=$(printf '{"project_id":"other-proj"}' | base64 | tr -d '\n')
216
- expect_rc 5 "stub SA JSON reaches project-mismatch check (exit 5)" \
217
- env HOME="$FAKE_HOME" USER=smoke FAKE_CRED_VALUE="$MISMATCH_SA_B64" \
218
- "$SH" "$LIB/fetch-crashlytics.sh" "$CRASH_URL"
219
- assert_in_file "project_id" "$ERR" "mismatch error mentions project_id"
220
-
221
- # The decoded SA JSON must never touch a predictable /tmp path.
222
- assert_not_in_file "/tmp/.fc-sa" "$LIB/fetch-crashlytics.sh" \
223
- "predictable /tmp SA path removed from source"
224
-
225
- # -----------------------------------------------------------------------------
226
- note "3. fetch-swagger.sh"
227
- # -----------------------------------------------------------------------------
228
- expect_rc 4 "no args exits 4 (usage)" \
229
- "$SH" "$LIB/fetch-swagger.sh"
230
-
231
- expect_rc 2 "offline curl exits 2 (network stage)" \
232
- env PATH="$BIN_CURL_FAIL:$PATH" \
233
- "$SH" "$LIB/fetch-swagger.sh" "https://spec.example.com/openapi.json"
234
-
235
- # Uppercase .YAML suffix with a non-matching content type exercises the
236
- # lowercase-URL branch (formerly bash-4 ${URL,,}, dies on /bin/bash 3.2).
237
- expect_rc 0 "uppercase .YAML suffix detected via lowercase branch" \
238
- env PATH="$BIN_CURL_META:$PATH" \
239
- "$SH" "$LIB/fetch-swagger.sh" "https://spec.example.com/openapi.YAML"
240
- assert_in_file '"format": "yaml"' "$OUT" "output reports yaml format"
241
-
242
- # -----------------------------------------------------------------------------
243
- note "4. fetch-fortify.sh"
244
- # -----------------------------------------------------------------------------
245
- expect_rc 6 "no host configured exits 6" \
246
- env HOME="$FAKE_HOME" USER=smoke \
247
- "$SH" "$LIB/fetch-fortify.sh" --version-id 123
248
- expect_rc 4 "host override + no version id exits 4 (usage)" \
249
- env HOME="$FAKE_HOME" USER=smoke FORTIFY_HOST_OVERRIDE=ssc.example.com \
250
- "$SH" "$LIB/fetch-fortify.sh"
251
-
252
- FORTIFY_URL="https://ssc.example.com/ssc/html/ssc/version/123/fix/ABCD-1"
253
- expect_rc 2 "URL parse reaches credential stage" \
254
- env HOME="$FAKE_HOME" USER=smoke FORTIFY_HOST_OVERRIDE=ssc.example.com \
255
- "$SH" "$LIB/fetch-fortify.sh" "$FORTIFY_URL"
256
- assert_in_file "missing-token" "$ERR" "blocked JSON names missing-token"
257
-
258
- expect_rc 0 "stub token + offline curl degrades to empty result (exit 0)" \
259
- env HOME="$FAKE_HOME" USER=smoke FORTIFY_HOST_OVERRIDE=ssc.example.com \
260
- FAKE_CRED_VALUE=fake-token PATH="$BIN_CURL_FAIL:$PATH" \
261
- "$SH" "$LIB/fetch-fortify.sh" "$FORTIFY_URL"
262
- assert_in_file '"gateOutcome"' "$OUT" "normalized JSON still emitted"
263
-
264
- # -----------------------------------------------------------------------------
265
- note "4b. fetch-graylog.sh"
266
- # -----------------------------------------------------------------------------
267
- expect_rc 6 "no host configured exits 6" \
268
- env HOME="$FAKE_HOME" USER=smoke \
269
- "$SH" "$LIB/fetch-graylog.sh" --trx T123
270
- expect_rc 4 "host override + no ids exits 4 (usage)" \
271
- env HOME="$FAKE_HOME" USER=smoke GRAYLOG_HOST_OVERRIDE=logs.example.com \
272
- "$SH" "$LIB/fetch-graylog.sh"
273
-
274
- expect_rc 2 "host override + id reaches credential stage" \
275
- env HOME="$FAKE_HOME" USER=smoke GRAYLOG_HOST_OVERRIDE=logs.example.com \
276
- "$SH" "$LIB/fetch-graylog.sh" --trx T123 --conv C456
277
- assert_in_file "missing-token" "$ERR" "blocked JSON names missing-token"
278
-
279
- # Non-blocking contract: with a stub token and a failing curl, the fetch must
280
- # degrade to an empty normalized result (messages present) and exit 0 so a log
281
- # fetch never blocks a run.
282
- expect_rc 0 "stub token + offline curl degrades to empty result (exit 0)" \
283
- env HOME="$FAKE_HOME" USER=smoke GRAYLOG_HOST_OVERRIDE=logs.example.com \
284
- FAKE_CRED_VALUE=fake-token PATH="$BIN_CURL_FAIL:$PATH" \
285
- "$SH" "$LIB/fetch-graylog.sh" --trx T123
286
- assert_in_file '"messages"' "$OUT" "normalized JSON still emitted"
287
-
288
- # -----------------------------------------------------------------------------
289
- note "5. figma-screenshot.sh"
290
- # -----------------------------------------------------------------------------
291
- expect_rc 1 "no args exits 1 (usage)" \
292
- "$SH" "$LIB/figma-screenshot.sh"
293
- expect_rc 0 "--help exits 0" \
294
- "$SH" "$LIB/figma-screenshot.sh" --help
295
-
296
- expect_rc 3 "no PAT resolvable exits 3 (Tier 3 required)" \
297
- env -u FIGMA_PAT HOME="$FAKE_HOME" USER=smoke \
298
- "$SH" "$LIB/figma-screenshot.sh" --file-key abc123 --node-id 1-2 \
299
- --output-dir "$WORK/shots-no-pat"
300
-
301
- expect_rc 2 "stub PAT + 401 curl exits 2 (auth stage, past parsing)" \
302
- env HOME="$FAKE_HOME" USER=smoke FIGMA_PAT=fake-pat \
303
- PATH="$BIN_CURL_401:$PATH" \
304
- "$SH" "$LIB/figma-screenshot.sh" --file-key abc123 --node-id 1-2 \
305
- --output-dir "$WORK/shots-401"
306
-
307
- # -----------------------------------------------------------------------------
308
- note "6. figma-mcp-refresh.sh"
309
- # -----------------------------------------------------------------------------
310
- expect_rc 2 "missing prefs exits 2" \
311
- env HOME="$FAKE_HOME" USER=smoke \
312
- "$SH" "$LIB/figma-mcp-refresh.sh"
313
-
314
- if command -v jq >/dev/null 2>&1; then
315
- PREFS_HOME="$WORK/home-prefs"
316
- mkdir -p "$PREFS_HOME/.claude"
317
- printf '{"global":{"keychainMapping":{"figma_mcp":"Smoke_Figma_MCP"}}}\n' \
318
- > "$PREFS_HOME/.claude/multi-agent-preferences.json"
319
- export SMOKE_CAPTURE_DIR="$WORK"
320
- expect_rc 2 "mapped key + empty keychain exits 2 (no refresh token)" \
321
- env HOME="$PREFS_HOME" USER=smoke SMOKE_CAPTURE_DIR="$WORK" \
322
- PATH="$BIN_DARWIN:$PATH" \
323
- "$SH" "$LIB/figma-mcp-refresh.sh"
324
- else
325
- note " (jq not installed - skipping mapped-key case)"
326
- fi
327
-
328
- # -----------------------------------------------------------------------------
329
- note "7. credential-store.sh + keychain-save.sh"
330
- # -----------------------------------------------------------------------------
331
- expect_rc 0 "platform subcommand works" \
332
- "$SH" "$LIB/credential-store.sh" platform
333
- expect_rc 3 "get without key exits 3 (usage)" \
334
- "$SH" "$LIB/credential-store.sh" get
335
- expect_rc 1 "keychain-save without service name exits 1 (usage)" \
336
- "$SH" "$SCRIPTS/keychain-save.sh"
337
-
338
- # set <key> - : the secret must travel via stdin to `security -i`, never on
339
- # the security argv. Fake uname forces the macOS branch; fake security logs
340
- # argv and stdin separately.
341
- rm -f "$WORK/security-argv.log" "$WORK/security-stdin.log"
342
- SECRET_VALUE="topsecret-smoke-value-123"
343
- rc=0
344
- printf '%s' "$SECRET_VALUE" \
345
- | env PATH="$BIN_DARWIN:$PATH" KEYCHAIN_DELEGATE=0 SMOKE_CAPTURE_DIR="$WORK" \
346
- "$SH" "$LIB/credential-store.sh" set smoke-test-key - >"$OUT" 2>"$ERR" || rc=$?
347
- if [ "$rc" -eq 0 ]; then
348
- pass "set <key> - via stdin succeeds (rc=0)"
349
- else
350
- fail "set <key> - via stdin failed (rc=$rc)"
351
- tail -5 "$ERR" | sed 's/^/ /'
352
- fi
353
- assert_in_file "^-i" "$WORK/security-argv.log" "security invoked in -i stdin mode"
354
- assert_not_in_file "$SECRET_VALUE" "$WORK/security-argv.log" "secret absent from security argv"
355
- assert_in_file "$SECRET_VALUE" "$WORK/security-stdin.log" "secret delivered via stdin"
356
-
357
- # -----------------------------------------------------------------------------
358
- note "7b. fetch-figma-annotations.sh (Tier-2 annotation ingestion)"
359
- # -----------------------------------------------------------------------------
360
- expect_rc 1 "no args exits 1 (usage)" \
361
- "$SH" "$LIB/fetch-figma-annotations.sh"
362
-
363
- # Missing token -> blocked JSON + exit 2 (no network).
364
- expect_rc 2 "missing token exits 2 with blocked JSON" \
365
- env HOME="$FAKE_HOME" USER=smoke \
366
- "$SH" "$LIB/fetch-figma-annotations.sh" --file-key ABC --node-id "1:23"
367
- assert_in_file "missing-token" "$OUT" "blocked JSON names missing-token"
368
-
369
- # Fake curl returns a /nodes doc carrying a TR:/EN: annotation; with a stub
370
- # token the parser must reach + parse it (regression guard for the parser).
371
- BIN_CURL_ANNOT="$WORK/bin-curl-annot"
372
- mkdir -p "$BIN_CURL_ANNOT"
373
- cat > "$BIN_CURL_ANNOT/curl" <<'FAKE'
374
- #!/bin/bash
375
- out=""; prev=""
376
- for a in "$@"; do
377
- [ "$prev" = "-o" ] && out="$a"
378
- prev="$a"
379
- done
380
- if [ -n "$out" ]; then
381
- cat > "$out" <<'JSON'
382
- {"nodes":{"1:23":{"document":{"id":"1:23","name":"Title","type":"TEXT","characters":"Giriniz","annotations":[{"label":"TR: Ucusunuzu secin\nEN: Select your flight"}]}}}}
383
- JSON
384
- fi
385
- printf '200'
386
- exit 0
387
- FAKE
388
- chmod +x "$BIN_CURL_ANNOT/curl"
389
-
390
- expect_rc 0 "stub token + annotation doc parses (exit 0)" \
391
- env HOME="$FAKE_HOME" USER=smoke FIGMA_PAT=fake-token \
392
- PATH="$BIN_CURL_ANNOT:$PATH" \
393
- "$SH" "$LIB/fetch-figma-annotations.sh" --file-key ABC --node-id "1:23" --lang-prefixes TR,EN
394
- assert_in_file "\"mode\": \"prefixed\"" "$OUT" "annotation parsed as prefixed"
395
- assert_in_file "Select your flight" "$OUT" "EN copy extracted from annotation"
396
-
397
- # -----------------------------------------------------------------------------
398
- note "8. static source checks (bash-3.2 compat + no secrets on argv)"
399
- # -----------------------------------------------------------------------------
400
- OWNED_FILES=(
401
- "$LIB/fetch-confluence.sh"
402
- "$LIB/fetch-crashlytics.sh"
403
- "$LIB/fetch-swagger.sh"
404
- "$LIB/fetch-fortify.sh"
405
- "$LIB/fetch-graylog.sh"
406
- "$LIB/fetch-figma-annotations.sh"
407
- "$LIB/figma-mcp-refresh.sh"
408
- "$LIB/figma-screenshot.sh"
409
- "$LIB/credential-store.sh"
410
- "$SCRIPTS/keychain-save.sh"
411
- )
412
-
413
- if grep -nE '\$\{[A-Za-z_0-9]+(,,|\^\^)|mapfile |readarray |declare -A' "${OWNED_FILES[@]}"; then
414
- fail "bash-4-only construct found (must run on /bin/bash 3.2)"
415
- else
416
- pass "no bash-4-only constructs"
417
- fi
418
-
419
- if grep -nE -- '-H "(Authorization|X-Figma-Token)' "${OWNED_FILES[@]}"; then
420
- fail "auth header passed to curl via argv (-H)"
421
- else
422
- pass "no auth headers on curl argv"
423
- fi
424
-
425
- if grep -nE -- '--data-urlencode "(refresh_token|client_secret)' "${OWNED_FILES[@]}"; then
426
- fail "OAuth secret passed to curl via argv (--data-urlencode)"
427
- else
428
- pass "no OAuth secrets on curl argv"
429
- fi
430
-
431
- if grep -nE 'add-generic-password[^|]*-w "\$' "${OWNED_FILES[@]}"; then
432
- fail "keychain secret passed to security via argv (-w)"
433
- else
434
- pass "no keychain secrets on security argv"
435
- fi
436
-
437
- # shellcheck disable=SC2016 # literal $HOME is the pattern being hunted
438
- if grep -nE '\$HOME/\.claude/lib/credential-store\.sh|~/\.claude/lib/credential-store\.sh' "${OWNED_FILES[@]}"; then
439
- fail "hardcoded credential-store path (must go through the resolver)"
440
- else
441
- pass "credential-store access routed through the resolver"
442
- fi
443
-
444
- # -----------------------------------------------------------------------------
445
- echo ""
446
- echo "smoke-fetchers-offline: $PASS passed, $FAIL failed"
447
- [ "$FAIL" -eq 0 ] || exit 1
448
- exit 0
@@ -1,112 +0,0 @@
1
- #!/usr/bin/env bash
2
- # smoke-figma-dispatch.sh - Phase 3 component dispatch contract (plugin-based).
3
- #
4
- # Verifies that multi-agent Phase 3 dispatches component tasks to the
5
- # ai-<platform>-engineering-toolkit MARKETPLACE PLUGIN (create-component,
6
- # fallback create-ui-component) instead of a bundled figma-to-component skill.
7
- #
8
- # Runs offline - scans docs only, no skill invocation.
9
-
10
- set -euo pipefail
11
-
12
- HERE="$(cd "$(dirname "$0")" && pwd)"
13
- ROOT="$(cd "$HERE/../.." && pwd)"
14
- PHASE0="$ROOT/pipeline/multi-agent-refs/phases/phase-0-init.md"
15
- PHASE3="$ROOT/pipeline/multi-agent-refs/phases/phase-3-dev.md"
16
- DISPATCH="$ROOT/pipeline/multi-agent-refs/component-dispatch.md"
17
-
18
- PASS=0
19
- FAIL=0
20
- pass() { PASS=$((PASS+1)); echo " ✓ $1"; }
21
- fail() { FAIL=$((FAIL+1)); echo " ✗ $1"; }
22
-
23
- [ -f "$PHASE0" ] || { echo "error: $PHASE0 missing" >&2; exit 1; }
24
- [ -f "$PHASE3" ] || { echo "error: $PHASE3 missing" >&2; exit 1; }
25
- [ -f "$DISPATCH" ] || { echo "error: $DISPATCH missing" >&2; exit 1; }
26
-
27
- echo "→ 1. no bundled figma orchestrator remains in the tree"
28
- if [ -e "$ROOT/pipeline/skills/figma-ios" ] || [ -e "$ROOT/pipeline/skills/figma-android" ] || [ -e "$ROOT/pipeline/skills/figma-common" ]; then
29
- fail "bundled pipeline/skills/figma-* tree still present (should be plugin-only)"
30
- else
31
- pass "no pipeline/skills/figma-* tree (component skills live in the plugin)"
32
- fi
33
-
34
- echo ""
35
- echo "→ 2. Phase 0 routes component tasks to the plugin component skill"
36
- if grep -Fq "create-component" "$PHASE0"; then
37
- pass "Phase 0 references the plugin create-component skill"
38
- else
39
- fail "Phase 0 does NOT reference create-component"
40
- fi
41
- if grep -Fq "figma-to-swiftui" "$PHASE0" || grep -Fq "skills/figma-ios/figma-to-component" "$PHASE0"; then
42
- fail "Phase 0 still references a legacy/bundled figma orchestrator path"
43
- else
44
- pass "Phase 0 has no legacy/bundled figma orchestrator reference"
45
- fi
46
-
47
- echo ""
48
- echo "→ 3. dispatch guards taskType and resolves the plugin (dual-name)"
49
- if grep -Fq 'taskType === "component"' "$DISPATCH"; then
50
- pass "dispatch mentions taskType guard"
51
- else
52
- fail "dispatch missing taskType guard"
53
- fi
54
- if grep -Fq "create-component" "$DISPATCH" && grep -Fq "create-ui-component" "$DISPATCH"; then
55
- pass "dispatch documents dual-name resolution (create-component / create-ui-component)"
56
- else
57
- fail "dispatch missing dual-name plugin resolution"
58
- fi
59
-
60
- echo ""
61
- echo "→ 4. dispatch layer owns subphase state + phase-tracker"
62
- if grep -Fq 'subphases[]' "$DISPATCH" && grep -Fq "phase-tracker" "$DISPATCH"; then
63
- pass "dispatch documents state.phases[3].subphases[] + phase-tracker"
64
- else
65
- fail "dispatch missing subphases[]/phase-tracker documentation"
66
- fi
67
-
68
- echo ""
69
- echo "→ 5. phase docs carry the progress-contract adoption marker"
70
- if grep -Fq "<!-- progress-contract: applied -->" "$PHASE3"; then
71
- pass "Phase 3 carries the adoption marker"
72
- else
73
- fail "Phase 3 missing the adoption marker"
74
- fi
75
- if grep -Fq "<!-- progress-contract: applied -->" "$PHASE0"; then
76
- pass "Phase 0 carries the adoption marker"
77
- else
78
- fail "Phase 0 missing the adoption marker"
79
- fi
80
-
81
- echo ""
82
- echo "→ 6. Phase 3 emits the plugin dispatch progress line"
83
- if grep -qE '→ dispatching create-component' "$PHASE3"; then
84
- pass "Phase 3 documents '→ dispatching create-component <name>' emission"
85
- else
86
- fail "Phase 3 missing dispatch progress line"
87
- fi
88
-
89
- echo ""
90
- echo "→ 7. dispatch has failure + retry semantics"
91
- if grep -Fq "retryCount" "$DISPATCH"; then
92
- pass "dispatch documents retryCount"
93
- else
94
- fail "dispatch missing retryCount documentation"
95
- fi
96
-
97
- echo ""
98
- echo "→ 8. dispatch covers multi-repo + intentional cross-CLI divergence"
99
- if grep -Fq 'state.projects[]' "$DISPATCH"; then
100
- pass "dispatch documents multi-repo report"
101
- else
102
- fail "dispatch missing multi-repo report paragraph"
103
- fi
104
- if grep -Fiq "Copilot" "$DISPATCH"; then
105
- pass "dispatch documents the Copilot cross-CLI divergence"
106
- else
107
- fail "dispatch missing cross-CLI divergence note"
108
- fi
109
-
110
- echo ""
111
- echo "══ figma-dispatch smoke: $PASS passed, $FAIL failed ══"
112
- [ "$FAIL" -eq 0 ]
@@ -1,74 +0,0 @@
1
- #!/usr/bin/env bash
2
- # smoke-gate-hooks.sh - the recommended Claude Code hooks template must be
3
- # valid JSON, wire the secret scan as a PreToolUse hook on git commit, and point
4
- # at the installed pre-commit-check.sh. This is the one gate that is OS-enforced
5
- # (a non-zero exit blocks the commit); the template is what makes it real for
6
- # end users instead of only the maintainer's local settings.
7
- #
8
- # Exit 0 = all pass, 1 = any failure.
9
-
10
- set -uo pipefail
11
-
12
- ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
13
- TMPL="$ROOT/install/templates/claude-hooks.json"
14
- PASS=0; FAIL=0
15
- pass() { PASS=$((PASS+1)); echo " ✓ $1"; }
16
- fail() { FAIL=$((FAIL+1)); echo " ✗ $1"; }
17
- command -v node >/dev/null 2>&1 || { echo "error: node required" >&2; exit 127; }
18
-
19
- [ -f "$TMPL" ] || { echo "FAIL: hooks template missing at $TMPL" >&2; exit 1; }
20
-
21
- # 1. valid JSON
22
- if node -e 'JSON.parse(require("fs").readFileSync(process.argv[1],"utf8"))' "$TMPL" 2>/dev/null; then
23
- pass "hooks template is valid JSON"
24
- else
25
- fail "hooks template is not valid JSON"
26
- fi
27
-
28
- # 2. wires a PreToolUse hook on git commit -> pre-commit-check.sh
29
- node -e '
30
- const t = JSON.parse(require("fs").readFileSync(process.argv[1],"utf8"));
31
- const pre = t.hooks && t.hooks.PreToolUse;
32
- if (!Array.isArray(pre) || pre.length === 0) { console.error("no PreToolUse"); process.exit(1); }
33
- const onCommit = pre.find(h => /git commit/.test(h.matcher || ""));
34
- if (!onCommit) { console.error("no git-commit matcher"); process.exit(1); }
35
- const cmds = (onCommit.hooks || []).map(h => h.command || "").join(" ");
36
- if (!/pre-commit-check\.sh/.test(cmds)) { console.error("does not call pre-commit-check.sh"); process.exit(1); }
37
- ' "$TMPL" 2>/dev/null && pass "template wires secret scan as PreToolUse on git commit" || fail "template does not wire the secret-scan hook"
38
-
39
- # 3. the referenced script exists in the source tree
40
- if [ -f "$ROOT/pipeline/scripts/pre-commit-check.sh" ]; then
41
- pass "pre-commit-check.sh exists to back the hook"
42
- else
43
- fail "pre-commit-check.sh missing"
44
- fi
45
-
46
- # 3b. template also wires agent-guard.sh on git commit AND git push
47
- node -e '
48
- const t = JSON.parse(require("fs").readFileSync(process.argv[1],"utf8"));
49
- const pre = (t.hooks && t.hooks.PreToolUse) || [];
50
- const commit = pre.find(h => /git commit/.test(h.matcher || ""));
51
- const push = pre.find(h => /git push/.test(h.matcher || ""));
52
- const cmds = e => (e && e.hooks || []).map(h => h.command || "").join(" ");
53
- if (!/agent-guard\.sh/.test(cmds(commit))) { console.error("guard not on git commit"); process.exit(1); }
54
- if (!/agent-guard\.sh/.test(cmds(push))) { console.error("guard not on git push"); process.exit(1); }
55
- ' "$TMPL" 2>/dev/null && pass "template wires agent-guard on git commit + git push" || fail "template does not wire agent-guard on both matchers"
56
-
57
- # 3c. the guard scripts exist in the source tree
58
- if [ -f "$ROOT/pipeline/scripts/agent-guard.sh" ] && [ -f "$ROOT/pipeline/scripts/agent-guard.py" ]; then
59
- pass "agent-guard.sh + agent-guard.py exist to back the hook"
60
- else
61
- fail "agent-guard scripts missing"
62
- fi
63
-
64
- # 4. picker-contract documents the hook template + the phase-enforced caveat
65
- PC="$ROOT/pipeline/multi-agent-refs/picker-contract.md"
66
- if grep -q "claude-hooks.json" "$PC" && grep -q "phase-enforced" "$PC"; then
67
- pass "picker-contract references the template + the phase-enforced gates caveat"
68
- else
69
- fail "picker-contract does not document the hooks template honestly"
70
- fi
71
-
72
- echo ""
73
- echo "══ gate-hooks smoke: $PASS passed, $FAIL failed ══"
74
- [ "$FAIL" -eq 0 ]