@avi770/testteam 1.2.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 +54 -0
- package/LICENSE +21 -0
- package/README.md +167 -0
- package/agents/01-analyst.ts +100 -0
- package/agents/02-seed-architect.ts +59 -0
- package/agents/03-test-generator.ts +191 -0
- package/agents/04-unit-runner.ts +160 -0
- package/agents/05-browser-crawler.ts +790 -0
- package/agents/06-api-exerciser.ts +311 -0
- package/agents/07-security-scout.ts +188 -0
- package/agents/08-a11y-guardian.ts +212 -0
- package/agents/09-healer.ts +228 -0
- package/agents/10-reporter.ts +266 -0
- package/agents/11-fixer.ts +253 -0
- package/agents/12-ux-inspector.ts +444 -0
- package/agents/13-performance-profiler.ts +271 -0
- package/agents/14-data-integrity-auditor.ts +417 -0
- package/agents/15-regression-sentinel.ts +307 -0
- package/agents/16-chaos-agent.ts +228 -0
- package/agents/17-documentation-validator.ts +266 -0
- package/agents/18-integration-watchdog.ts +178 -0
- package/agents/19-tenant-isolation-auditor.ts +199 -0
- package/agents/20-workflow-completion-tester.ts +203 -0
- package/agents/21-state-session-tester.ts +262 -0
- package/agents/22-email-notification-verifier.ts +244 -0
- package/agents/23-migration-tester.ts +80 -0
- package/agents/__tests__/01-analyst.test.ts +188 -0
- package/agents/__tests__/02-seed-architect.test.ts +152 -0
- package/agents/__tests__/03-test-generator-full.test.ts +321 -0
- package/agents/__tests__/03-test-generator.test.ts +318 -0
- package/agents/__tests__/04-unit-runner.test.ts +320 -0
- package/agents/__tests__/05-browser-crawler-beta.test.ts +492 -0
- package/agents/__tests__/05-browser-crawler-release.test.ts +412 -0
- package/agents/__tests__/05-browser-crawler-uat.test.ts +578 -0
- package/agents/__tests__/05-browser-crawler.test.ts +518 -0
- package/agents/__tests__/06-api-exerciser.test.ts +619 -0
- package/agents/__tests__/07-security-scout.test.ts +382 -0
- package/agents/__tests__/08-a11y-guardian.test.ts +530 -0
- package/agents/__tests__/09-healer.test.ts +384 -0
- package/agents/__tests__/10-reporter.test.ts +366 -0
- package/agents/__tests__/11-fixer.test.ts +406 -0
- package/agents/__tests__/12-ux-inspector-extended.test.ts +465 -0
- package/agents/__tests__/12-ux-inspector.test.ts +443 -0
- package/agents/__tests__/13-performance-profiler.test.ts +411 -0
- package/agents/__tests__/14-data-integrity-auditor-extended.test.ts +573 -0
- package/agents/__tests__/14-data-integrity-auditor.test.ts +407 -0
- package/agents/__tests__/15-regression-sentinel.test.ts +657 -0
- package/agents/__tests__/16-chaos-agent.test.ts +427 -0
- package/agents/__tests__/17-documentation-validator.test.ts +402 -0
- package/agents/__tests__/18-integration-watchdog.test.ts +263 -0
- package/agents/__tests__/19-tenant-isolation-auditor.test.ts +400 -0
- package/agents/__tests__/20-workflow-completion-tester.test.ts +586 -0
- package/agents/__tests__/21-state-session-tester.test.ts +374 -0
- package/agents/__tests__/22-email-notification-verifier.test.ts +441 -0
- package/agents/__tests__/23-migration-tester.test.ts +145 -0
- package/agents/__tests__/base-agent.test.ts +188 -0
- package/agents/__tests__/registry.test.ts +218 -0
- package/agents/base-agent.ts +77 -0
- package/agents/registry.ts +136 -0
- package/baselines/api-schemas/.gitkeep +0 -0
- package/baselines/performance/.gitkeep +0 -0
- package/baselines/screenshots/.gitkeep +0 -0
- package/bin/testteam.js +10 -0
- package/core/__tests__/ci-output.test.ts +430 -0
- package/core/__tests__/cli.test.ts +387 -0
- package/core/__tests__/config.test.ts +78 -0
- package/core/__tests__/cost-tracker.test.ts +158 -0
- package/core/__tests__/evidence.test.ts +265 -0
- package/core/__tests__/fix-loop.test.ts +210 -0
- package/core/__tests__/health-check.test.ts +44 -0
- package/core/__tests__/init.test.ts +609 -0
- package/core/__tests__/integration.test.ts +204 -0
- package/core/__tests__/license-gen.test.ts +227 -0
- package/core/__tests__/license.test.ts +326 -0
- package/core/__tests__/multi-browser.test.ts +278 -0
- package/core/__tests__/orchestrator.test.ts +519 -0
- package/core/__tests__/phase-gate.test.ts +43 -0
- package/core/__tests__/report-html.test.ts +398 -0
- package/core/__tests__/report-upload.test.ts +325 -0
- package/core/__tests__/run-counter.test.ts +234 -0
- package/core/ci-output.ts +240 -0
- package/core/cli.ts +232 -0
- package/core/config.ts +178 -0
- package/core/cost-tracker.ts +59 -0
- package/core/evidence.ts +132 -0
- package/core/fix-loop.ts +85 -0
- package/core/health-check.ts +54 -0
- package/core/init.ts +546 -0
- package/core/license-gen.ts +212 -0
- package/core/license.ts +211 -0
- package/core/messages.ts +67 -0
- package/core/multi-browser.ts +136 -0
- package/core/orchestrator.ts +354 -0
- package/core/phase-gate.ts +55 -0
- package/core/report-html.ts +657 -0
- package/core/report-upload.ts +188 -0
- package/core/run-counter.ts +175 -0
- package/core/types.ts +57 -0
- package/dist/agents/01-analyst.d.ts +11 -0
- package/dist/agents/01-analyst.d.ts.map +1 -0
- package/dist/agents/01-analyst.js +75 -0
- package/dist/agents/01-analyst.js.map +1 -0
- package/dist/agents/02-seed-architect.d.ts +11 -0
- package/dist/agents/02-seed-architect.d.ts.map +1 -0
- package/dist/agents/02-seed-architect.js +51 -0
- package/dist/agents/02-seed-architect.js.map +1 -0
- package/dist/agents/03-test-generator.d.ts +9 -0
- package/dist/agents/03-test-generator.d.ts.map +1 -0
- package/dist/agents/03-test-generator.js +167 -0
- package/dist/agents/03-test-generator.js.map +1 -0
- package/dist/agents/04-unit-runner.d.ts +9 -0
- package/dist/agents/04-unit-runner.d.ts.map +1 -0
- package/dist/agents/04-unit-runner.js +113 -0
- package/dist/agents/04-unit-runner.js.map +1 -0
- package/dist/agents/05-browser-crawler.d.ts +30 -0
- package/dist/agents/05-browser-crawler.d.ts.map +1 -0
- package/dist/agents/05-browser-crawler.js +685 -0
- package/dist/agents/05-browser-crawler.js.map +1 -0
- package/dist/agents/06-api-exerciser.d.ts +23 -0
- package/dist/agents/06-api-exerciser.d.ts.map +1 -0
- package/dist/agents/06-api-exerciser.js +253 -0
- package/dist/agents/06-api-exerciser.js.map +1 -0
- package/dist/agents/07-security-scout.d.ts +11 -0
- package/dist/agents/07-security-scout.d.ts.map +1 -0
- package/dist/agents/07-security-scout.js +142 -0
- package/dist/agents/07-security-scout.js.map +1 -0
- package/dist/agents/08-a11y-guardian.d.ts +13 -0
- package/dist/agents/08-a11y-guardian.d.ts.map +1 -0
- package/dist/agents/08-a11y-guardian.js +176 -0
- package/dist/agents/08-a11y-guardian.js.map +1 -0
- package/dist/agents/09-healer.d.ts +33 -0
- package/dist/agents/09-healer.d.ts.map +1 -0
- package/dist/agents/09-healer.js +167 -0
- package/dist/agents/09-healer.js.map +1 -0
- package/dist/agents/10-reporter.d.ts +26 -0
- package/dist/agents/10-reporter.d.ts.map +1 -0
- package/dist/agents/10-reporter.js +215 -0
- package/dist/agents/10-reporter.js.map +1 -0
- package/dist/agents/11-fixer.d.ts +26 -0
- package/dist/agents/11-fixer.d.ts.map +1 -0
- package/dist/agents/11-fixer.js +195 -0
- package/dist/agents/11-fixer.js.map +1 -0
- package/dist/agents/12-ux-inspector.d.ts +15 -0
- package/dist/agents/12-ux-inspector.d.ts.map +1 -0
- package/dist/agents/12-ux-inspector.js +364 -0
- package/dist/agents/12-ux-inspector.js.map +1 -0
- package/dist/agents/13-performance-profiler.d.ts +13 -0
- package/dist/agents/13-performance-profiler.d.ts.map +1 -0
- package/dist/agents/13-performance-profiler.js +216 -0
- package/dist/agents/13-performance-profiler.js.map +1 -0
- package/dist/agents/14-data-integrity-auditor.d.ts +12 -0
- package/dist/agents/14-data-integrity-auditor.d.ts.map +1 -0
- package/dist/agents/14-data-integrity-auditor.js +356 -0
- package/dist/agents/14-data-integrity-auditor.js.map +1 -0
- package/dist/agents/15-regression-sentinel.d.ts +25 -0
- package/dist/agents/15-regression-sentinel.d.ts.map +1 -0
- package/dist/agents/15-regression-sentinel.js +251 -0
- package/dist/agents/15-regression-sentinel.js.map +1 -0
- package/dist/agents/16-chaos-agent.d.ts +9 -0
- package/dist/agents/16-chaos-agent.d.ts.map +1 -0
- package/dist/agents/16-chaos-agent.js +207 -0
- package/dist/agents/16-chaos-agent.js.map +1 -0
- package/dist/agents/17-documentation-validator.d.ts +31 -0
- package/dist/agents/17-documentation-validator.d.ts.map +1 -0
- package/dist/agents/17-documentation-validator.js +246 -0
- package/dist/agents/17-documentation-validator.js.map +1 -0
- package/dist/agents/18-integration-watchdog.d.ts +10 -0
- package/dist/agents/18-integration-watchdog.d.ts.map +1 -0
- package/dist/agents/18-integration-watchdog.js +138 -0
- package/dist/agents/18-integration-watchdog.js.map +1 -0
- package/dist/agents/19-tenant-isolation-auditor.d.ts +9 -0
- package/dist/agents/19-tenant-isolation-auditor.d.ts.map +1 -0
- package/dist/agents/19-tenant-isolation-auditor.js +166 -0
- package/dist/agents/19-tenant-isolation-auditor.js.map +1 -0
- package/dist/agents/20-workflow-completion-tester.d.ts +12 -0
- package/dist/agents/20-workflow-completion-tester.d.ts.map +1 -0
- package/dist/agents/20-workflow-completion-tester.js +159 -0
- package/dist/agents/20-workflow-completion-tester.js.map +1 -0
- package/dist/agents/21-state-session-tester.d.ts +10 -0
- package/dist/agents/21-state-session-tester.d.ts.map +1 -0
- package/dist/agents/21-state-session-tester.js +233 -0
- package/dist/agents/21-state-session-tester.js.map +1 -0
- package/dist/agents/22-email-notification-verifier.d.ts +11 -0
- package/dist/agents/22-email-notification-verifier.d.ts.map +1 -0
- package/dist/agents/22-email-notification-verifier.js +199 -0
- package/dist/agents/22-email-notification-verifier.js.map +1 -0
- package/dist/agents/23-migration-tester.d.ts +10 -0
- package/dist/agents/23-migration-tester.d.ts.map +1 -0
- package/dist/agents/23-migration-tester.js +74 -0
- package/dist/agents/23-migration-tester.js.map +1 -0
- package/dist/agents/base-agent.d.ts +19 -0
- package/dist/agents/base-agent.d.ts.map +1 -0
- package/dist/agents/base-agent.js +67 -0
- package/dist/agents/base-agent.js.map +1 -0
- package/dist/agents/registry.d.ts +29 -0
- package/dist/agents/registry.d.ts.map +1 -0
- package/dist/agents/registry.js +117 -0
- package/dist/agents/registry.js.map +1 -0
- package/dist/core/ci-output.d.ts +35 -0
- package/dist/core/ci-output.d.ts.map +1 -0
- package/dist/core/ci-output.js +193 -0
- package/dist/core/ci-output.js.map +1 -0
- package/dist/core/cli.d.ts +11 -0
- package/dist/core/cli.d.ts.map +1 -0
- package/dist/core/cli.js +197 -0
- package/dist/core/cli.js.map +1 -0
- package/dist/core/config.d.ts +111 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +42 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/cost-tracker.d.ts +22 -0
- package/dist/core/cost-tracker.d.ts.map +1 -0
- package/dist/core/cost-tracker.js +41 -0
- package/dist/core/cost-tracker.js.map +1 -0
- package/dist/core/evidence.d.ts +28 -0
- package/dist/core/evidence.d.ts.map +1 -0
- package/dist/core/evidence.js +95 -0
- package/dist/core/evidence.js.map +1 -0
- package/dist/core/fix-loop.d.ts +29 -0
- package/dist/core/fix-loop.d.ts.map +1 -0
- package/dist/core/fix-loop.js +70 -0
- package/dist/core/fix-loop.js.map +1 -0
- package/dist/core/health-check.d.ts +21 -0
- package/dist/core/health-check.d.ts.map +1 -0
- package/dist/core/health-check.js +26 -0
- package/dist/core/health-check.js.map +1 -0
- package/dist/core/init.d.ts +2 -0
- package/dist/core/init.d.ts.map +1 -0
- package/dist/core/init.js +435 -0
- package/dist/core/init.js.map +1 -0
- package/dist/core/license-gen.d.ts +12 -0
- package/dist/core/license-gen.d.ts.map +1 -0
- package/dist/core/license-gen.js +169 -0
- package/dist/core/license-gen.js.map +1 -0
- package/dist/core/license.d.ts +33 -0
- package/dist/core/license.d.ts.map +1 -0
- package/dist/core/license.js +170 -0
- package/dist/core/license.js.map +1 -0
- package/dist/core/messages.d.ts +10 -0
- package/dist/core/messages.d.ts.map +1 -0
- package/dist/core/messages.js +47 -0
- package/dist/core/messages.js.map +1 -0
- package/dist/core/multi-browser.d.ts +36 -0
- package/dist/core/multi-browser.d.ts.map +1 -0
- package/dist/core/multi-browser.js +88 -0
- package/dist/core/multi-browser.js.map +1 -0
- package/dist/core/orchestrator.d.ts +48 -0
- package/dist/core/orchestrator.d.ts.map +1 -0
- package/dist/core/orchestrator.js +291 -0
- package/dist/core/orchestrator.js.map +1 -0
- package/dist/core/phase-gate.d.ts +4 -0
- package/dist/core/phase-gate.d.ts.map +1 -0
- package/dist/core/phase-gate.js +39 -0
- package/dist/core/phase-gate.js.map +1 -0
- package/dist/core/report-html.d.ts +9 -0
- package/dist/core/report-html.d.ts.map +1 -0
- package/dist/core/report-html.js +617 -0
- package/dist/core/report-html.js.map +1 -0
- package/dist/core/report-upload.d.ts +16 -0
- package/dist/core/report-upload.d.ts.map +1 -0
- package/dist/core/report-upload.js +124 -0
- package/dist/core/report-upload.js.map +1 -0
- package/dist/core/run-counter.d.ts +40 -0
- package/dist/core/run-counter.d.ts.map +1 -0
- package/dist/core/run-counter.js +120 -0
- package/dist/core/run-counter.js.map +1 -0
- package/dist/core/types.d.ts +53 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/helpers/api-client.d.ts +30 -0
- package/dist/helpers/api-client.d.ts.map +1 -0
- package/dist/helpers/api-client.js +77 -0
- package/dist/helpers/api-client.js.map +1 -0
- package/dist/helpers/element-discovery.d.ts +18 -0
- package/dist/helpers/element-discovery.d.ts.map +1 -0
- package/dist/helpers/element-discovery.js +82 -0
- package/dist/helpers/element-discovery.js.map +1 -0
- package/dist/helpers/env-resolver.d.ts +29 -0
- package/dist/helpers/env-resolver.d.ts.map +1 -0
- package/dist/helpers/env-resolver.js +51 -0
- package/dist/helpers/env-resolver.js.map +1 -0
- package/dist/helpers/form-filler.d.ts +13 -0
- package/dist/helpers/form-filler.d.ts.map +1 -0
- package/dist/helpers/form-filler.js +98 -0
- package/dist/helpers/form-filler.js.map +1 -0
- package/dist/helpers/modal-handler.d.ts +16 -0
- package/dist/helpers/modal-handler.d.ts.map +1 -0
- package/dist/helpers/modal-handler.js +95 -0
- package/dist/helpers/modal-handler.js.map +1 -0
- package/dist/helpers/navigation.d.ts +37 -0
- package/dist/helpers/navigation.d.ts.map +1 -0
- package/dist/helpers/navigation.js +83 -0
- package/dist/helpers/navigation.js.map +1 -0
- package/dist/helpers/quality-gate.d.ts +17 -0
- package/dist/helpers/quality-gate.d.ts.map +1 -0
- package/dist/helpers/quality-gate.js +144 -0
- package/dist/helpers/quality-gate.js.map +1 -0
- package/dist/helpers/screenshot.d.ts +24 -0
- package/dist/helpers/screenshot.d.ts.map +1 -0
- package/dist/helpers/screenshot.js +76 -0
- package/dist/helpers/screenshot.js.map +1 -0
- package/dist/helpers/seed-validator.d.ts +15 -0
- package/dist/helpers/seed-validator.d.ts.map +1 -0
- package/dist/helpers/seed-validator.js +53 -0
- package/dist/helpers/seed-validator.js.map +1 -0
- package/helpers/__tests__/api-client.test.ts +199 -0
- package/helpers/__tests__/element-discovery.test.ts +202 -0
- package/helpers/__tests__/form-filler-extended.test.ts +212 -0
- package/helpers/__tests__/form-filler.test.ts +99 -0
- package/helpers/__tests__/modal-handler.test.ts +152 -0
- package/helpers/__tests__/navigation.test.ts +214 -0
- package/helpers/__tests__/quality-gate.test.ts +117 -0
- package/helpers/__tests__/screenshot.test.ts +139 -0
- package/helpers/__tests__/seed-validator.test.ts +114 -0
- package/helpers/api-client.ts +111 -0
- package/helpers/element-discovery.ts +105 -0
- package/helpers/env-resolver.ts +69 -0
- package/helpers/form-filler.ts +126 -0
- package/helpers/modal-handler.ts +108 -0
- package/helpers/navigation.ts +100 -0
- package/helpers/quality-gate.ts +180 -0
- package/helpers/screenshot.ts +111 -0
- package/helpers/seed-validator.ts +70 -0
- package/package.json +88 -0
package/core/evidence.ts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import type { AgentResult, Finding, FindingType, Phase } from './types';
|
|
4
|
+
|
|
5
|
+
const SUBDIRS = [
|
|
6
|
+
'agent-results',
|
|
7
|
+
'findings/test-bugs',
|
|
8
|
+
'findings/code-bugs',
|
|
9
|
+
'evidence/screenshots',
|
|
10
|
+
'evidence/logs',
|
|
11
|
+
'evidence/reports',
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Creates the canonical `.run/{runId}/` directory structure.
|
|
16
|
+
* Safe to call multiple times — uses `{ recursive: true }`.
|
|
17
|
+
*/
|
|
18
|
+
export async function initRunDirectory(runDir: string): Promise<void> {
|
|
19
|
+
for (const subdir of SUBDIRS) {
|
|
20
|
+
await fs.mkdir(path.join(runDir, subdir), { recursive: true });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Writes an AgentResult as JSON to `agent-results/{agentId}.json`.
|
|
26
|
+
* Creates the parent directory lazily if it does not yet exist.
|
|
27
|
+
*/
|
|
28
|
+
export async function writeAgentResult(
|
|
29
|
+
runDir: string,
|
|
30
|
+
agentId: number,
|
|
31
|
+
result: AgentResult,
|
|
32
|
+
): Promise<void> {
|
|
33
|
+
const dir = path.join(runDir, 'agent-results');
|
|
34
|
+
await fs.mkdir(dir, { recursive: true });
|
|
35
|
+
await fs.writeFile(path.join(dir, `${agentId}.json`), JSON.stringify(result, null, 2), 'utf-8');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Reads an AgentResult from `agent-results/{agentId}.json`.
|
|
40
|
+
* Returns `null` when the file does not exist.
|
|
41
|
+
*/
|
|
42
|
+
export async function readAgentResult(
|
|
43
|
+
runDir: string,
|
|
44
|
+
agentId: number,
|
|
45
|
+
): Promise<AgentResult | null> {
|
|
46
|
+
const filePath = path.join(runDir, 'agent-results', `${agentId}.json`);
|
|
47
|
+
try {
|
|
48
|
+
const raw = await fs.readFile(filePath, 'utf-8');
|
|
49
|
+
return JSON.parse(raw) as AgentResult;
|
|
50
|
+
} catch (err: unknown) {
|
|
51
|
+
if (isNodeError(err) && err.code === 'ENOENT') {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
throw err;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Determines the findings subdirectory for a given FindingType.
|
|
60
|
+
*
|
|
61
|
+
* - `test-bug` → `findings/test-bugs/`
|
|
62
|
+
* - `code-bug-*` → `findings/code-bugs/`
|
|
63
|
+
* - `infra-issue` → `findings/code-bugs/`
|
|
64
|
+
*/
|
|
65
|
+
function findingSubdir(type: FindingType): string {
|
|
66
|
+
if (type === 'test-bug') {
|
|
67
|
+
return 'findings/test-bugs';
|
|
68
|
+
}
|
|
69
|
+
return 'findings/code-bugs';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Writes a Finding as JSON to the appropriate subdirectory.
|
|
74
|
+
* Creates the target directory lazily if it does not yet exist.
|
|
75
|
+
*/
|
|
76
|
+
export async function writeFinding(runDir: string, finding: Finding): Promise<void> {
|
|
77
|
+
const dir = path.join(runDir, findingSubdir(finding.type));
|
|
78
|
+
await fs.mkdir(dir, { recursive: true });
|
|
79
|
+
await fs.writeFile(
|
|
80
|
+
path.join(dir, `${finding.id}.json`),
|
|
81
|
+
JSON.stringify(finding, null, 2),
|
|
82
|
+
'utf-8',
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Moves all files currently in `agent-results/` to
|
|
88
|
+
* `archive/attempt-{attempt}/` and empties the source directory.
|
|
89
|
+
* Is a no-op when `agent-results/` is empty or does not exist.
|
|
90
|
+
*/
|
|
91
|
+
export async function archivePhaseResults(
|
|
92
|
+
runDir: string,
|
|
93
|
+
phase: Phase,
|
|
94
|
+
attempt: number,
|
|
95
|
+
): Promise<void> {
|
|
96
|
+
const sourceDir = path.join(runDir, 'agent-results');
|
|
97
|
+
|
|
98
|
+
let entries: string[];
|
|
99
|
+
try {
|
|
100
|
+
entries = await fs.readdir(sourceDir);
|
|
101
|
+
} catch (err: unknown) {
|
|
102
|
+
if (isNodeError(err) && err.code === 'ENOENT') {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
throw err;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (entries.length === 0) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const destDir = path.join(runDir, 'archive', `${phase}-attempt-${attempt}`);
|
|
113
|
+
await fs.mkdir(destDir, { recursive: true });
|
|
114
|
+
|
|
115
|
+
await Promise.all(
|
|
116
|
+
entries.map((entry) =>
|
|
117
|
+
fs.rename(path.join(sourceDir, entry), path.join(destDir, entry)),
|
|
118
|
+
),
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
// Internal helpers
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
|
|
126
|
+
interface NodeError extends Error {
|
|
127
|
+
code: string;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function isNodeError(err: unknown): err is NodeError {
|
|
131
|
+
return err instanceof Error && 'code' in err;
|
|
132
|
+
}
|
package/core/fix-loop.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { Finding, FindingType, Phase } from './types';
|
|
2
|
+
|
|
3
|
+
const SECURITY_KEYWORDS = ['xss', 'injection', 'csrf', 'auth-bypass', 'exposure'] as const;
|
|
4
|
+
const COSMETIC_KEYWORDS = ['css', 'aria', 'i18n', 'link', 'alt-text'] as const;
|
|
5
|
+
|
|
6
|
+
function isInTestFile(filePath: string): boolean {
|
|
7
|
+
return filePath.includes('/tests/');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function hasKeyword(description: string, keywords: readonly string[]): boolean {
|
|
11
|
+
const lower = description.toLowerCase();
|
|
12
|
+
return keywords.some((keyword) => lower.includes(keyword));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Classifies a finding based on its file location and description keywords.
|
|
17
|
+
*
|
|
18
|
+
* Priority order:
|
|
19
|
+
* 1. Test file with unchanged source → test-bug
|
|
20
|
+
* 2. Security keyword in description → code-bug-security
|
|
21
|
+
* 3. Cosmetic keyword in description → code-bug-cosmetic
|
|
22
|
+
* 4. Fallback → code-bug-logic
|
|
23
|
+
*/
|
|
24
|
+
export function classifyFinding(finding: Finding, changedFiles: string[]): FindingType {
|
|
25
|
+
const filePath = finding.file ?? '';
|
|
26
|
+
|
|
27
|
+
if (filePath !== '' && isInTestFile(filePath) && !changedFiles.includes(filePath)) {
|
|
28
|
+
return 'test-bug';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (hasKeyword(finding.description, SECURITY_KEYWORDS)) {
|
|
32
|
+
return 'code-bug-security';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (hasKeyword(finding.description, COSMETIC_KEYWORDS)) {
|
|
36
|
+
return 'code-bug-cosmetic';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return 'code-bug-logic';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Determines whether a finding should be automatically committed without human intervention.
|
|
44
|
+
*
|
|
45
|
+
* UAT phase never auto-commits regardless of finding type.
|
|
46
|
+
* Test bugs always auto-commit (routed to the Healer agent).
|
|
47
|
+
* Cosmetic bugs auto-commit in alpha and beta only.
|
|
48
|
+
* Logic and security bugs never auto-commit (require human gates).
|
|
49
|
+
*/
|
|
50
|
+
export function shouldAutoCommit(findingType: FindingType, phase: Phase): boolean {
|
|
51
|
+
// Test bugs always auto-commit — routed to the Healer agent regardless of phase
|
|
52
|
+
if (findingType === 'test-bug') {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// UAT requires human review for all non-test-bug finding types
|
|
57
|
+
if (phase === 'uat') {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (findingType === 'code-bug-cosmetic') {
|
|
62
|
+
return phase === 'alpha' || phase === 'beta';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Determines whether a finding requires human review before any action is taken.
|
|
70
|
+
*
|
|
71
|
+
* Security and logic bugs always require human review.
|
|
72
|
+
* UAT phase requires human review for all finding types.
|
|
73
|
+
* Cosmetic bugs and test bugs in alpha/beta do not require human review.
|
|
74
|
+
*/
|
|
75
|
+
export function shouldRequireHumanReview(findingType: FindingType, phase: Phase): boolean {
|
|
76
|
+
if (findingType === 'code-bug-security' || findingType === 'code-bug-logic') {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (phase === 'uat') {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export interface HealthCheck {
|
|
2
|
+
name: string;
|
|
3
|
+
check: () => Promise<boolean>;
|
|
4
|
+
required: boolean;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface HealthCheckResult {
|
|
8
|
+
name: string;
|
|
9
|
+
passed: boolean;
|
|
10
|
+
required: boolean;
|
|
11
|
+
error?: string;
|
|
12
|
+
durationMs: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface HealthCheckSummary {
|
|
16
|
+
canProceed: boolean;
|
|
17
|
+
results: HealthCheckResult[];
|
|
18
|
+
warnings: string[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function runHealthChecks({
|
|
22
|
+
checks,
|
|
23
|
+
}: {
|
|
24
|
+
checks: HealthCheck[];
|
|
25
|
+
}): Promise<HealthCheckSummary> {
|
|
26
|
+
const results: HealthCheckResult[] = [];
|
|
27
|
+
const warnings: string[] = [];
|
|
28
|
+
|
|
29
|
+
for (const { name, check, required } of checks) {
|
|
30
|
+
const start = Date.now();
|
|
31
|
+
let passed = false;
|
|
32
|
+
let error: string | undefined;
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
passed = await check();
|
|
36
|
+
} catch (err) {
|
|
37
|
+
passed = false;
|
|
38
|
+
error = err instanceof Error ? err.message : String(err);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const durationMs = Date.now() - start;
|
|
42
|
+
results.push({ name, passed, required, error, durationMs });
|
|
43
|
+
|
|
44
|
+
if (!passed && !required) {
|
|
45
|
+
warnings.push(`Optional check '${name}' failed`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const canProceed = results
|
|
50
|
+
.filter((r) => r.required)
|
|
51
|
+
.every((r) => r.passed);
|
|
52
|
+
|
|
53
|
+
return { canProceed, results, warnings };
|
|
54
|
+
}
|