@mmerterden/multi-agent-pipeline 12.5.0 → 12.7.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 +213 -0
- package/README.md +19 -19
- package/docs/FIGMA_PIPELINE.md +34 -34
- package/docs/adr/0001-three-model-triage.md +12 -12
- package/docs/adr/0002-instruction-driven-flag.md +5 -5
- package/docs/adr/0003-unified-shared-skills.md +5 -5
- package/docs/adr/0004-zero-dependency-philosophy.md +5 -5
- package/docs/adr/0005-lazy-phase-docs.md +2 -2
- package/docs/adr/0006-skills-core-external-split.md +6 -6
- package/docs/adr/0007-multi-tool-adapter-framework.md +19 -19
- package/docs/adr/0008-installer-modularization-and-secret-leak-defense.md +19 -19
- package/docs/adr/README.md +1 -1
- package/docs/best-practices.md +3 -3
- package/docs/features.md +48 -28
- package/docs/performance.md +16 -16
- package/docs/recovery-guide.md +39 -39
- package/index.js +11 -5
- package/install/_common.mjs +5 -11
- package/install/_copilot-instructions.mjs +2 -2
- package/install/_dev-only-files.mjs +2 -1
- package/install/_platform-filter.mjs +1 -1
- package/install/_telemetry.mjs +1 -1
- package/install/claude.mjs +10 -9
- package/install/copilot.mjs +10 -19
- package/install/index.mjs +7 -15
- package/install/templates/copilot-instructions.md +54 -54
- package/install.js +1 -1
- package/package.json +15 -11
- package/pipeline/agents/security-auditor.md +1 -1
- package/pipeline/commands/archive-guard.md +5 -5
- package/pipeline/commands/multi-agent/SKILL.md +3 -1
- package/pipeline/commands/multi-agent/analysis/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/analysis-resolve/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/autopilot/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/build-optimize/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/create-jira/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/design-check/SKILL.md +287 -0
- package/pipeline/commands/multi-agent/dev/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/dev-autopilot/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/dev-local/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/dev-local-autopilot/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/diff-explain/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/finish/SKILL.md +6 -6
- package/pipeline/commands/multi-agent/forget/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/help/SKILL.md +46 -6
- package/pipeline/commands/multi-agent/issue/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/jira/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/kill/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/language/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/local/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/local-autopilot/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/log/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/manual-test/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/prune-logs/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/purge/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/refactor/SKILL.md +107 -19
- package/pipeline/commands/multi-agent/resume/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/review/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/review-issue/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/review-jira/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/routines/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/save/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/scan/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/search/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/setup/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/stack/SKILL.md +3 -3
- package/pipeline/commands/multi-agent/status/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/sync/SKILL.md +123 -16
- package/pipeline/commands/multi-agent/test/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/uninstall/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/update/SKILL.md +3 -3
- package/pipeline/commands/sim-test.md +5 -5
- package/pipeline/eval/run-metrics-fixture.json +60 -13
- package/pipeline/lib/account-resolver.sh +1 -1
- package/pipeline/lib/channels-multi-repo.sh +1 -1
- package/pipeline/lib/context-link-extractor.sh +1 -1
- package/pipeline/lib/credential-store.sh +33 -1
- package/pipeline/lib/fetch-confluence.sh +1 -1
- package/pipeline/lib/fetch-crashlytics.sh +1 -1
- package/pipeline/lib/fetch-fortify.sh +1 -1
- package/pipeline/lib/fetch-graylog.sh +1 -1
- package/pipeline/lib/fetch-swagger.sh +1 -1
- package/pipeline/lib/issue-fetcher.sh +1 -1
- package/pipeline/lib/multi-repo-pipeline.sh +1 -1
- package/pipeline/lib/repo-cache.sh +1 -1
- package/pipeline/lib/submodule-detector.sh +1 -1
- package/pipeline/multi-agent-refs/component-dispatch.md +1 -1
- package/pipeline/multi-agent-refs/component-generation.md +121 -0
- package/pipeline/multi-agent-refs/cross-cli-contract.md +4 -4
- package/pipeline/multi-agent-refs/features/model-fallback.md +2 -2
- package/pipeline/multi-agent-refs/phases/phase-3-dev.md +2 -2
- package/pipeline/multi-agent-refs/phases/phase-4-review.md +1 -1
- package/pipeline/multi-agent-refs/phases/phase-5-test.md +4 -4
- package/pipeline/preferences-template.json +23 -12
- package/pipeline/schemas/agent-state.schema.json +125 -5
- package/pipeline/schemas/analysis-output.schema.json +18 -4
- package/pipeline/schemas/analysis-spec.schema.json +120 -32
- package/pipeline/schemas/clarify-output.schema.json +15 -5
- package/pipeline/schemas/design-check-config.schema.json +183 -0
- package/pipeline/schemas/dev-critic-output.schema.json +20 -5
- package/pipeline/schemas/figma-project-config.schema.json +42 -10
- package/pipeline/schemas/learnings-ledger.schema.json +10 -2
- package/pipeline/schemas/migrations/figma-config-1.0.0-to-2.0.0.mjs +1 -4
- package/pipeline/schemas/migrations/prefs-2.0.0-to-2.1.0.mjs +24 -7
- package/pipeline/schemas/migrations/state-2.0.0-to-2.1.0.mjs +30 -12
- package/pipeline/schemas/plan-todos.schema.json +6 -3
- package/pipeline/schemas/planning-output.schema.json +5 -1
- package/pipeline/schemas/prefs.schema.json +215 -197
- package/pipeline/schemas/test-gap.schema.json +5 -5
- package/pipeline/schemas/token-budget.json +8 -8
- package/pipeline/schemas/triage-corpus.schema.json +1 -1
- package/pipeline/scripts/README.md +7 -5
- package/pipeline/scripts/aggregate-metrics.mjs +18 -6
- package/pipeline/scripts/build-skills-index.mjs +6 -2
- package/pipeline/scripts/build-stack-plugins.mjs +142 -39
- package/pipeline/scripts/check-derived-drift.mjs +196 -0
- package/pipeline/scripts/check-md-links.mjs +6 -2
- package/pipeline/scripts/classify-plan-safety.mjs +26 -8
- package/pipeline/scripts/cost-budget-check.mjs +11 -6
- package/pipeline/scripts/cost-table.json +1 -1
- package/pipeline/scripts/diff-explain.mjs +7 -3
- package/pipeline/scripts/diff-risk-score.mjs +13 -3
- package/pipeline/scripts/eval-golden-tasks-live.mjs +8 -3
- package/pipeline/scripts/eval-golden-tasks.mjs +21 -9
- package/pipeline/scripts/eval-intent.mjs +8 -4
- package/pipeline/scripts/eval-mine-corpus.mjs +14 -4
- package/pipeline/scripts/evidence-gate.mjs +7 -2
- package/pipeline/scripts/fixtures/install-layout.tsv +7 -7
- package/pipeline/scripts/gen-mode-dispatch.mjs +38 -21
- package/pipeline/scripts/gen-skills-index.mjs +18 -3
- package/pipeline/scripts/learning-curve.mjs +13 -3
- package/pipeline/scripts/learnings-ledger.mjs +119 -34
- package/pipeline/scripts/lint-mcp-refs.mjs +218 -0
- package/pipeline/scripts/lint-skills.mjs +20 -9
- package/pipeline/scripts/localize-commands.mjs +6 -1
- package/pipeline/scripts/match-skills.mjs +15 -4
- package/pipeline/scripts/memory-load.sh +5 -1
- package/pipeline/scripts/migrate-prefs.mjs +33 -16
- package/pipeline/scripts/phase-tracker.sh +3 -1
- package/pipeline/scripts/render-work-summary.sh +4 -1
- package/pipeline/scripts/repo-map.mjs +110 -64
- package/pipeline/scripts/review-scope.mjs +7 -1
- package/pipeline/scripts/routine-registry.mjs +4 -9
- package/pipeline/scripts/run-aggregator.mjs +11 -5
- package/pipeline/scripts/run-metrics.mjs +13 -8
- package/pipeline/scripts/run-smokes.mjs +57 -3
- package/pipeline/scripts/scorecard.mjs +258 -0
- package/pipeline/scripts/smoke-command-inventory.sh +81 -0
- package/pipeline/scripts/smoke-commands-skills-parity.sh +1 -1
- package/pipeline/scripts/smoke-compliance-skills.sh +4 -4
- package/pipeline/scripts/smoke-context-budget.sh +72 -0
- package/pipeline/scripts/smoke-cross-cli-behavior.sh +12 -2
- package/pipeline/scripts/smoke-generate-issue.sh +6 -5
- package/pipeline/scripts/smoke-model-fallback.sh +1 -1
- package/pipeline/scripts/smoke-no-mcp-in-dev-phases.sh +86 -7
- package/pipeline/scripts/smoke-own-punctuation.sh +103 -0
- package/pipeline/scripts/smoke-per-repo-memory.sh +2 -2
- package/pipeline/scripts/smoke-review-readiness.sh +3 -2
- package/pipeline/scripts/smoke-schema-validation.sh +19 -5
- package/pipeline/scripts/smoke-shadow-git.sh +4 -2
- package/pipeline/scripts/smoke-workflow-audit.sh +43 -11
- package/pipeline/scripts/smoke-write-state.sh +49 -5
- package/pipeline/scripts/test-gap-rules/android.json +11 -11
- package/pipeline/scripts/test-gap-rules/ios.json +16 -11
- package/pipeline/scripts/test-gap-rules/node.json +19 -7
- package/pipeline/scripts/test-gap-rules/python.json +10 -4
- package/pipeline/scripts/test-gap-scan.mjs +44 -12
- package/pipeline/scripts/test-integrity-gate.mjs +5 -1
- package/pipeline/scripts/token-budget-report.mjs +44 -21
- package/pipeline/scripts/triage-memory.mjs +142 -32
- package/pipeline/scripts/uninstall.mjs +75 -31
- package/pipeline/scripts/validate-analysis-doc.mjs +15 -5
- package/pipeline/scripts/validate-diff-risk.mjs +32 -18
- package/pipeline/scripts/validate-test-gap.mjs +17 -7
- package/pipeline/scripts/validate-triage.mjs +17 -5
- package/pipeline/scripts/write-state.mjs +32 -9
- package/pipeline/skills/.skill-manifest.json +24 -8
- package/pipeline/skills/.skills-index.json +125 -89
- package/pipeline/skills/shared/README.md +65 -61
- package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +10 -8
- package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent/SKILL.md +26 -279
- package/pipeline/skills/shared/core/multi-agent-analysis/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-analysis-resolve/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-autopilot/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-build-optimize/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-create-jira/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-design-check/SKILL.md +248 -0
- package/pipeline/skills/shared/core/multi-agent-dev/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-dev-autopilot/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-dev-local/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-dev-local-autopilot/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-diff-explain/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-finish/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-forget/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-garbage-collect/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +23 -1
- package/pipeline/skills/shared/core/multi-agent-issue/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-jira/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-kill/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-local/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-local-autopilot/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-log/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-manual-test/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-prune-logs/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-purge/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +82 -18
- package/pipeline/skills/shared/core/multi-agent-resume/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +2 -2
- package/pipeline/skills/shared/core/multi-agent-review-issue/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-review-jira/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-routines/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-save/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-scan/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-search/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-stack/SKILL.md +3 -3
- package/pipeline/skills/shared/core/multi-agent-status/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +51 -9
- package/pipeline/skills/shared/core/multi-agent-test/SKILL.md +2 -2
- package/pipeline/skills/shared/core/multi-agent-uninstall/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-update/SKILL.md +1 -1
- package/pipeline/skills/shared/external/accessibility-compliance-accessibility-audit/SKILL.md +1 -1
- package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +4 -4
- package/pipeline/skills/shared/external/agentflow/SKILL.md +1 -1
- package/pipeline/skills/shared/external/android-jetpack-compose-expert/SKILL.md +1 -1
- package/pipeline/skills/shared/external/android_ui_verification/SKILL.md +1 -1
- package/pipeline/skills/shared/external/api-patterns/SKILL.md +1 -1
- package/pipeline/skills/shared/external/api-security-best-practices/SKILL.md +1 -1
- package/pipeline/skills/shared/external/app-store-changelog/SKILL.md +1 -1
- package/pipeline/skills/shared/external/backlog/BACKLOG.md +1 -1
- package/pipeline/skills/shared/external/backlog/SKILL.md +12 -12
- package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +1 -1
- package/pipeline/skills/shared/external/context-compression/SKILL.md +1 -1
- package/pipeline/skills/shared/external/council/SKILL.md +3 -3
- package/pipeline/skills/shared/external/css-modern/SKILL.md +1 -1
- package/pipeline/skills/shared/external/database-patterns/SKILL.md +1 -1
- package/pipeline/skills/shared/external/debugging-strategies/SKILL.md +1 -1
- package/pipeline/skills/shared/external/docker-expert/SKILL.md +1 -1
- package/pipeline/skills/shared/external/fastapi-pro/SKILL.md +1 -1
- package/pipeline/skills/shared/external/firebase/SKILL.md +1 -1
- package/pipeline/skills/shared/external/github-actions-templates/SKILL.md +1 -1
- package/pipeline/skills/shared/external/help-skills/SKILL.md +1 -1
- package/pipeline/skills/shared/external/hig-components-content/SKILL.md +1 -1
- package/pipeline/skills/shared/external/hig-components-layout/SKILL.md +1 -1
- package/pipeline/skills/shared/external/hig-components-status/SKILL.md +1 -1
- package/pipeline/skills/shared/external/hig-components-system/SKILL.md +1 -1
- package/pipeline/skills/shared/external/hig-foundations/SKILL.md +1 -1
- package/pipeline/skills/shared/external/hig-inputs/SKILL.md +1 -1
- package/pipeline/skills/shared/external/hig-patterns/SKILL.md +1 -1
- package/pipeline/skills/shared/external/hig-platforms/SKILL.md +1 -1
- package/pipeline/skills/shared/external/hig-technologies/SKILL.md +1 -1
- package/pipeline/skills/shared/external/html-semantic/SKILL.md +1 -1
- package/pipeline/skills/shared/external/humanizer/SKILL.md +1 -1
- package/pipeline/skills/shared/external/ios-debugger-agent/SKILL.md +1 -1
- package/pipeline/skills/shared/external/ios-developer/SKILL.md +1 -1
- package/pipeline/skills/shared/external/kotlin-coroutines-expert/SKILL.md +1 -1
- package/pipeline/skills/shared/external/macos-menubar-tuist-app/SKILL.md +1 -1
- package/pipeline/skills/shared/external/macos-spm-app-packaging/SKILL.md +1 -1
- package/pipeline/skills/shared/external/monorepo-architect/SKILL.md +1 -1
- package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +1 -1
- package/pipeline/skills/shared/external/nodejs-backend-patterns/SKILL.md +1 -1
- package/pipeline/skills/shared/external/observability-engineer/SKILL.md +1 -1
- package/pipeline/skills/shared/external/python-patterns/SKILL.md +1 -1
- package/pipeline/skills/shared/external/react-best-practices/SKILL.md +1 -1
- package/pipeline/skills/shared/external/rest-api-design/SKILL.md +1 -1
- package/pipeline/skills/shared/external/search-first/SKILL.md +2 -2
- package/pipeline/skills/shared/external/skill-creator/SKILL.md +12 -12
- package/pipeline/skills/shared/external/skill-creator/audit.md +21 -21
- package/pipeline/skills/shared/external/skill-creator/checklist.md +3 -3
- package/pipeline/skills/shared/external/skill-creator/examples.md +10 -10
- package/pipeline/skills/shared/external/skill-creator/label-check.md +17 -17
- package/pipeline/skills/shared/external/skill-creator/scripts/audit-panel.js +86 -50
- package/pipeline/skills/shared/external/skill-creator/template.md +9 -9
- package/pipeline/skills/shared/external/swift-concurrency-expert/SKILL.md +1 -1
- package/pipeline/skills/shared/external/swiftui-performance-audit/SKILL.md +1 -1
- package/pipeline/skills/shared/external/swiftui-ui-patterns/SKILL.md +1 -1
- package/pipeline/skills/shared/external/swiftui-view-refactor/SKILL.md +1 -1
- package/pipeline/skills/shared/external/tailwind-css/SKILL.md +1 -1
- package/pipeline/skills/shared/external/testing-backend/SKILL.md +1 -1
- package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +1 -1
- package/pipeline/skills/shared/external/vue-composition/SKILL.md +1 -1
- package/pipeline/skills/shared/external/web-accessibility/SKILL.md +1 -1
- package/pipeline/skills/shared/external/web-performance/SKILL.md +1 -1
- package/pipeline/skills/shared/external/web-testing/SKILL.md +1 -1
- package/pipeline/skills/shared/external/xcode-build-benchmark/schemas/build-benchmark.schema.json +9 -49
- package/pipeline/skills/skills-index.md +63 -59
- package/pipeline/scripts/smoke-plugin-validate.sh +0 -64
|
@@ -22,7 +22,43 @@ import { fileURLToPath } from "node:url";
|
|
|
22
22
|
const scriptsDir = dirname(fileURLToPath(import.meta.url));
|
|
23
23
|
const timeoutSec = Number(process.env.SMOKE_TIMEOUT_SECONDS || 180);
|
|
24
24
|
const bail = process.env.SMOKE_NO_BAIL !== "1";
|
|
25
|
-
const
|
|
25
|
+
const argv = process.argv.slice(2);
|
|
26
|
+
const reportCounts = argv.includes("--counts");
|
|
27
|
+
const filters = argv.filter((a) => !a.startsWith("--"));
|
|
28
|
+
|
|
29
|
+
// How many assertions did a suite actually make?
|
|
30
|
+
//
|
|
31
|
+
// Exit code alone cannot answer that, and the difference matters: three smokes
|
|
32
|
+
// were exiting 0 having checked nothing. smoke-workflow-audit skipped both its
|
|
33
|
+
// linters because neither was installed anywhere, so the GitHub Actions
|
|
34
|
+
// security audit had never run while showing green - it was hiding a
|
|
35
|
+
// high-severity finding. smoke-plugin-validate had no manifest to validate in
|
|
36
|
+
// this repo at all. A gate that cannot fail is worse than no gate, because the
|
|
37
|
+
// green tick is read as coverage.
|
|
38
|
+
//
|
|
39
|
+
// The four output shapes actually in use here, surveyed across all suites
|
|
40
|
+
// rather than assumed. Anything a suite prints that matches none of them
|
|
41
|
+
// counts as zero, which is the intended answer: an unrecognisable result is
|
|
42
|
+
// not evidence that something was checked.
|
|
43
|
+
//
|
|
44
|
+
// 1. "══ name: 22 passed, 0 failed ══" most suites
|
|
45
|
+
// 2. "check-md-links: 212 files OK" counted sweeps
|
|
46
|
+
// 3. per-line "✓" / "ok " / "PASS:" suites with no summary line
|
|
47
|
+
// 4. "smoke-language-axis: ok" terse single-verdict suites
|
|
48
|
+
function countAssertions(stdout) {
|
|
49
|
+
const passed = [...stdout.matchAll(/(\d+) passed/g)];
|
|
50
|
+
if (passed.length > 0) return Number(passed[passed.length - 1][1]);
|
|
51
|
+
|
|
52
|
+
const swept = [...stdout.matchAll(/(\d+) (?:files|patterns|checks|entries) (?:OK|clean)/gi)];
|
|
53
|
+
if (swept.length > 0) return Number(swept[swept.length - 1][1]);
|
|
54
|
+
|
|
55
|
+
const marks = stdout.match(/^[ \t]*(✓|ok |PASS[: ])/gm);
|
|
56
|
+
if (marks) return marks.length;
|
|
57
|
+
|
|
58
|
+
if (/^\S+: ok\s*$/m.test(stdout)) return 1;
|
|
59
|
+
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
26
62
|
|
|
27
63
|
const suites = readdirSync(scriptsDir)
|
|
28
64
|
.filter((f) => f.startsWith("smoke-") && f.endsWith(".sh"))
|
|
@@ -49,10 +85,28 @@ for (const suite of suites) {
|
|
|
49
85
|
const secs = ((Date.now() - t0) / 1000).toFixed(1);
|
|
50
86
|
|
|
51
87
|
const timedOut = res.error && res.error.code === "ETIMEDOUT";
|
|
52
|
-
const
|
|
88
|
+
const asserted = countAssertions(res.stdout || "");
|
|
89
|
+
const ok = !timedOut && res.status === 0 && (reportCounts || asserted > 0);
|
|
90
|
+
|
|
91
|
+
if (reportCounts) {
|
|
92
|
+
console.log(`${String(asserted).padStart(4)} ${suite}`);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
53
95
|
|
|
54
96
|
if (ok) {
|
|
55
|
-
console.log(`ok ${suite} (${secs}s)`);
|
|
97
|
+
console.log(`ok ${suite} (${secs}s, ${asserted} checks)`);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!timedOut && res.status === 0 && asserted === 0) {
|
|
102
|
+
console.error(
|
|
103
|
+
`FAIL ${suite} (exited 0 having asserted nothing, ${secs}s)\n` +
|
|
104
|
+
" A suite that checks nothing reports coverage it does not have.\n" +
|
|
105
|
+
" Give it something to assert, or delete it.",
|
|
106
|
+
);
|
|
107
|
+
if (res.stdout) console.error(res.stdout.split("\n").slice(-15).join("\n"));
|
|
108
|
+
failures.push(suite);
|
|
109
|
+
if (bail) break;
|
|
56
110
|
continue;
|
|
57
111
|
}
|
|
58
112
|
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// scorecard.mjs - the measurable part of the review score, as a gate.
|
|
3
|
+
//
|
|
4
|
+
// A refactor review scores ten categories out of ten. Six of those numbers can
|
|
5
|
+
// be measured; four cannot, and writing a number for those is how a scorecard
|
|
6
|
+
// turns into self-congratulation. So this reports exactly two things:
|
|
7
|
+
//
|
|
8
|
+
// MEASURED a metric with a threshold, pass or fail
|
|
9
|
+
// UNMEASURED a category no script can score, named as such
|
|
10
|
+
//
|
|
11
|
+
// Nothing here re-implements a check. Each metric either reads a committed
|
|
12
|
+
// threshold file or shells out to the gate that already owns the question, so
|
|
13
|
+
// there is one source of truth per question and the scorecard cannot drift from
|
|
14
|
+
// the gates it summarises.
|
|
15
|
+
//
|
|
16
|
+
// Thresholds are locked at the values measured when the gate was written. They
|
|
17
|
+
// are a ratchet: lowering one is a deliberate, reviewable edit, and a metric
|
|
18
|
+
// that improves should have its floor raised.
|
|
19
|
+
//
|
|
20
|
+
// Runs on a clean clone: no $HOME lookups, no credentials, no network. The one
|
|
21
|
+
// metric that needs local configuration (derived-skill drift) reports
|
|
22
|
+
// NOT CONFIGURED rather than passing by default.
|
|
23
|
+
//
|
|
24
|
+
// Usage: node pipeline/scripts/scorecard.mjs [--json]
|
|
25
|
+
// Exit: 0 every measured metric within threshold, 1 otherwise
|
|
26
|
+
|
|
27
|
+
import { execFileSync } from "node:child_process";
|
|
28
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
29
|
+
import { dirname, join } from "node:path";
|
|
30
|
+
import { fileURLToPath } from "node:url";
|
|
31
|
+
|
|
32
|
+
const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
33
|
+
const asJson = process.argv.includes("--json");
|
|
34
|
+
|
|
35
|
+
// Locked floors. Raise when a metric improves; lowering one is the reviewable act.
|
|
36
|
+
const FLOORS = {
|
|
37
|
+
coverageLines: 72,
|
|
38
|
+
coverageBranches: 68,
|
|
39
|
+
coverageFunctions: 85,
|
|
40
|
+
contextBytes: 60000,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const results = [];
|
|
44
|
+
|
|
45
|
+
function measured(category, metric, ok, detail) {
|
|
46
|
+
results.push({ kind: "MEASURED", category, metric, ok, detail });
|
|
47
|
+
}
|
|
48
|
+
function unmeasured(category, why) {
|
|
49
|
+
results.push({ kind: "UNMEASURED", category, why });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Run a gate and report whether it passed. The gate owns the assertion; this
|
|
53
|
+
// only records the verdict, so the two can never disagree.
|
|
54
|
+
function gate(category, metric, argv) {
|
|
55
|
+
try {
|
|
56
|
+
execFileSync(argv[0], argv.slice(1), { cwd: ROOT, stdio: "pipe" });
|
|
57
|
+
return measured(category, metric, true, "gate passed");
|
|
58
|
+
} catch (e) {
|
|
59
|
+
const out = `${e.stdout || ""}${e.stderr || ""}`.trim().split("\n").slice(-3).join(" | ");
|
|
60
|
+
return measured(category, metric, false, out || `exit ${e.status}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// --- Tests: the coverage floors must not be lowered ------------------------
|
|
65
|
+
// c8 enforces the numbers on every run; what nothing enforced was the numbers
|
|
66
|
+
// themselves. .c8rc.json reported 83% while the real figure over its own include
|
|
67
|
+
// set was 33%, because `all` was missing - so the floors are worth pinning.
|
|
68
|
+
{
|
|
69
|
+
const c8 = JSON.parse(readFileSync(join(ROOT, ".c8rc.json"), "utf-8"));
|
|
70
|
+
const checks = [
|
|
71
|
+
["lines", c8.lines, FLOORS.coverageLines],
|
|
72
|
+
["branches", c8.branches, FLOORS.coverageBranches],
|
|
73
|
+
["functions", c8.functions, FLOORS.coverageFunctions],
|
|
74
|
+
];
|
|
75
|
+
const low = checks.filter(([, actual, floor]) => !(actual >= floor));
|
|
76
|
+
measured(
|
|
77
|
+
"Tests",
|
|
78
|
+
"coverage floors held",
|
|
79
|
+
c8.all === true && low.length === 0,
|
|
80
|
+
c8.all !== true
|
|
81
|
+
? "`all` is not set, so the floors only cover files the tests already load"
|
|
82
|
+
: low.length
|
|
83
|
+
? low.map(([k, a, f]) => `${k} ${a} below the locked ${f}`).join(", ")
|
|
84
|
+
: checks.map(([k, a]) => `${k} ${a}`).join(", "),
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// --- Dependency management: no high or critical advisories ------------------
|
|
89
|
+
{
|
|
90
|
+
let vulns;
|
|
91
|
+
try {
|
|
92
|
+
const raw = execFileSync("npm", ["audit", "--json"], { cwd: ROOT, encoding: "utf-8" });
|
|
93
|
+
vulns = JSON.parse(raw).metadata.vulnerabilities;
|
|
94
|
+
} catch (e) {
|
|
95
|
+
// npm audit exits non-zero when it finds something; the JSON is still on stdout.
|
|
96
|
+
try {
|
|
97
|
+
vulns = JSON.parse(e.stdout).metadata.vulnerabilities;
|
|
98
|
+
} catch {
|
|
99
|
+
vulns = null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (!vulns) {
|
|
103
|
+
measured(
|
|
104
|
+
"Dependency management",
|
|
105
|
+
"no high or critical advisories",
|
|
106
|
+
false,
|
|
107
|
+
"npm audit produced no parseable report",
|
|
108
|
+
);
|
|
109
|
+
} else {
|
|
110
|
+
const bad = vulns.high + vulns.critical;
|
|
111
|
+
measured(
|
|
112
|
+
"Dependency management",
|
|
113
|
+
"no high or critical advisories",
|
|
114
|
+
bad === 0,
|
|
115
|
+
`critical ${vulns.critical}, high ${vulns.high}, moderate ${vulns.moderate}`,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// --- Performance: the bytes every run pays before it starts ----------------
|
|
121
|
+
gate("Performance", "fixed per-run context within budget", [
|
|
122
|
+
"bash",
|
|
123
|
+
"pipeline/scripts/smoke-context-budget.sh",
|
|
124
|
+
]);
|
|
125
|
+
|
|
126
|
+
// --- CI/CD: the workflow audit runs, and finds nothing ---------------------
|
|
127
|
+
// Strict by default, so a runner without the linters fails here rather than
|
|
128
|
+
// reporting a clean audit it never performed.
|
|
129
|
+
gate("CI/CD", "workflow audit clean (zizmor + actionlint)", [
|
|
130
|
+
"bash",
|
|
131
|
+
"pipeline/scripts/smoke-workflow-audit.sh",
|
|
132
|
+
]);
|
|
133
|
+
|
|
134
|
+
// --- Code quality: our own punctuation rule, both encodings ---------------
|
|
135
|
+
gate("Code quality", "no banned punctuation in shipped files", [
|
|
136
|
+
"bash",
|
|
137
|
+
"pipeline/scripts/smoke-own-punctuation.sh",
|
|
138
|
+
]);
|
|
139
|
+
|
|
140
|
+
// --- Documentation: every skill description routes ------------------------
|
|
141
|
+
gate("Documentation", "every skill description has a routing clause", [
|
|
142
|
+
"node",
|
|
143
|
+
"pipeline/scripts/lint-skills.mjs",
|
|
144
|
+
]);
|
|
145
|
+
|
|
146
|
+
// --- Documentation: the licence and changelog a consumer expects ----------
|
|
147
|
+
{
|
|
148
|
+
const missing = ["LICENSE", "CHANGELOG.md", "README.md", "SECURITY.md"].filter(
|
|
149
|
+
(f) => !existsSync(join(ROOT, f)),
|
|
150
|
+
);
|
|
151
|
+
measured(
|
|
152
|
+
"Documentation",
|
|
153
|
+
"licence, changelog, readme, security present",
|
|
154
|
+
missing.length === 0,
|
|
155
|
+
missing.length ? `missing: ${missing.join(", ")}` : "all four present",
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// --- Tests: no suite reports success without asserting anything ------------
|
|
160
|
+
// The runner owns this check; asking it for the counts would re-run 120 suites,
|
|
161
|
+
// so the scorecard asserts the capability is wired rather than re-measuring it.
|
|
162
|
+
{
|
|
163
|
+
const runner = readFileSync(join(ROOT, "pipeline", "scripts", "run-smokes.mjs"), "utf-8");
|
|
164
|
+
const wired = runner.includes("countAssertions") && /asserted nothing/.test(runner);
|
|
165
|
+
measured(
|
|
166
|
+
"Tests",
|
|
167
|
+
"runner rejects a suite that asserted nothing",
|
|
168
|
+
wired,
|
|
169
|
+
wired
|
|
170
|
+
? "zero-assertion check present in run-smokes.mjs"
|
|
171
|
+
: "run-smokes.mjs no longer counts assertions",
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// --- Drift: needs local configuration, so it reports honestly -------------
|
|
176
|
+
{
|
|
177
|
+
// The exit code alone cannot answer this. check-derived-drift exits 0 both
|
|
178
|
+
// when every derivation is current AND when nothing is configured at all, and
|
|
179
|
+
// those are different facts: one is a pass, the other is an absence of
|
|
180
|
+
// evidence. Reading `configured` off the JSON is what tells them apart. The
|
|
181
|
+
// first version of this block trusted exit 0 and reported an unconfigured
|
|
182
|
+
// machine as a passing metric, which is the exact failure this whole gate set
|
|
183
|
+
// exists to prevent.
|
|
184
|
+
let state;
|
|
185
|
+
let ok = false;
|
|
186
|
+
let parsed;
|
|
187
|
+
try {
|
|
188
|
+
parsed = JSON.parse(
|
|
189
|
+
execFileSync("node", ["pipeline/scripts/check-derived-drift.mjs", "--json"], {
|
|
190
|
+
cwd: ROOT,
|
|
191
|
+
encoding: "utf-8",
|
|
192
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
193
|
+
}),
|
|
194
|
+
);
|
|
195
|
+
} catch (e) {
|
|
196
|
+
// Non-zero exit still writes the report to stdout; an unparseable one means
|
|
197
|
+
// the check itself could not run.
|
|
198
|
+
try {
|
|
199
|
+
parsed = JSON.parse(e.stdout);
|
|
200
|
+
} catch {
|
|
201
|
+
parsed = undefined;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (parsed && parsed.configured > 0) {
|
|
205
|
+
const bad = parsed.drifted + parsed.unverified + parsed.unreachable;
|
|
206
|
+
ok = bad === 0;
|
|
207
|
+
state = ok
|
|
208
|
+
? `${parsed.configured} derivation(s) current with upstream`
|
|
209
|
+
: `${parsed.drifted} drifted, ${parsed.unverified} unverified, ${parsed.unreachable} unreachable`;
|
|
210
|
+
} else if (parsed) {
|
|
211
|
+
state = "NOT CONFIGURED - prefs carry no derivedSkillSources on this machine";
|
|
212
|
+
} else {
|
|
213
|
+
state = "NOT CONFIGURED - the drift check produced no parseable report";
|
|
214
|
+
}
|
|
215
|
+
if (state.startsWith("NOT CONFIGURED")) {
|
|
216
|
+
unmeasured("Derived-skill drift", state);
|
|
217
|
+
} else {
|
|
218
|
+
measured("Architecture", "derived skills current with upstream", ok, state);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// --- What no script can score --------------------------------------------
|
|
223
|
+
unmeasured("Architecture", "layer separation and dependency direction are judgement, not a number");
|
|
224
|
+
unmeasured("DevEx", "onboarding time and error-message quality need a person");
|
|
225
|
+
unmeasured(
|
|
226
|
+
"Accessibility",
|
|
227
|
+
"nothing in this repo renders UI; the audits it ships are scored per target app",
|
|
228
|
+
);
|
|
229
|
+
unmeasured(
|
|
230
|
+
"Code quality",
|
|
231
|
+
"naming, cohesion and altitude are judgement; only the mechanical rules above are gated",
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
const failed = results.filter((r) => r.kind === "MEASURED" && !r.ok);
|
|
235
|
+
const passed = results.filter((r) => r.kind === "MEASURED" && r.ok);
|
|
236
|
+
|
|
237
|
+
if (asJson) {
|
|
238
|
+
console.log(JSON.stringify({ passed: passed.length, failed: failed.length, results }, null, 2));
|
|
239
|
+
} else {
|
|
240
|
+
console.log("MEASURED");
|
|
241
|
+
for (const r of results.filter((x) => x.kind === "MEASURED")) {
|
|
242
|
+
console.log(` ${r.ok ? "✓" : "✗"} ${r.category}: ${r.metric}`);
|
|
243
|
+
console.log(` ${r.detail}`);
|
|
244
|
+
}
|
|
245
|
+
console.log("");
|
|
246
|
+
console.log("UNMEASURED (reported, never scored)");
|
|
247
|
+
for (const r of results.filter((x) => x.kind === "UNMEASURED")) {
|
|
248
|
+
console.log(` - ${r.category}: ${r.why}`);
|
|
249
|
+
}
|
|
250
|
+
console.log("");
|
|
251
|
+
console.log(`══ scorecard: ${passed.length} measured metrics passed, ${failed.length} failed ══`);
|
|
252
|
+
if (failed.length === 0) {
|
|
253
|
+
console.log("Every mechanically checkable claim holds. The four unmeasured");
|
|
254
|
+
console.log("categories above are not covered by that statement.");
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
process.exit(failed.length === 0 ? 0 : 1);
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# smoke-command-inventory.sh - the command inventory is DERIVED, never asserted.
|
|
3
|
+
#
|
|
4
|
+
# Every count that describes "how many multi-agent commands exist" used to be a
|
|
5
|
+
# literal in prose (contract header, sync skill, dispatcher). Adding a command
|
|
6
|
+
# left those literals stale while every gate stayed green, because the gates
|
|
7
|
+
# asserted the literal instead of the tree. This gate computes the count from
|
|
8
|
+
# pipeline/commands/multi-agent/*/ and requires the prose to agree.
|
|
9
|
+
#
|
|
10
|
+
# Verifies:
|
|
11
|
+
# 1. contract header count == number of command directories
|
|
12
|
+
# 2. every command directory appears in the contract inventory block
|
|
13
|
+
# 3. both sync surfaces (command + Copilot skill) carry the same count twice
|
|
14
|
+
# ("N commands are synced" + "instructions + N sub-command skills")
|
|
15
|
+
# 4. every command directory appears in both sync inventory blocks
|
|
16
|
+
# 5. every command directory has its shared/core skill counterpart
|
|
17
|
+
#
|
|
18
|
+
# Exit: 0 all green, 1 any failure.
|
|
19
|
+
|
|
20
|
+
set -euo pipefail
|
|
21
|
+
|
|
22
|
+
HERE="$(cd "$(dirname "$0")" && pwd)"
|
|
23
|
+
ROOT="$(cd "$HERE/../.." && pwd)"
|
|
24
|
+
CMD_DIR="$ROOT/pipeline/commands/multi-agent"
|
|
25
|
+
CONTRACT="$ROOT/pipeline/multi-agent-refs/cross-cli-contract.md"
|
|
26
|
+
SYNC="$ROOT/pipeline/commands/multi-agent/sync/SKILL.md"
|
|
27
|
+
SYNC_SKILL="$ROOT/pipeline/skills/shared/core/multi-agent-sync/SKILL.md"
|
|
28
|
+
SKILLS_DIR="$ROOT/pipeline/skills/shared/core"
|
|
29
|
+
|
|
30
|
+
PASS=0
|
|
31
|
+
FAIL=0
|
|
32
|
+
pass() { PASS=$((PASS+1)); echo " ✓ $1"; }
|
|
33
|
+
fail() { FAIL=$((FAIL+1)); echo " ✗ $1"; }
|
|
34
|
+
|
|
35
|
+
echo "══ smoke-command-inventory ══"
|
|
36
|
+
|
|
37
|
+
for f in "$CONTRACT" "$SYNC" "$SYNC_SKILL"; do
|
|
38
|
+
[ -f "$f" ] || { echo " ✗ missing file: ${f#$ROOT/}"; exit 1; }
|
|
39
|
+
done
|
|
40
|
+
|
|
41
|
+
COMMANDS=$(find "$CMD_DIR" -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | sort)
|
|
42
|
+
N=$(printf '%s\n' "$COMMANDS" | grep -c . || true)
|
|
43
|
+
|
|
44
|
+
echo "→ 1. derived count from the command tree: $N commands"
|
|
45
|
+
[ "$N" -gt 0 ] && pass "found $N command directories" || fail "no command directories under ${CMD_DIR#$ROOT/}"
|
|
46
|
+
|
|
47
|
+
echo "→ 2. contract header agrees"
|
|
48
|
+
if grep -Fq "## 1. Command Inventory ($N commands)" "$CONTRACT"; then
|
|
49
|
+
pass "contract header = $N"
|
|
50
|
+
else
|
|
51
|
+
fail "contract header does not say ($N commands): $(grep -o '## 1\. Command Inventory ([0-9]* commands)' "$CONTRACT" || echo 'header not found')"
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
echo "→ 3. sync surfaces agree (2 counts x 2 files)"
|
|
55
|
+
for f in "$SYNC" "$SYNC_SKILL"; do
|
|
56
|
+
rel="${f#$ROOT/}"
|
|
57
|
+
grep -Fq "**$N commands are synced**" "$f" && pass "$rel: synced count = $N" || fail "$rel: 'N commands are synced' != $N"
|
|
58
|
+
grep -Fq "instructions + $N sub-command skills" "$f" && pass "$rel: step-2 count = $N" || fail "$rel: 'instructions + N sub-command skills' != $N"
|
|
59
|
+
done
|
|
60
|
+
|
|
61
|
+
echo "→ 4. every command is listed in the contract + both sync inventories"
|
|
62
|
+
MISSING_LIST=0
|
|
63
|
+
while IFS= read -r cmd; do
|
|
64
|
+
[ -n "$cmd" ] || continue
|
|
65
|
+
for f in "$CONTRACT" "$SYNC" "$SYNC_SKILL"; do
|
|
66
|
+
grep -Eq "(^|[ ,])$cmd([ ,]|$)" "$f" || { fail "${f#$ROOT/}: inventory missing '$cmd'"; MISSING_LIST=1; }
|
|
67
|
+
done
|
|
68
|
+
done <<< "$COMMANDS"
|
|
69
|
+
[ "$MISSING_LIST" -eq 0 ] && pass "all $N commands listed on all 3 surfaces"
|
|
70
|
+
|
|
71
|
+
echo "→ 5. shared/core skill counterpart exists for every command"
|
|
72
|
+
MISSING_SKILL=0
|
|
73
|
+
while IFS= read -r cmd; do
|
|
74
|
+
[ -n "$cmd" ] || continue
|
|
75
|
+
[ -f "$SKILLS_DIR/multi-agent-$cmd/SKILL.md" ] || { fail "no shared/core skill for '$cmd'"; MISSING_SKILL=1; }
|
|
76
|
+
done <<< "$COMMANDS"
|
|
77
|
+
[ "$MISSING_SKILL" -eq 0 ] && pass "all $N commands have a shared/core skill"
|
|
78
|
+
|
|
79
|
+
echo ""
|
|
80
|
+
echo "══ command-inventory smoke: $PASS passed, $FAIL failed ══"
|
|
81
|
+
[ "$FAIL" -eq 0 ] || exit 1
|
|
@@ -36,7 +36,7 @@ fail() { FAIL=$((FAIL+1)); echo " ✗ $1"; }
|
|
|
36
36
|
# Underscore-prefixed files (e.g. _account-picker.md) are internal fragments
|
|
37
37
|
# loaded by other commands via Read; they're not invocable slash commands and
|
|
38
38
|
# intentionally have no matching skill.
|
|
39
|
-
CMDS=$(find "$CMDS_DIR" -mindepth 2 -maxdepth 2 -name "SKILL.md" -exec dirname
|
|
39
|
+
CMDS=$(find "$CMDS_DIR" -mindepth 2 -maxdepth 2 -name "SKILL.md" -exec sh -c 'for f do basename "$(dirname "$f")"; done' sh {} + | sort)
|
|
40
40
|
|
|
41
41
|
# help.md in commands maps to multi-agent-help skill; the main "multi-agent"
|
|
42
42
|
# skill covers the behavior documented across multiple command files, so we
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# that the 4 claimed consumer surfaces actually reference them (not just promise).
|
|
6
6
|
#
|
|
7
7
|
# Covers:
|
|
8
|
-
# 1. apple-archive-compliance/SKILL.md exists, has frontmatter,
|
|
8
|
+
# 1. apple-archive-compliance/SKILL.md exists, has frontmatter, 18-rule catalog,
|
|
9
9
|
# EN + TR humanizer blocks, severity table, prerequisite detection.
|
|
10
10
|
# 2. google-play-compliance/SKILL.md exists, has frontmatter, 21-rule catalog
|
|
11
11
|
# across 4 categories, EN + TR humanizer blocks, severity table, prereq detection.
|
|
@@ -43,8 +43,8 @@ grep -q "^name: apple-archive-compliance$" "$APPLE_SKILL" && pass "apple frontma
|
|
|
43
43
|
grep -q "^user-invocable: true$" "$APPLE_SKILL" && pass "apple user-invocable" || fail "apple user-invocable"
|
|
44
44
|
grep -q "argument-hint:" "$APPLE_SKILL" && pass "apple argument-hint" || fail "apple argument-hint"
|
|
45
45
|
# Count rule rows in the catalog table (excluding header + separator)
|
|
46
|
-
APPLE_RULES=$(awk '/^##
|
|
47
|
-
[ "$APPLE_RULES" -eq
|
|
46
|
+
APPLE_RULES=$(awk '/^## 18-Rule Catalog/,/^## Severity mapping/' "$APPLE_SKILL" | grep -cE '^\| *[0-9]+ *\|' || true)
|
|
47
|
+
[ "$APPLE_RULES" -eq 18 ] && pass "apple catalog has 18 rule rows" || fail "apple catalog has $APPLE_RULES rule rows (want 18)"
|
|
48
48
|
|
|
49
49
|
echo "→ 2. apple skill humanizer blocks EN + TR + severity table"
|
|
50
50
|
# v8.2 split humanizer language from picker language: gating moved from
|
|
@@ -59,7 +59,7 @@ echo "→ 3. apple skill prerequisite detection + archive resolution (v8.4.0+ us
|
|
|
59
59
|
grep -q 'ios_app_store_audit' "$APPLE_SKILL" && pass "apple references ios_app_store_audit MCP tool" || fail "apple ios_app_store_audit reference missing"
|
|
60
60
|
grep -q '.xcarchive' "$APPLE_SKILL" && pass "apple references .xcarchive" || fail "apple .xcarchive missing"
|
|
61
61
|
grep -q '@mmerterden/dev-toolkit-mcp' "$APPLE_SKILL" && pass "apple references @mmerterden/dev-toolkit-mcp package" || fail "apple dev-toolkit-mcp reference missing"
|
|
62
|
-
grep -q '
|
|
62
|
+
grep -q 'mcp__dev-toolkit__ios_app_store_audit' "$APPLE_SKILL" && pass "apple shows MCP-call invocation form" || fail "apple MCP-call invocation form missing"
|
|
63
63
|
|
|
64
64
|
echo "→ 4. google-play-compliance SKILL.md frontmatter + catalog shape"
|
|
65
65
|
grep -q "^name: google-play-compliance$" "$GOOGLE_SKILL" && pass "google frontmatter name" || fail "google frontmatter name"
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# smoke-context-budget.sh - the bytes every pipeline run pays before it starts.
|
|
4
|
+
#
|
|
5
|
+
# core/multi-agent/SKILL.md plus multi-agent-refs/rules.md load on every run of
|
|
6
|
+
# every mode, whatever the task. They were 67150 bytes together, roughly 17k
|
|
7
|
+
# tokens spent before the first phase, because the orchestrator skill had grown
|
|
8
|
+
# its own inline copies of things that already existed as loadable references -
|
|
9
|
+
# the log-file template (whose copy had gone stale and named a path the code no
|
|
10
|
+
# longer uses), the help text the multi-agent-help skill owns, and a component
|
|
11
|
+
# generation guide that only applies to design tasks.
|
|
12
|
+
#
|
|
13
|
+
# A budget nobody measures only moves one way, so this pins it. The ceiling is
|
|
14
|
+
# the measured value plus a small margin: enough to add a paragraph, not enough
|
|
15
|
+
# to move a chapter back in. Lowering it is always fine.
|
|
16
|
+
#
|
|
17
|
+
# Exit codes: 0=within budget, 1=over, 2=a tracked file is missing
|
|
18
|
+
|
|
19
|
+
set -euo pipefail
|
|
20
|
+
|
|
21
|
+
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
22
|
+
|
|
23
|
+
# The files loaded unconditionally at run start.
|
|
24
|
+
TRACKED="
|
|
25
|
+
pipeline/skills/shared/core/multi-agent/SKILL.md
|
|
26
|
+
pipeline/multi-agent-refs/rules.md
|
|
27
|
+
"
|
|
28
|
+
|
|
29
|
+
# Measured 57289 after the split. 60000 leaves ~2.7 kB of headroom.
|
|
30
|
+
CEILING=${CONTEXT_BUDGET_CEILING:-60000}
|
|
31
|
+
|
|
32
|
+
PASS=0
|
|
33
|
+
FAIL=0
|
|
34
|
+
pass() { PASS=$((PASS + 1)); echo " ✓ $1"; }
|
|
35
|
+
fail() { FAIL=$((FAIL + 1)); echo " ✗ $1"; }
|
|
36
|
+
|
|
37
|
+
echo "→ 1. every tracked file exists"
|
|
38
|
+
TOTAL=0
|
|
39
|
+
for rel in $TRACKED; do
|
|
40
|
+
f="$REPO_ROOT/$rel"
|
|
41
|
+
if [ ! -f "$f" ]; then
|
|
42
|
+
echo " ✗ missing: $rel"
|
|
43
|
+
echo " a tracked file that vanished makes the budget meaningless"
|
|
44
|
+
exit 2
|
|
45
|
+
fi
|
|
46
|
+
n=$(wc -c < "$f" | tr -d ' ')
|
|
47
|
+
TOTAL=$((TOTAL + n))
|
|
48
|
+
pass "$rel ($n bytes)"
|
|
49
|
+
done
|
|
50
|
+
|
|
51
|
+
echo "→ 2. fixed per-run load is within budget"
|
|
52
|
+
if [ "$TOTAL" -le "$CEILING" ]; then
|
|
53
|
+
pass "fixed load $TOTAL bytes, ceiling $CEILING"
|
|
54
|
+
else
|
|
55
|
+
fail "fixed load $TOTAL bytes exceeds the $CEILING ceiling by $((TOTAL - CEILING))"
|
|
56
|
+
echo " Move detail into multi-agent-refs/ and point at it, rather than"
|
|
57
|
+
echo " raising the ceiling. Every byte here is paid by every run."
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
echo "→ 3. the orchestrator points at the references instead of copying them"
|
|
61
|
+
SKILL="$REPO_ROOT/pipeline/skills/shared/core/multi-agent/SKILL.md"
|
|
62
|
+
REFS=$(grep -c "multi-agent-refs" "$SKILL" || true)
|
|
63
|
+
if [ "$REFS" -ge 3 ]; then
|
|
64
|
+
pass "orchestrator cites multi-agent-refs $REFS times"
|
|
65
|
+
else
|
|
66
|
+
fail "orchestrator cites multi-agent-refs only $REFS time(s)"
|
|
67
|
+
echo " It carried zero citations while duplicating three of those files."
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
echo ""
|
|
71
|
+
echo "══ smoke-context-budget: $PASS passed, $FAIL failed ══"
|
|
72
|
+
[ "$FAIL" -gt 0 ] && exit 1 || exit 0
|
|
@@ -61,6 +61,16 @@ fi
|
|
|
61
61
|
# ──────────────────────────────────────────────────────────────────────────
|
|
62
62
|
echo ""
|
|
63
63
|
echo "→ 2. No deprecated placeholders in Claude source"
|
|
64
|
+
# Corpus guard: the scans below can only be trusted if there is something to
|
|
65
|
+
# scan. Without this, an empty or missing command tree reports every pattern
|
|
66
|
+
# clean instead of reporting that it found nothing to check.
|
|
67
|
+
SKILL_COUNT=$(find "$CLAUDE_CMDS" -name SKILL.md 2>/dev/null | wc -l | tr -d ' ')
|
|
68
|
+
if [ "$SKILL_COUNT" -gt 0 ]; then
|
|
69
|
+
pass "command corpus non-empty ($SKILL_COUNT SKILL.md)"
|
|
70
|
+
else
|
|
71
|
+
fail "no SKILL.md under $CLAUDE_CMDS - placeholder and hardcode scans below are vacuous"
|
|
72
|
+
fi
|
|
73
|
+
|
|
64
74
|
# Per refs/cross-cli-contract.md Section 2.5
|
|
65
75
|
DEPRECATED=(
|
|
66
76
|
"{github-username}"
|
|
@@ -72,7 +82,7 @@ DEPRECATED=(
|
|
|
72
82
|
)
|
|
73
83
|
for p in "${DEPRECATED[@]}"; do
|
|
74
84
|
# grep -l returns filenames; empty = no matches
|
|
75
|
-
FOUND=$(grep -l -F -- "$p"
|
|
85
|
+
FOUND=$(find "$CLAUDE_CMDS" -name SKILL.md -exec grep -l -F -- "$p" {} + 2>/dev/null || true)
|
|
76
86
|
if [ -z "$FOUND" ]; then
|
|
77
87
|
pass "no '$p' in Claude commands"
|
|
78
88
|
else
|
|
@@ -88,7 +98,7 @@ PERSONAL_HARDCODES=(
|
|
|
88
98
|
"${USER}_tkgithub"
|
|
89
99
|
)
|
|
90
100
|
for p in "${PERSONAL_HARDCODES[@]}"; do
|
|
91
|
-
FOUND=$(grep -l -F -- "$p"
|
|
101
|
+
FOUND=$(find "$CLAUDE_CMDS" -name SKILL.md -exec grep -l -F -- "$p" {} + 2>/dev/null || true)
|
|
92
102
|
if [ -z "$FOUND" ]; then
|
|
93
103
|
pass "no '$p' leaked into Claude commands"
|
|
94
104
|
else
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
# 5. Convention mining + createmeta + Agile sprint endpoints present.
|
|
10
10
|
# 6. UTF-8 verbatim POST path (--rawfile + --data-binary) present.
|
|
11
11
|
# 7. Standard template vocab: Task/Story (Scope/Acceptance/Test Scenarios), Bug (Steps/Expected/Actual/Environment), Swagger.
|
|
12
|
-
# 8. Registration: dispatcher rows, inventory lists, count
|
|
12
|
+
# 8. Registration: dispatcher rows, inventory lists, count derived from the command tree.
|
|
13
13
|
# 9. Forbidden strings absent (em-dash, section sign, the M-word, unicode_escape).
|
|
14
14
|
|
|
15
15
|
set -euo pipefail
|
|
@@ -21,6 +21,7 @@ REF="$ROOT/pipeline/multi-agent-refs/generate-issue.md"
|
|
|
21
21
|
SKILL="$ROOT/pipeline/skills/shared/core/multi-agent-create-jira/SKILL.md"
|
|
22
22
|
DISPATCHER="$ROOT/pipeline/commands/multi-agent/SKILL.md"
|
|
23
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 ' ')
|
|
24
25
|
SYNC="$ROOT/pipeline/commands/multi-agent/sync/SKILL.md"
|
|
25
26
|
HELP="$ROOT/pipeline/commands/multi-agent/help/SKILL.md"
|
|
26
27
|
|
|
@@ -88,14 +89,14 @@ grep -Fqi "auto-sizing" "$REF" && pass "auto-sizing rule present" || fail "auto-
|
|
|
88
89
|
grep -Fqi "swagger" "$REF" && pass "swagger context present" || fail "swagger context missing"
|
|
89
90
|
|
|
90
91
|
echo ""
|
|
91
|
-
echo "→ 8. registration + count consistency (
|
|
92
|
+
echo "→ 8. registration + count consistency (derived)"
|
|
92
93
|
grep -Fq '| `create-jira ' "$DISPATCHER" && pass "dispatcher routing: create-jira" || fail "dispatcher routing missing: generate"
|
|
93
94
|
grep -Fq "create-jira/SKILL.md" "$DISPATCHER" && pass "dispatcher loading row" || fail "dispatcher loading row missing"
|
|
94
|
-
grep -Fq "## 1. Command Inventory (
|
|
95
|
+
grep -Fq "## 1. Command Inventory ($CMD_COUNT commands)" "$CONTRACT" && pass "contract count = $CMD_COUNT (derived)" || fail "contract count wrong"
|
|
95
96
|
grep -Eq '(^|[ ,])create-jira([ ,]|$)' "$CONTRACT" && pass "contract list has create-jira" || fail "contract list missing generate"
|
|
96
|
-
grep -Fq "
|
|
97
|
+
grep -Fq "**$CMD_COUNT commands are synced**" "$SYNC" && pass "sync count = $CMD_COUNT (derived)" || fail "sync count wrong"
|
|
97
98
|
SYNC_SKILL="$ROOT/pipeline/skills/shared/core/multi-agent-sync/SKILL.md"
|
|
98
|
-
grep -Fq "
|
|
99
|
+
grep -Fq "**$CMD_COUNT commands are synced**" "$SYNC_SKILL" && pass "sync SKILL count = $CMD_COUNT (derived)" || fail "sync SKILL count wrong (Copilot parity)"
|
|
99
100
|
grep -Fq "create-jira" "$ROOT/pipeline/skills/shared/core/multi-agent-help/SKILL.md" && pass "help SKILL lists create-jira" || fail "help SKILL missing create-jira (Copilot parity)"
|
|
100
101
|
grep -c "multi-agent:create-jira" "$HELP" | awk '{exit !($1>=2)}' && pass "help.md has EN + TR entries" || fail "help.md entries incomplete"
|
|
101
102
|
# no stale split-command references anywhere in the synced surfaces
|
|
@@ -70,7 +70,7 @@ if [ "$FABLE_COUNT" -ge 4 ]; then
|
|
|
70
70
|
else
|
|
71
71
|
fail "expected >=4 fable personas (architects + Reviewer-1), found $FABLE_COUNT"
|
|
72
72
|
fi
|
|
73
|
-
# Opus stays a valid tier
|
|
73
|
+
# Opus stays a valid tier - the first fallback below fable, and the top tier for security personas.
|
|
74
74
|
OPUS_COUNT=$(grep -l "^preferredModel: opus" "$REPO_ROOT"/pipeline/agents/*.md 2>/dev/null | wc -l | tr -d ' ')
|
|
75
75
|
if [ "$OPUS_COUNT" -ge 1 ]; then
|
|
76
76
|
ok "opus personas intact ($OPUS_COUNT files)"
|