swarm-orchestrator 7.0.0-alpha.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/LICENSE +15 -0
- package/README.md +199 -0
- package/agents/reviewer.agent.md +50 -0
- package/agents/worker.agent.md +41 -0
- package/config/default-agents.yaml +56 -0
- package/config/pm-agent.yaml +36 -0
- package/config/quality-gates.yaml +88 -0
- package/config/repair-agent.yaml +34 -0
- package/config/semgrep-rules/complexity-mismatch.yaml +6 -0
- package/config/semgrep-rules/exception-swallowing.yaml +13 -0
- package/config/semgrep-rules/hardcoded-answer.yaml +6 -0
- package/config/semgrep-rules/mock-mutation.yaml +6 -0
- package/config/semgrep-rules/test-modification.yaml +6 -0
- package/config/user-agents.yaml +23 -0
- package/dist/src/adapters/adapter-factory.js +29 -0
- package/dist/src/adapters/agent-adapter.js +32 -0
- package/dist/src/adapters/claude-code-adapter.js +126 -0
- package/dist/src/adapters/claude-code-teams.js +119 -0
- package/dist/src/adapters/codex-adapter.js +118 -0
- package/dist/src/adapters/copilot-adapter.js +224 -0
- package/dist/src/adapters/fatal-error-classifier.js +88 -0
- package/dist/src/adapters/index.js +44 -0
- package/dist/src/adapters/persistent-session.js +204 -0
- package/dist/src/adapters/process-supervisor.js +199 -0
- package/dist/src/agents-exporter.js +398 -0
- package/dist/src/analytics-log.js +161 -0
- package/dist/src/baseline-scanner.js +65 -0
- package/dist/src/bootstrap-evidence.js +88 -0
- package/dist/src/bootstrap-orchestrator.js +205 -0
- package/dist/src/bootstrap-types.js +5 -0
- package/dist/src/branch-merger.js +427 -0
- package/dist/src/cli/attest-handlers.js +44 -0
- package/dist/src/cli/cost-prompt.js +51 -0
- package/dist/src/cli/demo-handlers.js +274 -0
- package/dist/src/cli/flags.js +152 -0
- package/dist/src/cli/index.js +57 -0
- package/dist/src/cli/live-status.js +186 -0
- package/dist/src/cli/misc-handlers.js +242 -0
- package/dist/src/cli/plan-handlers.js +350 -0
- package/dist/src/cli/share-handlers.js +163 -0
- package/dist/src/cli/status-handlers.js +457 -0
- package/dist/src/cli/swarm-handlers.js +638 -0
- package/dist/src/cli/usage.js +72 -0
- package/dist/src/cli.js +217 -0
- package/dist/src/commit-pattern-detector.js +143 -0
- package/dist/src/commit-quality-analyzer.js +38 -0
- package/dist/src/config-loader.js +339 -0
- package/dist/src/context-broker.js +358 -0
- package/dist/src/copilot-cli-wrapper.js +258 -0
- package/dist/src/cost-estimator.js +241 -0
- package/dist/src/defaults.js +18 -0
- package/dist/src/demo-mode.js +180 -0
- package/dist/src/deployment-handler.js +78 -0
- package/dist/src/deployment-manager.js +228 -0
- package/dist/src/execution-queue.js +196 -0
- package/dist/src/external-tool-manager.js +184 -0
- package/dist/src/gate-prompt-builder.js +117 -0
- package/dist/src/gate-remediation.js +173 -0
- package/dist/src/github-issues-ingester.js +152 -0
- package/dist/src/github-mcp-integrator.js +164 -0
- package/dist/src/hook-generator.js +229 -0
- package/dist/src/index.js +48 -0
- package/dist/src/knowledge-base.js +300 -0
- package/dist/src/logger.js +111 -0
- package/dist/src/meta-analyzer.js +208 -0
- package/dist/src/metrics-collector.js +209 -0
- package/dist/src/metrics-types.js +5 -0
- package/dist/src/multi-repo-coordinator.js +179 -0
- package/dist/src/orchestrator/async-meta-analysis.js +84 -0
- package/dist/src/orchestrator/fatal-run-error.js +43 -0
- package/dist/src/orchestrator/final-gates-remediation.js +258 -0
- package/dist/src/orchestrator/git-state-utils.js +119 -0
- package/dist/src/orchestrator/pause-controller.js +55 -0
- package/dist/src/orchestrator/replan-runner.js +258 -0
- package/dist/src/orchestrator/step-executor.js +391 -0
- package/dist/src/orchestrator/wave-scheduler-loop.js +204 -0
- package/dist/src/owasp-mapper.js +153 -0
- package/dist/src/owasp-report-renderer.js +39 -0
- package/dist/src/plan-files.js +142 -0
- package/dist/src/plan-generator.js +1207 -0
- package/dist/src/pm-agent.js +296 -0
- package/dist/src/post-run-reporter.js +203 -0
- package/dist/src/pr-automation.js +103 -0
- package/dist/src/pr-manager.js +318 -0
- package/dist/src/presenter/index.js +209 -0
- package/dist/src/prompt-builder.js +173 -0
- package/dist/src/quality-gates/config-loader.js +196 -0
- package/dist/src/quality-gates/default-config.js +243 -0
- package/dist/src/quality-gates/file-utils.js +152 -0
- package/dist/src/quality-gates/gate-runner.js +171 -0
- package/dist/src/quality-gates/gates/accessibility.js +355 -0
- package/dist/src/quality-gates/gates/duplicate-blocks.js +144 -0
- package/dist/src/quality-gates/gates/hardcoded-config.js +52 -0
- package/dist/src/quality-gates/gates/readme-claims.js +62 -0
- package/dist/src/quality-gates/gates/runtime-checks.js +265 -0
- package/dist/src/quality-gates/gates/scaffold-defaults.js +108 -0
- package/dist/src/quality-gates/gates/test-coverage.js +240 -0
- package/dist/src/quality-gates/gates/test-file-protection.js +85 -0
- package/dist/src/quality-gates/gates/test-isolation.js +74 -0
- package/dist/src/quality-gates/index.js +17 -0
- package/dist/src/quality-gates/registry.js +205 -0
- package/dist/src/quality-gates/types.js +2 -0
- package/dist/src/quick-fix-mode.js +302 -0
- package/dist/src/recipe-loader.js +122 -0
- package/dist/src/repair-agent.js +396 -0
- package/dist/src/repo-analyzer.js +342 -0
- package/dist/src/report-generator.js +146 -0
- package/dist/src/report-renderer.js +90 -0
- package/dist/src/requirement-filter.js +52 -0
- package/dist/src/sarif-formatter.js +140 -0
- package/dist/src/scheduling/dependency-analyzer.js +178 -0
- package/dist/src/scheduling/work-stealing-queue.js +123 -0
- package/dist/src/secret-redactor.js +90 -0
- package/dist/src/session-executor.js +587 -0
- package/dist/src/session-manager.js +221 -0
- package/dist/src/share/transcript-verification.js +128 -0
- package/dist/src/share-parser.js +477 -0
- package/dist/src/spinner.js +146 -0
- package/dist/src/step-runner.js +365 -0
- package/dist/src/swarm-orchestrator.js +686 -0
- package/dist/src/task-classifier.js +134 -0
- package/dist/src/test-command-discovery.js +123 -0
- package/dist/src/text-similarity.js +24 -0
- package/dist/src/tier-maps.js +158 -0
- package/dist/src/types.js +5 -0
- package/dist/src/url-shortener.js +135 -0
- package/dist/src/verification/attestation.js +166 -0
- package/dist/src/verification/cheat-detector.js +240 -0
- package/dist/src/verification/command-runner.js +70 -0
- package/dist/src/verification/composite-score.js +157 -0
- package/dist/src/verification/cosign-attestation.js +137 -0
- package/dist/src/verification/diff-analysis.js +89 -0
- package/dist/src/verification/differential-gate.js +173 -0
- package/dist/src/verification/index.js +41 -0
- package/dist/src/verification/mutation-gate.js +242 -0
- package/dist/src/verification/property-gate.js +201 -0
- package/dist/src/verification/test-synthesizer.js +243 -0
- package/dist/src/verifier/outcome-checks.js +396 -0
- package/dist/src/verifier/transcript-checks.js +207 -0
- package/dist/src/verifier/verification-reporters.js +148 -0
- package/dist/src/verifier-engine.js +491 -0
- package/dist/src/wave-resizer.js +131 -0
- package/dist/src/wave-scheduler.js +44 -0
- package/dist/src/worktree-manager.js +368 -0
- package/dist/src/worktree-reserved-paths.js +97 -0
- package/package.json +80 -0
- package/plugin/agents/.gitkeep +0 -0
- package/plugin/agents/backend_master.agent.md +72 -0
- package/plugin/agents/devops_pro.agent.md +45 -0
- package/plugin/agents/frontend_expert.agent.md +59 -0
- package/plugin/agents/integrator_finalizer.agent.md +44 -0
- package/plugin/agents/meta_reviewer.agent.md +44 -0
- package/plugin/agents/security_auditor.agent.md +43 -0
- package/plugin/agents/tester_elite.agent.md +43 -0
- package/plugin/hooks/hooks.json +19 -0
- package/plugin/hooks/post-tool-use.json +9 -0
- package/plugin/hooks/pre-tool-use.json +9 -0
- package/plugin/plugin.json +47 -0
- package/plugin/skills/swarm-gates/SKILL.md +53 -0
- package/plugin/skills/swarm-orchestrate/SKILL.md +34 -0
- package/plugin/skills/swarm-verify/SKILL.md +44 -0
- package/templates/README.md +35 -0
- package/templates/cli-tool.json +31 -0
- package/templates/fullstack.json +52 -0
- package/templates/library.json +38 -0
- package/templates/react-app.json +45 -0
- package/templates/recipes/add-api-docs.json +35 -0
- package/templates/recipes/add-auth.json +47 -0
- package/templates/recipes/add-ci.json +39 -0
- package/templates/recipes/add-tests.json +39 -0
- package/templates/recipes/migrate-to-ts.json +42 -0
- package/templates/recipes/refactor-modularize.json +44 -0
- package/templates/recipes/security-audit.json +35 -0
- package/templates/rest-api.json +38 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.run_test_coverage_gate = run_test_coverage_gate;
|
|
4
|
+
const file_utils_1 = require("../file-utils");
|
|
5
|
+
// Patterns that indicate a file is an entry point (not a standalone module needing its own test).
|
|
6
|
+
// The (^|\/) prefix handles monorepo layouts like frontend/src/main.jsx alongside flat src/main.tsx.
|
|
7
|
+
const DEFAULT_ENTRY_PATTERNS = [
|
|
8
|
+
/(^|\/)src\/(main|index)\.(tsx?|jsx?|mjs)$/,
|
|
9
|
+
/(^|\/)src\/app\.(tsx?|jsx?)$/i
|
|
10
|
+
];
|
|
11
|
+
async function run_test_coverage_gate(ctx, config, maxFileSizeBytes) {
|
|
12
|
+
const start = Date.now();
|
|
13
|
+
const issues = [];
|
|
14
|
+
// Custom patterns extend the structural defaults (main/index/app are always
|
|
15
|
+
// entry points regardless of project config), not replace them.
|
|
16
|
+
const customPatterns = config.entryPointPatterns.map(p => new RegExp(p, 'i'));
|
|
17
|
+
const entryPatterns = [...DEFAULT_ENTRY_PATTERNS, ...customPatterns];
|
|
18
|
+
// Identify source files that should have tests
|
|
19
|
+
const sourceFiles = ctx.files.filter(f => {
|
|
20
|
+
if (!/\.(tsx?|jsx?|mjs)$/i.test(f.relativePath))
|
|
21
|
+
return false;
|
|
22
|
+
if (/^(test|tests|__tests__)\//.test(f.relativePath))
|
|
23
|
+
return false;
|
|
24
|
+
if (/\.test\.|\.spec\./.test(f.relativePath))
|
|
25
|
+
return false;
|
|
26
|
+
// Root-level test scripts (test.js, tests.js) are test files, not source
|
|
27
|
+
if (/^tests?\.(tsx?|jsx?|mjs)$/i.test(f.relativePath))
|
|
28
|
+
return false;
|
|
29
|
+
// Integration/e2e test files at root level
|
|
30
|
+
if (/^(integration|e2e)[.-]/i.test(f.relativePath))
|
|
31
|
+
return false;
|
|
32
|
+
if (/^(server|config|scripts|examples?|deploy|benchmarks)\//.test(f.relativePath))
|
|
33
|
+
return false;
|
|
34
|
+
// Test setup/config files nested inside src/ (e.g. src/test/setup.js,
|
|
35
|
+
// src/setupTests.ts, frontend/src/test/setup.js) are test infrastructure
|
|
36
|
+
if (/\btest\/setup\b|\bsetup[Tt]ests?\b|\btestSetup\b/i.test(f.relativePath))
|
|
37
|
+
return false;
|
|
38
|
+
// Exclude standalone server entry points (e.g. src/server.js that just calls app.listen)
|
|
39
|
+
if (/\bserver\.(tsx?|jsx?|mjs)$/i.test(f.relativePath))
|
|
40
|
+
return false;
|
|
41
|
+
// Exclude vite/webpack configs and similar build tooling
|
|
42
|
+
if (/\.(config|d)\.(ts|js|mjs)$/i.test(f.relativePath))
|
|
43
|
+
return false;
|
|
44
|
+
// Exclude root-level entry scripts (start-*, index.js, app.js) outside src/
|
|
45
|
+
if (!/\//.test(f.relativePath) || /^[^/]+\.(js|mjs)$/.test(f.relativePath)) {
|
|
46
|
+
if (/^(start|launch|boot|serve)[-.]/i.test(f.relativePath))
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
// Exclude entry points
|
|
50
|
+
if (entryPatterns.some(p => p.test(f.relativePath)))
|
|
51
|
+
return false;
|
|
52
|
+
// Exclude Ink TUI components: .tsx files importing from 'ink' are terminal UI
|
|
53
|
+
// renderers that require ink-testing-library, not standard DOM test utilities.
|
|
54
|
+
// Coverage comes from integration tests that exercise the underlying data model.
|
|
55
|
+
if (/\.tsx$/i.test(f.relativePath)) {
|
|
56
|
+
const text = f.text ?? (0, file_utils_1.maybe_read_text)(f, maxFileSizeBytes);
|
|
57
|
+
if (text && /from\s+['"]ink['"]|require\s*\(\s*['"]ink['"]\)/.test(text)) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return true;
|
|
62
|
+
});
|
|
63
|
+
// Identify test files: convention-named (.test./.spec.) and root-level test scripts
|
|
64
|
+
const testFiles = ctx.files.filter(f => /\.(test|spec)\.(tsx?|jsx?|mjs)$/i.test(f.relativePath) ||
|
|
65
|
+
/^tests?\.(tsx?|jsx?|mjs)$/i.test(f.relativePath));
|
|
66
|
+
// Collect all require/import edges from every source and test file so we
|
|
67
|
+
// can resolve transitive coverage. An integration test importing app.js
|
|
68
|
+
// should count as covering the controllers, middleware, and routes that
|
|
69
|
+
// app.js itself requires.
|
|
70
|
+
const allFiles = [...ctx.files];
|
|
71
|
+
const fileImports = new Map();
|
|
72
|
+
const importRegex = /(?:from\s+['"]|require\s*\(\s*['"])([^'"]+)['"]/g;
|
|
73
|
+
// Resolve a relative import specifier against the importing file's directory
|
|
74
|
+
function resolveImport(specifier, importerRelPath) {
|
|
75
|
+
const stripped = specifier.replace(/\.(js|ts|jsx|tsx|mjs)$/, '');
|
|
76
|
+
if (!specifier.startsWith('.'))
|
|
77
|
+
return stripped;
|
|
78
|
+
const importerKey = importerRelPath.replace(/\.(js|ts|jsx|tsx|mjs)$/, '');
|
|
79
|
+
const slashIdx = importerKey.lastIndexOf('/');
|
|
80
|
+
let dir = slashIdx >= 0 ? importerKey.substring(0, slashIdx) : '';
|
|
81
|
+
let remaining = stripped;
|
|
82
|
+
if (remaining.startsWith('./')) {
|
|
83
|
+
remaining = remaining.substring(2);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
while (remaining.startsWith('../')) {
|
|
87
|
+
remaining = remaining.substring(3);
|
|
88
|
+
const parentSlash = dir.lastIndexOf('/');
|
|
89
|
+
dir = parentSlash >= 0 ? dir.substring(0, parentSlash) : '';
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return dir ? `${dir}/${remaining}` : remaining;
|
|
93
|
+
}
|
|
94
|
+
for (const f of allFiles) {
|
|
95
|
+
if (!/\.(tsx?|jsx?|mjs)$/i.test(f.relativePath))
|
|
96
|
+
continue;
|
|
97
|
+
const text = f.text ?? (0, file_utils_1.maybe_read_text)(f, maxFileSizeBytes);
|
|
98
|
+
if (!text)
|
|
99
|
+
continue;
|
|
100
|
+
const imports = [];
|
|
101
|
+
let m;
|
|
102
|
+
importRegex.lastIndex = 0;
|
|
103
|
+
while ((m = importRegex.exec(text)) !== null) {
|
|
104
|
+
if (!m[1].startsWith('.'))
|
|
105
|
+
continue;
|
|
106
|
+
imports.push(resolveImport(m[1], f.relativePath));
|
|
107
|
+
}
|
|
108
|
+
const key = f.relativePath.replace(/\.(js|ts|jsx|tsx|mjs)$/, '');
|
|
109
|
+
fileImports.set(key, imports);
|
|
110
|
+
// Register barrel alias: directory imports resolve to dir/index
|
|
111
|
+
const basename = key.split('/').pop();
|
|
112
|
+
if (basename === 'index') {
|
|
113
|
+
const dirKey = key.replace(/\/index$/, '');
|
|
114
|
+
fileImports.set(dirKey, imports);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Walk transitive imports from test files to build the full coverage set
|
|
118
|
+
const importedByTests = new Set();
|
|
119
|
+
function walkImports(moduleKey, visited) {
|
|
120
|
+
if (visited.has(moduleKey))
|
|
121
|
+
return;
|
|
122
|
+
visited.add(moduleKey);
|
|
123
|
+
importedByTests.add(moduleKey);
|
|
124
|
+
const deps = fileImports.get(moduleKey) || fileImports.get(`src/${moduleKey}`) || [];
|
|
125
|
+
for (const dep of deps) {
|
|
126
|
+
walkImports(dep, visited);
|
|
127
|
+
// Also try with src/ prefix
|
|
128
|
+
if (!dep.startsWith('src/')) {
|
|
129
|
+
walkImports(`src/${dep}`, visited);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
for (const tf of testFiles) {
|
|
134
|
+
const text = tf.text ?? (0, file_utils_1.maybe_read_text)(tf, maxFileSizeBytes);
|
|
135
|
+
if (!text)
|
|
136
|
+
continue;
|
|
137
|
+
importRegex.lastIndex = 0;
|
|
138
|
+
let match;
|
|
139
|
+
while ((match = importRegex.exec(text)) !== null) {
|
|
140
|
+
if (!match[1].startsWith('.'))
|
|
141
|
+
continue;
|
|
142
|
+
const resolved = resolveImport(match[1], tf.relativePath);
|
|
143
|
+
walkImports(resolved, new Set());
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// 1. Check that each source file has a corresponding test or is imported by a test.
|
|
147
|
+
// Only flag files created by agents; pre-existing files are the project owner's concern.
|
|
148
|
+
for (const src of sourceFiles) {
|
|
149
|
+
if (ctx.baselineFiles?.has(src.relativePath))
|
|
150
|
+
continue;
|
|
151
|
+
const baseName = src.relativePath
|
|
152
|
+
.replace(/^src\//, '')
|
|
153
|
+
.replace(/\.(tsx?|jsx?|mjs)$/, '');
|
|
154
|
+
const hasDirectTest = testFiles.some(tf => {
|
|
155
|
+
const testBase = tf.relativePath
|
|
156
|
+
.replace(/^(test|tests|__tests__)\//, '')
|
|
157
|
+
.replace(/^(unit|integration|e2e)\//, '')
|
|
158
|
+
.replace(/\.(test|spec)\.(tsx?|jsx?|mjs)$/, '');
|
|
159
|
+
// Match by full relative path, by stripping common prefixes, or
|
|
160
|
+
// by filename only (test/unit/foo.test.js covers src/services/foo.js)
|
|
161
|
+
const testBaseName = testBase.split('/').pop() || testBase;
|
|
162
|
+
const srcBaseName = baseName.split('/').pop() || baseName;
|
|
163
|
+
return testBase === baseName
|
|
164
|
+
|| testBase === baseName.replace(/^utils\//, '')
|
|
165
|
+
|| testBaseName === srcBaseName;
|
|
166
|
+
});
|
|
167
|
+
const isImportedByTest = importedByTests.has(`src/${baseName}`) ||
|
|
168
|
+
importedByTests.has(baseName) ||
|
|
169
|
+
importedByTests.has(src.relativePath.replace(/\.(tsx?|jsx?|mjs)$/, ''));
|
|
170
|
+
if (!hasDirectTest && !isImportedByTest) {
|
|
171
|
+
issues.push({
|
|
172
|
+
message: `no test coverage for ${src.relativePath}`,
|
|
173
|
+
filePath: src.relativePath,
|
|
174
|
+
hint: `create a test file or import ${src.relativePath} in an existing test`
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// 2. Check that test files contain real assertions (not empty stubs).
|
|
179
|
+
// Only validate agent-created test files, not pre-existing ones.
|
|
180
|
+
for (const tf of testFiles) {
|
|
181
|
+
if (ctx.baselineFiles?.has(tf.relativePath))
|
|
182
|
+
continue;
|
|
183
|
+
const text = tf.text ?? (0, file_utils_1.maybe_read_text)(tf, maxFileSizeBytes);
|
|
184
|
+
if (!text)
|
|
185
|
+
continue;
|
|
186
|
+
const assertionPatterns = /\b(assert\.|expect\(|\.toBe|\.toEqual|\.toThrow|\.ok\(|\.strictEqual|\.deepEqual|\.deepStrictEqual|\.match\(|\.rejects|\.resolves)/;
|
|
187
|
+
const assertionCount = (text.match(new RegExp(assertionPatterns.source, 'g')) || []).length;
|
|
188
|
+
if (assertionCount < config.minTestAssertions) {
|
|
189
|
+
issues.push({
|
|
190
|
+
message: `${tf.relativePath} has ${assertionCount} assertion(s), minimum is ${config.minTestAssertions}`,
|
|
191
|
+
filePath: tf.relativePath,
|
|
192
|
+
hint: 'add meaningful assertions that verify module behavior'
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// 3. Check for component-level tests in React projects
|
|
197
|
+
// Skip for Ink (terminal UI) projects where DOM testing libraries don't apply.
|
|
198
|
+
if (config.requireComponentTests) {
|
|
199
|
+
const isReactProject = ctx.files.some(f => {
|
|
200
|
+
const text = f.text ?? (0, file_utils_1.maybe_read_text)(f, maxFileSizeBytes);
|
|
201
|
+
if (!text)
|
|
202
|
+
return false;
|
|
203
|
+
return /from\s+['"]react['"]|require\s*\(\s*['"]react['"]\)/.test(text);
|
|
204
|
+
});
|
|
205
|
+
const isInkProject = ctx.files.some(f => {
|
|
206
|
+
const text = f.text ?? (0, file_utils_1.maybe_read_text)(f, maxFileSizeBytes);
|
|
207
|
+
if (!text)
|
|
208
|
+
return false;
|
|
209
|
+
return /from\s+['"]ink['"]|require\s*\(\s*['"]ink['"]\)/.test(text);
|
|
210
|
+
});
|
|
211
|
+
if (isReactProject && !isInkProject) {
|
|
212
|
+
const hasComponentTest = testFiles.some(f => {
|
|
213
|
+
const text = f.text ?? (0, file_utils_1.maybe_read_text)(f, maxFileSizeBytes);
|
|
214
|
+
if (!text)
|
|
215
|
+
return false;
|
|
216
|
+
return /(render\s*\(|screen\.|document\.|getBy|queryBy|findBy|innerHTML|textContent|@testing-library)/i.test(text);
|
|
217
|
+
});
|
|
218
|
+
if (!hasComponentTest) {
|
|
219
|
+
issues.push({
|
|
220
|
+
message: 'React project has no component-level tests',
|
|
221
|
+
hint: 'add at least one test that renders a component and asserts DOM output'
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
const durationMs = Date.now() - start;
|
|
227
|
+
const status = issues.length > 0 ? 'fail' : 'pass';
|
|
228
|
+
return {
|
|
229
|
+
id: 'test-coverage',
|
|
230
|
+
title: 'Test coverage checks',
|
|
231
|
+
status,
|
|
232
|
+
durationMs,
|
|
233
|
+
issues,
|
|
234
|
+
stats: {
|
|
235
|
+
sourceFiles: sourceFiles.length,
|
|
236
|
+
testFiles: testFiles.length,
|
|
237
|
+
issues: issues.length
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.run_test_file_protection_gate = run_test_file_protection_gate;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
/**
|
|
6
|
+
* D4: Test-File Protection Gate
|
|
7
|
+
*
|
|
8
|
+
* Detects when an agent has **modified** (not added) pre-existing test files.
|
|
9
|
+
* Agents should write new tests, not weaken existing ones.
|
|
10
|
+
*
|
|
11
|
+
* Uses `git diff --name-only --diff-filter=M` against a base commit
|
|
12
|
+
* and matches the results against configurable test-file patterns.
|
|
13
|
+
*/
|
|
14
|
+
async function run_test_file_protection_gate(projectRoot, config, baseCommit) {
|
|
15
|
+
const start = Date.now();
|
|
16
|
+
const issues = [];
|
|
17
|
+
const base = baseCommit || 'HEAD~1';
|
|
18
|
+
const patterns = config.testFileGlobs;
|
|
19
|
+
try {
|
|
20
|
+
// Get all MODIFIED (not Added) files relative to the base commit
|
|
21
|
+
const raw = (0, child_process_1.execSync)(`git diff --name-only --diff-filter=M ${base}`, { cwd: projectRoot, encoding: 'utf8', timeout: 30_000, stdio: ['ignore', 'pipe', 'pipe'] }).trim();
|
|
22
|
+
if (raw.length === 0) {
|
|
23
|
+
return result('pass', issues, Date.now() - start, 0);
|
|
24
|
+
}
|
|
25
|
+
const modifiedFiles = raw.split('\n').filter(Boolean);
|
|
26
|
+
// Compile glob-like patterns to regexes
|
|
27
|
+
const matchers = patterns.map(glob_to_regex);
|
|
28
|
+
let flagged = 0;
|
|
29
|
+
for (const file of modifiedFiles) {
|
|
30
|
+
if (matchers.some(re => re.test(file))) {
|
|
31
|
+
flagged++;
|
|
32
|
+
issues.push({
|
|
33
|
+
message: `Pre-existing test file was modified by an agent`,
|
|
34
|
+
filePath: file,
|
|
35
|
+
hint: 'Agents should add new test files, not modify existing ones. ' +
|
|
36
|
+
'If the modification is fixing an import path or test config, ' +
|
|
37
|
+
'consider an allowlist entry in quality-gates.yaml.'
|
|
38
|
+
});
|
|
39
|
+
if (issues.length >= (config.maxFindings ?? 25))
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const status = issues.length > 0 ? 'fail' : 'pass';
|
|
44
|
+
return result(status, issues, Date.now() - start, flagged);
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
// git not available or not a repo — skip gracefully
|
|
48
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
49
|
+
return {
|
|
50
|
+
id: 'test-file-protection',
|
|
51
|
+
title: 'Test files not modified by agents',
|
|
52
|
+
status: 'skip',
|
|
53
|
+
durationMs: Date.now() - start,
|
|
54
|
+
issues: [{
|
|
55
|
+
message: `Could not run git diff: ${msg.slice(0, 200)}`,
|
|
56
|
+
hint: 'Ensure the project is a git repo with at least one commit.'
|
|
57
|
+
}],
|
|
58
|
+
stats: { flagged: 0 }
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function result(status, issues, durationMs, flagged) {
|
|
63
|
+
return {
|
|
64
|
+
id: 'test-file-protection',
|
|
65
|
+
title: 'Test files not modified by agents',
|
|
66
|
+
status,
|
|
67
|
+
durationMs,
|
|
68
|
+
issues,
|
|
69
|
+
stats: { flagged }
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Convert a simple glob pattern to a RegExp.
|
|
74
|
+
* Supports: ** (any path), * (any segment chars), ? (single char).
|
|
75
|
+
* Patterns are matched against the full relative path.
|
|
76
|
+
*/
|
|
77
|
+
function glob_to_regex(glob) {
|
|
78
|
+
const re = glob
|
|
79
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&') // escape regex specials (except * and ?)
|
|
80
|
+
.replace(/\*\*/g, '$$GLOBSTAR$$') // placeholder for **
|
|
81
|
+
.replace(/\*/g, '[^/]*') // * = anything except /
|
|
82
|
+
.replace(/\?/g, '.') // ? = single char
|
|
83
|
+
.replace(/\$\$GLOBSTAR\$\$/g, '.*'); // ** = anything including /
|
|
84
|
+
return new RegExp(`^${re}$`, 'i');
|
|
85
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.run_test_isolation_gate = run_test_isolation_gate;
|
|
4
|
+
const file_utils_1 = require("../file-utils");
|
|
5
|
+
function is_probably_source_file(relPath) {
|
|
6
|
+
return /\.(ts|js|tsx|jsx)$/.test(relPath) && !/\.d\.ts$/.test(relPath);
|
|
7
|
+
}
|
|
8
|
+
async function run_test_isolation_gate(ctx, config, maxFileSizeBytes) {
|
|
9
|
+
const start = Date.now();
|
|
10
|
+
const issues = [];
|
|
11
|
+
const storeRegexes = (0, file_utils_1.compile_regexes)(config.mutableStoreRegexes);
|
|
12
|
+
const allowIfFileContains = (0, file_utils_1.compile_regexes)(config.allowIfFileContainsRegexes);
|
|
13
|
+
const testFileRegexes = config.testFileRegexes.map(r => new RegExp(r, 'i'));
|
|
14
|
+
const allowIfAnyTestContains = (0, file_utils_1.compile_regexes)(config.allowIfAnyTestContainsRegexes);
|
|
15
|
+
const testTexts = [];
|
|
16
|
+
for (const file of ctx.files) {
|
|
17
|
+
if (!testFileRegexes.some(r => r.test(file.relativePath))) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
const text = (0, file_utils_1.maybe_read_text)(file, maxFileSizeBytes);
|
|
21
|
+
if (text) {
|
|
22
|
+
testTexts.push(text);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const anyTestHasResetHook = testTexts.some(t => allowIfAnyTestContains.some(r => r.test(t)));
|
|
26
|
+
for (const file of ctx.files) {
|
|
27
|
+
if (!is_probably_source_file(file.relativePath)) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const text = (0, file_utils_1.maybe_read_text)(file, maxFileSizeBytes);
|
|
31
|
+
if (!text) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const lines = text.split('\n');
|
|
35
|
+
// scan first ~80 lines for module-scope mutable stores
|
|
36
|
+
const scanLines = lines.slice(0, Math.min(80, lines.length));
|
|
37
|
+
for (let i = 0; i < scanLines.length; i++) {
|
|
38
|
+
const line = scanLines[i] || '';
|
|
39
|
+
if (!storeRegexes.some(r => r.test(line))) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const allowed = allowIfFileContains.some(r => r.test(text)) || anyTestHasResetHook;
|
|
43
|
+
if (allowed) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
issues.push({
|
|
47
|
+
message: 'mutable module-scope store detected without reset strategy',
|
|
48
|
+
filePath: file.relativePath,
|
|
49
|
+
line: i + 1,
|
|
50
|
+
excerpt: line.trim(),
|
|
51
|
+
hint: 'export a reset hook for tests or reset state in beforeEach()'
|
|
52
|
+
});
|
|
53
|
+
if (issues.length >= 25) {
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (issues.length >= 25) {
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const durationMs = Date.now() - start;
|
|
62
|
+
const status = issues.length > 0 ? 'fail' : 'pass';
|
|
63
|
+
return {
|
|
64
|
+
id: 'test-isolation',
|
|
65
|
+
title: 'Tests are isolated (reset mutable state)',
|
|
66
|
+
status,
|
|
67
|
+
durationMs,
|
|
68
|
+
issues,
|
|
69
|
+
stats: {
|
|
70
|
+
issues: issues.length,
|
|
71
|
+
testFiles: testTexts.length
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parse_gitignore_dirs = exports.list_project_files = exports.registerGate = exports.loadProjectGateRegistrations = exports.getRegisteredGates = exports.getRegisteredGateKeys = exports.run_quality_gates = exports.DEFAULT_QUALITY_GATES_CONFIG = exports.load_quality_gates_config = void 0;
|
|
4
|
+
var config_loader_1 = require("./config-loader");
|
|
5
|
+
Object.defineProperty(exports, "load_quality_gates_config", { enumerable: true, get: function () { return config_loader_1.load_quality_gates_config; } });
|
|
6
|
+
var default_config_1 = require("./default-config");
|
|
7
|
+
Object.defineProperty(exports, "DEFAULT_QUALITY_GATES_CONFIG", { enumerable: true, get: function () { return default_config_1.DEFAULT_QUALITY_GATES_CONFIG; } });
|
|
8
|
+
var gate_runner_1 = require("./gate-runner");
|
|
9
|
+
Object.defineProperty(exports, "run_quality_gates", { enumerable: true, get: function () { return gate_runner_1.run_quality_gates; } });
|
|
10
|
+
var registry_1 = require("./registry");
|
|
11
|
+
Object.defineProperty(exports, "getRegisteredGateKeys", { enumerable: true, get: function () { return registry_1.getRegisteredGateKeys; } });
|
|
12
|
+
Object.defineProperty(exports, "getRegisteredGates", { enumerable: true, get: function () { return registry_1.getRegisteredGates; } });
|
|
13
|
+
Object.defineProperty(exports, "loadProjectGateRegistrations", { enumerable: true, get: function () { return registry_1.loadProjectGateRegistrations; } });
|
|
14
|
+
Object.defineProperty(exports, "registerGate", { enumerable: true, get: function () { return registry_1.registerGate; } });
|
|
15
|
+
var file_utils_1 = require("./file-utils");
|
|
16
|
+
Object.defineProperty(exports, "list_project_files", { enumerable: true, get: function () { return file_utils_1.list_project_files; } });
|
|
17
|
+
Object.defineProperty(exports, "parse_gitignore_dirs", { enumerable: true, get: function () { return file_utils_1.parse_gitignore_dirs; } });
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.SELF_IMPROVEMENT_GATE_KEYS = void 0;
|
|
37
|
+
exports.registerGate = registerGate;
|
|
38
|
+
exports.resetProjectGates = resetProjectGates;
|
|
39
|
+
exports.getRegisteredGates = getRegisteredGates;
|
|
40
|
+
exports.getRegisteredGateKeys = getRegisteredGateKeys;
|
|
41
|
+
exports.loadProjectGateRegistrations = loadProjectGateRegistrations;
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const default_config_1 = require("./default-config");
|
|
45
|
+
const accessibility_1 = require("./gates/accessibility");
|
|
46
|
+
const duplicate_blocks_1 = require("./gates/duplicate-blocks");
|
|
47
|
+
const hardcoded_config_1 = require("./gates/hardcoded-config");
|
|
48
|
+
const readme_claims_1 = require("./gates/readme-claims");
|
|
49
|
+
const runtime_checks_1 = require("./gates/runtime-checks");
|
|
50
|
+
const scaffold_defaults_1 = require("./gates/scaffold-defaults");
|
|
51
|
+
const test_coverage_1 = require("./gates/test-coverage");
|
|
52
|
+
const test_file_protection_1 = require("./gates/test-file-protection");
|
|
53
|
+
const test_isolation_1 = require("./gates/test-isolation");
|
|
54
|
+
const registry = new Map();
|
|
55
|
+
const builtInKeys = new Set();
|
|
56
|
+
const projectKeys = new Set();
|
|
57
|
+
function registerBuiltInGate(gate) {
|
|
58
|
+
registry.set(gate.key, gate);
|
|
59
|
+
builtInKeys.add(gate.key);
|
|
60
|
+
}
|
|
61
|
+
function registerGate(gate) {
|
|
62
|
+
registry.set(gate.key, gate);
|
|
63
|
+
projectKeys.add(gate.key);
|
|
64
|
+
}
|
|
65
|
+
function resetProjectGates() {
|
|
66
|
+
for (const key of projectKeys) {
|
|
67
|
+
if (!builtInKeys.has(key)) {
|
|
68
|
+
registry.delete(key);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
projectKeys.clear();
|
|
72
|
+
}
|
|
73
|
+
function getRegisteredGates() {
|
|
74
|
+
return Array.from(registry.values());
|
|
75
|
+
}
|
|
76
|
+
function getRegisteredGateKeys() {
|
|
77
|
+
return getRegisteredGates().map(gate => gate.key);
|
|
78
|
+
}
|
|
79
|
+
function resolveProjectGateModule(projectRoot) {
|
|
80
|
+
const candidates = [
|
|
81
|
+
path.join(projectRoot, '.swarm', 'gates', 'index.js'),
|
|
82
|
+
path.join(projectRoot, '.swarm', 'gates', 'index.cjs'),
|
|
83
|
+
];
|
|
84
|
+
for (const candidate of candidates) {
|
|
85
|
+
if (fs.existsSync(candidate)) {
|
|
86
|
+
return candidate;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
function registerProjectExports(entry) {
|
|
92
|
+
if (typeof entry.registerGates === 'function') {
|
|
93
|
+
entry.registerGates({ registerGate });
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (Array.isArray(entry.gates)) {
|
|
97
|
+
for (const gate of entry.gates)
|
|
98
|
+
registerGate(gate);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (typeof entry.default === 'function') {
|
|
102
|
+
entry.default({ registerGate });
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (Array.isArray(entry.default)) {
|
|
106
|
+
for (const gate of entry.default)
|
|
107
|
+
registerGate(gate);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function loadProjectGateRegistrations(projectRoot) {
|
|
111
|
+
resetProjectGates();
|
|
112
|
+
const entryPath = resolveProjectGateModule(projectRoot);
|
|
113
|
+
if (!entryPath)
|
|
114
|
+
return [];
|
|
115
|
+
delete require.cache[require.resolve(entryPath)];
|
|
116
|
+
const loaded = require(entryPath);
|
|
117
|
+
registerProjectExports(loaded);
|
|
118
|
+
return [entryPath];
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Gate keys that are "self-improvement" gates — the orchestrator applies
|
|
122
|
+
* them to its OWN generated code to enforce quality on code it produced.
|
|
123
|
+
* When the orchestrator is running against a target repo (swarm bootstrap
|
|
124
|
+
* against an external codebase), these gates should NOT fire: the target
|
|
125
|
+
* has its own conventions and the gates misattribute target-repo features
|
|
126
|
+
* as agent defects. Phase 4a smoke4 evidence: the accessibility gate
|
|
127
|
+
* flagged sympy (computer-algebra library, no UI) and triggered replan
|
|
128
|
+
* churn that wasted cycles and polluted the diff-capture.
|
|
129
|
+
*
|
|
130
|
+
* Gates NOT in this set are "universal" — they enforce agent-behavior
|
|
131
|
+
* contracts that apply regardless of whose codebase is being modified:
|
|
132
|
+
* - hardcodedConfig agent must not add secrets / hardcoded config
|
|
133
|
+
* (the gate scopes to baselineFiles, so it only
|
|
134
|
+
* flags what the agent added, not pre-existing
|
|
135
|
+
* target state — safe in target mode)
|
|
136
|
+
* - testFileProtection agent must not modify pre-existing test files
|
|
137
|
+
* (SWE-bench evaluation integrity + general
|
|
138
|
+
* safety property; always fires)
|
|
139
|
+
*
|
|
140
|
+
* `run_quality_gates` consults this set via the `skippedGateKeys` param
|
|
141
|
+
* the orchestrator passes when `targetMode === true`.
|
|
142
|
+
*/
|
|
143
|
+
exports.SELF_IMPROVEMENT_GATE_KEYS = new Set([
|
|
144
|
+
'scaffoldDefaults',
|
|
145
|
+
'duplicateBlocks',
|
|
146
|
+
'readmeClaims',
|
|
147
|
+
'testIsolation',
|
|
148
|
+
'runtimeChecks',
|
|
149
|
+
'accessibility',
|
|
150
|
+
'testCoverage',
|
|
151
|
+
]);
|
|
152
|
+
registerBuiltInGate({
|
|
153
|
+
key: 'scaffoldDefaults',
|
|
154
|
+
title: 'Scaffold Defaults',
|
|
155
|
+
defaultConfig: default_config_1.DEFAULT_QUALITY_GATES_CONFIG.gates.scaffoldDefaults,
|
|
156
|
+
run: (ctx, config, maxFileSizeBytes) => (0, scaffold_defaults_1.run_scaffold_defaults_gate)(ctx, config, maxFileSizeBytes),
|
|
157
|
+
});
|
|
158
|
+
registerBuiltInGate({
|
|
159
|
+
key: 'duplicateBlocks',
|
|
160
|
+
title: 'Duplicate Blocks',
|
|
161
|
+
defaultConfig: default_config_1.DEFAULT_QUALITY_GATES_CONFIG.gates.duplicateBlocks,
|
|
162
|
+
run: (ctx, config, maxFileSizeBytes) => (0, duplicate_blocks_1.run_duplicate_blocks_gate)(ctx, config, maxFileSizeBytes),
|
|
163
|
+
});
|
|
164
|
+
registerBuiltInGate({
|
|
165
|
+
key: 'hardcodedConfig',
|
|
166
|
+
title: 'Hardcoded Config',
|
|
167
|
+
defaultConfig: default_config_1.DEFAULT_QUALITY_GATES_CONFIG.gates.hardcodedConfig,
|
|
168
|
+
run: (ctx, config, maxFileSizeBytes) => (0, hardcoded_config_1.run_hardcoded_config_gate)(ctx, config, maxFileSizeBytes),
|
|
169
|
+
});
|
|
170
|
+
registerBuiltInGate({
|
|
171
|
+
key: 'readmeClaims',
|
|
172
|
+
title: 'README Claims',
|
|
173
|
+
defaultConfig: default_config_1.DEFAULT_QUALITY_GATES_CONFIG.gates.readmeClaims,
|
|
174
|
+
run: (ctx, config, maxFileSizeBytes) => (0, readme_claims_1.run_readme_claims_gate)(ctx, config, maxFileSizeBytes),
|
|
175
|
+
});
|
|
176
|
+
registerBuiltInGate({
|
|
177
|
+
key: 'testIsolation',
|
|
178
|
+
title: 'Test Isolation',
|
|
179
|
+
defaultConfig: default_config_1.DEFAULT_QUALITY_GATES_CONFIG.gates.testIsolation,
|
|
180
|
+
run: (ctx, config, maxFileSizeBytes) => (0, test_isolation_1.run_test_isolation_gate)(ctx, config, maxFileSizeBytes),
|
|
181
|
+
});
|
|
182
|
+
registerBuiltInGate({
|
|
183
|
+
key: 'runtimeChecks',
|
|
184
|
+
title: 'Runtime Checks',
|
|
185
|
+
defaultConfig: default_config_1.DEFAULT_QUALITY_GATES_CONFIG.gates.runtimeChecks,
|
|
186
|
+
run: (ctx, config) => (0, runtime_checks_1.run_runtime_checks_gate)(ctx.projectRoot, config, ctx.baseCommit),
|
|
187
|
+
});
|
|
188
|
+
registerBuiltInGate({
|
|
189
|
+
key: 'accessibility',
|
|
190
|
+
title: 'Accessibility',
|
|
191
|
+
defaultConfig: default_config_1.DEFAULT_QUALITY_GATES_CONFIG.gates.accessibility,
|
|
192
|
+
run: (ctx, config, maxFileSizeBytes) => (0, accessibility_1.run_accessibility_gate)(ctx, config, maxFileSizeBytes),
|
|
193
|
+
});
|
|
194
|
+
registerBuiltInGate({
|
|
195
|
+
key: 'testCoverage',
|
|
196
|
+
title: 'Test Coverage',
|
|
197
|
+
defaultConfig: default_config_1.DEFAULT_QUALITY_GATES_CONFIG.gates.testCoverage,
|
|
198
|
+
run: (ctx, config, maxFileSizeBytes) => (0, test_coverage_1.run_test_coverage_gate)(ctx, config, maxFileSizeBytes),
|
|
199
|
+
});
|
|
200
|
+
registerBuiltInGate({
|
|
201
|
+
key: 'testFileProtection',
|
|
202
|
+
title: 'Test File Protection',
|
|
203
|
+
defaultConfig: default_config_1.DEFAULT_QUALITY_GATES_CONFIG.gates.testFileProtection,
|
|
204
|
+
run: (ctx, config) => (0, test_file_protection_1.run_test_file_protection_gate)(ctx.projectRoot, config, ctx.baseCommit),
|
|
205
|
+
});
|