@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.
- package/CHANGELOG.md +126 -0
- package/install/_common.mjs +48 -0
- package/install/_dev-only-files.mjs +125 -5
- package/install/claude.mjs +14 -8
- package/install/copilot.mjs +5 -8
- package/package.json +17 -2
- package/pipeline/commands/multi-agent/analysis/SKILL.md +1 -1
- package/pipeline/lib/credential-store.sh +20 -0
- package/pipeline/multi-agent-refs/_account-picker.md +1 -1
- package/pipeline/multi-agent-refs/_dev-context.md +1 -1
- package/pipeline/multi-agent-refs/_repo-picker.md +1 -1
- package/pipeline/multi-agent-refs/phases/operations.md +28 -0
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +1 -0
- package/pipeline/multi-agent-refs/phases/phase-2-planning.md +1 -1
- package/pipeline/multi-agent-refs/phases/phase-3-dev.md +1 -2
- package/pipeline/multi-agent-refs/phases/phase-4-review.md +49 -4
- package/pipeline/schemas/prefs.schema.json +6 -0
- package/pipeline/scripts/_smoke-root.sh +61 -0
- package/pipeline/scripts/audit-log.sh +25 -0
- package/pipeline/scripts/smoke-cross-cli-behavior.sh +21 -7
- package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-1-analysis.json +0 -25
- package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-2-plan.json +0 -30
- package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-4-review.json +0 -20
- package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-4-triage.json +0 -15
- package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/metadata.json +0 -14
- package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/task.json +0 -12
- package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-1-analysis.json +0 -29
- package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-2-plan.json +0 -43
- package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-4-review.json +0 -35
- package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-4-triage.json +0 -35
- package/pipeline/eval/golden-tasks/02-android-feature-compose/metadata.json +0 -14
- package/pipeline/eval/golden-tasks/02-android-feature-compose/task.json +0 -12
- package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-1-analysis.json +0 -29
- package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-2-plan.json +0 -42
- package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-4-review.json +0 -20
- package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-4-triage.json +0 -15
- package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/metadata.json +0 -14
- package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/task.json +0 -12
- package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-1-analysis.json +0 -29
- package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-2-plan.json +0 -40
- package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-4-review.json +0 -20
- package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-4-triage.json +0 -15
- package/pipeline/eval/golden-tasks/04-frontend-next-hydration/metadata.json +0 -14
- package/pipeline/eval/golden-tasks/04-frontend-next-hydration/task.json +0 -12
- package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-1-analysis.json +0 -29
- package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-2-plan.json +0 -42
- package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-4-review.json +0 -28
- package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-4-triage.json +0 -27
- package/pipeline/eval/golden-tasks/05-ios-security-keychain/metadata.json +0 -14
- package/pipeline/eval/golden-tasks/05-ios-security-keychain/task.json +0 -12
- package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-1-analysis.json +0 -29
- package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-2-plan.json +0 -41
- package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-4-review.json +0 -12
- package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-4-triage.json +0 -6
- package/pipeline/eval/golden-tasks/06-android-refactor-usecase/metadata.json +0 -14
- package/pipeline/eval/golden-tasks/06-android-refactor-usecase/task.json +0 -12
- package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-1-analysis.json +0 -29
- package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-2-plan.json +0 -42
- package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-4-review.json +0 -28
- package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-4-triage.json +0 -27
- package/pipeline/eval/golden-tasks/07-backend-node-idempotency/metadata.json +0 -14
- package/pipeline/eval/golden-tasks/07-backend-node-idempotency/task.json +0 -12
- package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-1-analysis.json +0 -25
- package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-2-plan.json +0 -31
- package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-4-review.json +0 -12
- package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-4-triage.json +0 -18
- package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/metadata.json +0 -14
- package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/task.json +0 -12
- package/pipeline/eval/golden-tasks/README.md +0 -65
- package/pipeline/eval/intent-cases.json +0 -40
- package/pipeline/eval/run-metrics-fixture.json +0 -93
- package/pipeline/eval/triage/01-empty-findings/expected.json +0 -6
- package/pipeline/eval/triage/01-empty-findings/input.json +0 -5
- package/pipeline/eval/triage/01-empty-findings/notes.md +0 -7
- package/pipeline/eval/triage/02-real-blocker/expected.json +0 -15
- package/pipeline/eval/triage/02-real-blocker/input.json +0 -14
- package/pipeline/eval/triage/02-real-blocker/notes.md +0 -7
- package/pipeline/eval/triage/03-out-of-scope-defer/expected.json +0 -18
- package/pipeline/eval/triage/03-out-of-scope-defer/input.json +0 -14
- package/pipeline/eval/triage/03-out-of-scope-defer/notes.md +0 -10
- package/pipeline/eval/triage/04-false-positive-reject/expected.json +0 -18
- package/pipeline/eval/triage/04-false-positive-reject/input.json +0 -14
- package/pipeline/eval/triage/04-false-positive-reject/notes.md +0 -10
- package/pipeline/eval/triage/05-mixed-classification/expected.json +0 -43
- package/pipeline/eval/triage/05-mixed-classification/input.json +0 -38
- package/pipeline/eval/triage/05-mixed-classification/notes.md +0 -17
- package/pipeline/eval/triage/06-severity-mismatch/expected.json +0 -15
- package/pipeline/eval/triage/06-severity-mismatch/input.json +0 -14
- package/pipeline/eval/triage/06-severity-mismatch/notes.md +0 -9
- package/pipeline/eval/triage/07-duplicate-reviewers/expected.json +0 -27
- package/pipeline/eval/triage/07-duplicate-reviewers/input.json +0 -22
- package/pipeline/eval/triage/07-duplicate-reviewers/notes.md +0 -9
- package/pipeline/eval/triage/08-style-misclassified/expected.json +0 -18
- package/pipeline/eval/triage/08-style-misclassified/input.json +0 -14
- package/pipeline/eval/triage/08-style-misclassified/notes.md +0 -9
- package/pipeline/eval/triage/09-cascading-finding/expected.json +0 -23
- package/pipeline/eval/triage/09-cascading-finding/input.json +0 -22
- package/pipeline/eval/triage/09-cascading-finding/notes.md +0 -9
- package/pipeline/eval/triage/10-deferred-crossref/expected.json +0 -18
- package/pipeline/eval/triage/10-deferred-crossref/input.json +0 -14
- package/pipeline/eval/triage/10-deferred-crossref/notes.md +0 -9
- package/pipeline/eval/triage/11-vercel-token-leak-blocker/expected.json +0 -27
- package/pipeline/eval/triage/11-vercel-token-leak-blocker/input.json +0 -22
- package/pipeline/eval/triage/11-vercel-token-leak-blocker/notes.md +0 -14
- package/pipeline/eval/triage/README.md +0 -54
- package/pipeline/scripts/benchmark-phase-0.sh +0 -128
- package/pipeline/scripts/check-md-links.mjs +0 -88
- package/pipeline/scripts/eval-golden-tasks-live.mjs +0 -302
- package/pipeline/scripts/eval-golden-tasks.mjs +0 -224
- package/pipeline/scripts/eval-intent.mjs +0 -107
- package/pipeline/scripts/eval-mine-corpus.mjs +0 -211
- package/pipeline/scripts/eval-triage.mjs +0 -171
- package/pipeline/scripts/fixtures/diff-risk-android.diff +0 -40
- package/pipeline/scripts/fixtures/diff-risk-ios.diff +0 -48
- package/pipeline/scripts/fixtures/diff-risk-test-removal.diff +0 -40
- package/pipeline/scripts/fixtures/install-layout.tsv +0 -19
- package/pipeline/scripts/fixtures/pack-expected-count.txt +0 -1
- package/pipeline/scripts/fixtures/test-gap-node.diff +0 -30
- package/pipeline/scripts/fixtures/test-gap-python.diff +0 -32
- package/pipeline/scripts/lint-mcp-refs.mjs +0 -218
- package/pipeline/scripts/lint-skills.mjs +0 -154
- package/pipeline/scripts/run-smokes.mjs +0 -130
- package/pipeline/scripts/scorecard.mjs +0 -258
- package/pipeline/scripts/smoke-add-detail.sh +0 -137
- package/pipeline/scripts/smoke-agent-guard.sh +0 -74
- package/pipeline/scripts/smoke-agent-log-cost.sh +0 -262
- package/pipeline/scripts/smoke-agent-model-routing.sh +0 -87
- package/pipeline/scripts/smoke-ask-choice.sh +0 -42
- package/pipeline/scripts/smoke-autopilot-circuit-breaker.sh +0 -36
- package/pipeline/scripts/smoke-bitbucket-contract.sh +0 -255
- package/pipeline/scripts/smoke-changelog-version.sh +0 -47
- package/pipeline/scripts/smoke-channels-approval-gate.sh +0 -60
- package/pipeline/scripts/smoke-channels-flow.sh +0 -130
- package/pipeline/scripts/smoke-ci-workflows.sh +0 -88
- package/pipeline/scripts/smoke-clarify.sh +0 -148
- package/pipeline/scripts/smoke-command-inventory.sh +0 -81
- package/pipeline/scripts/smoke-commands-skills-parity.sh +0 -87
- package/pipeline/scripts/smoke-community-gates.sh +0 -75
- package/pipeline/scripts/smoke-compliance-skills.sh +0 -119
- package/pipeline/scripts/smoke-config-hygiene.sh +0 -58
- package/pipeline/scripts/smoke-context-budget.sh +0 -72
- package/pipeline/scripts/smoke-cost-budget.sh +0 -70
- package/pipeline/scripts/smoke-cost-summary.sh +0 -139
- package/pipeline/scripts/smoke-cross-phase-cohesion.sh +0 -128
- package/pipeline/scripts/smoke-description-tr.sh +0 -82
- package/pipeline/scripts/smoke-dev-critic.sh +0 -144
- package/pipeline/scripts/smoke-diff-explain.sh +0 -147
- package/pipeline/scripts/smoke-diff-risk.sh +0 -190
- package/pipeline/scripts/smoke-dynamic-skill-loading.sh +0 -160
- package/pipeline/scripts/smoke-eval-live.sh +0 -136
- package/pipeline/scripts/smoke-evidence-gate.sh +0 -93
- package/pipeline/scripts/smoke-extract-conventions.sh +0 -163
- package/pipeline/scripts/smoke-fetchers-offline.sh +0 -448
- package/pipeline/scripts/smoke-figma-dispatch.sh +0 -112
- package/pipeline/scripts/smoke-gate-hooks.sh +0 -74
- package/pipeline/scripts/smoke-gc-tmp.sh +0 -130
- package/pipeline/scripts/smoke-gc-worktrees.sh +0 -125
- package/pipeline/scripts/smoke-generate-issue.sh +0 -120
- package/pipeline/scripts/smoke-handoff-contract.sh +0 -92
- package/pipeline/scripts/smoke-identity-isolation.sh +0 -70
- package/pipeline/scripts/smoke-install-layout.sh +0 -248
- package/pipeline/scripts/smoke-intent-guard.sh +0 -86
- package/pipeline/scripts/smoke-issue-comment-template.sh +0 -86
- package/pipeline/scripts/smoke-issue-jira-triad.sh +0 -120
- package/pipeline/scripts/smoke-keychain.sh +0 -158
- package/pipeline/scripts/smoke-language-axis.sh +0 -109
- package/pipeline/scripts/smoke-learning-curve.sh +0 -61
- package/pipeline/scripts/smoke-learnings-ledger.sh +0 -86
- package/pipeline/scripts/smoke-lib-scripts.sh +0 -448
- package/pipeline/scripts/smoke-mcp-gate.sh +0 -68
- package/pipeline/scripts/smoke-md-links.sh +0 -8
- package/pipeline/scripts/smoke-md2confluence.sh +0 -126
- package/pipeline/scripts/smoke-metrics-cache-ratio.sh +0 -72
- package/pipeline/scripts/smoke-migrate-state.sh +0 -102
- package/pipeline/scripts/smoke-mode-dispatch-drift.sh +0 -161
- package/pipeline/scripts/smoke-model-fallback.sh +0 -89
- package/pipeline/scripts/smoke-multi-repo-integration.sh +0 -116
- package/pipeline/scripts/smoke-multi-repo-worktree.sh +0 -61
- package/pipeline/scripts/smoke-no-mcp-in-dev-phases.sh +0 -194
- package/pipeline/scripts/smoke-no-token-prompt.sh +0 -85
- package/pipeline/scripts/smoke-own-punctuation.sh +0 -103
- package/pipeline/scripts/smoke-pack-contents.sh +0 -140
- package/pipeline/scripts/smoke-pat-audit.sh +0 -128
- package/pipeline/scripts/smoke-per-repo-memory.sh +0 -156
- package/pipeline/scripts/smoke-phase-0-multi-repo.sh +0 -170
- package/pipeline/scripts/smoke-phase-6-multi.sh +0 -79
- package/pipeline/scripts/smoke-phase-banner.sh +0 -101
- package/pipeline/scripts/smoke-phase-tracker.sh +0 -324
- package/pipeline/scripts/smoke-phase0-bridge-contract.sh +0 -241
- package/pipeline/scripts/smoke-phase4-gates.sh +0 -45
- package/pipeline/scripts/smoke-phase4-triage.sh +0 -229
- package/pipeline/scripts/smoke-plan-approval-gate.sh +0 -71
- package/pipeline/scripts/smoke-plan-safety.sh +0 -139
- package/pipeline/scripts/smoke-plan-todos.sh +0 -196
- package/pipeline/scripts/smoke-pr-review-actions.sh +0 -152
- package/pipeline/scripts/smoke-pre-commit.sh +0 -170
- package/pipeline/scripts/smoke-pref-migration.sh +0 -226
- package/pipeline/scripts/smoke-prefs-language.sh +0 -134
- package/pipeline/scripts/smoke-progress-contract.sh +0 -127
- package/pipeline/scripts/smoke-prune-logs.sh +0 -137
- package/pipeline/scripts/smoke-purge.sh +0 -138
- package/pipeline/scripts/smoke-push-retry.sh +0 -75
- package/pipeline/scripts/smoke-repo-map.sh +0 -300
- package/pipeline/scripts/smoke-review-readiness.sh +0 -92
- package/pipeline/scripts/smoke-review-watch.sh +0 -146
- package/pipeline/scripts/smoke-routines.sh +0 -84
- package/pipeline/scripts/smoke-run-aggregator.sh +0 -216
- package/pipeline/scripts/smoke-run-metrics.sh +0 -50
- package/pipeline/scripts/smoke-search.sh +0 -187
- package/pipeline/scripts/smoke-shadow-git.sh +0 -224
- package/pipeline/scripts/smoke-skill-authoring.sh +0 -137
- package/pipeline/scripts/smoke-skill-language.sh +0 -83
- package/pipeline/scripts/smoke-skill-manifest.sh +0 -138
- package/pipeline/scripts/smoke-skill-scan.sh +0 -198
- package/pipeline/scripts/smoke-source-parity.sh +0 -85
- package/pipeline/scripts/smoke-subagent-validators.sh +0 -108
- package/pipeline/scripts/smoke-sync-parity.sh +0 -92
- package/pipeline/scripts/smoke-tasklist-ordering.sh +0 -112
- package/pipeline/scripts/smoke-telemetry.sh +0 -147
- package/pipeline/scripts/smoke-test-gap.sh +0 -183
- package/pipeline/scripts/smoke-token-budget.sh +0 -67
- package/pipeline/scripts/smoke-token-preflight.sh +0 -82
- package/pipeline/scripts/smoke-tracker-contract.sh +0 -191
- package/pipeline/scripts/smoke-tracker-tokens-invocation.sh +0 -73
- package/pipeline/scripts/smoke-triage-memory.sh +0 -174
- package/pipeline/scripts/smoke-update-check.sh +0 -135
- package/pipeline/scripts/smoke-url-enrichment.sh +0 -70
- package/pipeline/scripts/smoke-validate-analysis-doc.sh +0 -161
- package/pipeline/scripts/smoke-validator-contradiction.sh +0 -67
- package/pipeline/scripts/smoke-validator-gates.sh +0 -164
- package/pipeline/scripts/smoke-vercel-deploy-redact.sh +0 -129
- package/pipeline/scripts/smoke-verify-by-test.sh +0 -148
- package/pipeline/scripts/smoke-wiki-integration.sh +0 -122
- package/pipeline/scripts/smoke-work-summary.sh +0 -163
- package/pipeline/scripts/smoke-workflow-audit.sh +0 -101
- package/pipeline/scripts/smoke-worktree-path-convention.sh +0 -86
- package/pipeline/scripts/smoke-wrapper-preservation.sh +0 -68
- package/pipeline/scripts/smoke-write-state.sh +0 -159
- package/pipeline/scripts/sync-parity-check.sh +0 -135
- package/pipeline/scripts/test-gap-rules/android.json +0 -25
- package/pipeline/scripts/test-gap-rules/ios.json +0 -34
- package/pipeline/scripts/test-gap-rules/node.json +0 -29
- package/pipeline/scripts/test-gap-rules/python.json +0 -25
- 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 ]
|