@skyramp/mcp 0.3.1 → 0.3.2-rc.pom-2
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/build/index.js +2 -1
- package/build/prompts/code-reuse.d.ts +7 -1
- package/build/prompts/code-reuse.js +8 -5
- package/build/prompts/code-reuse.test.d.ts +1 -0
- package/build/prompts/code-reuse.test.js +62 -0
- package/build/prompts/pom-aware-code-reuse.d.ts +6 -1
- package/build/prompts/pom-aware-code-reuse.js +100 -53
- package/build/prompts/pom-aware-code-reuse.test.d.ts +1 -0
- package/build/prompts/pom-aware-code-reuse.test.js +11 -0
- package/build/prompts/test-recommendation/diffExecutionPlan.d.ts +4 -2
- package/build/prompts/test-recommendation/diffExecutionPlan.js +11 -65
- package/build/prompts/test-recommendation/fullRepoCatalog.d.ts +2 -2
- package/build/prompts/test-recommendation/recommendationSections.js +5 -2
- package/build/prompts/test-recommendation/scopeAssessment.js +1 -1
- package/build/prompts/test-recommendation/test-recommendation-prompt.d.ts +26 -1
- package/build/prompts/test-recommendation/test-recommendation-prompt.js +68 -56
- package/build/prompts/test-recommendation/test-recommendation-prompt.test.js +48 -11
- package/build/prompts/testbot/testbot-prompts.d.ts +1 -1
- package/build/prompts/testbot/testbot-prompts.js +67 -21
- package/build/prompts/testbot/testbot-prompts.test.js +44 -0
- package/build/recommendation/budgeters/diversityBalancedBudgeter.d.ts +7 -0
- package/build/recommendation/budgeters/diversityBalancedBudgeter.js +71 -0
- package/build/recommendation/budgeters/diversityBalancedBudgeter.test.d.ts +1 -0
- package/build/recommendation/budgeters/diversityBalancedBudgeter.test.js +75 -0
- package/build/recommendation/budgeters/fixedNBudgeter.d.ts +7 -0
- package/build/recommendation/budgeters/fixedNBudgeter.js +11 -0
- package/build/recommendation/budgeters/fixedNBudgeter.test.d.ts +1 -0
- package/build/recommendation/budgeters/fixedNBudgeter.test.js +66 -0
- package/build/recommendation/budgeters/shared.d.ts +19 -0
- package/build/recommendation/budgeters/shared.js +66 -0
- package/build/recommendation/discriminators.d.ts +31 -0
- package/build/recommendation/discriminators.js +355 -0
- package/build/recommendation/discriminators.test.d.ts +1 -0
- package/build/recommendation/discriminators.test.js +324 -0
- package/build/recommendation/diversity.d.ts +47 -0
- package/build/recommendation/diversity.js +101 -0
- package/build/recommendation/diversity.test.d.ts +1 -0
- package/build/recommendation/diversity.test.js +77 -0
- package/build/recommendation/planRanker.d.ts +50 -0
- package/build/recommendation/planRanker.js +67 -0
- package/build/recommendation/planRanker.test.d.ts +1 -0
- package/build/recommendation/planRanker.test.js +110 -0
- package/build/recommendation/testFixtures.d.ts +25 -0
- package/build/recommendation/testFixtures.js +45 -0
- package/build/resources/testbotResource.js +4 -1
- package/build/services/ScenarioGenerationService.d.ts +5 -0
- package/build/services/ScenarioGenerationService.js +16 -1
- package/build/services/ScenarioGenerationService.test.js +44 -0
- package/build/services/TestExecutionService.d.ts +15 -1
- package/build/services/TestExecutionService.js +210 -55
- package/build/services/TestExecutionService.test.js +397 -0
- package/build/services/TestGenerationService.js +19 -1
- package/build/services/TestGenerationService.test.js +58 -0
- package/build/tool-phases.js +1 -0
- package/build/toolNames.d.ts +19 -0
- package/build/toolNames.js +19 -0
- package/build/tools/code-refactor/codeReuseTool.d.ts +7 -0
- package/build/tools/code-refactor/codeReuseTool.js +130 -4
- package/build/tools/code-refactor/codeReuseTool.test.d.ts +1 -0
- package/build/tools/code-refactor/codeReuseTool.test.js +290 -0
- package/build/tools/executeSkyrampTestTool.js +8 -2
- package/build/tools/generate-tests/generateBatchScenarioRestTool.d.ts +6 -1
- package/build/tools/generate-tests/generateBatchScenarioRestTool.js +110 -17
- package/build/tools/generate-tests/generateBatchScenarioRestTool.test.js +147 -0
- package/build/tools/generate-tests/generateContractRestTool.js +11 -1
- package/build/tools/generate-tests/generateIntegrationRestTool.js +24 -1
- package/build/tools/generate-tests/generateIntegrationRestTool.test.d.ts +1 -0
- package/build/tools/generate-tests/generateIntegrationRestTool.test.js +159 -0
- package/build/tools/generate-tests/planGuard.d.ts +13 -0
- package/build/tools/generate-tests/planGuard.js +78 -0
- package/build/tools/generate-tests/planGuard.test.d.ts +1 -0
- package/build/tools/generate-tests/planGuard.test.js +185 -0
- package/build/tools/generate-tests/scenarioFileIdentity.d.ts +10 -0
- package/build/tools/generate-tests/scenarioFileIdentity.js +46 -0
- package/build/tools/generate-tests/scenarioLint.d.ts +30 -0
- package/build/tools/generate-tests/scenarioLint.js +150 -0
- package/build/tools/generate-tests/scenarioLint.test.d.ts +1 -0
- package/build/tools/generate-tests/scenarioLint.test.js +100 -0
- package/build/tools/submitReportTool.js +78 -0
- package/build/tools/submitReportTool.test.js +255 -0
- package/build/tools/test-management/analyzeChangesTool.js +55 -2
- package/build/tools/test-management/analyzeChangesTool.test.js +12 -0
- package/build/tools/test-management/index.d.ts +1 -0
- package/build/tools/test-management/index.js +1 -0
- package/build/tools/test-management/registerTestPlanTool.d.ts +2 -0
- package/build/tools/test-management/registerTestPlanTool.js +329 -0
- package/build/tools/test-management/registerTestPlanTool.test.d.ts +1 -0
- package/build/tools/test-management/registerTestPlanTool.test.js +296 -0
- package/build/types/Recommendation.d.ts +97 -0
- package/build/types/Recommendation.js +48 -0
- package/build/types/RepositoryAnalysis.d.ts +14 -14
- package/build/types/TestExecution.d.ts +2 -0
- package/build/types/TestRecommendation.d.ts +12 -1
- package/build/types/TestRecommendation.js +26 -11
- package/build/types/TestTypes.js +1 -1
- package/build/utils/AnalysisStateManager.d.ts +47 -0
- package/build/utils/docker.test.js +1 -1
- package/build/utils/planMatchKeys.d.ts +61 -0
- package/build/utils/planMatchKeys.js +125 -0
- package/build/utils/pom-scope/import-expansion.d.ts +5 -0
- package/build/utils/pom-scope/import-expansion.js +32 -0
- package/build/utils/pom-scope/index.d.ts +39 -0
- package/build/utils/pom-scope/index.js +120 -0
- package/build/utils/pom-scope/index.test.d.ts +1 -0
- package/build/utils/pom-scope/index.test.js +239 -0
- package/build/utils/pom-scope/pom-files.d.ts +3 -0
- package/build/utils/pom-scope/pom-files.js +48 -0
- package/build/utils/pom-scope/pom-files.test.d.ts +1 -0
- package/build/utils/pom-scope/pom-files.test.js +29 -0
- package/build/utils/pom-scope/scoring.d.ts +20 -0
- package/build/utils/pom-scope/scoring.js +45 -0
- package/build/utils/pom-scope/scoring.test.d.ts +1 -0
- package/build/utils/pom-scope/scoring.test.js +39 -0
- package/build/utils/pom-scope/selector-extractor.d.ts +7 -0
- package/build/utils/pom-scope/selector-extractor.js +57 -0
- package/build/utils/pom-scope/selector-extractor.test.d.ts +1 -0
- package/build/utils/pom-scope/selector-extractor.test.js +67 -0
- package/build/utils/pom-verify/__fixtures__/af-style/asset-list.page.d.ts +5 -0
- package/build/utils/pom-verify/__fixtures__/af-style/asset-list.page.js +5 -0
- package/build/utils/pom-verify/__fixtures__/af-style/pageobjects/asset-list-page.d.ts +5 -0
- package/build/utils/pom-verify/__fixtures__/af-style/pageobjects/asset-list-page.js +9 -0
- package/build/utils/pom-verify/__fixtures__/af-style/report.iframe.page.d.ts +4 -0
- package/build/utils/pom-verify/__fixtures__/af-style/report.iframe.page.js +4 -0
- package/build/utils/pom-verify/__fixtures__/af-style/workflow-footer.page.d.ts +4 -0
- package/build/utils/pom-verify/__fixtures__/af-style/workflow-footer.page.js +4 -0
- package/build/utils/pom-verify/bindings.d.ts +19 -0
- package/build/utils/pom-verify/bindings.js +161 -0
- package/build/utils/pom-verify/bindings.test.d.ts +1 -0
- package/build/utils/pom-verify/bindings.test.js +164 -0
- package/build/utils/pom-verify/calls.d.ts +16 -0
- package/build/utils/pom-verify/calls.js +42 -0
- package/build/utils/pom-verify/calls.test.d.ts +1 -0
- package/build/utils/pom-verify/calls.test.js +61 -0
- package/build/utils/pom-verify/index.d.ts +4 -0
- package/build/utils/pom-verify/index.js +4 -0
- package/build/utils/pom-verify/resolve.d.ts +7 -0
- package/build/utils/pom-verify/resolve.js +27 -0
- package/build/utils/pom-verify/resolve.test.d.ts +1 -0
- package/build/utils/pom-verify/resolve.test.js +68 -0
- package/build/utils/pom-verify/strip.d.ts +9 -0
- package/build/utils/pom-verify/strip.js +89 -0
- package/build/utils/pom-verify/verify.d.ts +14 -0
- package/build/utils/pom-verify/verify.js +158 -0
- package/build/utils/pom-verify/verify.test.d.ts +1 -0
- package/build/utils/pom-verify/verify.test.js +325 -0
- package/build/utils/reportVerification.d.ts +61 -0
- package/build/utils/reportVerification.js +104 -0
- package/build/utils/reportVerification.test.d.ts +1 -0
- package/build/utils/reportVerification.test.js +185 -0
- package/build/utils/scenarioDrafting.js +5 -5
- package/build/utils/versions.d.ts +3 -3
- package/build/utils/versions.js +1 -1
- package/build/utils/workspaceAuth.d.ts +9 -1
- package/build/utils/workspaceAuth.js +25 -5
- package/build/utils/workspaceAuth.test.js +48 -0
- package/build/workspace/workspace.d.ts +20 -0
- package/build/workspace/workspace.js +4 -0
- package/build/workspace/workspace.test.js +10 -0
- package/node_modules/playwright/lib/mcp/skyramp/traceRecordingBackend.js +77 -8
- package/node_modules/playwright/node_modules/playwright-core/lib/generated/injectedScriptSource.js +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/generated/pollingRecorderSource.js +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/utils/isomorphic/volatileDate.js +101 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/utils.js +2 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/{codeMirrorModule-aszq5EdG.js → codeMirrorModule-Bzd72-bG.js} +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/{defaultSettingsView-BxS7Jm4s.js → defaultSettingsView-DzxTioTK.js} +101 -101
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/{index.D4JTTy4R.js → index.BGc30U3S.js} +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.html +2 -2
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/{uiMode.DaRMQKOI.js → uiMode.IaDrb29A.js} +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.html +2 -2
- package/node_modules/playwright/node_modules/playwright-core/package.json +1 -1
- package/node_modules/playwright/node_modules/playwright-core/src/generated/injectedScriptSource.ts +1 -1
- package/node_modules/playwright/node_modules/playwright-core/src/generated/pollingRecorderSource.ts +1 -1
- package/node_modules/playwright/node_modules/playwright-core/src/utils/isomorphic/volatileDate.ts +131 -0
- package/node_modules/playwright/node_modules/playwright-core/src/utils.ts +1 -0
- package/node_modules/playwright/package.json +1 -1
- package/package.json +3 -3
- package/node_modules/playwright/node_modules/playwright-core/.DS_Store +0 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { DraftedScenario } from "../types/RepositoryAnalysis.js";
|
|
2
|
+
import { Novelty, PriorityTier } from "../types/TestRecommendation.js";
|
|
3
|
+
/**
|
|
4
|
+
* The structural bug-shape a candidate claims to probe. Verified against the
|
|
5
|
+
* candidate's `steps[]` by `validateDiscriminator` (discriminators.ts); a claim
|
|
6
|
+
* that does not survive verification is demoted, never used to reject.
|
|
7
|
+
*/
|
|
8
|
+
export declare enum DiscriminatorKind {
|
|
9
|
+
BOUNDARY_EQUALITY = "boundary_equality",
|
|
10
|
+
MULTI_RECORD_AGGREGATE = "multi_record_aggregate",
|
|
11
|
+
STATE_TRANSITION = "state_transition",
|
|
12
|
+
NEGATIVE_MATCH = "negative_match"
|
|
13
|
+
}
|
|
14
|
+
/** Who drafted a candidate: the LLM loop, or the MCP server's own pre-ranking. */
|
|
15
|
+
export declare enum CandidateSource {
|
|
16
|
+
AGENT = "agent",
|
|
17
|
+
SERVER = "server"
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A ranked test candidate — the existing scored scenario plus the fields the
|
|
21
|
+
* budgeting stage reads. Matches the shape produced today by the scoring block
|
|
22
|
+
* in test-recommendation-prompt.ts (`{ scenario, priority, novelty }`), extended
|
|
23
|
+
* for the SKYR-3879 Path B register-plan checkpoint with provenance, a stable id
|
|
24
|
+
* and the verified-discriminator marker the ranker reads.
|
|
25
|
+
*/
|
|
26
|
+
export interface Candidate {
|
|
27
|
+
scenario: DraftedScenario;
|
|
28
|
+
priority: PriorityTier;
|
|
29
|
+
novelty: Novelty;
|
|
30
|
+
/** Who drafted this candidate: the LLM loop or the MCP server. */
|
|
31
|
+
source: CandidateSource;
|
|
32
|
+
/**
|
|
33
|
+
* Stable, deterministic id: slugified `scenarioName` + short content hash.
|
|
34
|
+
* Reproducible across calls (same scenario → same id) so the generation-tool
|
|
35
|
+
* plan guard can match a generated test back to its approved candidate.
|
|
36
|
+
*/
|
|
37
|
+
candidateId: string;
|
|
38
|
+
/**
|
|
39
|
+
* Set by the caller AFTER `validateDiscriminator` succeeds for a declared
|
|
40
|
+
* discriminator. Present only when the structural claim was verified against
|
|
41
|
+
* `steps[]` and the diff anchor; the ranker floats these ahead of unverified
|
|
42
|
+
* peers. Absent = no verified discriminator (unclaimed or demoted).
|
|
43
|
+
*/
|
|
44
|
+
verifiedDiscriminator?: DiscriminatorKind;
|
|
45
|
+
}
|
|
46
|
+
/** Environment-derived inputs a Budgeter needs to split GENERATE vs ADDITIONAL. */
|
|
47
|
+
export interface BudgetContext {
|
|
48
|
+
/** Upper bound on GENERATE items (a strategy parameter, formerly the hard cap). */
|
|
49
|
+
maxGenerate: number;
|
|
50
|
+
/** Total recommendations (GENERATE + ADDITIONAL); today's `topN`. */
|
|
51
|
+
maxTotal: number;
|
|
52
|
+
isUIOnlyPR: boolean;
|
|
53
|
+
hasFrontendChanges: boolean;
|
|
54
|
+
/** Method-aware coverage keys of external tests; matching candidates are dropped. */
|
|
55
|
+
externalCoverage: Set<string>;
|
|
56
|
+
}
|
|
57
|
+
/** A demoted claim: which candidate, and the human-readable reason returned to
|
|
58
|
+
* the agent so it can fix the claim (never a silent drop). */
|
|
59
|
+
export interface Demotion {
|
|
60
|
+
candidateId: string;
|
|
61
|
+
reason: string;
|
|
62
|
+
}
|
|
63
|
+
/** Result of budgeting: the GENERATE set, the ADDITIONAL set, how many UI
|
|
64
|
+
* placeholder slots the render layer should add (mixed/UI-only PRs), and the
|
|
65
|
+
* demoted-claim channel (the missing rejection surface for register-plan). */
|
|
66
|
+
export interface SelectionResult {
|
|
67
|
+
generate: Candidate[];
|
|
68
|
+
additional: Candidate[];
|
|
69
|
+
reservedUISlots: number;
|
|
70
|
+
demotions: Demotion[];
|
|
71
|
+
}
|
|
72
|
+
/** A pluggable budgeting algorithm. Deterministic and pure. */
|
|
73
|
+
export interface Budgeter {
|
|
74
|
+
readonly name: string;
|
|
75
|
+
select(ranked: Candidate[], ctx: BudgetContext): SelectionResult;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Deterministic candidate id: a slug of the scenario name plus an 8-char content
|
|
79
|
+
* hash. Pure and reproducible — the same scenario always yields the same id, so
|
|
80
|
+
* a candidate registered in the plan can be matched back when its test is later
|
|
81
|
+
* generated. The hash covers the salient, stable structural fields (name,
|
|
82
|
+
* category, testType, and each step's method/path/interactionType/status) so
|
|
83
|
+
* cosmetic re-serialization does not change the id while a real edit does.
|
|
84
|
+
*/
|
|
85
|
+
export declare function computeCandidateId(scenario: DraftedScenario): string;
|
|
86
|
+
/** One approved plan item as persisted in `UnifiedAnalysisState.approvedPlan`.
|
|
87
|
+
* Deliberately slim (no steps/requestBody/etc.) — `matchKeys` already carries
|
|
88
|
+
* everything a downstream matcher needs. */
|
|
89
|
+
export interface ApprovedPlanItem {
|
|
90
|
+
candidateId: string;
|
|
91
|
+
scenarioName: string;
|
|
92
|
+
testType: string;
|
|
93
|
+
category: string;
|
|
94
|
+
source: CandidateSource;
|
|
95
|
+
verifiedDiscriminator?: string;
|
|
96
|
+
matchKeys: string[];
|
|
97
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as crypto from "crypto";
|
|
2
|
+
/**
|
|
3
|
+
* The structural bug-shape a candidate claims to probe. Verified against the
|
|
4
|
+
* candidate's `steps[]` by `validateDiscriminator` (discriminators.ts); a claim
|
|
5
|
+
* that does not survive verification is demoted, never used to reject.
|
|
6
|
+
*/
|
|
7
|
+
export var DiscriminatorKind;
|
|
8
|
+
(function (DiscriminatorKind) {
|
|
9
|
+
DiscriminatorKind["BOUNDARY_EQUALITY"] = "boundary_equality";
|
|
10
|
+
DiscriminatorKind["MULTI_RECORD_AGGREGATE"] = "multi_record_aggregate";
|
|
11
|
+
DiscriminatorKind["STATE_TRANSITION"] = "state_transition";
|
|
12
|
+
DiscriminatorKind["NEGATIVE_MATCH"] = "negative_match";
|
|
13
|
+
})(DiscriminatorKind || (DiscriminatorKind = {}));
|
|
14
|
+
/** Who drafted a candidate: the LLM loop, or the MCP server's own pre-ranking. */
|
|
15
|
+
export var CandidateSource;
|
|
16
|
+
(function (CandidateSource) {
|
|
17
|
+
CandidateSource["AGENT"] = "agent";
|
|
18
|
+
CandidateSource["SERVER"] = "server";
|
|
19
|
+
})(CandidateSource || (CandidateSource = {}));
|
|
20
|
+
/**
|
|
21
|
+
* Deterministic candidate id: a slug of the scenario name plus an 8-char content
|
|
22
|
+
* hash. Pure and reproducible — the same scenario always yields the same id, so
|
|
23
|
+
* a candidate registered in the plan can be matched back when its test is later
|
|
24
|
+
* generated. The hash covers the salient, stable structural fields (name,
|
|
25
|
+
* category, testType, and each step's method/path/interactionType/status) so
|
|
26
|
+
* cosmetic re-serialization does not change the id while a real edit does.
|
|
27
|
+
*/
|
|
28
|
+
export function computeCandidateId(scenario) {
|
|
29
|
+
const slugSource = scenario.scenarioName ?? "";
|
|
30
|
+
const slug = slugSource
|
|
31
|
+
.toLowerCase()
|
|
32
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
33
|
+
.replace(/^-+|-+$/g, "")
|
|
34
|
+
.slice(0, 48) || "scenario";
|
|
35
|
+
const canonical = {
|
|
36
|
+
scenarioName: scenario.scenarioName ?? "",
|
|
37
|
+
category: scenario.category ?? "",
|
|
38
|
+
testType: scenario.testType ?? "",
|
|
39
|
+
steps: (scenario.steps ?? []).map((s) => ({
|
|
40
|
+
method: s?.method ?? "",
|
|
41
|
+
path: s?.path ?? "",
|
|
42
|
+
interactionType: s?.interactionType ?? "",
|
|
43
|
+
expectedStatusCode: s?.expectedStatusCode ?? 0,
|
|
44
|
+
})),
|
|
45
|
+
};
|
|
46
|
+
const hash = crypto.createHash("sha256").update(JSON.stringify(canonical)).digest("hex").slice(0, 8);
|
|
47
|
+
return `${slug}-${hash}`;
|
|
48
|
+
}
|
|
@@ -1309,25 +1309,25 @@ export declare const branchDiffContextSchema: z.ZodObject<{
|
|
|
1309
1309
|
}, "strip", z.ZodTypeAny, {
|
|
1310
1310
|
method: string;
|
|
1311
1311
|
sourceFile: string;
|
|
1312
|
-
changeType: "
|
|
1312
|
+
changeType: "modified" | "added" | "removed";
|
|
1313
1313
|
}, {
|
|
1314
1314
|
method: string;
|
|
1315
1315
|
sourceFile: string;
|
|
1316
|
-
changeType: "
|
|
1316
|
+
changeType: "modified" | "added" | "removed";
|
|
1317
1317
|
}>, "many">;
|
|
1318
1318
|
}, "strip", z.ZodTypeAny, {
|
|
1319
1319
|
path: string;
|
|
1320
1320
|
methods: {
|
|
1321
1321
|
method: string;
|
|
1322
1322
|
sourceFile: string;
|
|
1323
|
-
changeType: "
|
|
1323
|
+
changeType: "modified" | "added" | "removed";
|
|
1324
1324
|
}[];
|
|
1325
1325
|
}, {
|
|
1326
1326
|
path: string;
|
|
1327
1327
|
methods: {
|
|
1328
1328
|
method: string;
|
|
1329
1329
|
sourceFile: string;
|
|
1330
|
-
changeType: "
|
|
1330
|
+
changeType: "modified" | "added" | "removed";
|
|
1331
1331
|
}[];
|
|
1332
1332
|
}>, "many">;
|
|
1333
1333
|
removedEndpoints: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -1379,7 +1379,7 @@ export declare const branchDiffContextSchema: z.ZodObject<{
|
|
|
1379
1379
|
methods: {
|
|
1380
1380
|
method: string;
|
|
1381
1381
|
sourceFile: string;
|
|
1382
|
-
changeType: "
|
|
1382
|
+
changeType: "modified" | "added" | "removed";
|
|
1383
1383
|
}[];
|
|
1384
1384
|
}[];
|
|
1385
1385
|
affectedServices: string[];
|
|
@@ -1409,7 +1409,7 @@ export declare const branchDiffContextSchema: z.ZodObject<{
|
|
|
1409
1409
|
methods: {
|
|
1410
1410
|
method: string;
|
|
1411
1411
|
sourceFile: string;
|
|
1412
|
-
changeType: "
|
|
1412
|
+
changeType: "modified" | "added" | "removed";
|
|
1413
1413
|
}[];
|
|
1414
1414
|
}[];
|
|
1415
1415
|
affectedServices: string[];
|
|
@@ -2483,25 +2483,25 @@ export declare const repositoryAnalysisSchema: z.ZodObject<{
|
|
|
2483
2483
|
}, "strip", z.ZodTypeAny, {
|
|
2484
2484
|
method: string;
|
|
2485
2485
|
sourceFile: string;
|
|
2486
|
-
changeType: "
|
|
2486
|
+
changeType: "modified" | "added" | "removed";
|
|
2487
2487
|
}, {
|
|
2488
2488
|
method: string;
|
|
2489
2489
|
sourceFile: string;
|
|
2490
|
-
changeType: "
|
|
2490
|
+
changeType: "modified" | "added" | "removed";
|
|
2491
2491
|
}>, "many">;
|
|
2492
2492
|
}, "strip", z.ZodTypeAny, {
|
|
2493
2493
|
path: string;
|
|
2494
2494
|
methods: {
|
|
2495
2495
|
method: string;
|
|
2496
2496
|
sourceFile: string;
|
|
2497
|
-
changeType: "
|
|
2497
|
+
changeType: "modified" | "added" | "removed";
|
|
2498
2498
|
}[];
|
|
2499
2499
|
}, {
|
|
2500
2500
|
path: string;
|
|
2501
2501
|
methods: {
|
|
2502
2502
|
method: string;
|
|
2503
2503
|
sourceFile: string;
|
|
2504
|
-
changeType: "
|
|
2504
|
+
changeType: "modified" | "added" | "removed";
|
|
2505
2505
|
}[];
|
|
2506
2506
|
}>, "many">;
|
|
2507
2507
|
removedEndpoints: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -2553,7 +2553,7 @@ export declare const repositoryAnalysisSchema: z.ZodObject<{
|
|
|
2553
2553
|
methods: {
|
|
2554
2554
|
method: string;
|
|
2555
2555
|
sourceFile: string;
|
|
2556
|
-
changeType: "
|
|
2556
|
+
changeType: "modified" | "added" | "removed";
|
|
2557
2557
|
}[];
|
|
2558
2558
|
}[];
|
|
2559
2559
|
affectedServices: string[];
|
|
@@ -2583,7 +2583,7 @@ export declare const repositoryAnalysisSchema: z.ZodObject<{
|
|
|
2583
2583
|
methods: {
|
|
2584
2584
|
method: string;
|
|
2585
2585
|
sourceFile: string;
|
|
2586
|
-
changeType: "
|
|
2586
|
+
changeType: "modified" | "added" | "removed";
|
|
2587
2587
|
}[];
|
|
2588
2588
|
}[];
|
|
2589
2589
|
affectedServices: string[];
|
|
@@ -2785,7 +2785,7 @@ export declare const repositoryAnalysisSchema: z.ZodObject<{
|
|
|
2785
2785
|
methods: {
|
|
2786
2786
|
method: string;
|
|
2787
2787
|
sourceFile: string;
|
|
2788
|
-
changeType: "
|
|
2788
|
+
changeType: "modified" | "added" | "removed";
|
|
2789
2789
|
}[];
|
|
2790
2790
|
}[];
|
|
2791
2791
|
affectedServices: string[];
|
|
@@ -2987,7 +2987,7 @@ export declare const repositoryAnalysisSchema: z.ZodObject<{
|
|
|
2987
2987
|
methods: {
|
|
2988
2988
|
method: string;
|
|
2989
2989
|
sourceFile: string;
|
|
2990
|
-
changeType: "
|
|
2990
|
+
changeType: "modified" | "added" | "removed";
|
|
2991
2991
|
}[];
|
|
2992
2992
|
}[];
|
|
2993
2993
|
affectedServices: string[];
|
|
@@ -37,6 +37,8 @@ export interface BatchExecutionResult {
|
|
|
37
37
|
export interface TestExecutionOptions {
|
|
38
38
|
testFile: string;
|
|
39
39
|
workspacePath: string;
|
|
40
|
+
/** Cross-repo test repository root (testsRepoDir) when testFile was delivered outside workspacePath (SKYR-3819). */
|
|
41
|
+
testRepoPath?: string;
|
|
40
42
|
language: string;
|
|
41
43
|
testType: string;
|
|
42
44
|
token?: string;
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
/** Internal scenario-scoring tier — UPPERCASE, includes CRITICAL. */
|
|
2
|
-
export
|
|
2
|
+
export declare enum PriorityTier {
|
|
3
|
+
CRITICAL = "CRITICAL",
|
|
4
|
+
HIGH = "HIGH",
|
|
5
|
+
MEDIUM = "MEDIUM",
|
|
6
|
+
LOW = "LOW"
|
|
7
|
+
}
|
|
8
|
+
/** How a scenario relates to the diff — tie-breaker within a priority tier. */
|
|
9
|
+
export declare enum Novelty {
|
|
10
|
+
NEW = "new",
|
|
11
|
+
MODIFIED = "modified",
|
|
12
|
+
EXISTING = "existing"
|
|
13
|
+
}
|
|
3
14
|
/** All categories including internal ones. */
|
|
4
15
|
export declare const SCENARIO_CATEGORIES: readonly ["new_endpoint", "bug_caught", "business_rule", "security_boundary", "data_integrity", "breaking_change", "auth", "error_handling", "workflow", "data_validation", "crud"];
|
|
5
16
|
export type ScenarioCategory = typeof SCENARIO_CATEGORIES[number];
|
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
/** Internal scenario-scoring tier — UPPERCASE, includes CRITICAL. */
|
|
2
|
+
export var PriorityTier;
|
|
3
|
+
(function (PriorityTier) {
|
|
4
|
+
PriorityTier["CRITICAL"] = "CRITICAL";
|
|
5
|
+
PriorityTier["HIGH"] = "HIGH";
|
|
6
|
+
PriorityTier["MEDIUM"] = "MEDIUM";
|
|
7
|
+
PriorityTier["LOW"] = "LOW";
|
|
8
|
+
})(PriorityTier || (PriorityTier = {}));
|
|
9
|
+
/** How a scenario relates to the diff — tie-breaker within a priority tier. */
|
|
10
|
+
export var Novelty;
|
|
11
|
+
(function (Novelty) {
|
|
12
|
+
Novelty["NEW"] = "new";
|
|
13
|
+
Novelty["MODIFIED"] = "modified";
|
|
14
|
+
Novelty["EXISTING"] = "existing";
|
|
15
|
+
})(Novelty || (Novelty = {}));
|
|
1
16
|
/** Internal-only categories (not submitted to tools). */
|
|
2
17
|
const INTERNAL_CATEGORIES = [
|
|
3
18
|
"new_endpoint", // CRITICAL - diff-direct scenarios always fill GENERATE slots first
|
|
@@ -24,17 +39,17 @@ export const SCENARIO_CATEGORIES = [...INTERNAL_CATEGORIES, ...CATEGORIES];
|
|
|
24
39
|
export const TEST_CATEGORIES = CATEGORIES;
|
|
25
40
|
/** Priority assignment for each category. */
|
|
26
41
|
export const CATEGORY_PRIORITY = {
|
|
27
|
-
new_endpoint:
|
|
28
|
-
bug_caught:
|
|
29
|
-
business_rule:
|
|
30
|
-
security_boundary:
|
|
31
|
-
data_integrity:
|
|
32
|
-
breaking_change:
|
|
33
|
-
auth:
|
|
34
|
-
error_handling:
|
|
35
|
-
workflow:
|
|
36
|
-
data_validation:
|
|
37
|
-
crud:
|
|
42
|
+
new_endpoint: PriorityTier.CRITICAL,
|
|
43
|
+
bug_caught: PriorityTier.CRITICAL, // tests targeting a <bug_found> flaw — always in GENERATE
|
|
44
|
+
business_rule: PriorityTier.HIGH, // formula/business-logic bugs are high priority but CRITICAL is reserved for new-endpoint diff-direct scenarios
|
|
45
|
+
security_boundary: PriorityTier.HIGH,
|
|
46
|
+
data_integrity: PriorityTier.HIGH,
|
|
47
|
+
breaking_change: PriorityTier.HIGH,
|
|
48
|
+
auth: PriorityTier.HIGH,
|
|
49
|
+
error_handling: PriorityTier.HIGH,
|
|
50
|
+
workflow: PriorityTier.MEDIUM,
|
|
51
|
+
data_validation: PriorityTier.MEDIUM,
|
|
52
|
+
crud: PriorityTier.LOW,
|
|
38
53
|
};
|
|
39
54
|
/** Map internal-only categories to their external equivalent for tool submission. */
|
|
40
55
|
export function externalCategory(cat) {
|
package/build/types/TestTypes.js
CHANGED
|
@@ -243,7 +243,7 @@ export const codeRefactoringSchema = z.object({
|
|
|
243
243
|
codeReuse: z
|
|
244
244
|
.boolean()
|
|
245
245
|
.default(false)
|
|
246
|
-
.describe("
|
|
246
|
+
.describe("Reuse existing code in the generated test — for TS/JS Playwright tests this refactors the test to use the repo's existing Page Object Model"),
|
|
247
247
|
modularizeCode: z
|
|
248
248
|
.boolean()
|
|
249
249
|
.default(false)
|
|
@@ -4,6 +4,7 @@ import { PRTestContext } from "./pr-comment-parser.js";
|
|
|
4
4
|
import { ParsedDiffEndpoint } from "./routeParsers.js";
|
|
5
5
|
import type { CandidateUiPage } from "./uiPageEnumerator.js";
|
|
6
6
|
import type { FrontendFileIntegration } from "../types/FrontendIntegration.js";
|
|
7
|
+
import type { ApprovedPlanItem } from "../types/Recommendation.js";
|
|
7
8
|
export type { CandidateUiPage } from "./uiPageEnumerator.js";
|
|
8
9
|
export declare function setTestsRepoDir(dir: string | undefined): void;
|
|
9
10
|
export declare function getTestsRepoDir(): string | undefined;
|
|
@@ -65,6 +66,41 @@ export interface UiAnalysisContext {
|
|
|
65
66
|
*/
|
|
66
67
|
frontendFileIntegration?: FrontendFileIntegration[];
|
|
67
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* SKYR-3879 Path B — the server-side selection checkpoint's persisted result.
|
|
71
|
+
* Written by skyramp_register_test_plan (and pre-seeded by skyramp_analyze_changes
|
|
72
|
+
* when it has its own pre-ranked GENERATE items). `generate` is the mandated,
|
|
73
|
+
* final list generation tools gate against (see planGuard.ts); `additional` is
|
|
74
|
+
* report-only; `demotions` carries discriminator claims that failed structural
|
|
75
|
+
* verification (the candidate itself is never dropped, only the claim).
|
|
76
|
+
*/
|
|
77
|
+
export interface ApprovedPlan {
|
|
78
|
+
planId: string;
|
|
79
|
+
createdAt: string;
|
|
80
|
+
generate: ApprovedPlanItem[];
|
|
81
|
+
additional: ApprovedPlanItem[];
|
|
82
|
+
demotions: Array<{
|
|
83
|
+
candidateId: string;
|
|
84
|
+
reason: string;
|
|
85
|
+
}>;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Budget inputs computed once by skyramp_analyze_changes (from the same
|
|
89
|
+
* classification the Execution Plan prompt is built from) and reused by
|
|
90
|
+
* skyramp_register_test_plan, so re-ranking the agent's candidates never
|
|
91
|
+
* drifts from the budget the agent was shown. Persisted even when no
|
|
92
|
+
* `approvedPlan` is pre-seeded (e.g. no pre-drafted scenarios) so a
|
|
93
|
+
* register_test_plan call with only agent-drafted candidates still budgets
|
|
94
|
+
* against the correct maxGenerate/maxTotal/UI split.
|
|
95
|
+
*/
|
|
96
|
+
export interface PlanBudgetContext {
|
|
97
|
+
maxGenerate: number;
|
|
98
|
+
maxTotal: number;
|
|
99
|
+
isUIOnlyPR: boolean;
|
|
100
|
+
hasFrontendChanges: boolean;
|
|
101
|
+
/** Serialized form of the BudgetContext.externalCoverage Set. */
|
|
102
|
+
externalCoverageKeys: string[];
|
|
103
|
+
}
|
|
68
104
|
/**
|
|
69
105
|
* Unified state data combining test discovery + endpoint scanning
|
|
70
106
|
* Used by the unified test-management workflow
|
|
@@ -86,6 +122,17 @@ export interface UnifiedAnalysisState {
|
|
|
86
122
|
/** Maintenance actions applied via skyramp_actions — skyramp_submit_report derives
|
|
87
123
|
* testMaintenance from this. */
|
|
88
124
|
maintenanceVerdicts?: MaintenanceActionCore[];
|
|
125
|
+
/**
|
|
126
|
+
* Raw branch-diff text, size-capped (~200KB), persisted so
|
|
127
|
+
* skyramp_register_test_plan can verify a discriminator's `changedCodeAnchor`
|
|
128
|
+
* occurs verbatim in the actual diff. Absent when the analysis wasn't
|
|
129
|
+
* diff-scoped or no diff content was produced.
|
|
130
|
+
*/
|
|
131
|
+
diffText?: string;
|
|
132
|
+
/** SKYR-3879 Path B — see {@link PlanBudgetContext}. */
|
|
133
|
+
planBudgetContext?: PlanBudgetContext;
|
|
134
|
+
/** SKYR-3879 Path B — see {@link ApprovedPlan}. */
|
|
135
|
+
approvedPlan?: ApprovedPlan;
|
|
89
136
|
}
|
|
90
137
|
/**
|
|
91
138
|
* State file metadata
|
|
@@ -55,7 +55,7 @@ describe("dockerImageExistsLocally", () => {
|
|
|
55
55
|
});
|
|
56
56
|
});
|
|
57
57
|
describe("pullDockerImage", () => {
|
|
58
|
-
const IMAGE = "skyramp/executor:v1.3.
|
|
58
|
+
const IMAGE = "skyramp/executor:v1.3.35";
|
|
59
59
|
beforeEach(() => jest.clearAllMocks());
|
|
60
60
|
describe("on amd64 host", () => {
|
|
61
61
|
const originalArch = process.arch;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SKYR-3879 Path B — shared match-key computation for the register-plan
|
|
3
|
+
* checkpoint. `computeMatchKeys` runs ONCE, at approval time (inside
|
|
4
|
+
* registerTestPlanTool / the analyze_changes pre-seed), so the two
|
|
5
|
+
* consumers — planGuard (generation-tool hard gate) and submitReportTool
|
|
6
|
+
* (report cross-check) — only ever do a Set/array membership check, never
|
|
7
|
+
* re-derive normalization logic against a live candidate.
|
|
8
|
+
*
|
|
9
|
+
* Two kinds of key:
|
|
10
|
+
* - `name:<slug>` — normalized scenarioName, for multi-step
|
|
11
|
+
* candidates (batch-scenario / integration) where the agent's own name is
|
|
12
|
+
* the natural join key.
|
|
13
|
+
* - `ep:<testType>:<METHOD>:<path>` — one per step, for single-endpoint
|
|
14
|
+
* matching (contract tests, or a fallback when names drift between
|
|
15
|
+
* register and generate).
|
|
16
|
+
*/
|
|
17
|
+
import { DraftedScenario } from "../types/RepositoryAnalysis.js";
|
|
18
|
+
import { ApprovedPlanItem, Candidate } from "../types/Recommendation.js";
|
|
19
|
+
/** Query shape built from a generation-tool call or a submitted report entry. */
|
|
20
|
+
export interface PlanMatchQuery {
|
|
21
|
+
scenarioName?: string;
|
|
22
|
+
testType?: string;
|
|
23
|
+
method?: string;
|
|
24
|
+
path?: string;
|
|
25
|
+
}
|
|
26
|
+
/** Lowercase, collapse non-alphanumeric runs to '-', trim leading/trailing '-'. */
|
|
27
|
+
export declare function slugifyName(name: string | undefined): string;
|
|
28
|
+
/**
|
|
29
|
+
* Normalize a path so param segments collapse: numeric ids, `{brace}` params,
|
|
30
|
+
* `:colon` params, and long hex/uuid segments all become `:p`. Mirrors
|
|
31
|
+
* discriminators.ts's normalizePath (duplicated here rather than imported —
|
|
32
|
+
* that function verifies discriminator claims against a diff, a different
|
|
33
|
+
* concern from plan matching, and keeping them independent avoids coupling
|
|
34
|
+
* this module's stability to phase 1's internal helper).
|
|
35
|
+
*/
|
|
36
|
+
export declare function normalizeMatchPath(rawPath: string | undefined): string;
|
|
37
|
+
/** Name key (if a name exists) plus one endpoint key per step. */
|
|
38
|
+
export declare function computeMatchKeys(scenario: DraftedScenario): string[];
|
|
39
|
+
/** Build the persisted plan item from a ranked Candidate. */
|
|
40
|
+
export declare function buildApprovedPlanItem(candidate: Candidate): ApprovedPlanItem;
|
|
41
|
+
/**
|
|
42
|
+
* True when `query` matches at least one of `items`' matchKeys:
|
|
43
|
+
* - by scenarioName slug (`name:<slug>`), or
|
|
44
|
+
* - by testType + path (`ep:<testType>:*:<path>`), method-exact when
|
|
45
|
+
* `query.method` is given, method-agnostic (any method) otherwise — the
|
|
46
|
+
* contract tool's `method: ""` ("test all methods") case.
|
|
47
|
+
*/
|
|
48
|
+
export declare function matchesApprovedItem(items: ApprovedPlanItem[], query: PlanMatchQuery): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* True when `query` is admissible under the approved plan: it matches a
|
|
51
|
+
* GENERATE item, or it matches an ADDITIONAL item while the plan has at least
|
|
52
|
+
* one GENERATE item. ADDITIONAL is strictly a backfill pool for failed
|
|
53
|
+
* GENERATE items — on a zero-budget plan (`generate: []`, e.g. maxGenerate=0
|
|
54
|
+
* for a config-only PR) there is nothing to backfill, so ADDITIONAL must not
|
|
55
|
+
* admit generation. Shared by planGuard and submitReportTool so the gate and
|
|
56
|
+
* the report cross-check can never disagree on admissibility.
|
|
57
|
+
*/
|
|
58
|
+
export declare function matchesApprovedPlan(plan: {
|
|
59
|
+
generate: ApprovedPlanItem[];
|
|
60
|
+
additional: ApprovedPlanItem[];
|
|
61
|
+
}, query: PlanMatchQuery): boolean;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SKYR-3879 Path B — shared match-key computation for the register-plan
|
|
3
|
+
* checkpoint. `computeMatchKeys` runs ONCE, at approval time (inside
|
|
4
|
+
* registerTestPlanTool / the analyze_changes pre-seed), so the two
|
|
5
|
+
* consumers — planGuard (generation-tool hard gate) and submitReportTool
|
|
6
|
+
* (report cross-check) — only ever do a Set/array membership check, never
|
|
7
|
+
* re-derive normalization logic against a live candidate.
|
|
8
|
+
*
|
|
9
|
+
* Two kinds of key:
|
|
10
|
+
* - `name:<slug>` — normalized scenarioName, for multi-step
|
|
11
|
+
* candidates (batch-scenario / integration) where the agent's own name is
|
|
12
|
+
* the natural join key.
|
|
13
|
+
* - `ep:<testType>:<METHOD>:<path>` — one per step, for single-endpoint
|
|
14
|
+
* matching (contract tests, or a fallback when names drift between
|
|
15
|
+
* register and generate).
|
|
16
|
+
*/
|
|
17
|
+
/** Lowercase, collapse non-alphanumeric runs to '-', trim leading/trailing '-'. */
|
|
18
|
+
export function slugifyName(name) {
|
|
19
|
+
return (name ?? "")
|
|
20
|
+
.toLowerCase()
|
|
21
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
22
|
+
.replace(/^-+|-+$/g, "");
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Normalize a path so param segments collapse: numeric ids, `{brace}` params,
|
|
26
|
+
* `:colon` params, and long hex/uuid segments all become `:p`. Mirrors
|
|
27
|
+
* discriminators.ts's normalizePath (duplicated here rather than imported —
|
|
28
|
+
* that function verifies discriminator claims against a diff, a different
|
|
29
|
+
* concern from plan matching, and keeping them independent avoids coupling
|
|
30
|
+
* this module's stability to phase 1's internal helper).
|
|
31
|
+
*/
|
|
32
|
+
export function normalizeMatchPath(rawPath) {
|
|
33
|
+
const pathPart = (rawPath ?? "").split("?")[0];
|
|
34
|
+
return pathPart
|
|
35
|
+
.split("/")
|
|
36
|
+
.map((seg) => {
|
|
37
|
+
if (seg === "")
|
|
38
|
+
return seg;
|
|
39
|
+
if (/^\{.*\}$/.test(seg))
|
|
40
|
+
return ":p";
|
|
41
|
+
if (/^:.+/.test(seg))
|
|
42
|
+
return ":p";
|
|
43
|
+
if (/^\d+$/.test(seg))
|
|
44
|
+
return ":p";
|
|
45
|
+
if (/^[0-9a-fA-F-]{16,}$/.test(seg))
|
|
46
|
+
return ":p";
|
|
47
|
+
return seg.toLowerCase();
|
|
48
|
+
})
|
|
49
|
+
.join("/");
|
|
50
|
+
}
|
|
51
|
+
function inferTestType(scenario) {
|
|
52
|
+
return (scenario.testType ?? (scenario.steps.length === 1 ? "contract" : "integration")).toLowerCase();
|
|
53
|
+
}
|
|
54
|
+
/** Name key (if a name exists) plus one endpoint key per step. */
|
|
55
|
+
export function computeMatchKeys(scenario) {
|
|
56
|
+
const keys = [];
|
|
57
|
+
const slug = slugifyName(scenario.scenarioName);
|
|
58
|
+
if (slug)
|
|
59
|
+
keys.push(`name:${slug}`);
|
|
60
|
+
const testType = inferTestType(scenario);
|
|
61
|
+
for (const step of scenario.steps ?? []) {
|
|
62
|
+
if (!step?.method || !step?.path)
|
|
63
|
+
continue;
|
|
64
|
+
keys.push(`ep:${testType}:${step.method.toUpperCase()}:${normalizeMatchPath(step.path)}`);
|
|
65
|
+
}
|
|
66
|
+
return [...new Set(keys)];
|
|
67
|
+
}
|
|
68
|
+
/** Build the persisted plan item from a ranked Candidate. */
|
|
69
|
+
export function buildApprovedPlanItem(candidate) {
|
|
70
|
+
return {
|
|
71
|
+
candidateId: candidate.candidateId,
|
|
72
|
+
scenarioName: candidate.scenario.scenarioName,
|
|
73
|
+
testType: inferTestType(candidate.scenario),
|
|
74
|
+
category: candidate.scenario.category,
|
|
75
|
+
source: candidate.source,
|
|
76
|
+
...(candidate.verifiedDiscriminator ? { verifiedDiscriminator: candidate.verifiedDiscriminator } : {}),
|
|
77
|
+
matchKeys: computeMatchKeys(candidate.scenario),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* True when `query` matches at least one of `items`' matchKeys:
|
|
82
|
+
* - by scenarioName slug (`name:<slug>`), or
|
|
83
|
+
* - by testType + path (`ep:<testType>:*:<path>`), method-exact when
|
|
84
|
+
* `query.method` is given, method-agnostic (any method) otherwise — the
|
|
85
|
+
* contract tool's `method: ""` ("test all methods") case.
|
|
86
|
+
*/
|
|
87
|
+
export function matchesApprovedItem(items, query) {
|
|
88
|
+
const nameSlug = query.scenarioName ? slugifyName(query.scenarioName) : "";
|
|
89
|
+
if (nameSlug) {
|
|
90
|
+
const nameKey = `name:${nameSlug}`;
|
|
91
|
+
if (items.some((item) => item.matchKeys.includes(nameKey)))
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
if (query.testType && query.path) {
|
|
95
|
+
const testType = query.testType.toLowerCase();
|
|
96
|
+
const normPath = normalizeMatchPath(query.path);
|
|
97
|
+
if (query.method) {
|
|
98
|
+
const epKey = `ep:${testType}:${query.method.toUpperCase()}:${normPath}`;
|
|
99
|
+
if (items.some((item) => item.matchKeys.includes(epKey)))
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
const prefix = `ep:${testType}:`;
|
|
104
|
+
const suffix = `:${normPath}`;
|
|
105
|
+
if (items.some((item) => item.matchKeys.some((k) => k.startsWith(prefix) && k.endsWith(suffix)))) {
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* True when `query` is admissible under the approved plan: it matches a
|
|
114
|
+
* GENERATE item, or it matches an ADDITIONAL item while the plan has at least
|
|
115
|
+
* one GENERATE item. ADDITIONAL is strictly a backfill pool for failed
|
|
116
|
+
* GENERATE items — on a zero-budget plan (`generate: []`, e.g. maxGenerate=0
|
|
117
|
+
* for a config-only PR) there is nothing to backfill, so ADDITIONAL must not
|
|
118
|
+
* admit generation. Shared by planGuard and submitReportTool so the gate and
|
|
119
|
+
* the report cross-check can never disagree on admissibility.
|
|
120
|
+
*/
|
|
121
|
+
export function matchesApprovedPlan(plan, query) {
|
|
122
|
+
if (matchesApprovedItem(plan.generate, query))
|
|
123
|
+
return true;
|
|
124
|
+
return plan.generate.length > 0 && matchesApprovedItem(plan.additional, query);
|
|
125
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { readFile } from "fs/promises";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
const REF_RE = /(?:from\s+["']([^"']+)["']|require\(\s*["']([^"']+)["']\s*\))/g;
|
|
4
|
+
/** One hop: for each selected file, resolve its relative import/require refs to files in the POM set. */
|
|
5
|
+
export async function expandImports(selected, allPoms) {
|
|
6
|
+
const pomSet = new Set(allPoms);
|
|
7
|
+
const out = selected.map((file) => ({ file }));
|
|
8
|
+
const seen = new Set(selected);
|
|
9
|
+
for (const file of selected) {
|
|
10
|
+
let content;
|
|
11
|
+
try {
|
|
12
|
+
content = await readFile(file, "utf8");
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
for (const m of content.matchAll(REF_RE)) {
|
|
18
|
+
const ref = m[1] ?? m[2];
|
|
19
|
+
if (!ref || !ref.startsWith("."))
|
|
20
|
+
continue;
|
|
21
|
+
const base = path.resolve(path.dirname(file), ref);
|
|
22
|
+
for (const cand of [base, `${base}.js`, `${base}.ts`, base.replace(/\.js$/, ".ts")]) {
|
|
23
|
+
if (pomSet.has(cand) && !seen.has(cand)) {
|
|
24
|
+
seen.add(cand);
|
|
25
|
+
out.push({ file: cand, referrer: file });
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return out;
|
|
32
|
+
}
|