@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,300 +0,0 @@
1
- #!/usr/bin/env bash
2
- # smoke-repo-map.sh
3
- #
4
- # Verifies pipeline/scripts/repo-map.mjs:
5
- # 1. CLI parses --root, --budget, --top, --format, --include, --exclude
6
- # 2. Empty repo → empty output (exit 0, never crashes)
7
- # 3. Swift fixture extracts class/struct/protocol/func
8
- # 4. Kotlin fixture extracts class/fun
9
- # 5. TS fixture extracts exported class/function
10
- # 6. Python fixture extracts class/def
11
- # 7. Bash fixture extracts top-level functions
12
- # 8. TF-IDF rule: an identifier defined in many files does not dominate rank
13
- # 9. Token budget honored - output stops at budget
14
- # 10. Determinism - same input twice = byte-identical output
15
- # 11. JSON format emits valid JSON with score / declarations
16
- # 12. Word-boundary match: substring of an identifier is NOT counted
17
- #
18
- # Exit 0 = all pass, 1 = any failure.
19
-
20
- set -euo pipefail
21
-
22
- ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
23
- SCRIPT="$ROOT/pipeline/scripts/repo-map.mjs"
24
-
25
- pass=0
26
- fail=0
27
- failures=()
28
- record_pass() { pass=$((pass + 1)); printf ' \033[0;32mPASS\033[0m %s\n' "$1"; }
29
- record_fail() { fail=$((fail + 1)); failures+=("$1"); printf ' \033[0;31mFAIL\033[0m %s\n' "$1"; }
30
-
31
- printf '→ smoke-repo-map: Aider-style token-budgeted repo map contract\n'
32
-
33
- # Sanity: node + script
34
- if ! command -v node >/dev/null 2>&1; then
35
- echo "SKIP smoke-repo-map: node not installed" >&2
36
- exit 0
37
- fi
38
- if [ ! -f "$SCRIPT" ]; then
39
- echo "FAIL: $SCRIPT missing" >&2
40
- exit 1
41
- fi
42
-
43
- # --- Fixture builder --------------------------------------------------------
44
- FIX=$(mktemp -d)
45
- trap 'rm -rf "$FIX"' EXIT
46
-
47
- mkdir -p "$FIX/swift" "$FIX/kotlin" "$FIX/ts" "$FIX/py" "$FIX/bash" "$FIX/shared"
48
-
49
- # Swift
50
- cat > "$FIX/swift/Order.swift" <<'EOF'
51
- import Foundation
52
-
53
- public final class OrderViewModel {
54
- public func loadOrders() async throws -> [Order] { return [] }
55
- }
56
-
57
- public struct OrderConfiguration {
58
- var pageSize: Int = 20
59
- }
60
-
61
- public protocol OrderRepository {
62
- func fetch() async throws -> [Order]
63
- }
64
- EOF
65
-
66
- cat > "$FIX/swift/Product.swift" <<'EOF'
67
- public class ProductViewModel {
68
- public func loadProducts() async throws { _ = OrderViewModel() }
69
- }
70
- EOF
71
-
72
- # Kotlin
73
- cat > "$FIX/kotlin/User.kt" <<'EOF'
74
- package com.example
75
-
76
- data class User(val id: String, val name: String)
77
-
78
- class UserViewModel(private val repo: UserRepository) {
79
- fun loadUsers(): List<User> = repo.all()
80
- }
81
-
82
- interface UserRepository {
83
- fun all(): List<User>
84
- }
85
- EOF
86
-
87
- # TypeScript
88
- cat > "$FIX/ts/api.ts" <<'EOF'
89
- export class APIClient {
90
- async fetchUsers(): Promise<User[]> { return []; }
91
- }
92
- export interface User {
93
- id: string;
94
- name: string;
95
- }
96
- export function buildClient(): APIClient { return new APIClient(); }
97
- EOF
98
-
99
- # Python
100
- cat > "$FIX/py/server.py" <<'EOF'
101
- class Server:
102
- def __init__(self): pass
103
-
104
- def make_server() -> Server:
105
- return Server()
106
- EOF
107
-
108
- # Bash
109
- cat > "$FIX/bash/helpers.sh" <<'EOF'
110
- #!/usr/bin/env bash
111
- common_helper() {
112
- echo "hi"
113
- }
114
- specific_helper_for_repo() {
115
- common_helper
116
- }
117
- EOF
118
-
119
- # Two shared-name files to test the TF-IDF rule (same identifier defined twice)
120
- cat > "$FIX/shared/A.swift" <<'EOF'
121
- class CommonName { var x = 1 }
122
- EOF
123
- cat > "$FIX/shared/B.swift" <<'EOF'
124
- class CommonName { var y = 2 }
125
- EOF
126
-
127
- # A reference file that mentions OrderViewModel (rare) AND CommonName (split)
128
- cat > "$FIX/shared/refs.swift" <<'EOF'
129
- import Foundation
130
- // References: OrderViewModel (defined once), CommonName (defined twice → split credit)
131
- let a = OrderViewModel()
132
- let b = CommonName()
133
- let c = CommonName()
134
- EOF
135
-
136
- # --- 1: CLI args parse without crashing ------------------------------------
137
- if node "$SCRIPT" --root "$FIX" --budget 800 --top 5 --format md >/dev/null 2>&1; then
138
- record_pass "CLI parses standard flags"
139
- else
140
- record_fail "CLI failed on standard flags"
141
- fi
142
-
143
- # --- 2: empty repo behaviour -----------------------------------------------
144
- EMPTY=$(mktemp -d)
145
- out2=$(node "$SCRIPT" --root "$EMPTY" --budget 200 --top 5 --format md 2>&1)
146
- rc=$?
147
- rm -rf "$EMPTY"
148
- if [ "$rc" -eq 0 ]; then
149
- record_pass "empty repo → exit 0"
150
- else
151
- record_fail "empty repo should exit 0 (got $rc)"
152
- fi
153
-
154
- # --- 3-7: language extractors --------------------------------------------
155
- MD=$(node "$SCRIPT" --root "$FIX" --budget 5000 --top 50 --format md 2>&1)
156
-
157
- if grep -qF "OrderViewModel" <<<"$MD" && grep -qF "OrderConfiguration" <<<"$MD" && grep -qF "OrderRepository" <<<"$MD"; then
158
- record_pass "Swift extractor finds class/struct/protocol"
159
- else
160
- record_fail "Swift extractor missed declarations"
161
- fi
162
-
163
- if grep -qF "UserViewModel" <<<"$MD" && grep -qF "UserRepository" <<<"$MD" && grep -qF "User" <<<"$MD"; then
164
- record_pass "Kotlin extractor finds class/data class/interface"
165
- else
166
- record_fail "Kotlin extractor missed declarations"
167
- fi
168
-
169
- if grep -qF "APIClient" <<<"$MD" && grep -qF "buildClient" <<<"$MD"; then
170
- record_pass "TS extractor finds export class/function"
171
- else
172
- record_fail "TS extractor missed declarations"
173
- fi
174
-
175
- if grep -qF "class Server" <<<"$MD" && grep -qF "def make_server" <<<"$MD"; then
176
- record_pass "Python extractor finds class/def"
177
- else
178
- record_fail "Python extractor missed declarations"
179
- fi
180
-
181
- if grep -qF "common_helper()" <<<"$MD" && grep -qF "specific_helper_for_repo()" <<<"$MD"; then
182
- record_pass "Bash extractor finds functions"
183
- else
184
- record_fail "Bash extractor missed functions"
185
- fi
186
-
187
- # --- 8: TF-IDF rule - rare identifier ranks higher than shared identifier ---
188
- # OrderViewModel defined once, referenced from refs.swift.
189
- # CommonName defined twice (A + B), referenced from refs.swift.
190
- # refs.swift's outgoing edge to Order.swift should weigh more than to A/B
191
- # combined - so Order.swift should rank above A.swift in this fixture.
192
- order_line=$(echo "$MD" | grep -nF "Order.swift" | head -1 | cut -d: -f1)
193
- a_line=$(echo "$MD" | grep -nF "shared/A.swift" | head -1 | cut -d: -f1)
194
- if [ -n "$order_line" ] && [ -n "$a_line" ]; then
195
- if [ "$order_line" -lt "$a_line" ]; then
196
- record_pass "TF-IDF - rarely-defined identifier outranks shared identifier"
197
- else
198
- record_fail "TF-IDF rule failed: Order.swift should rank above shared/A.swift"
199
- fi
200
- else
201
- record_fail "TF-IDF - could not locate Order.swift or shared/A.swift in output"
202
- fi
203
-
204
- # --- 9: token budget honored -----------------------------------------------
205
- SMALL=$(node "$SCRIPT" --root "$FIX" --budget 150 --top 50 --format md 2>&1)
206
- small_bytes=$(printf '%s' "$SMALL" | wc -c)
207
- # 150 tokens × 4 chars/token = 600 chars; output may end on file boundary so allow +200
208
- if [ "$small_bytes" -lt 900 ]; then
209
- record_pass "token budget honored (budget=150 → $small_bytes chars)"
210
- else
211
- record_fail "token budget exceeded ($small_bytes chars for budget=150)"
212
- fi
213
-
214
- # --- 10: determinism --------------------------------------------------------
215
- RUN1=$(node "$SCRIPT" --root "$FIX" --budget 800 --top 10 --format md 2>&1)
216
- RUN2=$(node "$SCRIPT" --root "$FIX" --budget 800 --top 10 --format md 2>&1)
217
- if [ "$RUN1" = "$RUN2" ]; then
218
- record_pass "determinism - same input twice produces byte-identical output"
219
- else
220
- record_fail "non-deterministic output across runs"
221
- fi
222
-
223
- # --- 11: JSON format --------------------------------------------------------
224
- JSON=$(node "$SCRIPT" --root "$FIX" --budget 2000 --top 5 --format json 2>&1)
225
- if echo "$JSON" | python3 -c 'import json,sys; data=json.load(sys.stdin); assert isinstance(data,list); assert all("path" in d and "score" in d and "declarations" in d for d in data); print("ok")' >/dev/null 2>&1; then
226
- record_pass "JSON format produces valid array with score+declarations"
227
- else
228
- record_fail "JSON output failed schema check"
229
- fi
230
-
231
- # --- 12: word-boundary match -----------------------------------------------
232
- # Isolated fixture: define a unique identifier in one file, reference its
233
- # *substring* (no word boundary) in another, then verify in_refs stays 0.
234
- WB=$(mktemp -d)
235
- cat > "$WB/def.swift" <<'EOF'
236
- class WidgetXYZ123 { var x = 0 }
237
- EOF
238
- cat > "$WB/ref.swift" <<'EOF'
239
- // Mentions a SUPER-string only: WidgetXYZ123Helper.
240
- // \bWidgetXYZ123\b should NOT match inside WidgetXYZ123Helper.
241
- struct WidgetXYZ123Helper { }
242
- EOF
243
- WB_JSON=$(node "$SCRIPT" --root "$WB" --budget 2000 --top 5 --format json 2>&1)
244
- rm -rf "$WB"
245
-
246
- def_refs=$(echo "$WB_JSON" | python3 -c '
247
- import json, sys
248
- data = json.load(sys.stdin)
249
- for d in data:
250
- if d["path"] == "def.swift":
251
- print(d["incoming_refs"])
252
- break
253
- ')
254
- if [ -n "$def_refs" ] && python3 -c "import sys; sys.exit(0 if abs(${def_refs}) < 0.01 else 1)" 2>/dev/null; then
255
- record_pass "word-boundary - super-string match (WidgetXYZ123Helper) does not count as WidgetXYZ123 ref"
256
- else
257
- record_fail "word-boundary regression: def.swift in_refs=$def_refs (expected ~0)"
258
- fi
259
-
260
- # --- 13: prefs schema exposes repoMap toggle -------------------------------
261
- SCHEMA_PATH="$ROOT/pipeline/schemas/prefs.schema.json"
262
- if jq -e '.properties.global.properties.repoMap.properties.enabled' "$SCHEMA_PATH" >/dev/null 2>&1; then
263
- record_pass "prefs schema exposes repoMap.enabled"
264
- else
265
- record_fail "prefs schema missing repoMap.enabled"
266
- fi
267
- for prop in tokenBudget topFiles include exclude; do
268
- if jq -e ".properties.global.properties.repoMap.properties.${prop}" "$SCHEMA_PATH" >/dev/null 2>&1; then
269
- record_pass "prefs schema exposes repoMap.${prop}"
270
- else
271
- record_fail "prefs schema missing repoMap.${prop}"
272
- fi
273
- done
274
- # Off by default - preserve baseline for existing users.
275
- if jq -e '.properties.global.properties.repoMap.properties.enabled
276
- | has("default") and .default == false' "$SCHEMA_PATH" >/dev/null 2>&1; then
277
- record_pass "repoMap.enabled defaults to false (opt-in)"
278
- else
279
- record_fail "repoMap.enabled should default to false"
280
- fi
281
-
282
- # --- 14: Phase 1 + Phase 4 docs wire the injection ------------------------
283
- P1="$ROOT/pipeline/multi-agent-refs/phases/phase-1-analysis.md"
284
- P4="$ROOT/pipeline/multi-agent-refs/phases/phase-4-review.md"
285
- for f in "$P1" "$P4"; do
286
- base=$(basename "$f")
287
- if grep -qF "repoMap.enabled" "$f" && grep -qF "repo-map.mjs" "$f" && grep -qF '${REPO_MAP}' "$f"; then
288
- record_pass "$base wires repoMap injection"
289
- else
290
- record_fail "$base missing repoMap wiring (need: repoMap.enabled + repo-map.mjs + \${REPO_MAP})"
291
- fi
292
- done
293
-
294
- printf '\n══ repo-map smoke: %d passed, %d failed ══\n' "$pass" "$fail"
295
- if [ "$fail" -gt 0 ]; then
296
- printf '\nFailures:\n'
297
- for msg in "${failures[@]}"; do printf ' - %s\n' "$msg"; done
298
- exit 1
299
- fi
300
- exit 0
@@ -1,92 +0,0 @@
1
- #!/usr/bin/env bash
2
- # smoke-review-readiness.sh - contract for /multi-agent:review-jira + /multi-agent:review-issue.
3
- #
4
- # Verifies:
5
- # 1. Files exist: 2 commands, 2 Copilot skills, 1 shared ref.
6
- # 2. Frontmatter keys on both surfaces.
7
- # 3. Both commands delegate to refs/readiness-review.md and reuse issue-fetcher.
8
- # 4. The shared ref names the maturity engine + both comment channels + the confirm gate.
9
- # 5. Registration: dispatcher rows, routing rows, help EN+TR, contract inventory + count (38).
10
- # 6. Read-only guarantee (no worktree/commit/create) stated.
11
- # 7. Forbidden strings absent (em-dash, section sign, the M-word).
12
-
13
- set -euo pipefail
14
- HERE="$(cd "$(dirname "$0")" && pwd)"
15
- ROOT="$(cd "$HERE/../.." && pwd)"
16
-
17
- REF="$ROOT/pipeline/multi-agent-refs/readiness-review.md"
18
- CMD_J="$ROOT/pipeline/commands/multi-agent/review-jira/SKILL.md"
19
- CMD_I="$ROOT/pipeline/commands/multi-agent/review-issue/SKILL.md"
20
- SK_J="$ROOT/pipeline/skills/shared/core/multi-agent-review-jira/SKILL.md"
21
- SK_I="$ROOT/pipeline/skills/shared/core/multi-agent-review-issue/SKILL.md"
22
- DISPATCHER="$ROOT/pipeline/commands/multi-agent/SKILL.md"
23
- CONTRACT="$ROOT/pipeline/multi-agent-refs/cross-cli-contract.md"
24
- CMD_COUNT=$(find "$ROOT/pipeline/commands/multi-agent" -mindepth 1 -maxdepth 1 -type d | wc -l | tr -d ' ')
25
- HELP="$ROOT/pipeline/commands/multi-agent/help/SKILL.md"
26
-
27
- PASS=0; FAIL=0
28
- pass() { PASS=$((PASS+1)); echo " ✓ $1"; }
29
- fail() { FAIL=$((FAIL+1)); echo " ✗ $1"; }
30
-
31
- echo "→ 1. files exist"
32
- for f in "$REF" "$CMD_J" "$CMD_I" "$SK_J" "$SK_I"; do
33
- if [ -f "$f" ]; then pass "exists: ${f#$ROOT/}"; else fail "missing: ${f#$ROOT/}"; fi
34
- done
35
- [ "$FAIL" -eq 0 ] || { echo "══ review-readiness smoke: $PASS passed, $FAIL failed ══"; exit 1; }
36
-
37
- echo ""
38
- echo "→ 2. frontmatter keys"
39
- for f in "$CMD_J" "$CMD_I"; do
40
- head -4 "$f" | grep -q '^description:' && pass "description: ${f#$ROOT/}" || fail "description missing: ${f#$ROOT/}"
41
- head -4 "$f" | grep -q '^argument-hint:' && pass "argument-hint: ${f#$ROOT/}" || fail "argument-hint missing: ${f#$ROOT/}"
42
- done
43
- head -8 "$SK_J" | grep -q '^name: multi-agent-review-jira$' && pass "name: multi-agent-review-jira" || fail "name wrong: $SK_J"
44
- head -8 "$SK_I" | grep -q '^name: multi-agent-review-issue$' && pass "name: multi-agent-review-issue" || fail "name wrong: $SK_I"
45
- for f in "$SK_J" "$SK_I"; do
46
- head -8 "$f" | grep -q '^user-invocable: true' && pass "user-invocable: ${f#$ROOT/}" || fail "user-invocable missing: ${f#$ROOT/}"
47
- done
48
-
49
- echo ""
50
- echo "→ 3. delegate to shared ref + reuse issue-fetcher"
51
- for f in "$CMD_J" "$CMD_I" "$SK_J" "$SK_I"; do
52
- grep -Fq "readiness-review.md" "$f" && pass "ref link: ${f#$ROOT/}" || fail "ref link missing: ${f#$ROOT/}"
53
- grep -Fq "issue-fetcher.sh" "$f" && pass "issue-fetcher reuse: ${f#$ROOT/}" || fail "issue-fetcher missing: ${f#$ROOT/}"
54
- done
55
-
56
- echo ""
57
- echo "→ 4. shared ref names maturity + channels + confirm gate"
58
- grep -Fqi "maturity" "$REF" && pass "ref uses maturity engine" || fail "ref missing maturity"
59
- grep -Fq "channels/jira.md" "$REF" && pass "ref -> jira comment channel" || fail "ref missing jira channel"
60
- grep -Fq "channels/issue-comment.md" "$REF" && pass "ref -> github comment channel" || fail "ref missing issue channel"
61
- grep -Fqi "confirm" "$REF" && pass "ref has confirm-before-post gate" || fail "ref missing confirm gate"
62
- grep -Fqi "rubric" "$REF" && pass "ref has readiness rubric" || fail "ref missing rubric"
63
-
64
- echo ""
65
- echo "→ 5. registration + count (derived)"
66
- grep -Fq '| `review-jira ' "$DISPATCHER" && pass "dispatcher desc: review-jira" || fail "dispatcher desc missing review-jira"
67
- grep -Fq '| `review-issue ' "$DISPATCHER" && pass "dispatcher desc: review-issue" || fail "dispatcher desc missing review-issue"
68
- grep -Fq "review-jira/SKILL.md" "$DISPATCHER" && pass "dispatcher routing: review-jira" || fail "dispatcher routing missing review-jira"
69
- grep -Fq "review-issue/SKILL.md" "$DISPATCHER" && pass "dispatcher routing: review-issue" || fail "dispatcher routing missing review-issue"
70
- grep -Fq "## 1. Command Inventory ($CMD_COUNT commands)" "$CONTRACT" && pass "contract count = $CMD_COUNT (derived)" || fail "contract count wrong"
71
- grep -Eq '(^|[ ,])review-jira([ ,]|$)' "$CONTRACT" && pass "contract inventory has review-jira" || fail "contract missing review-jira"
72
- grep -Eq '(^|[ ,])review-issue([ ,]|$)' "$CONTRACT" && pass "contract inventory has review-issue" || fail "contract missing review-issue"
73
- grep -Fq "multi-agent:review-jira" "$HELP" && pass "help lists review-jira" || fail "help missing review-jira"
74
- grep -Fq "multi-agent:review-issue" "$HELP" && pass "help lists review-issue" || fail "help missing review-issue"
75
-
76
- echo ""
77
- echo "→ 6. read-only guarantee stated"
78
- for f in "$CMD_J" "$CMD_I"; do
79
- grep -Fqi "no worktree" "$f" && pass "read-only stated: ${f#$ROOT/}" || fail "read-only note missing: ${f#$ROOT/}"
80
- done
81
-
82
- echo ""
83
- echo "→ 7. forbidden strings absent"
84
- MWORD="MAN""DATORY"
85
- for f in "$REF" "$CMD_J" "$CMD_I" "$SK_J" "$SK_I"; do
86
- if grep -q $'—\|§\|…' "$f"; then fail "forbidden unicode punctuation in ${f##*/}"; else pass "punctuation clean: ${f##*/}"; fi
87
- if grep -q "$MWORD" "$f"; then fail "forbidden word in ${f##*/}"; else pass "vocabulary clean: ${f##*/}"; fi
88
- done
89
-
90
- echo ""
91
- echo "══ review-readiness smoke: $PASS passed, $FAIL failed ══"
92
- [ "$FAIL" -eq 0 ]
@@ -1,146 +0,0 @@
1
- #!/usr/bin/env bash
2
- # smoke-review-watch.sh
3
- #
4
- # Verifies the auto-review-incoming-PRs surface:
5
- # 1. pipeline/lib/review-watch.sh exists and parses cleanly
6
- # 2. --doctor runs without crashing on an unconfigured environment
7
- # 3. --help shows usage
8
- # 4. State directory is created
9
- # 5. prefs schema exposes global.reviewWatch.{enabled,repos,intervalSeconds,labelFilter}
10
- # 6. global.reviewWatch.enabled defaults to false (opt-in)
11
- # 7. global.review.dedupeInlineComments default is true (dedupe parity)
12
- # 8. post-pr-review.sh exposes finding_fingerprint + comment_exists_with_fingerprint
13
- # 9. render_inline_body accepts a 5th fingerprint arg and embeds the marker
14
- # 10. Unknown command exits non-zero
15
- #
16
- # Exit 0 = all pass, 1 = any failure.
17
-
18
- set -uo pipefail
19
-
20
- ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
21
- WATCH="$ROOT/pipeline/lib/review-watch.sh"
22
- POSTER="$ROOT/pipeline/lib/post-pr-review.sh"
23
- SCHEMA="$ROOT/pipeline/schemas/prefs.schema.json"
24
-
25
- pass=0
26
- fail=0
27
- failures=()
28
- record_pass() { pass=$((pass + 1)); printf ' \033[0;32mPASS\033[0m %s\n' "$1"; }
29
- record_fail() { fail=$((fail + 1)); failures+=("$1"); printf ' \033[0;31mFAIL\033[0m %s\n' "$1"; }
30
-
31
- printf '→ smoke-review-watch: incoming-PR auto-review surface contract\n'
32
-
33
- # 1. lib script exists + parses
34
- if [ ! -f "$WATCH" ]; then
35
- record_fail "pipeline/lib/review-watch.sh missing"
36
- elif ! bash -n "$WATCH" 2>/dev/null; then
37
- record_fail "review-watch.sh syntax error"
38
- else
39
- record_pass "review-watch.sh exists and parses"
40
- fi
41
-
42
- # 2. --doctor runs cleanly (zero exit) on unconfigured prefs
43
- if bash "$WATCH" --doctor >/dev/null 2>&1; then
44
- record_pass "--doctor exits 0 on unconfigured environment"
45
- else
46
- record_fail "--doctor crashed (must be safe on unconfigured environment)"
47
- fi
48
-
49
- # 3. --help shows usage
50
- if bash "$WATCH" --help 2>&1 | grep -qE 'review-watch|usage:'; then
51
- record_pass "--help shows usage"
52
- else
53
- record_fail "--help should show usage banner"
54
- fi
55
-
56
- # 4. State dir is created
57
- STATE_DIR="$HOME/.claude/state/review-watch"
58
- if [ -d "$STATE_DIR" ]; then
59
- record_pass "state dir created at $STATE_DIR"
60
- else
61
- record_fail "state dir not created"
62
- fi
63
-
64
- # 5. Schema toggles
65
- for prop in enabled repos intervalSeconds labelFilter; do
66
- if jq -e ".properties.global.properties.reviewWatch.properties.${prop}" "$SCHEMA" >/dev/null 2>&1; then
67
- record_pass "prefs schema exposes reviewWatch.${prop}"
68
- else
69
- record_fail "prefs schema missing reviewWatch.${prop}"
70
- fi
71
- done
72
-
73
- # 6. reviewWatch.enabled defaults to false
74
- if jq -e '.properties.global.properties.reviewWatch.properties.enabled
75
- | has("default") and .default == false' "$SCHEMA" >/dev/null 2>&1; then
76
- record_pass "reviewWatch.enabled defaults to false (opt-in)"
77
- else
78
- record_fail "reviewWatch.enabled should default to false"
79
- fi
80
-
81
- # 7. dedupeInlineComments default true
82
- if jq -e '.properties.global.properties.review.properties.dedupeInlineComments
83
- | has("default") and .default == true' "$SCHEMA" >/dev/null 2>&1; then
84
- record_pass "review.dedupeInlineComments defaults to true (dedupe parity)"
85
- else
86
- record_fail "review.dedupeInlineComments should default to true"
87
- fi
88
-
89
- # 8. post-pr-review.sh exposes the dedupe helpers (provider-agnostic)
90
- if grep -qE '^finding_fingerprint\(\)' "$POSTER" \
91
- && grep -qE '^comment_exists_with_fingerprint\(\)' "$POSTER" \
92
- && grep -qE '^load_existing_comments_github\(\)' "$POSTER" \
93
- && grep -qE '^load_existing_comments_bitbucket\(\)' "$POSTER"; then
94
- record_pass "post-pr-review.sh declares dedupe helpers (fingerprint + check + github + bitbucket loaders)"
95
- else
96
- record_fail "post-pr-review.sh missing one of the dedupe helpers (github or bitbucket loader)"
97
- fi
98
-
99
- # 8b. Bitbucket dedupe gate wired in post_bitbucket_server
100
- if awk '/^post_bitbucket_server\(\)/,/^}/' "$POSTER" \
101
- | grep -q 'load_existing_comments_bitbucket'; then
102
- record_pass "post_bitbucket_server wires the dedupe gate"
103
- else
104
- record_fail "post_bitbucket_server missing load_existing_comments_bitbucket call"
105
- fi
106
- if awk '/^post_bitbucket_server\(\)/,/^}/' "$POSTER" \
107
- | grep -q 'comment_exists_with_fingerprint'; then
108
- record_pass "post_bitbucket_server checks fingerprint before posting"
109
- else
110
- record_fail "post_bitbucket_server missing fingerprint check"
111
- fi
112
-
113
- # 9. render_inline_body takes 5 args (sev issue fix rule_id fingerprint) and writes the marker
114
- if grep -qE 'render_inline_body\(\)' "$POSTER" \
115
- && grep -qE '<!-- multi-agent-finding:' "$POSTER"; then
116
- record_pass "render_inline_body embeds the fingerprint marker"
117
- else
118
- record_fail "render_inline_body must embed <!-- multi-agent-finding: ... --> marker"
119
- fi
120
-
121
- # 10. Unknown command exits non-zero
122
- if bash "$WATCH" --garbage >/dev/null 2>&1; then
123
- record_fail "unknown command should exit non-zero"
124
- else
125
- record_pass "unknown command exits non-zero"
126
- fi
127
-
128
- # 11. PR loop must NOT pipe into `while` (a pipe subshell discards every
129
- # state= / cursor mutation, so save_state would persist the stale cursor and
130
- # the watcher would re-dispatch the same PRs forever). It must use process
131
- # substitution so the loop runs in the function's own shell.
132
- if grep -qE "jq -c '\.\[\]' <<<\"\\\$prs_json\" \| while" "$WATCH"; then
133
- record_fail "review-watch PR loop pipes into while (subshell loses cursor state)"
134
- elif awk '/while read -r pr;/,/done < <\(jq/' "$WATCH" | grep -q 'done < <(jq'; then
135
- record_pass "PR loop uses process substitution (cursor mutations persist)"
136
- else
137
- record_fail "PR loop structure unrecognized - verify it does not pipe into while"
138
- fi
139
-
140
- printf '\n══ review-watch smoke: %d passed, %d failed ══\n' "$pass" "$fail"
141
- if [ "$fail" -gt 0 ]; then
142
- printf '\nFailures:\n'
143
- for msg in "${failures[@]}"; do printf ' - %s\n' "$msg"; done
144
- exit 1
145
- fi
146
- exit 0
@@ -1,84 +0,0 @@
1
- #!/usr/bin/env bash
2
- # smoke-routines.sh - contract for routine-registry.mjs, the backend of the
3
- # user-defined routine commands (/multi-agent:save, :routines, :forget).
4
-
5
- set -uo pipefail
6
-
7
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
8
- RR="$SCRIPT_DIR/routine-registry.mjs"
9
-
10
- PASS=0
11
- FAIL=0
12
- record_pass() { PASS=$((PASS + 1)); printf ' \342\234\223 %s\n' "$1"; }
13
- record_fail() { FAIL=$((FAIL + 1)); printf ' \342\234\227 %s\n' "$1"; }
14
-
15
- printf '\342\206\222 smoke-routines: routine-registry backend contract\n'
16
-
17
- tmp=$(mktemp -d "${TMPDIR:-/tmp}/routines.XXXXXX")
18
- trap 'rm -rf "$tmp"' EXIT
19
- H="$tmp/home"
20
- mkdir -p "$H/.claude/commands/multi-agent"
21
- printf '{"global":{}}\n' > "$H/.claude/multi-agent-preferences.json"
22
- printf 'Run steps 1-6 of the checkin service migration.\n' > "$tmp/body.md"
23
-
24
- # 1. add -> writes a local-only command dir + registry entry
25
- node "$RR" add --name checkin-services --description "Checkin servis kontrolu" \
26
- --source "CLAUDE.md" --body-file "$tmp/body.md" --home "$H" >/dev/null 2>&1
27
- skill="$H/.claude/commands/multi-agent/checkin-services/SKILL.md"
28
- if [ -f "$skill" ] && grep -qx "local-only: true" "$skill"; then
29
- record_pass "add writes a local-only command SKILL.md"
30
- else
31
- record_fail "add did not write a local-only routine command"
32
- fi
33
- if node "$RR" list --json --home "$H" | grep -q '"name": "checkin-services"'; then
34
- record_pass "registry records the routine"
35
- else
36
- record_fail "registry missing the routine"
37
- fi
38
-
39
- # 2. add is name-collision safe (same name rejected)
40
- node "$RR" add --name checkin-services --description x --source y --body-file "$tmp/body.md" --home "$H" >/dev/null 2>&1
41
- [ "$?" -eq 1 ] && record_pass "duplicate name rejected" || record_fail "duplicate name should reject"
42
-
43
- # 3. invalid name rejected
44
- node "$RR" add --name "Bad Name" --description x --source y --body-file "$tmp/body.md" --home "$H" >/dev/null 2>&1
45
- [ "$?" -eq 1 ] && record_pass "invalid name rejected" || record_fail "invalid name should reject"
46
-
47
- # 4. shipped-command guard: never remove a non-local-only command
48
- mkdir -p "$H/.claude/commands/multi-agent/status"
49
- printf -- '---\ndescription: "shipped"\n---\nbody\n' > "$H/.claude/commands/multi-agent/status/SKILL.md"
50
- node "$RR" remove --name status --home "$H" >/dev/null 2>&1
51
- if [ "$?" -eq 1 ] && [ -d "$H/.claude/commands/multi-agent/status" ]; then
52
- record_pass "refuses to remove a shipped command"
53
- else
54
- record_fail "shipped command must be protected"
55
- fi
56
-
57
- # 5. sync backstop proxy: the generated routine carries local-only:true, which is
58
- # exactly what sync/SKILL.md greps to keep it out of the public repo.
59
- if grep -qx "local-only: true" "$skill"; then
60
- record_pass "routine is sync-excluded (local-only marker present)"
61
- else
62
- record_fail "routine missing local-only marker (would leak on sync)"
63
- fi
64
-
65
- # 6. remove -> deletes dir + registry entry
66
- node "$RR" remove --name checkin-services --home "$H" >/dev/null 2>&1
67
- if [ ! -d "$H/.claude/commands/multi-agent/checkin-services" ] \
68
- && ! node "$RR" list --json --home "$H" | grep -q "checkin-services"; then
69
- record_pass "remove deletes dir + registry entry"
70
- else
71
- record_fail "remove left dir or registry entry behind"
72
- fi
73
-
74
- # 7. install preservation proxy: snapshotLocalOnlyWrappers keys on local-only:true.
75
- # Re-add, then confirm the marker survives a simulated namespace re-read.
76
- node "$RR" add --name my-routine --description d --source s --body-file "$tmp/body.md" --home "$H" >/dev/null 2>&1
77
- if grep -qx "local-only: true" "$H/.claude/commands/multi-agent/my-routine/SKILL.md"; then
78
- record_pass "re-added routine keeps the install-preserving marker"
79
- else
80
- record_fail "re-added routine lost its local-only marker"
81
- fi
82
-
83
- printf '\n\342\225\220\342\225\220 smoke-routines: %d passed, %d failed \342\225\220\342\225\220\n' "$PASS" "$FAIL"
84
- [ "$FAIL" -eq 0 ]