@skyramp/mcp 0.0.59 → 0.0.60-rc.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.
Files changed (35) hide show
  1. package/build/index.js +32 -5
  2. package/build/prompts/test-recommendation/analysisOutputPrompt.js +98 -0
  3. package/build/prompts/test-recommendation/recommendationSections.js +226 -0
  4. package/build/prompts/test-recommendation/registerRecommendTestsPrompt.js +71 -0
  5. package/build/prompts/test-recommendation/test-recommendation-prompt.js +166 -104
  6. package/build/prompts/testGenerationPrompt.js +2 -3
  7. package/build/prompts/testbot/testbot-prompts.js +96 -93
  8. package/build/resources/analysisResources.js +254 -0
  9. package/build/services/ScenarioGenerationService.js +70 -26
  10. package/build/tools/generate-tests/generateIntegrationRestTool.js +54 -1
  11. package/build/tools/generate-tests/generateScenarioRestTool.js +8 -5
  12. package/build/tools/submitReportTool.js +28 -0
  13. package/build/tools/test-maintenance/stateCleanupTool.js +8 -0
  14. package/build/tools/test-recommendation/analyzeRepositoryTool.js +349 -217
  15. package/build/tools/test-recommendation/recommendTestsTool.js +163 -159
  16. package/build/tools/workspace/initializeWorkspaceTool.js +1 -1
  17. package/build/types/RepositoryAnalysis.js +99 -12
  18. package/build/utils/AnalysisStateManager.js +40 -23
  19. package/build/utils/branchDiff.js +47 -0
  20. package/build/utils/pr-comment-parser.js +124 -0
  21. package/build/utils/projectMetadata.js +188 -0
  22. package/build/utils/projectMetadata.test.js +81 -0
  23. package/build/utils/repoScanner.js +378 -0
  24. package/build/utils/routeParsers.js +213 -0
  25. package/build/utils/routeParsers.test.js +87 -0
  26. package/build/utils/scenarioDrafting.js +119 -0
  27. package/build/utils/scenarioDrafting.test.js +66 -0
  28. package/build/utils/trace-parser.js +166 -0
  29. package/build/utils/workspaceAuth.js +16 -0
  30. package/package.json +1 -1
  31. package/build/prompts/test-recommendation/repository-analysis-prompt.js +0 -326
  32. package/build/prompts/test-recommendation/test-mapping-prompt.js +0 -266
  33. package/build/tools/test-recommendation/mapTestsTool.js +0 -243
  34. package/build/types/TestMapping.js +0 -173
  35. package/build/utils/scoring-engine.js +0 -380
@@ -1,137 +1,199 @@
1
- /**
2
- * Test Recommendation Prompt
3
- * Prompt for generating actionable test recommendations
4
- */
5
- export function getTestRecommendationPrompt(mapping, analysis, topN = 7, analysisScope = "full_repo") {
1
+ import { buildPrioritizationDimensions, buildTestExamples, buildTestPatternGuidelines, buildTestQualityCriteria, buildGenerationRules, buildToolWorkflows, buildCoverageChecklist, } from "./recommendationSections.js";
2
+ function formatTestLocations(locs) {
3
+ const entries = Object.entries(locs || {});
4
+ if (entries.length === 0)
5
+ return "";
6
+ return "\n**Existing test files (do NOT duplicate these):**\n" +
7
+ entries.map(([type, files]) => " - [" + type + "] " + files).join("\n");
8
+ }
9
+ export function buildRecommendationPrompt(analysis, analysisScope = "full_repo", focus = "all", topN = 10, prContext, workspaceAuthHeader) {
6
10
  const isDiffScope = analysisScope === "current_branch_diff";
7
11
  const diffContext = analysis.branchDiffContext;
8
- // --- Build a compact summary of priority scores (no full JSON dump) ---
9
- const topScores = mapping.priorityScores
10
- .filter((s) => s.feasibility !== "not-applicable")
11
- .slice(0, topN);
12
- const scoreLines = topScores
13
- .map((s) => {
14
- const priority = s._finalScore >= 100 ? "high" : s._finalScore >= 70 ? "medium" : "low";
15
- const avail = s.requiredArtifacts.available.join(", ") || "none";
16
- const miss = s.requiredArtifacts.missing.join(", ") || "none";
17
- return (`- **${s.testType.toUpperCase()}** | priority: ${priority} | feasibility: ${s.feasibility}\n` +
18
- ` Reasoning: ${s.reasoning}\n` +
19
- ` Artifacts available: ${avail} | missing: ${miss}`);
20
- })
21
- .join("\n");
22
- // --- Build compact repo context (no full JSON dump) ---
23
- const endpoints = analysis.apiEndpoints.endpoints
24
- .slice(0, 30) // cap at 30 to keep size sane
25
- .map((e) => ` ${e.method} ${e.path}${e.authRequired ? " [auth]" : ""}`)
12
+ const openApiSpec = analysis.artifacts?.openApiSpecs?.[0];
13
+ // ── Frontend / UI change detection ──
14
+ const FRONTEND_FILE_PATTERN = /\.(tsx?|jsx?|vue|svelte|css|scss|less|html)$/;
15
+ const API_DIR_PATTERN = /\/(api|routes?|controllers?|routers?|handlers?|endpoints?|server)\//;
16
+ const hasFrontendChanges = isDiffScope && diffContext
17
+ ? diffContext.changedFiles.some(f => FRONTEND_FILE_PATTERN.test(f) &&
18
+ !API_DIR_PATTERN.test(f) &&
19
+ /\/(components?|pages?|views?|layouts?|app|src\/app|frontend|client|public|styles?)\//i.test(f))
20
+ : false;
21
+ const hasApiChanges = isDiffScope && diffContext
22
+ ? (diffContext.newEndpoints.length > 0 || diffContext.modifiedEndpoints.length > 0)
23
+ : false;
24
+ const isUIOnlyPR = hasFrontendChanges && !hasApiChanges;
25
+ // ── Mode preamble ──
26
+ const modePreamble = isDiffScope
27
+ ? `You are in **PR mode**. Maximize test coverage for the branch changes.
28
+ Focus on tests that validate the changed fields, endpoints, and their interactions.
29
+ **CRITICAL**: Recommend MULTIPLE integration tests at minimum one multi-resource workflow
30
+ AND one CRUD lifecycle.
31
+ ${isUIOnlyPR ? `\n**UI-only PR.** Prioritize UI tests and E2E. Skip fuzz/contract.`
32
+ : hasFrontendChanges ? `\n**Mixed PR (frontend + API).** Integration > E2E > UI > fuzz/contract.`
33
+ : ``}
34
+ Output should be concise and immediately actionable.`
35
+ : `You are in **Repo mode**. Comprehensive test strategy across all endpoints.`;
36
+ // ── Endpoint listing ──
37
+ const allEndpoints = analysis.apiEndpoints.endpoints;
38
+ const endpointLines = allEndpoints
39
+ .flatMap((ep) => (ep.methods ?? []).map((m) => ` ${m.method} ${ep.path}${m.authRequired ? " [auth]" : ""} (${(m.interactions ?? []).length} interactions)`))
26
40
  .join("\n");
41
+ const authMethod = analysis.authentication.method || "unknown";
42
+ const authHeaderValue = workspaceAuthHeader
43
+ ? workspaceAuthHeader
44
+ : /session|cookie|nextauth/i.test(authMethod) ? "Cookie"
45
+ : /api[_-]?key/i.test(authMethod) ? "X-API-Key"
46
+ : "Authorization";
27
47
  const repoContext = `
28
48
  Repository: ${analysis.metadata.repositoryName}
29
49
  Framework: ${analysis.projectClassification.primaryFramework} (${analysis.projectClassification.primaryLanguage})
30
50
  Project type: ${analysis.projectClassification.projectType}
31
- Auth: ${analysis.authentication.method}
51
+ Auth: ${authMethod} (header: ${authHeaderValue})
32
52
  Base URL: ${analysis.apiEndpoints.baseUrl}
33
- Endpoints (${analysis.apiEndpoints.totalCount} total):
34
- ${endpoints}
53
+ Endpoints (${analysis.apiEndpoints.totalCount}):
54
+ ${endpointLines}
35
55
  `.trim();
36
- // --- Branch diff context (only the essentials) ---
56
+ // ── Branch diff ──
37
57
  let diffSection = "";
38
58
  if (isDiffScope && diffContext) {
39
- const newEps = diffContext.newEndpoints
40
- .map((e) => ` ${e.method} ${e.path} (${e.sourceFile})`)
41
- .join("\n") || " none";
42
- const modEps = diffContext.modifiedEndpoints
43
- .map((e) => ` ${e.method} ${e.path} (${e.sourceFile})`)
44
- .join("\n") || " none";
59
+ const fmtEps = (eps, detail) => eps.flatMap((ep) => (ep.methods ?? []).map((m) => ` ${m.method} ${ep.path} (${detail(m)})`)).join("\n") || " none";
45
60
  diffSection = `
46
61
  ## Branch Diff Context
47
62
  Branch: \`${diffContext.currentBranch}\` → base: \`${diffContext.baseBranch}\`
48
63
  Changed files: ${diffContext.changedFiles.join(", ")}
49
64
  New endpoints:
50
- ${newEps}
65
+ ${fmtEps(diffContext.newEndpoints, (m) => `${m.sourceFile}, ${m.interactionCount} interactions`)}
51
66
  Modified endpoints:
52
- ${modEps}
67
+ ${fmtEps(diffContext.modifiedEndpoints, (m) => `${m.sourceFile}, ${m.changeType}`)}
53
68
  Affected services: ${diffContext.affectedServices.join(", ") || "N/A"}
54
- Summary: ${diffContext?.summary ?? "N/A"}
55
69
 
56
- **CRITICAL**: Focus recommendations ONLY on tests that validate the branch changes above.
70
+ **CRITICAL**: Focus on tests that validate these changes and how they interact with existing resources.
71
+ `;
72
+ }
73
+ // ── Interactions ──
74
+ let interactionSection = "";
75
+ if (focus === "all" || focus === "interactions") {
76
+ const diffEndpointKeys = new Set();
77
+ if (isDiffScope && diffContext) {
78
+ for (const ep of [...(diffContext.newEndpoints || []), ...(diffContext.modifiedEndpoints || [])]) {
79
+ for (const m of (ep.methods ?? []))
80
+ diffEndpointKeys.add(`${m.method} ${ep.path}`);
81
+ }
82
+ }
83
+ const summaryLines = allEndpoints
84
+ .flatMap((ep) => (ep.methods ?? []).flatMap((m) => (m.interactions ?? []).map((i) => ` ${m.method} ${ep.path} → ${i.response.statusCode} (${i.type}): ${i.description}`)))
85
+ .join("\n");
86
+ const detailEndpoints = isDiffScope
87
+ ? allEndpoints.filter((ep) => (ep.methods ?? []).some((m) => diffEndpointKeys.has(`${m.method} ${ep.path}`)))
88
+ : allEndpoints;
89
+ const detailBlocks = detailEndpoints
90
+ .flatMap((ep) => (ep.methods ?? []).flatMap((m) => (m.interactions ?? []).map((i) => {
91
+ const reqBody = i.request.body ? `\n requestBody: ${JSON.stringify(i.request.body)}` : "";
92
+ const resBody = i.response.body ? `\n responseBody: ${JSON.stringify(i.response.body)}` : "";
93
+ const headers = i.request.headers ? `\n headers: ${JSON.stringify(i.request.headers)}` : "";
94
+ return ` ${m.method} ${ep.path} → ${i.response.statusCode} (${i.type}): ${i.description}${reqBody}${resBody}${headers}`;
95
+ })))
96
+ .join("\n");
97
+ interactionSection = `
98
+ ## Endpoint Interactions
99
+ ${summaryLines}
100
+
101
+ ### Detailed (request/response bodies)
102
+ ${isDiffScope ? "Changed endpoints only. " : ""}Use source code schemas (Zod/Pydantic/DTOs) for actual request bodies.
103
+ ${detailBlocks}
104
+ `;
105
+ }
106
+ // ── Scenarios ──
107
+ let scenarioSection = "";
108
+ if (focus === "all" || focus === "scenarios") {
109
+ const scenarios = analysis.businessContext.draftedScenarios;
110
+ if (scenarios.length > 0) {
111
+ const baseUrl = analysis.apiEndpoints.baseUrl;
112
+ const scenarioBlocks = scenarios
113
+ .map((s) => {
114
+ const stepLines = s.steps.map((st) => ` ${st.order ?? ""}. **${st.method} ${st.path}** → ${st.expectedStatusCode ?? 200}: ${st.description || ""}`).join("\n");
115
+ const toolCalls = s.steps.map((st) => ` skyramp_scenario_test_generation({ scenarioName: "${s.scenarioName}", destination: "${s.scenarioName}", baseURL: "${baseUrl}", method: "${st.method}", path: "${st.path}", statusCode: ${st.expectedStatusCode ?? 200}, authHeader: "${authHeaderValue}", requestBody: <from source schemas for ${st.method} ${st.path}> })`).join("\n");
116
+ return (` ### ${s.scenarioName} (${s.category}, ${s.priority})\n` +
117
+ ` ${s.description}\n` +
118
+ ` **Steps:**\n${stepLines}\n` +
119
+ ` **Chaining keys:** ${s.chainingKeys.join(", ") || "none"}\n` +
120
+ ` **Tool calls:**\n${toolCalls}\n` +
121
+ ` Then: skyramp_integration_test_generation({ scenarioFile: "scenario_${s.scenarioName}.json", authHeader: "${authHeaderValue}" })`);
122
+ })
123
+ .join("\n\n");
124
+ scenarioSection = `
125
+ ## Drafted Scenarios — EACH = MANDATORY Integration Test
126
+ **Base URL:** \`${baseUrl}\` | **Auth:** \`${authHeaderValue}\`
127
+
128
+ Only use scenarios where resources are ACTUALLY related in the codebase. Replace any
129
+ scenario that pairs unrelated resources with one reflecting real foreign key relationships.
130
+
131
+ **Quality bar:** Realistic request bodies, actual foreign keys for chaining, response data
132
+ verification (not just status codes), realistic test data (not "test product").
133
+ **Path verification:** Cross-reference paths against Router Mounting context — use correct
134
+ nested paths. **Request bodies:** Replace placeholders with actual schemas from source code.
135
+
136
+ ${scenarioBlocks}
137
+ `;
138
+ }
139
+ else {
140
+ scenarioSection = `
141
+ ## Scenarios — Draft From Your Analysis
142
+
143
+ Draft at least 2-3 MEANINGFUL scenarios based on your codebase analysis:
144
+ 1. **Cross-resource workflow** — resources referencing each other via foreign keys
145
+ 2. **Search/filter + verify** — create data, search, verify results
146
+ 3. **Error handling** — invalid cross-resource references → appropriate errors
147
+
148
+ Use base URL: \`${analysis.apiEndpoints.baseUrl}\` and auth: \`${authHeaderValue}\`.
149
+ `;
150
+ }
151
+ }
152
+ // ── PR History ──
153
+ let prHistorySection = "";
154
+ if (prContext && prContext.previousRecommendations.length > 0) {
155
+ const recLines = prContext.previousRecommendations
156
+ .map((r) => ` - [${r.status.toUpperCase()}] ${r.testType} — ${r.endpoint}${r.scenarioName ? ` (scenario: ${r.scenarioName})` : ""}`)
157
+ .join("\n");
158
+ prHistorySection = `
159
+ ## PR History (PR #${prContext.prNumber})
160
+ ${recLines}
161
+ **Do NOT re-recommend tests already listed above.**
57
162
  `;
58
163
  }
164
+ // ── Compose all sections ──
59
165
  const scopeNote = isDiffScope
60
- ? "Recommendations are scoped to the current branch changes only. All specific test suggestions MUST target the new/modified endpoints listed in the Branch Diff Context."
61
- : "Recommendations cover the full repository.";
166
+ ? "Scoped to current branch changes."
167
+ : "Covers the full repository.";
62
168
  return `
63
- Generate actionable test recommendations based on the priority scores and repository analysis below.
169
+ ${modePreamble}
64
170
 
65
171
  Scope: ${scopeNote}
172
+
173
+ ${buildTestQualityCriteria()}
174
+
175
+ ${buildPrioritizationDimensions()}
176
+
177
+ ${buildTestExamples()}
178
+
179
+ ${buildTestPatternGuidelines()}
180
+
181
+ ${buildGenerationRules(isUIOnlyPR)}
182
+
66
183
  ${diffSection}
67
184
  ## Repository Context
68
185
 
69
186
  ${repoContext}
70
187
 
71
- ## Prioritized Test Types (top ${topN})
72
-
73
- ${scoreLines}
74
-
75
- ## Priority Mapping Summary
76
- - High priority: ${mapping.summary.highPriority.join(", ") || "none"}
77
- - Medium priority: ${mapping.summary.mediumPriority.join(", ") || "none"}
78
- - Low priority: ${mapping.summary.lowPriority.join(", ") || "none"}
79
-
80
- ## Your Task
81
-
82
- Generate specific, actionable test recommendations for the top ${topN} test types listed above.
83
-
84
- **MANDATORY RULES**:
85
- 1. **NO numeric scores** in output — use only: "high", "medium", "low".
86
- 2. **DO NOT mark any test "blocked"** even if artifacts are missing.
87
- 3. **Branch scope**: All specific test suggestions MUST target endpoints/code that changed in the branch diff.
88
- 4. **DO NOT create or save any files** — output everything inline in your response.
89
-
90
- ## Output Structure
91
-
92
- Return a JSON object with this structure:
93
-
94
- \`\`\`json
95
- {
96
- "summary": {
97
- "totalRecommended": 3,
98
- "highPriorityCount": 2,
99
- "estimatedEffort": "4-6 hours for top 3 tests",
100
- "quickWins": ["Smoke tests (OpenAPI available, 30 min)"]
101
- },
102
- "recommendations": [
103
- {
104
- "priority": "high",
105
- "testType": "contract",
106
- "rationale": "Why this is high priority (DO NOT mention numeric scores)",
107
- "specificTests": [
108
- {
109
- "testName": "Order quantity validation contract test",
110
- "description": "Verify POST /api/v1/orders rejects quantity < 1",
111
- "targetEndpoint": "POST /api/v1/orders",
112
- "targetFlow": "Order creation validation",
113
- "requiredInputs": {
114
- "available": [{"name": "openApiSpec", "path": "./openapi.json"}],
115
- "missing": []
116
- },
117
- "estimatedValue": "High - catches regression in validation rule change"
118
- }
119
- ],
120
- "gettingStarted": {
121
- "prerequisites": ["Service running at localhost:8000"],
122
- "quickStartCommand": "Use Skyramp MCP generate tools",
123
- "documentationUrl": "https://www.skyramp.dev/docs"
124
- }
125
- }
126
- ],
127
- "nextSteps": [
128
- "1. Start with highest priority test type",
129
- "2. Use Skyramp MCP generate tools to create each test",
130
- "3. Execute and validate results"
131
- ]
132
- }
133
- \`\`\`
188
+ ${interactionSection}
189
+ ${scenarioSection}
190
+ ${prHistorySection}
191
+ ## Existing Tests
192
+ - Frameworks: ${analysis.existingTests.frameworks.join(", ") || "none"}
193
+ ${formatTestLocations(analysis.existingTests.testLocations)}
194
+
195
+ ${buildToolWorkflows(authHeaderValue)}
134
196
 
135
- Generate recommendations now. Return the JSON object directly in your response text.
197
+ ${buildCoverageChecklist(openApiSpec, isUIOnlyPR, hasFrontendChanges, authHeaderValue, topN)}
136
198
  `;
137
199
  }
@@ -1,4 +1,3 @@
1
- // src/prompts/skyrampPrompt.ts
2
1
  import { logger } from "../utils/logger.js";
3
2
  export function registerTestGenerationPrompt(mcpServer) {
4
3
  logger.info("test generation prompt");
@@ -26,7 +25,7 @@ export function registerTestGenerationPrompt(mcpServer) {
26
25
  1. **Priority Scores Must Remain Unchanged**: When a test type is missing required inputs (e.g., Playwright recordings, traces), **DO NOT**:
27
26
  - Mark the test as "blocked" in the output
28
27
  - Adjust or reduce the priority score
29
- - Exclude it from recommendations if it ranks in the top 7
28
+ - Exclude it from recommendations
30
29
  2. DO NOT CREATE ANY .json or .md file during repository analysis, test mapping, or test recommendation.
31
30
 
32
31
  **CONTRACT TEST:**
@@ -115,7 +114,7 @@ Let us generate a UI test with frontend playwright trace file skyramp_playwright
115
114
 
116
115
  **SCENARIO PARSING:**
117
116
  - Purpose: Parse natural language scenarios into structured JSON arrays of API requests
118
- - Requirements: A natural language scenario description, API schema (OpenAPI/Swagger file or URL)
117
+ - Requirements: A natural language scenario description. API schema (OpenAPI/Swagger file or URL) is OPTIONAL — scenarios work without it using endpointURL and requestBody from source code
119
118
  - Features: Automatically breaks down any user-provided scenario into sequential API calls with request chaining
120
119
  - Output: Returns a JSON array where each element represents an API request with method, endpoint, parameters, and dependencies
121
120
 
@@ -9,99 +9,102 @@ function getTestbotPrompt(prTitle, prDescription, diffFile, testDirectory, summa
9
9
  <TEST DIRECTORY>${testDirectory}</TEST DIRECTORY>
10
10
  <REPOSITORY PATH>${repositoryPath}</REPOSITORY PATH>
11
11
 
12
- For all the following work, use the tools offered by Skyramp MCP server.
13
-
14
- Then perform ALL of the following tasks. Every task is MANDATORY — do NOT skip any task based on your own judgment unless the task itself gives you an explicit condition to skip.
15
-
16
- ## Task 1: Recommend New Tests (MANDATORY but skip if no application code changed)
17
-
18
- Read the diff at \`${diffFile}\`. Classify EVERY changed file using these categories:
19
-
20
- **Non-application files (DO NOT generate tests for these):**
21
- - CI/CD workflow files (.github/workflows/*.yml, .gitlab-ci.yml, Jenkinsfile, etc.)
22
- - Markdown documentation (.md files, README, CHANGELOG, CONTRIBUTING, etc.)
23
- - Dependency lock files (package-lock.json, yarn.lock, Pipfile.lock, poetry.lock, Gemfile.lock, go.sum, etc.)
24
- - Configuration-only files (.gitignore, .editorconfig, .prettierrc, renovate.json, dependabot.yml, etc.)
25
- - License files (LICENSE, NOTICE, etc.)
26
-
27
- **Application source code (generate tests for these):**
28
- - Routes, controllers, handlers, API endpoints
29
- - Models, schemas, validators, serializers, DTOs
30
- - Business logic, services, middleware, utilities
31
- - Test helpers and test fixtures
32
- - Any file with a source extension (.py, .ts, .js, .java, .go, .rb, .cs, .kt, .swift, etc.) that is NOT in the non-application list above
33
-
34
- **SKIP RULE — THIS IS MANDATORY:**
35
- If EVERY changed file in the diff falls into the "non-application files" category above, you MUST skip steps 1–6 entirely. Do NOT call \`skyramp_analyze_repository\`, do NOT call \`skyramp_map_tests\`, do NOT generate any tests. Instead, proceed directly to Task 2. In your report, state: "Task 1 skipped: PR contains only non-application changes (CI/docs/config)."
36
-
37
- **When in doubt:** If even ONE changed file looks like it could be application source code, run steps 1–6.
38
-
39
- 1. Call \`skyramp_analyze_repository\` with:
40
- - \`repositoryPath\`: "${repositoryPath}"
41
- - \`analysisScope\`: "current_branch_diff"${baseBranch ? `\n - \`baseBranch\`: "${baseBranch}"` : ''}
42
- 2. MANDATORY: Call \`skyramp_map_tests\` with \`stateFile\` (the state file path returned above) and \`analysisScope: "current_branch_diff"\`.
43
- 3. MANDATORY: Call \`skyramp_recommend_tests\` with the \`stateFile\` returned by \`skyramp_map_tests\`. Use the priority summary and the specific endpoints/files that changed to determine exactly what to test.
44
- 4. Generate tests using the Skyramp MCP generate tools, in priority order (minimum 3 test types).
45
- 5. Use Skyramp MCP to execute the generated tests and validate the results.
46
- 6. **E2E / UI Test Generation from Trace Files**: Search the repository for existing Skyramp trace files that can be used for E2E or UI test generation. Look for:
47
- - Backend trace files: files matching patterns like \`**/skyramp*trace*.json\`, \`**/skyramp-traces.json\`, or \`**/*trace*.json\` in test directories
48
- - Playwright UI trace files: files matching patterns like \`**/skyramp*playwright*.zip\`, \`**/*playwright*.zip\`, or \`**/*ui*trace*.zip\`
49
- Search in the test directory (\`${testDirectory}\`), the repository root, and any \`.skyramp/\` directories.
50
- - If you find BOTH a backend trace file AND a Playwright trace ZIP, call \`skyramp_e2e_test_generation\` with both files to generate an E2E test.
51
- - If you find ONLY a Playwright trace ZIP (no backend trace), call \`skyramp_ui_test_generation\` with the Playwright file to generate a UI test.
52
- - When generating E2E/UI tests, use the same language and framework as other tests in the repository. Default to Python with pytest if no convention is detected.
53
- - Execute any generated E2E/UI tests to validate them. Note: Playwright browsers are pre-installed in the CI environment.
54
-
55
- **IMPORTANT — Endpoint Renames:** If the diff shows an endpoint path was renamed (e.g. \`/products\` changed to \`/items\`) and existing tests already cover that endpoint under the old name, do NOT generate new tests for the renamed endpoint. The existing tests will be updated with the new path in Task 2 (Test Maintenance). Only generate new tests for genuinely new endpoints that have no existing test coverage under any name.
56
-
57
- ## Task 2: Existing Test Maintenance (MANDATORY)
58
-
59
- You MUST always run the steps below. Do NOT skip this task based on your own assessment of whether tests exist or are relevant — use the tools to determine that.
60
-
61
- 1. Call \`skyramp_discover_tests\` with \`repositoryPath\`: "${repositoryPath}" to find all existing Skyramp-generated tests.
62
- You may skip the rest of this task ONLY if it explicitly returns zero Skyramp-generated tests.
63
-
64
- 2. **Baseline — check for parallel CI first:**
65
- a. Read the workflow files in \`.github/workflows/\` and check if any workflow (other than the Skyramp Testbot workflow) is triggered on \`pull_request\` AND runs tests against the test directory (look for commands like \`pytest\`, \`jest\`, \`npm test\`, \`go test\`, \`skyramp test\`, or similar test execution commands).
66
- b. If such a workflow exists, run: \`gh run list --commit $(git rev-parse HEAD) --workflow <workflow-filename> --json status,conclusion --limit 1\` to check if it has completed for the current commit.
67
- c. If the parallel workflow completed successfully record beforeStatus as "Pass" for the discovered tests and note "baseline from CI workflow <workflow-name>" in beforeDetails. Skip to step 3.
68
- d. If the parallel workflow completed with failure — record beforeStatus as "Fail" and capture the failure context in beforeDetails. Skip to step 3.
69
- e. If no parallel test workflow exists, it hasn't completed yet, or the \`gh\` command fails for any reason (e.g. permissions, CLI not available) — execute ALL discovered tests AS-IS (before any modifications) using \`skyramp_execute_tests_batch\` or \`skyramp_execute_test\`. Record each test's status and details as the "before" results. In beforeDetails, describe the execution result (e.g. "Pass (10.8s)" or "Fail (404 Not Found)"). If you could not query CI, just note "unable to query existing CI pipeline" — do NOT expose internal details like authentication errors.
70
-
71
- 3. Call \`skyramp_analyze_test_drift\` with the \`stateFile\` returned by \`skyramp_discover_tests\`.
72
- 4. Call \`skyramp_calculate_health_scores\` with the \`stateFile\` from the previous step.
73
- 5. Call \`skyramp_actions\` with the updated \`stateFile\`. This tool returns instructions describing what needs to change in each test file — it does NOT modify the files itself.
74
- 6. **You MUST modify the existing test files in-place using your file editing tools.** Read the instructions from \`skyramp_actions\`, cross-reference with the code diff, and edit each test file directly.
75
- - If \`skyramp_actions\` returns endpoint rename mappings (old path → new path), apply them as simple find-and-replace on the test file URLs. Do NOT regenerate or restructure the test — only update the paths.
76
- - If \`skyramp_actions\` suggests file renames (e.g. \`products_smoke_test.py\` → \`items_smoke_test.py\`), rename the files using \`git mv\` after updating their content.
77
- - The goal is to fix the discovered tests so they pass with the new code, preserving the original test structure and logic. Do NOT create new test files as a substitute for fixing existing ones.
78
- 7. Execute the modified tests using Skyramp MCP and validate the results. This includes E2E and UI tests — Playwright browsers are pre-installed in the CI environment, so E2E/UI test execution is fully supported. Record each test's status and details as the "after" results.
79
- 8. For each maintained test, report BOTH the before and after results in the \`testMaintenance\` array of the report (using the fileName, beforeStatus, beforeDetails, afterStatus, afterDetails fields), so the user has full visibility into whether the code change or the existing test was at fault.
80
-
81
- ## Task 3: Submit Report (MANDATORY)
82
-
83
- After completing Tasks 1 and 2, you MUST call the Skyramp MCP tool "skyramp_submit_report" to submit your report.
84
- Pass '${summaryOutputFile}' as the summaryOutputFile parameter.
85
-
86
- For the commitMessage parameter, write a succinct summary (under 72 chars) of what you did, without any prefix. Examples:
87
- - "add contract tests for /products endpoint"
88
- - "update smoke tests for order API changes"
89
- - "add smoke and e2e tests for new /reviews endpoint"
90
-
91
- Do NOT write the report to a file yourself. Do NOT skip this step. The skyramp_submit_report tool is the ONLY way to submit the report.
92
-
93
- ## Report Guidelines
94
-
95
- **businessCaseAnalysis:** Base this ONLY on facts from the PR title, description, and what the tools reported. If \`skyramp_analyze_repository\` reported 0 new endpoints, do NOT claim new endpoints were added — instead describe the change accurately (e.g. "frontend changes to consume existing API endpoints", "refactored service layer", "updated test configuration"). Never infer new backend endpoints from frontend fetch/API calls in the diff.
96
-
97
- When reporting test results, if you chose to skip executing a test, you MUST explain WHY you skipped it.
98
- NEVER use the phrase "CI timeout" or imply a timeout occurred unless a tool call actually timed out.
99
- Instead, set the status to "Skipped" and provide an honest reason in the details, for example:
100
- - "Skipped: no code changes affect this endpoint"
101
- - "Skipped: skyramp_discover_tests found no existing Skyramp tests"
102
- - "Skipped: only CI/config changes in this PR, no API changes"
103
-
104
- Reminder: Use the Skyramp MCP tools available to you for test analysis, generation, and execution.`;
12
+ Use the Skyramp MCP server tools for all tasks below.
13
+
14
+ ## Task 1: Recommend & Generate New Tests
15
+
16
+ Read the diff at \`${diffFile}\`. Skip Task 1 if all changed files are non-application
17
+ (CI/CD, docs, lock files, config). Otherwise proceed:
18
+
19
+ ### Steps
20
+
21
+ 1. Call \`skyramp_analyze_repository\` with \`repositoryPath\`: "${repositoryPath}", \`analysisScope\`: "current_branch_diff"${baseBranch ? `\n , \`baseBranch\`: "${baseBranch}"` : ''}
22
+ 2. Call \`skyramp_recommend_tests\` with the returned \`sessionId\`.
23
+ It returns 7 ranked recommendations. Generate the top 4, report the remaining 3
24
+ as \`additionalRecommendations\`.
25
+
26
+ 3. **Generate** at most 4 tests from the top 4 recommendations. Stop after 4.
27
+ Keep a list of every file the CLI creates (test files AND scenario JSON files).
28
+
29
+ **Frontend-only PRs** (no backend/API changes): only generate tests if relevant
30
+ Playwright traces exist. If no traces are available, skip generation entirely and
31
+ move all 7 recommendations to \`additionalRecommendations\` with scenario steps and
32
+ trace recording instructions. Do not generate integration tests for unchanged backend
33
+ APIs just to fill the quota — those tests don't validate the PR's changes.
34
+
35
+ **How to generate each type:**
36
+ - **Integration**: call \`skyramp_scenario_test_generation\` per step, then
37
+ \`skyramp_integration_test_generation\` with the scenario file.
38
+ The scenario JSON is written to the same \`outputDir\` as the test files
39
+ (e.g. \`tests/scenario_<name>.json\`), not \`.skyramp/\`.
40
+ - **Contract**: call \`skyramp_contract_test_generation\` with \`endpointURL\`, \`method\`,
41
+ and \`requestData\` for POST/PUT endpoints.
42
+ Pass \`apiSchema\` if an OpenAPI spec exists it validates response structure.
43
+ - **Fuzz**: call \`skyramp_fuzz_test_generation\` with \`endpointURL\`, \`method\`, \`requestData\`.
44
+ Pass \`apiSchema\` if available it generates smarter boundary values.
45
+ - **E2E/UI**: only generate when relevant Playwright traces exist (see step 5).
46
+ Without traces, move the test to \`additionalRecommendations\` with scenario steps
47
+ and trace recording instructions instead.
48
+ - Skip smoke tests entirely.
49
+
50
+ **Scenario quality:** Before generating, verify each step's preconditions are met by
51
+ prior steps. For example, you can't update a membership that was never created check
52
+ the controller code for existence checks and ensure the scenario creates records first.
53
+
54
+ **Filenames:** Pass a descriptive \`--output\` name per test to avoid CLI overwrites.
55
+
56
+ 4. **Execute** the generated tests and record results.
57
+
58
+ 5. **Trace search** for E2E/UI: look in \`\${testDirectory}\`, repo root, and \`.skyramp/\` for
59
+ trace files (\`*trace*.json\`, \`*playwright*.zip\`). Only use a trace if it covers code
60
+ changed in this PR and targets localhost — skip traces for external hosts or unrelated code.
61
+
62
+ With relevant traces: backend + Playwright \`skyramp_e2e_test_generation\`,
63
+ Playwright only → \`skyramp_ui_test_generation\`.
64
+
65
+ **After generation, fix chaining only.** The CLI may use literal/hardcoded IDs instead
66
+ of dynamic values from prior responses. Fix these two cases:
67
+ 1. **Path params:** variables like \`product_id = 'product_id'\` use the response accessor
68
+ (e.g. \`getResponseValue(response, "response.id")\` in TS, \`skyramp.get_response_value(response, "id")\` in Python).
69
+ 2. **Request body refs:** hardcoded IDs in request bodies (e.g. \`"product_id": 1\`) replace
70
+ with the dynamic ID extracted from the prior POST response (e.g. \`product_id\` variable or
71
+ \`dataOverride\`/\`data_override\` for the field).
72
+
73
+ Change ONLY chaining-related values (path param assignments and body ID references).
74
+ Preserve everything else exactly as the CLI generated it headers, auth code, assertions,
75
+ imports, and all other request body fields.
76
+
77
+ ## Task 2: Existing Test Maintenance
78
+
79
+ Run this task regardless of Task 1 outcome even if Task 1 was skipped or generated zero tests.
80
+
81
+ 1. Call \`skyramp_discover_tests\` with \`repositoryPath\`: "${repositoryPath}".
82
+ 2. If zero Skyramp tests found, report \`testMaintenance\` as an empty array with
83
+ a note in \`issuesFound\`: "No existing Skyramp tests found for maintenance."
84
+ 3. If tests exist:
85
+ a. Baseline them (from CI status or by executing).
86
+ b. Run \`skyramp_analyze_test_drift\` \`skyramp_calculate_health_scores\` \`skyramp_actions\`.
87
+ c. Apply actions (path renames, schema updates) in-place. Do not regenerate.
88
+ d. Execute modified tests. Report before/after in \`testMaintenance\`.
89
+
90
+ ## Task 3: Submit Report
91
+
92
+ Verify Tasks 1 and 2 are complete, then call \`skyramp_submit_report\` with
93
+ \`summaryOutputFile\`: "${summaryOutputFile}".
94
+
95
+ \`commitMessage\`: under 72 chars, e.g. "add integration tests for /products and /orders"
96
+
97
+ **newTestsCreated** list every generated test file (at most 4):
98
+ \`testType\`, \`endpoint\`, \`fileName\`, \`description\`, \`scenarioFile\`, \`traceFile\`, \`frontendTrace\`
99
+ Use the actual file path returned by the generation tool for \`scenarioFile\`.
100
+ Include scenario JSON files in the git commit alongside test files.
101
+ Every test file in the commit should appear here. If you over-generated, delete extras first.
102
+ If no tests were generated (e.g. frontend-only PR without traces), pass an empty array.
103
+
104
+ **additionalRecommendations** remaining recommendations not generated:
105
+ \`testType\`, \`scenarioName\`, \`priority\`, \`description\`, \`steps\`, artifact paths
106
+
107
+ **businessCaseAnalysis** — based only on PR data and tool outputs.`;
105
108
  }
106
109
  export function registerTestbotPrompt(server) {
107
110
  logger.info("Registering testbot prompt");