@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.
Files changed (229) hide show
  1. package/build/commands/commandLibrary.d.ts +1 -1
  2. package/build/commands/commandLibrary.js +3 -3
  3. package/build/commands/recommendTestsAndExecuteCommand.d.ts +1 -1
  4. package/build/commands/recommendTestsAndExecuteCommand.js +35 -20
  5. package/build/commands/testThisEndpointCommand.js +35 -19
  6. package/build/index.js +9 -3
  7. package/build/playwright/blueprintDigest.d.ts +15 -0
  8. package/build/playwright/blueprintDigest.js +152 -0
  9. package/build/playwright/blueprintDigestStore.d.ts +31 -0
  10. package/build/playwright/blueprintDigestStore.js +117 -0
  11. package/build/playwright/registerPlaywrightTools.js +60 -12
  12. package/build/playwright/traceRecordingPrompt.js +8 -7
  13. package/build/prompts/enhance-assertions/sharedAssertionRules.js +9 -8
  14. package/build/prompts/enhance-assertions/uiAssertionsPrompt.js +24 -2
  15. package/build/prompts/promptAssets.d.ts +20 -0
  16. package/build/prompts/promptAssets.js +55 -0
  17. package/build/prompts/sut-setup/modes/dockerComposePrompt.js +19 -5
  18. package/build/prompts/test-maintenance/actionsInstructions.d.ts +4 -0
  19. package/build/prompts/test-maintenance/actionsInstructions.js +14 -2
  20. package/build/prompts/test-maintenance/drift-analysis-prompt.d.ts +0 -10
  21. package/build/prompts/test-maintenance/drift-analysis-prompt.js +2 -11
  22. package/build/prompts/test-maintenance/uiDriftAnalysisSections.js +8 -4
  23. package/build/prompts/test-recommendation/diffExecutionPlan.d.ts +5 -22
  24. package/build/prompts/test-recommendation/diffExecutionPlan.js +37 -465
  25. package/build/prompts/test-recommendation/recommendationSections.d.ts +7 -17
  26. package/build/prompts/test-recommendation/recommendationSections.js +67 -309
  27. package/build/prompts/test-recommendation/recommendationShared.d.ts +19 -47
  28. package/build/prompts/test-recommendation/recommendationShared.js +49 -155
  29. package/build/prompts/test-recommendation/registerRecommendTestsPrompt.d.ts +0 -5
  30. package/build/prompts/test-recommendation/registerRecommendTestsPrompt.js +10 -153
  31. package/build/prompts/test-recommendation/test-recommendation-prompt.d.ts +2 -29
  32. package/build/prompts/test-recommendation/test-recommendation-prompt.js +32 -457
  33. package/build/prompts/testbot/planDeclarations.d.ts +6 -0
  34. package/build/prompts/testbot/planDeclarations.js +9 -0
  35. package/build/prompts/testbot/testbot-prompts.d.ts +8 -0
  36. package/build/prompts/testbot/testbot-prompts.js +256 -381
  37. package/build/recommendation/answers.d.ts +35 -0
  38. package/build/recommendation/answers.js +96 -0
  39. package/build/recommendation/registerPlan.d.ts +49 -0
  40. package/build/recommendation/registerPlan.js +117 -0
  41. package/build/recommendation/runVerifiers.d.ts +10 -0
  42. package/build/recommendation/runVerifiers.js +49 -0
  43. package/build/recommendation/subjectStep.d.ts +42 -0
  44. package/build/recommendation/subjectStep.js +86 -0
  45. package/build/recommendation/types.d.ts +163 -0
  46. package/build/recommendation/types.js +20 -0
  47. package/build/recommendation/verifierContracts.d.ts +382 -0
  48. package/build/recommendation/verifierContracts.js +263 -0
  49. package/build/recommendation/verifiers/changedFile.d.ts +2 -0
  50. package/build/recommendation/verifiers/changedFile.js +82 -0
  51. package/build/recommendation/verifiers/citedPath.d.ts +12 -0
  52. package/build/recommendation/verifiers/citedPath.js +35 -0
  53. package/build/recommendation/verifiers/coverage.d.ts +7 -0
  54. package/build/recommendation/verifiers/coverage.js +617 -0
  55. package/build/recommendation/verifiers/deliveredMatchesPlan.d.ts +11 -0
  56. package/build/recommendation/verifiers/deliveredMatchesPlan.js +33 -0
  57. package/build/recommendation/verifiers/endpointGrounded.d.ts +17 -0
  58. package/build/recommendation/verifiers/endpointGrounded.js +128 -0
  59. package/build/recommendation/verifiers/existingCoverage.d.ts +6 -0
  60. package/build/recommendation/verifiers/existingCoverage.js +51 -0
  61. package/build/recommendation/verifiers/expectedOutcome.d.ts +31 -0
  62. package/build/recommendation/verifiers/expectedOutcome.js +105 -0
  63. package/build/recommendation/verifiers/removedElementGuarded.d.ts +2 -0
  64. package/build/recommendation/verifiers/removedElementGuarded.js +57 -0
  65. package/build/recommendation/verifiers/reportedCategory.d.ts +26 -0
  66. package/build/recommendation/verifiers/reportedCategory.js +84 -0
  67. package/build/recommendation/verifiers/screenRoute.d.ts +10 -0
  68. package/build/recommendation/verifiers/screenRoute.js +118 -0
  69. package/build/recommendation/verifiers/statedDifference.d.ts +6 -0
  70. package/build/recommendation/verifiers/statedDifference.js +140 -0
  71. package/build/recommendation/verifiers/uiElementGrounded.d.ts +7 -0
  72. package/build/recommendation/verifiers/uiElementGrounded.js +318 -0
  73. package/build/resources/analysisResources.js +1 -114
  74. package/build/resources/testbotResource.js +23 -13
  75. package/build/services/ModularizationService.js +2 -1
  76. package/build/services/TestDiscoveryService.d.ts +3 -72
  77. package/build/services/TestDiscoveryService.js +10 -303
  78. package/build/services/containerEnv.d.ts +1 -1
  79. package/build/services/containerEnv.js +12 -0
  80. package/build/skills/fixTestImportErrorsSkill.d.ts +13 -0
  81. package/build/skills/fixTestImportErrorsSkill.js +20 -0
  82. package/build/toolNames.d.ts +1 -0
  83. package/build/toolNames.js +1 -0
  84. package/build/tools/code-refactor/enhanceAssertionsTool.js +3 -3
  85. package/build/tools/code-refactor/modularizationTool.js +2 -1
  86. package/build/tools/executeSkyrampTestTool.d.ts +80 -0
  87. package/build/tools/executeSkyrampTestTool.js +246 -19
  88. package/build/tools/generate-tests/generateBatchScenarioRestTool.js +6 -0
  89. package/build/tools/generate-tests/generateContractRestTool.js +3 -3
  90. package/build/tools/generate-tests/planGuard.d.ts +2 -2
  91. package/build/tools/generate-tests/planGuard.js +78 -18
  92. package/build/tools/one-click/oneClickTool.d.ts +0 -1
  93. package/build/tools/one-click/oneClickTool.js +0 -5
  94. package/build/tools/submitReportTool.d.ts +48 -42
  95. package/build/tools/submitReportTool.js +576 -193
  96. package/build/tools/test-management/actionsTool.js +72 -4
  97. package/build/tools/test-management/analyzeChangesTool.d.ts +144 -48
  98. package/build/tools/test-management/analyzeChangesTool.js +212 -1219
  99. package/build/tools/test-management/analyzeTestHealthTool.js +13 -24
  100. package/build/tools/test-management/index.d.ts +1 -0
  101. package/build/tools/test-management/index.js +1 -0
  102. package/build/tools/test-management/registerTestPlanTool.d.ts +795 -172
  103. package/build/tools/test-management/registerTestPlanTool.js +609 -542
  104. package/build/tools/test-management/resolveScreenTool.d.ts +75 -0
  105. package/build/tools/test-management/resolveScreenTool.js +289 -0
  106. package/build/types/BlueprintDigest.d.ts +34 -0
  107. package/build/types/BlueprintDigest.js +1 -0
  108. package/build/types/RepositoryAnalysis.d.ts +20 -1559
  109. package/build/types/RepositoryAnalysis.js +2 -58
  110. package/build/types/StepMethod.d.ts +40 -0
  111. package/build/types/StepMethod.js +77 -0
  112. package/build/types/TestAnalysis.d.ts +12 -0
  113. package/build/types/TestExecution.d.ts +4 -0
  114. package/build/types/TestRecommendation.d.ts +24 -24
  115. package/build/types/TestRecommendation.js +91 -89
  116. package/build/types/TestbotPromptOptions.d.ts +0 -4
  117. package/build/types/TestbotReport.d.ts +64 -2
  118. package/build/utils/AnalysisStateManager.d.ts +79 -113
  119. package/build/utils/AnalysisStateManager.js +147 -57
  120. package/build/utils/assertion-verify/api-shared-lints.js +1 -1
  121. package/build/utils/assertion-verify/metrics.js +85 -36
  122. package/build/utils/assertion-verify/ui-lints.d.ts +0 -5
  123. package/build/utils/assertion-verify/ui-lints.js +32 -0
  124. package/build/utils/branchDiff.d.ts +63 -31
  125. package/build/utils/branchDiff.js +242 -94
  126. package/build/utils/containedPath.d.ts +18 -0
  127. package/build/utils/containedPath.js +73 -0
  128. package/build/utils/dartRouteExtractor.d.ts +18 -34
  129. package/build/utils/dartRouteExtractor.js +101 -173
  130. package/build/utils/featureFlags.d.ts +12 -0
  131. package/build/utils/featureFlags.js +14 -0
  132. package/build/utils/frontendSelectors.d.ts +48 -27
  133. package/build/utils/frontendSelectors.js +241 -80
  134. package/build/utils/pathMatching.d.ts +2 -4
  135. package/build/utils/pathMatching.js +2 -4
  136. package/build/utils/planMatchKeys.d.ts +38 -47
  137. package/build/utils/planMatchKeys.js +143 -81
  138. package/build/utils/rebaselineSnapshots.d.ts +24 -0
  139. package/build/utils/rebaselineSnapshots.js +65 -0
  140. package/build/utils/removedUiElements.d.ts +22 -0
  141. package/build/utils/removedUiElements.js +106 -0
  142. package/build/utils/reportVerification.d.ts +2 -6
  143. package/build/utils/reportVerification.js +61 -2
  144. package/build/utils/screenRoutes.d.ts +66 -0
  145. package/build/utils/screenRoutes.js +727 -0
  146. package/build/utils/sourceRouteExtractor.js +320 -112
  147. package/build/utils/testFileClassification.d.ts +11 -2
  148. package/build/utils/testFileClassification.js +44 -2
  149. package/build/utils/testFixtures.d.ts +5 -0
  150. package/build/utils/testFixtures.js +13 -0
  151. package/build/utils/utils.d.ts +0 -1
  152. package/build/utils/utils.js +0 -11
  153. package/build/utils/versions.d.ts +3 -3
  154. package/build/utils/versions.js +1 -1
  155. package/build/workspace/workspace.d.ts +12 -12
  156. package/node_modules/playwright/lib/mcp/skyramp/assertHiddenTool.js +56 -0
  157. package/node_modules/playwright/lib/mcp/skyramp/assertTool.js +2 -1
  158. package/node_modules/playwright/lib/mcp/skyramp/loadTraceTool.js +10 -0
  159. package/node_modules/playwright/lib/mcp/skyramp/skyRampImport.js +4 -1
  160. package/node_modules/playwright/lib/mcp/skyramp/traceRecordingBackend.js +160 -1
  161. package/node_modules/playwright/lib/mcp/test/skyRampExport.js +4 -2
  162. package/node_modules/playwright/node_modules/playwright-core/lib/server/codegen/skyramp/jsonlReader.js +1 -0
  163. package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/recorderSignalProcessor.js +2 -0
  164. package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder.js +5 -1
  165. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/{index.-Id052Lr.js → index.B7KbSQcC.js} +1 -1
  166. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.html +1 -1
  167. package/node_modules/playwright/node_modules/playwright-core/package.json +1 -1
  168. package/node_modules/playwright/node_modules/playwright-core/src/server/codegen/skyramp/jsonlReader.ts +1 -1
  169. package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/recorderSignalProcessor.ts +7 -0
  170. package/node_modules/playwright/node_modules/playwright-core/src/server/recorder.ts +6 -1
  171. package/node_modules/playwright/package.json +1 -1
  172. package/package.json +4 -3
  173. package/plugin/.claude-plugin/plugin.json +8 -0
  174. package/plugin/plugin.json +6 -0
  175. package/plugin/prompts/declaring-a-plan.md +20 -0
  176. package/plugin/prompts/generate-tests/context-fetching.md +4 -0
  177. package/plugin/prompts/generate-tests/execution-plan.md +63 -0
  178. package/plugin/prompts/generate-tests/generation.md +108 -0
  179. package/plugin/prompts/generate-tests/path-parameters.md +1 -0
  180. package/plugin/prompts/generate-tests/reasoning-protocol.md +17 -0
  181. package/plugin/prompts/generate-tests/tool-workflow-variants.md +61 -0
  182. package/plugin/prompts/generate-tests/tool-workflows.md +65 -0
  183. package/plugin/prompts/plan-tests.md +42 -0
  184. package/plugin/prompts/testbot-task1.md +82 -0
  185. package/plugin/skills/fix-test-import-errors/SKILL.md +98 -0
  186. package/build/prompts/test-recommendation/analysisOutputPrompt.d.ts +0 -84
  187. package/build/prompts/test-recommendation/analysisOutputPrompt.js +0 -369
  188. package/build/prompts/test-recommendation/fullRepoCatalog.d.ts +0 -7
  189. package/build/prompts/test-recommendation/fullRepoCatalog.js +0 -283
  190. package/build/prompts/test-recommendation/scopeAssessment.d.ts +0 -81
  191. package/build/prompts/test-recommendation/scopeAssessment.js +0 -359
  192. package/build/recommendation/budgeters/diversityBalancedBudgeter.d.ts +0 -7
  193. package/build/recommendation/budgeters/diversityBalancedBudgeter.js +0 -105
  194. package/build/recommendation/budgeters/fixedNBudgeter.d.ts +0 -7
  195. package/build/recommendation/budgeters/fixedNBudgeter.js +0 -11
  196. package/build/recommendation/budgeters/shared.d.ts +0 -32
  197. package/build/recommendation/budgeters/shared.js +0 -246
  198. package/build/recommendation/discriminators.d.ts +0 -37
  199. package/build/recommendation/discriminators.js +0 -379
  200. package/build/recommendation/diversity.d.ts +0 -47
  201. package/build/recommendation/diversity.js +0 -101
  202. package/build/recommendation/planRanker.d.ts +0 -65
  203. package/build/recommendation/planRanker.js +0 -83
  204. package/build/recommendation/testFixtures.d.ts +0 -25
  205. package/build/recommendation/testFixtures.js +0 -45
  206. package/build/types/FrontendIntegration.d.ts +0 -28
  207. package/build/types/FrontendIntegration.js +0 -22
  208. package/build/types/Recommendation.d.ts +0 -146
  209. package/build/types/Recommendation.js +0 -74
  210. package/build/utils/changedRoutes.d.ts +0 -29
  211. package/build/utils/changedRoutes.js +0 -87
  212. package/build/utils/frontendIntegration.d.ts +0 -9
  213. package/build/utils/frontendIntegration.js +0 -243
  214. package/build/utils/importerHop.d.ts +0 -135
  215. package/build/utils/importerHop.js +0 -489
  216. package/build/utils/pathAffinityClassification.d.ts +0 -49
  217. package/build/utils/pathAffinityClassification.js +0 -180
  218. package/build/utils/pythonMountPrefixes.d.ts +0 -25
  219. package/build/utils/pythonMountPrefixes.js +0 -347
  220. package/build/utils/repoScanner.d.ts +0 -34
  221. package/build/utils/repoScanner.js +0 -300
  222. package/build/utils/routeParsers.d.ts +0 -95
  223. package/build/utils/routeParsers.js +0 -951
  224. package/build/utils/scenarioDrafting.d.ts +0 -92
  225. package/build/utils/scenarioDrafting.js +0 -951
  226. package/build/utils/subjectEndpoints.d.ts +0 -19
  227. package/build/utils/subjectEndpoints.js +0 -98
  228. package/build/utils/uiPageEnumerator.d.ts +0 -172
  229. 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;