@skyramp/mcp 0.3.8 → 0.4.0-rc.1
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/commands/commandLibrary.d.ts +1 -1
- package/build/commands/commandLibrary.js +3 -3
- package/build/commands/recommendTestsAndExecuteCommand.d.ts +1 -1
- package/build/commands/recommendTestsAndExecuteCommand.js +35 -20
- package/build/commands/testThisEndpointCommand.js +35 -19
- package/build/index.js +9 -3
- package/build/playwright/blueprintDigest.d.ts +15 -0
- package/build/playwright/blueprintDigest.js +152 -0
- package/build/playwright/blueprintDigestStore.d.ts +31 -0
- package/build/playwright/blueprintDigestStore.js +117 -0
- package/build/playwright/registerPlaywrightTools.js +60 -12
- package/build/playwright/traceRecordingPrompt.js +8 -7
- package/build/prompts/enhance-assertions/sharedAssertionRules.js +9 -8
- package/build/prompts/enhance-assertions/uiAssertionsPrompt.js +24 -2
- package/build/prompts/promptAssets.d.ts +20 -0
- package/build/prompts/promptAssets.js +55 -0
- package/build/prompts/sut-setup/modes/dockerComposePrompt.js +19 -5
- package/build/prompts/test-maintenance/actionsInstructions.d.ts +4 -0
- package/build/prompts/test-maintenance/actionsInstructions.js +14 -2
- package/build/prompts/test-maintenance/drift-analysis-prompt.d.ts +0 -10
- package/build/prompts/test-maintenance/drift-analysis-prompt.js +2 -11
- package/build/prompts/test-maintenance/uiDriftAnalysisSections.js +8 -4
- package/build/prompts/test-recommendation/diffExecutionPlan.d.ts +5 -22
- package/build/prompts/test-recommendation/diffExecutionPlan.js +37 -465
- package/build/prompts/test-recommendation/recommendationSections.d.ts +7 -17
- package/build/prompts/test-recommendation/recommendationSections.js +67 -309
- package/build/prompts/test-recommendation/recommendationShared.d.ts +19 -47
- package/build/prompts/test-recommendation/recommendationShared.js +49 -155
- package/build/prompts/test-recommendation/registerRecommendTestsPrompt.d.ts +0 -5
- package/build/prompts/test-recommendation/registerRecommendTestsPrompt.js +10 -153
- package/build/prompts/test-recommendation/test-recommendation-prompt.d.ts +2 -29
- package/build/prompts/test-recommendation/test-recommendation-prompt.js +32 -457
- package/build/prompts/testbot/planDeclarations.d.ts +6 -0
- package/build/prompts/testbot/planDeclarations.js +9 -0
- package/build/prompts/testbot/testbot-prompts.d.ts +8 -0
- package/build/prompts/testbot/testbot-prompts.js +256 -381
- package/build/recommendation/answers.d.ts +35 -0
- package/build/recommendation/answers.js +96 -0
- package/build/recommendation/registerPlan.d.ts +49 -0
- package/build/recommendation/registerPlan.js +117 -0
- package/build/recommendation/runVerifiers.d.ts +10 -0
- package/build/recommendation/runVerifiers.js +49 -0
- package/build/recommendation/subjectStep.d.ts +42 -0
- package/build/recommendation/subjectStep.js +86 -0
- package/build/recommendation/types.d.ts +163 -0
- package/build/recommendation/types.js +20 -0
- package/build/recommendation/verifierContracts.d.ts +382 -0
- package/build/recommendation/verifierContracts.js +263 -0
- package/build/recommendation/verifiers/changedFile.d.ts +2 -0
- package/build/recommendation/verifiers/changedFile.js +82 -0
- package/build/recommendation/verifiers/citedPath.d.ts +12 -0
- package/build/recommendation/verifiers/citedPath.js +35 -0
- package/build/recommendation/verifiers/coverage.d.ts +7 -0
- package/build/recommendation/verifiers/coverage.js +617 -0
- package/build/recommendation/verifiers/deliveredMatchesPlan.d.ts +11 -0
- package/build/recommendation/verifiers/deliveredMatchesPlan.js +33 -0
- package/build/recommendation/verifiers/endpointGrounded.d.ts +17 -0
- package/build/recommendation/verifiers/endpointGrounded.js +128 -0
- package/build/recommendation/verifiers/existingCoverage.d.ts +6 -0
- package/build/recommendation/verifiers/existingCoverage.js +51 -0
- package/build/recommendation/verifiers/expectedOutcome.d.ts +31 -0
- package/build/recommendation/verifiers/expectedOutcome.js +105 -0
- package/build/recommendation/verifiers/removedElementGuarded.d.ts +2 -0
- package/build/recommendation/verifiers/removedElementGuarded.js +57 -0
- package/build/recommendation/verifiers/reportedCategory.d.ts +26 -0
- package/build/recommendation/verifiers/reportedCategory.js +84 -0
- package/build/recommendation/verifiers/screenRoute.d.ts +10 -0
- package/build/recommendation/verifiers/screenRoute.js +118 -0
- package/build/recommendation/verifiers/statedDifference.d.ts +6 -0
- package/build/recommendation/verifiers/statedDifference.js +140 -0
- package/build/recommendation/verifiers/uiElementGrounded.d.ts +7 -0
- package/build/recommendation/verifiers/uiElementGrounded.js +318 -0
- package/build/resources/analysisResources.js +1 -114
- package/build/resources/testbotResource.js +23 -13
- package/build/services/ModularizationService.js +2 -1
- package/build/services/TestDiscoveryService.d.ts +3 -72
- package/build/services/TestDiscoveryService.js +10 -303
- package/build/services/containerEnv.d.ts +1 -1
- package/build/services/containerEnv.js +12 -0
- package/build/skills/fixTestImportErrorsSkill.d.ts +13 -0
- package/build/skills/fixTestImportErrorsSkill.js +20 -0
- package/build/toolNames.d.ts +1 -0
- package/build/toolNames.js +1 -0
- package/build/tools/code-refactor/enhanceAssertionsTool.js +3 -3
- package/build/tools/code-refactor/modularizationTool.js +2 -1
- package/build/tools/executeSkyrampTestTool.d.ts +80 -0
- package/build/tools/executeSkyrampTestTool.js +246 -19
- package/build/tools/generate-tests/generateBatchScenarioRestTool.js +6 -0
- package/build/tools/generate-tests/generateContractRestTool.js +3 -3
- package/build/tools/generate-tests/planGuard.d.ts +2 -2
- package/build/tools/generate-tests/planGuard.js +78 -18
- package/build/tools/one-click/oneClickTool.d.ts +0 -1
- package/build/tools/one-click/oneClickTool.js +0 -5
- package/build/tools/submitReportTool.d.ts +48 -42
- package/build/tools/submitReportTool.js +576 -193
- package/build/tools/test-management/actionsTool.js +72 -4
- package/build/tools/test-management/analyzeChangesTool.d.ts +144 -48
- package/build/tools/test-management/analyzeChangesTool.js +212 -1219
- package/build/tools/test-management/analyzeTestHealthTool.js +13 -24
- 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 +795 -172
- package/build/tools/test-management/registerTestPlanTool.js +609 -542
- package/build/tools/test-management/resolveScreenTool.d.ts +75 -0
- package/build/tools/test-management/resolveScreenTool.js +289 -0
- package/build/types/BlueprintDigest.d.ts +34 -0
- package/build/types/BlueprintDigest.js +1 -0
- package/build/types/RepositoryAnalysis.d.ts +20 -1559
- package/build/types/RepositoryAnalysis.js +2 -58
- package/build/types/StepMethod.d.ts +40 -0
- package/build/types/StepMethod.js +77 -0
- package/build/types/TestAnalysis.d.ts +12 -0
- package/build/types/TestExecution.d.ts +4 -0
- package/build/types/TestRecommendation.d.ts +24 -24
- package/build/types/TestRecommendation.js +91 -89
- package/build/types/TestbotPromptOptions.d.ts +0 -4
- package/build/types/TestbotReport.d.ts +64 -2
- package/build/utils/AnalysisStateManager.d.ts +79 -113
- package/build/utils/AnalysisStateManager.js +147 -57
- package/build/utils/assertion-verify/api-shared-lints.js +1 -1
- package/build/utils/assertion-verify/metrics.js +85 -36
- package/build/utils/assertion-verify/ui-lints.d.ts +0 -5
- package/build/utils/assertion-verify/ui-lints.js +32 -0
- package/build/utils/branchDiff.d.ts +63 -31
- package/build/utils/branchDiff.js +242 -94
- package/build/utils/containedPath.d.ts +18 -0
- package/build/utils/containedPath.js +73 -0
- package/build/utils/dartRouteExtractor.d.ts +18 -34
- package/build/utils/dartRouteExtractor.js +101 -173
- package/build/utils/featureFlags.d.ts +12 -0
- package/build/utils/featureFlags.js +14 -0
- package/build/utils/frontendSelectors.d.ts +48 -27
- package/build/utils/frontendSelectors.js +241 -80
- package/build/utils/pathMatching.d.ts +2 -4
- package/build/utils/pathMatching.js +2 -4
- package/build/utils/planMatchKeys.d.ts +38 -47
- package/build/utils/planMatchKeys.js +143 -81
- package/build/utils/rebaselineSnapshots.d.ts +24 -0
- package/build/utils/rebaselineSnapshots.js +65 -0
- package/build/utils/removedUiElements.d.ts +22 -0
- package/build/utils/removedUiElements.js +106 -0
- package/build/utils/reportVerification.d.ts +2 -6
- package/build/utils/reportVerification.js +61 -2
- package/build/utils/screenRoutes.d.ts +66 -0
- package/build/utils/screenRoutes.js +727 -0
- package/build/utils/sourceRouteExtractor.js +320 -112
- package/build/utils/testFileClassification.d.ts +11 -2
- package/build/utils/testFileClassification.js +44 -2
- package/build/utils/testFixtures.d.ts +5 -0
- package/build/utils/testFixtures.js +13 -0
- package/build/utils/utils.d.ts +0 -1
- package/build/utils/utils.js +0 -11
- package/build/utils/versions.d.ts +3 -3
- package/build/utils/versions.js +1 -1
- package/build/workspace/workspace.d.ts +12 -12
- package/node_modules/playwright/lib/mcp/skyramp/assertHiddenTool.js +56 -0
- package/node_modules/playwright/lib/mcp/skyramp/assertTool.js +2 -1
- package/node_modules/playwright/lib/mcp/skyramp/loadTraceTool.js +10 -0
- package/node_modules/playwright/lib/mcp/skyramp/skyRampImport.js +4 -1
- package/node_modules/playwright/lib/mcp/skyramp/traceRecordingBackend.js +160 -1
- package/node_modules/playwright/lib/mcp/test/skyRampExport.js +4 -2
- package/node_modules/playwright/node_modules/playwright-core/lib/server/codegen/skyramp/jsonlReader.js +1 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/recorderSignalProcessor.js +2 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder.js +5 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/{index.-Id052Lr.js → index.B7KbSQcC.js} +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.html +1 -1
- package/node_modules/playwright/node_modules/playwright-core/package.json +1 -1
- package/node_modules/playwright/node_modules/playwright-core/src/server/codegen/skyramp/jsonlReader.ts +1 -1
- package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/recorderSignalProcessor.ts +7 -0
- package/node_modules/playwright/node_modules/playwright-core/src/server/recorder.ts +6 -1
- package/node_modules/playwright/package.json +1 -1
- package/package.json +4 -3
- package/plugin/.claude-plugin/plugin.json +8 -0
- package/plugin/plugin.json +6 -0
- package/plugin/prompts/declaring-a-plan.md +20 -0
- package/plugin/prompts/generate-tests/context-fetching.md +4 -0
- package/plugin/prompts/generate-tests/execution-plan.md +63 -0
- package/plugin/prompts/generate-tests/generation.md +108 -0
- package/plugin/prompts/generate-tests/path-parameters.md +1 -0
- package/plugin/prompts/generate-tests/reasoning-protocol.md +17 -0
- package/plugin/prompts/generate-tests/tool-workflow-variants.md +61 -0
- package/plugin/prompts/generate-tests/tool-workflows.md +65 -0
- package/plugin/prompts/plan-tests.md +42 -0
- package/plugin/prompts/testbot-task1.md +82 -0
- package/plugin/skills/fix-test-import-errors/SKILL.md +98 -0
- package/build/prompts/test-recommendation/analysisOutputPrompt.d.ts +0 -84
- package/build/prompts/test-recommendation/analysisOutputPrompt.js +0 -369
- package/build/prompts/test-recommendation/fullRepoCatalog.d.ts +0 -7
- package/build/prompts/test-recommendation/fullRepoCatalog.js +0 -283
- package/build/prompts/test-recommendation/scopeAssessment.d.ts +0 -81
- package/build/prompts/test-recommendation/scopeAssessment.js +0 -359
- package/build/recommendation/budgeters/diversityBalancedBudgeter.d.ts +0 -7
- package/build/recommendation/budgeters/diversityBalancedBudgeter.js +0 -105
- package/build/recommendation/budgeters/fixedNBudgeter.d.ts +0 -7
- package/build/recommendation/budgeters/fixedNBudgeter.js +0 -11
- package/build/recommendation/budgeters/shared.d.ts +0 -32
- package/build/recommendation/budgeters/shared.js +0 -246
- package/build/recommendation/discriminators.d.ts +0 -37
- package/build/recommendation/discriminators.js +0 -379
- package/build/recommendation/diversity.d.ts +0 -47
- package/build/recommendation/diversity.js +0 -101
- package/build/recommendation/planRanker.d.ts +0 -65
- package/build/recommendation/planRanker.js +0 -83
- package/build/recommendation/testFixtures.d.ts +0 -25
- package/build/recommendation/testFixtures.js +0 -45
- package/build/types/FrontendIntegration.d.ts +0 -28
- package/build/types/FrontendIntegration.js +0 -22
- package/build/types/Recommendation.d.ts +0 -146
- package/build/types/Recommendation.js +0 -74
- package/build/utils/changedRoutes.d.ts +0 -29
- package/build/utils/changedRoutes.js +0 -87
- package/build/utils/frontendIntegration.d.ts +0 -9
- package/build/utils/frontendIntegration.js +0 -243
- package/build/utils/importerHop.d.ts +0 -135
- package/build/utils/importerHop.js +0 -489
- package/build/utils/pathAffinityClassification.d.ts +0 -49
- package/build/utils/pathAffinityClassification.js +0 -180
- package/build/utils/pythonMountPrefixes.d.ts +0 -25
- package/build/utils/pythonMountPrefixes.js +0 -347
- package/build/utils/repoScanner.d.ts +0 -34
- package/build/utils/repoScanner.js +0 -300
- package/build/utils/routeParsers.d.ts +0 -95
- package/build/utils/routeParsers.js +0 -951
- package/build/utils/scenarioDrafting.d.ts +0 -92
- package/build/utils/scenarioDrafting.js +0 -951
- package/build/utils/subjectEndpoints.d.ts +0 -19
- package/build/utils/subjectEndpoints.js +0 -98
- package/build/utils/uiPageEnumerator.d.ts +0 -172
- package/build/utils/uiPageEnumerator.js +0 -474
|
@@ -1,283 +0,0 @@
|
|
|
1
|
-
import { isFlawTargetingCategory } from "../../types/TestRecommendation.js";
|
|
2
|
-
import { logger } from "../../utils/logger.js";
|
|
3
|
-
import { buildTestQualityCriteria } from "./recommendationSections.js";
|
|
4
|
-
import { externalDedupKeys, isAttackSurfaceSecurityBoundary } from "./recommendationShared.js";
|
|
5
|
-
export function buildFullRepoRecommendations(scored, topN, baseUrl, authHeaderValue, authSchemeSnippet, authTypeValue, isFrontendProject = false, isFrontendOnlyProject = false, externalCoverage = new Set()) {
|
|
6
|
-
// Full-repo mode only — percentage-based UI/E2E slot targets (15% each, floor 1).
|
|
7
|
-
const rawE2E = isFrontendProject ? Math.max(1, Math.round(topN * 0.15)) : 0;
|
|
8
|
-
const rawUI = isFrontendProject ? Math.max(1, Math.round(topN * 0.15)) : 0;
|
|
9
|
-
const slotsFloor = Math.floor(topN / 2);
|
|
10
|
-
const minE2ESlots = Math.min(rawE2E, slotsFloor);
|
|
11
|
-
const minUISlots = Math.min(rawUI, Math.max(0, topN - minE2ESlots));
|
|
12
|
-
const authRef = authHeaderValue
|
|
13
|
-
? `, authHeader: "${authHeaderValue}"${authSchemeSnippet}`
|
|
14
|
-
: `, authHeader: <check OpenAPI securitySchemes or auth middleware; "" if confirmed unauthenticated>`;
|
|
15
|
-
const hasWorkspaceAuthType = !!authTypeValue && authTypeValue !== "none";
|
|
16
|
-
const authHeaderOnlyRef = hasWorkspaceAuthType
|
|
17
|
-
? ""
|
|
18
|
-
: authHeaderValue
|
|
19
|
-
? `, authHeader: "${authHeaderValue}"`
|
|
20
|
-
: `, authHeader: <check OpenAPI securitySchemes or auth middleware; "" if confirmed unauthenticated>`;
|
|
21
|
-
const toTitle = (name) => name.replace(/-/g, " ").replace(/\b\w/g, c => c.toUpperCase());
|
|
22
|
-
const TYPE_ORDER = ["e2e", "ui", "integration", "contract"];
|
|
23
|
-
const TYPE_LABEL = {
|
|
24
|
-
e2e: "E2E", ui: "UI", integration: "Integration", contract: "Contract",
|
|
25
|
-
};
|
|
26
|
-
// Filter out scenarios already covered by external tests before slicing.
|
|
27
|
-
// The bug/attack-surface exemption matches applyExternalDedup in
|
|
28
|
-
// budgeters/shared.ts: those scenarios cover a semantic flaw that a
|
|
29
|
-
// same-endpoint external test does not, so an external match must not
|
|
30
|
-
// remove them here either.
|
|
31
|
-
const scoredFiltered = externalCoverage.size > 0
|
|
32
|
-
? scored.filter(item => {
|
|
33
|
-
const keys = externalDedupKeys(item.scenario);
|
|
34
|
-
if (keys.length === 0)
|
|
35
|
-
return true;
|
|
36
|
-
if (!keys.every((key) => externalCoverage.has(key)))
|
|
37
|
-
return true;
|
|
38
|
-
if (isFlawTargetingCategory(item.scenario.category) || isAttackSurfaceSecurityBoundary(item.scenario)) {
|
|
39
|
-
logger.info(`External dedup (full-repo): preserving "${item.scenario.scenarioName}" (${keys.join(", ")}) — protected bug/requirement-conflict/attack-surface scenario requires semantic flaw coverage`);
|
|
40
|
-
return true;
|
|
41
|
-
}
|
|
42
|
-
logger.info(`External dedup (full-repo): skipping "${item.scenario.scenarioName}" (${keys.join(", ")})`);
|
|
43
|
-
return false;
|
|
44
|
-
})
|
|
45
|
-
: scored;
|
|
46
|
-
// For full-stack repos, carve out E2E and UI slots before filling with backend tests.
|
|
47
|
-
const backendSlotCount = isFrontendProject
|
|
48
|
-
? Math.max(0, topN - minE2ESlots - minUISlots)
|
|
49
|
-
: topN;
|
|
50
|
-
const allItems = scoredFiltered.slice(0, backendSlotCount);
|
|
51
|
-
// Count the supplements against what this prompt actually lists. Reading the
|
|
52
|
-
// pre-filter `scored.length` claimed more pre-ranked items than the sections
|
|
53
|
-
// below render, so a pool thinned by external dedup asked for no supplements.
|
|
54
|
-
const supplementCount = topN - Math.min(allItems.length, topN);
|
|
55
|
-
const byType = new Map();
|
|
56
|
-
for (const t of TYPE_ORDER)
|
|
57
|
-
byType.set(t, []);
|
|
58
|
-
for (const item of allItems) {
|
|
59
|
-
const t = item.scenario.testType ?? (item.scenario.steps.length === 1 ? "contract" : "integration");
|
|
60
|
-
if (!byType.has(t))
|
|
61
|
-
byType.set(t, []);
|
|
62
|
-
byType.get(t).push(item);
|
|
63
|
-
}
|
|
64
|
-
const renderItem = (item, rank) => {
|
|
65
|
-
const s = item.scenario;
|
|
66
|
-
const testType = s.testType ?? (s.steps.length === 1 ? "contract" : "integration");
|
|
67
|
-
const title = toTitle(s.scenarioName);
|
|
68
|
-
if (testType === "contract") {
|
|
69
|
-
const step = s.steps[0];
|
|
70
|
-
const endpointURL = `${baseUrl}${step.path}`;
|
|
71
|
-
const isBodyMethod = ["POST", "PUT", "PATCH"].includes(step.method);
|
|
72
|
-
const dataParam = isBodyMethod
|
|
73
|
-
? `, requestData: <${step.method} ${step.path} required fields from source code>`
|
|
74
|
-
: "";
|
|
75
|
-
return [
|
|
76
|
-
`**${rank}. ${title}**`,
|
|
77
|
-
` ${s.description}`,
|
|
78
|
-
` ${step.method} ${step.path} \u2192 ${step.expectedStatusCode}`,
|
|
79
|
-
` Tool: \`skyramp_contract_test_generation({ endpointURL: "${endpointURL}", method: "${step.method}"${authRef}${dataParam} })\``,
|
|
80
|
-
` From source: fill in requestData field names and the specific production boundary this validates`,
|
|
81
|
-
].join("\n");
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
const stepLines = s.steps.map(st => {
|
|
85
|
-
const isBody = ["POST", "PUT", "PATCH"].includes(st.method);
|
|
86
|
-
const bodyHint = isBody ? ` \u2014 body: <${st.method} ${st.path} required fields from source>` : "";
|
|
87
|
-
return ` ${st.order}. ${st.method} ${st.path} \u2192 ${st.expectedStatusCode}: ${st.description}${bodyHint}`;
|
|
88
|
-
}).join("\n");
|
|
89
|
-
const isTraceBased = testType === "e2e" || testType === "ui";
|
|
90
|
-
let toolCallsBlock;
|
|
91
|
-
if (isTraceBased) {
|
|
92
|
-
// E2E and UI need browser recording first, then generation
|
|
93
|
-
const frontendUrl = "<frontend_url>";
|
|
94
|
-
const zipPath = `<repositoryPath>/.skyramp/${s.scenarioName}_trace.zip`;
|
|
95
|
-
if (testType === "ui") {
|
|
96
|
-
toolCallsBlock = [
|
|
97
|
-
` 1. browser_navigate({ url: "${frontendUrl}" })`,
|
|
98
|
-
` 2. Interact with the changed components (browser_click, browser_type, browser_fill_form, etc.)`,
|
|
99
|
-
` 3. browser_snapshot() after each key interaction`,
|
|
100
|
-
` 4. skyramp_export_zip({ outputPath: "${zipPath}" }) — use absolute path`,
|
|
101
|
-
` 5. skyramp_ui_test_generation({ playwrightInput: "${zipPath}"${authHeaderOnlyRef} })`,
|
|
102
|
-
].join("\n");
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
toolCallsBlock = [
|
|
106
|
-
` 1. browser_navigate({ url: "${frontendUrl}" }) — record frontend trace`,
|
|
107
|
-
` 2. Interact with the user journey described above`,
|
|
108
|
-
` 3. skyramp_export_zip({ outputPath: "${zipPath}" }) — use absolute path`,
|
|
109
|
-
` 4. Capture backend trace JSON separately (skyramp_start_trace_collection / skyramp_stop_trace_collection)`,
|
|
110
|
-
` 5. skyramp_e2e_test_generation({ playwrightInput: "${zipPath}", trace: "<backend trace path>"${authHeaderOnlyRef} })`,
|
|
111
|
-
].join("\n");
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
// Integration: use batch scenario tool (all steps in one call)
|
|
116
|
-
let destinationHost = s.scenarioName;
|
|
117
|
-
try {
|
|
118
|
-
destinationHost = new URL(baseUrl).hostname;
|
|
119
|
-
}
|
|
120
|
-
catch { /* keep fallback */ }
|
|
121
|
-
const batchSteps = s.steps.map(st => {
|
|
122
|
-
const isBody = ["POST", "PUT", "PATCH"].includes(st.method);
|
|
123
|
-
let dataParam = "";
|
|
124
|
-
if (isBody) {
|
|
125
|
-
if (st.requestBody && Object.keys(st.requestBody).length > 0) {
|
|
126
|
-
const bodyJson = JSON.stringify(st.requestBody).replace(/"/g, '\\"');
|
|
127
|
-
dataParam = `, requestBody: "${bodyJson}"`;
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
dataParam = `, requestBody: <${st.method} ${st.path} required fields from source code>`;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
return ` { method: "${st.method}", path: "${st.path}", statusCode: ${st.expectedStatusCode}${dataParam} }`;
|
|
134
|
-
}).join(",\n");
|
|
135
|
-
toolCallsBlock = [
|
|
136
|
-
` skyramp_batch_scenario_test_generation({ scenarioName: "${s.scenarioName}", destination: "${destinationHost}", baseURL: "${baseUrl}"${authRef}, steps: [\n${batchSteps}\n ] })`,
|
|
137
|
-
` skyramp_integration_test_generation({ scenarioFile: <filePath returned by skyramp_batch_scenario_test_generation above>${authHeaderOnlyRef} })`,
|
|
138
|
-
].join("\n");
|
|
139
|
-
}
|
|
140
|
-
return [
|
|
141
|
-
`**${rank}. ${title}**`,
|
|
142
|
-
` ${s.description}`,
|
|
143
|
-
` Steps:`,
|
|
144
|
-
stepLines,
|
|
145
|
-
` Tool calls:`,
|
|
146
|
-
toolCallsBlock,
|
|
147
|
-
` From source: fill in requestBody field values and assert all computed response fields`,
|
|
148
|
-
].join("\n");
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
const backendSections = TYPE_ORDER
|
|
152
|
-
.filter(t => (byType.get(t) ?? []).length > 0)
|
|
153
|
-
.map(t => {
|
|
154
|
-
const items = byType.get(t);
|
|
155
|
-
const label = TYPE_LABEL[t];
|
|
156
|
-
let globalRank = 0;
|
|
157
|
-
for (const prev of TYPE_ORDER) {
|
|
158
|
-
if (prev === t)
|
|
159
|
-
break;
|
|
160
|
-
globalRank += (byType.get(prev) ?? []).length;
|
|
161
|
-
}
|
|
162
|
-
const entries = items.map((item, i) => renderItem(item, globalRank + i + 1)).join("\n\n");
|
|
163
|
-
return `### ${label} (${items.length})\n\n${entries}`;
|
|
164
|
-
});
|
|
165
|
-
// Pre-allocate E2E and UI placeholder sections for full-stack repos.
|
|
166
|
-
const e2eSectionParts = [];
|
|
167
|
-
const uiSectionParts = [];
|
|
168
|
-
if (isFrontendProject) {
|
|
169
|
-
for (let i = 0; i < minE2ESlots; i++) {
|
|
170
|
-
const rank = i + 1;
|
|
171
|
-
e2eSectionParts.push(`**${rank}. E2E User Journey ${i + 1}**\n` +
|
|
172
|
-
` End-to-end test covering a complete user journey through the frontend and backend.\n` +
|
|
173
|
-
` To generate: record a browser trace, then call the generation tool.\n` +
|
|
174
|
-
` browser_navigate({ url: "${baseUrl}" }) \u2192 exercise key user flow \u2192 skyramp_export_zip({ outputPath: "<repo>/.skyramp/e2e_journey_${i + 1}.zip" })\n` +
|
|
175
|
-
` Tool: \`skyramp_e2e_test_generation({ playwrightInput: "<repo>/.skyramp/e2e_journey_${i + 1}.zip"${authHeaderOnlyRef} })\`\n` +
|
|
176
|
-
` From source: read frontend components and their API calls to identify the highest-value user journey`);
|
|
177
|
-
}
|
|
178
|
-
for (let i = 0; i < minUISlots; i++) {
|
|
179
|
-
const rank = minE2ESlots + i + 1;
|
|
180
|
-
uiSectionParts.push(`**${rank}. UI Component Test ${i + 1}**\n` +
|
|
181
|
-
` Test key UI component interactions and state changes.\n` +
|
|
182
|
-
` To generate: record a browser trace, then call the generation tool.\n` +
|
|
183
|
-
` browser_navigate({ url: "${baseUrl}" }) \u2192 interact with UI components \u2192 skyramp_export_zip({ outputPath: "<repo>/.skyramp/ui_component_${i + 1}.zip" })\n` +
|
|
184
|
-
` Tool: \`skyramp_ui_test_generation({ playwrightInput: "<repo>/.skyramp/ui_component_${i + 1}.zip"${authHeaderOnlyRef} })\`\n` +
|
|
185
|
-
` From source: read frontend component files to identify interactions, form submissions, and state transitions`);
|
|
186
|
-
}
|
|
187
|
-
// Offset backend section ranks by the number of E2E + UI placeholders
|
|
188
|
-
const offset = minE2ESlots + minUISlots;
|
|
189
|
-
backendSections.forEach((_, idx) => {
|
|
190
|
-
const t = TYPE_ORDER.filter(t => (byType.get(t) ?? []).length > 0)[idx];
|
|
191
|
-
if (!t)
|
|
192
|
-
return;
|
|
193
|
-
const items = byType.get(t);
|
|
194
|
-
const label = TYPE_LABEL[t];
|
|
195
|
-
let globalRank = offset;
|
|
196
|
-
for (const prev of TYPE_ORDER) {
|
|
197
|
-
if (prev === t)
|
|
198
|
-
break;
|
|
199
|
-
globalRank += (byType.get(prev) ?? []).length;
|
|
200
|
-
}
|
|
201
|
-
backendSections[idx] = `### ${label} (${items.length})\n\n${items.map((item, i) => renderItem(item, globalRank + i + 1)).join("\n\n")}`;
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
const allSections = [
|
|
205
|
-
...(e2eSectionParts.length > 0 ? [`### E2E (${e2eSectionParts.length})\n\n${e2eSectionParts.join("\n\n")}`] : []),
|
|
206
|
-
...(uiSectionParts.length > 0 ? [`### UI (${uiSectionParts.length})\n\n${uiSectionParts.join("\n\n")}`] : []),
|
|
207
|
-
...backendSections,
|
|
208
|
-
];
|
|
209
|
-
const sections = allSections.join("\n\n");
|
|
210
|
-
const frontendTierNote = isFrontendOnlyProject
|
|
211
|
-
? `\n\n**Frontend repo:** supplement MUST include at least ${minE2ESlots} E2E test${minE2ESlots > 1 ? "s" : ""} (\`skyramp_e2e_test_generation\`) and at least ${minUISlots} UI test${minUISlots > 1 ? "s" : ""} (\`skyramp_ui_test_generation\`). Do NOT add integration or contract tests.`
|
|
212
|
-
: isFrontendProject
|
|
213
|
-
? `\n\n**Full-stack repo:** supplement MUST include at least ${minE2ESlots} E2E test${minE2ESlots > 1 ? "s" : ""} (\`skyramp_e2e_test_generation\`) and at least ${minUISlots} UI test${minUISlots > 1 ? "s" : ""} (\`skyramp_ui_test_generation\`). Add these before exhausting backend tiers.`
|
|
214
|
-
: "";
|
|
215
|
-
const repoSupplementNote = supplementCount > 0
|
|
216
|
-
? `
|
|
217
|
-
<supplement_guidance>
|
|
218
|
-
**When to use:** The pre-ranked sections above contain fewer than ${topN} items. Add exactly ${supplementCount} more using the tiers below — exhaust each tier before moving to the next.
|
|
219
|
-
|
|
220
|
-
**Tier 1 — Error paths for endpoints already in the list** (highest value, do first):
|
|
221
|
-
• Auth boundary (no Authorization header → 403/401) → \`testType: contract, category: security_boundary\`
|
|
222
|
-
• Invalid/non-existent IDs (→ 404) → \`testType: contract, category: error_handling\`
|
|
223
|
-
• Missing required fields (→ 422) → \`testType: contract, category: data_validation\`
|
|
224
|
-
• Boundary values for numeric fields → \`testType: integration, category: data_validation\`
|
|
225
|
-
Note: DISCARD unique-constraint scenarios if the storage backend is Redis, MongoDB, or schema-less.
|
|
226
|
-
|
|
227
|
-
**Tier 2 — Auth coverage for any endpoint not yet covered by Tier 1:**
|
|
228
|
-
→ \`testType: contract, category: security_boundary\`
|
|
229
|
-
|
|
230
|
-
**Tier 3 — Cross-resource integration** (only when one resource's POST body contains another's \`_id\` field):
|
|
231
|
-
→ \`testType: integration, category: workflow\`
|
|
232
|
-
|
|
233
|
-
**Tier 4 — CRUD lifecycle** for any resource not yet covered:
|
|
234
|
-
→ \`testType: integration, category: crud\`
|
|
235
|
-
|
|
236
|
-
**How to fill each item:** Use path parameters in \`{param}\` format. Use real field names from the analysis or handler source — no generic placeholders. Describe behavior in API terms (HTTP method, path, status code), not storage internals.${frontendTierNote}
|
|
237
|
-
</supplement_guidance>`
|
|
238
|
-
: "";
|
|
239
|
-
const typeMixText = isFrontendOnlyProject
|
|
240
|
-
? `This is a frontend repo. Focus on E2E and UI tests only. Include at least ${minE2ESlots} E2E test${minE2ESlots > 1 ? "s" : ""} (\`skyramp_e2e_test_generation\`) and at least ${minUISlots} UI test${minUISlots > 1 ? "s" : ""} (\`skyramp_ui_test_generation\`). Do NOT add integration or contract tests.`
|
|
241
|
-
: isFrontendProject
|
|
242
|
-
? `This is a full-stack repo. Coverage ranking: E2E > UI > Integration > Contract. Include at least ${minE2ESlots} E2E test${minE2ESlots > 1 ? "s" : ""} (\`skyramp_e2e_test_generation\`) and at least ${minUISlots} UI test${minUISlots > 1 ? "s" : ""} (\`skyramp_ui_test_generation\`), in addition to backend integration and contract tests.`
|
|
243
|
-
: `Focus on integration and contract tests for all API endpoints.`;
|
|
244
|
-
return `## Test Recommendations — ${topN} total (grouped by test type)
|
|
245
|
-
|
|
246
|
-
> Repo mode — no tests are executed. Ranked by risk within each type.
|
|
247
|
-
> To generate any item: read the handler source, fill \`<…from source>\` placeholders with real values, then call the tool.
|
|
248
|
-
|
|
249
|
-
${sections}
|
|
250
|
-
|
|
251
|
-
**Test type mix — MANDATORY. No smoke tests. No fuzz tests. Only: integration, contract, E2E, UI.**
|
|
252
|
-
${typeMixText}
|
|
253
|
-
|
|
254
|
-
${repoSupplementNote}
|
|
255
|
-
|
|
256
|
-
**Present up to ${topN} recommendations.** Prioritize quality — only include a recommendation if it adds genuine new coverage. If fewer than ${topN} high-value tests exist for this codebase, stop at the last useful item rather than padding with trivial ones.
|
|
257
|
-
|
|
258
|
-
---
|
|
259
|
-
<enrichment_notes>
|
|
260
|
-
**Path resolution (do this before filling in any tool call):**
|
|
261
|
-
Cross-check every endpoint path against the Router Mounting / Nesting section in the analysis above. Sub-routers may be mounted at nested prefixes — e.g. a reviews router with \`@router.get("/")\` may actually be \`GET /api/v1/products/{product_id}/reviews\` if mounted under that prefix. Always use the fully-qualified nested path in tool calls, not the path as it appears in the route file alone.
|
|
262
|
-
|
|
263
|
-
**Existing test files (check before assigning output filenames):**
|
|
264
|
-
See the Existing Tests section above. If a recommendation's primary resource already has a \`[skyramp]\` test file listed there, prefer passing an explicit \`output\` filename (e.g. \`output: "orders_integration_test.py"\`) to update the existing file rather than creating a duplicate. Do NOT update \`[external]\` test files — they are user-maintained.
|
|
265
|
-
|
|
266
|
-
Before filling in tool call parameters for each item, use the analysis data already provided above (endpoint interactions, source context) first. Only read the route handler source code directly when the analysis data does not contain the specific value you need:
|
|
267
|
-
- Required request body fields (POST/PUT/PATCH) — use field names from the analysis interactions; read source only if they show \`{}\` or are missing
|
|
268
|
-
- Computed/derived response fields and their formulas — assert exact values; read source for formula details not captured in the analysis
|
|
269
|
-
- Auth middleware — set authHeader/authScheme from the repository context above; FastAPI HTTPBearer → 403 not 401
|
|
270
|
-
- Storage backend — if Redis or schema-less, discard unique-constraint and cascade-delete scenarios
|
|
271
|
-
- Delete behavior — hard-delete → 204; soft-delete/cancel → 200
|
|
272
|
-
|
|
273
|
-
${buildTestQualityCriteria()}
|
|
274
|
-
|
|
275
|
-
**5-dimension rubric — use to assign priority for supplement items:**
|
|
276
|
-
| Dimension | What to assess |
|
|
277
|
-
| Production Safety | Guards a critical boundary (auth, unique constraint, cascade delete, data integrity, breaking migration)? → HIGH |
|
|
278
|
-
| Bug-Finding Potential | Targets a known failure mode (race condition, data consistency, state transition, cascade effect)? → HIGH |
|
|
279
|
-
| User Journey Relevance | Reflects how real users interact (from traces, business flows, critical paths)? → HIGH or MEDIUM |
|
|
280
|
-
| Coverage Gap | Addresses an area with zero existing test coverage? → bump up one tier |
|
|
281
|
-
| Code Insight | Derived from actual implementation (spotted middleware pattern, N+1 risk, unique constraint)? → bump up one tier |
|
|
282
|
-
</enrichment_notes>`;
|
|
283
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Returns true if the file path looks like i18n/locale content (a JSON/YAML
|
|
3
|
-
* file under an i18n/, locale(s)/, lang/, or translation(s)/ directory).
|
|
4
|
-
* Exported so callers outside the frontend/backend classification itself
|
|
5
|
-
* (e.g. the production-importer integration check, which greps for static
|
|
6
|
-
* quoted imports) can special-case these files: real i18n loaders commonly
|
|
7
|
-
* fetch locale content by a templated runtime path rather than a static
|
|
8
|
-
* import, so the grep-based check would otherwise misreport them as
|
|
9
|
-
* unintegrated dead code (SKYR-3977).
|
|
10
|
-
*/
|
|
11
|
-
export declare function isI18nLocaleFile(filePath: string): boolean;
|
|
12
|
-
export declare function hasFlutterSdkDep(repositoryPath: string): boolean;
|
|
13
|
-
/**
|
|
14
|
-
* Returns true if the file path is a frontend file.
|
|
15
|
-
*
|
|
16
|
-
* Five tiers:
|
|
17
|
-
* 1. .vue / .svelte — always frontend; these file types cannot be route handlers.
|
|
18
|
-
* 2. .dart — always frontend IFF `hasFlutterSdkDep` is true (Flutter project).
|
|
19
|
-
* Sits above `STRICT_API_DIR_PATTERN` because there's no server-side Dart
|
|
20
|
-
* web framework in scope when the Flutter SDK dep is present.
|
|
21
|
-
* 3. i18n/locale JSON/YAML (e.g. locales/en/common.json) — frontend UNLESS in
|
|
22
|
-
* an API/backend directory (e.g. an i18n content API under api/), since
|
|
23
|
-
* unlike tiers 1-2 a locale file CAN be served by a backend route (SKYR-3977).
|
|
24
|
-
* 4. .tsx / .jsx — frontend unless in an API/backend directory (e.g. pages/api/).
|
|
25
|
-
* 5. Ambiguous extensions (.ts, .js, .css, .html, …) — require a recognised
|
|
26
|
-
* frontend directory AND must not be in an API/backend directory.
|
|
27
|
-
*
|
|
28
|
-
* The `hasFlutterSdkDep` opt is passed in by the budget-driving caller
|
|
29
|
-
* (analyzeChangesTool) which has repository context.
|
|
30
|
-
* Pure-path callers (test-recommendation-prompt, analysisOutputPrompt,
|
|
31
|
-
* scopeAssessment's own buildScopeAssessmentSection) default to false —
|
|
32
|
-
* they don't drive the budget.
|
|
33
|
-
*/
|
|
34
|
-
export declare function isFrontendFile(filePath: string, { hasFlutterSdkDep }?: {
|
|
35
|
-
hasFlutterSdkDep?: boolean;
|
|
36
|
-
}): boolean;
|
|
37
|
-
/**
|
|
38
|
-
* Returns true if the file path looks like a test file rather than UI source.
|
|
39
|
-
*
|
|
40
|
-
* Catches:
|
|
41
|
-
* - Skyramp-generated tests (`*_test.ts`, `*_smoke.ts`, `*_contract.ts`,
|
|
42
|
-
* `*_fuzz.ts`, `*_integration.ts`, `*_load.ts`, `*_e2e.ts`, `*_ui.ts`)
|
|
43
|
-
* - Skyramp scenario files (`scenario_*.json`)
|
|
44
|
-
* - Conventional Vitest/Jest/Playwright spec naming
|
|
45
|
-
* (`*.spec.{ts,tsx,js,jsx}`, `*.test.{ts,tsx,js,jsx}`)
|
|
46
|
-
* - Files inside `__tests__/` directories (Jest convention)
|
|
47
|
-
*
|
|
48
|
-
* Used by callers that want to filter test files OUT of frontend-source
|
|
49
|
-
* processing — `isFrontendFile` returns true for `.spec.ts` under a
|
|
50
|
-
* frontend directory because the rule is "tier-3 ambiguous + frontend dir,"
|
|
51
|
-
* but those tests aren't UI source we'd want to ground recommendations in.
|
|
52
|
-
*/
|
|
53
|
-
export declare function isTestFile(filePath: string): boolean;
|
|
54
|
-
/**
|
|
55
|
-
* Builds the PR scope assessment section.
|
|
56
|
-
*
|
|
57
|
-
* When `precomputedUIPct` is provided (0 = backend-only, 100 = UI-only) the server has
|
|
58
|
-
* already determined the split unambiguously, so Steps A–C are skipped. Backend-only
|
|
59
|
-
* (0) renders a single Budget Plan line; UI-only (100) renders that line plus the
|
|
60
|
-
* changed-behavior budget rule (SKYR-4292), because a frontend GENERATE list is
|
|
61
|
-
* placeholders the agent fills from the diff and the total must track what changed.
|
|
62
|
-
*
|
|
63
|
-
* For mixed PRs (`precomputedUIPct` is undefined, `hasFrontendChanges` is true) skip
|
|
64
|
-
* Steps A–C but keep Step D so the LLM can apply judgment to determine the UI%.
|
|
65
|
-
*
|
|
66
|
-
* Falls back to the full four-step assessment when no precomputed data is available.
|
|
67
|
-
*/
|
|
68
|
-
export declare function buildScopeAssessmentSection(maxTotal?: number, maxGenerate?: number, isUIOnly?: boolean,
|
|
69
|
-
/** Server-determined UI/E2E percentage. `undefined` = mixed PR or unknown. */
|
|
70
|
-
precomputedUIPct?: number,
|
|
71
|
-
/** Whether the diff contains frontend files (true ↔ mixed PR when precomputedUIPct is undefined). */
|
|
72
|
-
hasFrontendChanges?: boolean,
|
|
73
|
-
/**
|
|
74
|
-
* PR-mode: whether the diff classified at least one new/modified/removed endpoint.
|
|
75
|
-
* When false on the backend branch (precomputedUIPct === 0), the Budget Plan
|
|
76
|
-
* defaults to 0 total with a conditional ceiling instead of a fixed mandate —
|
|
77
|
-
* SKYR-3820: a config-only PR must not be pushed to fill the budget with
|
|
78
|
-
* baseline tests for unchanged endpoints. Defaults to true so existing callers
|
|
79
|
-
* keep the unconditional fixed-budget rendering.
|
|
80
|
-
*/
|
|
81
|
-
hasClassifiedApiChanges?: boolean): string;
|