@skyramp/mcp 0.2.6 → 0.2.150-rc.mntnc
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 +12 -0
- package/build/commands/recommendTestsAndExecuteCommand.d.ts +2 -0
- package/build/commands/testThisEndpointCommand.d.ts +2 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +6 -4
- package/build/playwright/PlaywrightTraceService.d.ts +32 -0
- package/build/playwright/index.d.ts +3 -0
- package/build/playwright/registerPlaywrightTools.d.ts +8 -0
- package/build/playwright/registerPlaywrightTools.js +12 -11
- package/build/playwright/traceRecordingPrompt.d.ts +13 -0
- package/build/playwright/traceRecordingPrompt.js +3 -11
- package/build/prompts/code-reuse.d.ts +1 -0
- package/build/prompts/enhance-assertions/contractProviderAssertionsPrompt.d.ts +2 -0
- package/build/prompts/enhance-assertions/integrationAssertionsPrompt.d.ts +2 -0
- package/build/prompts/enhance-assertions/sharedAssertionRules.d.ts +15 -0
- package/build/prompts/enhance-assertions/uiAssertionsPrompt.d.ts +2 -0
- package/build/prompts/enhance-assertions/uiAssertionsPrompt.js +24 -5
- package/build/prompts/fix-error-prompt.d.ts +1 -0
- package/build/prompts/initialize-workspace/initializeWorkspacePrompt.d.ts +1 -0
- package/build/prompts/modularization/integration-test-modularization.d.ts +1 -0
- package/build/prompts/modularization/ui-test-modularization.d.ts +1 -0
- package/build/prompts/personas.d.ts +21 -0
- package/build/prompts/pom-aware-code-reuse.d.ts +1 -0
- package/build/prompts/startTraceCollectionPrompts.d.ts +2 -0
- package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.d.ts +2 -0
- package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.js +114 -0
- package/build/prompts/sut-setup/modes/dockerComposePrompt.d.ts +2 -0
- package/build/prompts/sut-setup/modes/dockerComposePrompt.js +292 -0
- package/build/prompts/sut-setup/shared.d.ts +39 -0
- package/build/prompts/sut-setup/shared.js +132 -0
- package/build/prompts/test-maintenance/actionsInstructions.d.ts +35 -0
- package/build/prompts/test-maintenance/drift-analysis-prompt.d.ts +4 -0
- package/build/prompts/test-maintenance/driftAnalysisSections.d.ts +13 -0
- package/build/prompts/test-maintenance/driftAnalysisSections.js +9 -3
- package/build/prompts/test-recommendation/analysisOutputPrompt.d.ts +84 -0
- package/build/prompts/test-recommendation/analysisOutputPrompt.js +1 -1
- package/build/prompts/test-recommendation/analysisOutputPrompt.test.d.ts +1 -0
- package/build/prompts/test-recommendation/analysisOutputPrompt.test.js +1 -0
- package/build/prompts/test-recommendation/diffExecutionPlan.d.ts +17 -0
- package/build/prompts/test-recommendation/diffExecutionPlan.js +7 -16
- package/build/prompts/test-recommendation/fullRepoCatalog.d.ts +7 -0
- package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.d.ts +1 -0
- package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.js +1 -0
- package/build/prompts/test-recommendation/promptPlan.d.ts +203 -0
- package/build/prompts/test-recommendation/promptPlan.test.d.ts +1 -0
- package/build/prompts/test-recommendation/recommendationSections.d.ts +35 -0
- package/build/prompts/test-recommendation/recommendationShared.d.ts +31 -0
- package/build/prompts/test-recommendation/registerRecommendTestsPrompt.d.ts +7 -0
- package/build/prompts/test-recommendation/scopeAssessment.d.ts +55 -0
- package/build/prompts/test-recommendation/scopeAssessment.js +2 -2
- package/build/prompts/test-recommendation/scopeAssessment.test.d.ts +1 -0
- package/build/prompts/test-recommendation/scopeAssessment.test.js +1 -0
- package/build/prompts/test-recommendation/test-recommendation-prompt.d.ts +6 -0
- package/build/prompts/test-recommendation/test-recommendation-prompt.js +4 -4
- package/build/prompts/test-recommendation/test-recommendation-prompt.test.d.ts +1 -0
- package/build/prompts/test-recommendation/test-recommendation-prompt.test.js +6 -99
- package/build/prompts/testbot/testbot-prompts.d.ts +11 -0
- package/build/prompts/testbot/testbot-prompts.js +213 -42
- package/build/prompts/testbot/testbot-prompts.test.d.ts +1 -0
- package/build/prompts/testbot/testbot-prompts.test.js +15 -117
- package/build/resources/analysisResources.d.ts +17 -0
- package/build/resources/progressResource.d.ts +2 -0
- package/build/resources/sutSetupResource.d.ts +2 -0
- package/build/resources/sutSetupResource.js +45 -0
- package/build/resources/testbotResource.d.ts +2 -0
- package/build/resources/testbotResource.js +1 -1
- package/build/services/AnalyticsService.d.ts +13 -0
- package/build/services/AnalyticsService.test.d.ts +1 -0
- package/build/services/AnalyticsService.test.js +86 -0
- package/build/services/ModularizationService.d.ts +11 -0
- package/build/services/ScenarioGenerationService.d.ts +37 -0
- package/build/services/ScenarioGenerationService.integration.test.d.ts +1 -0
- package/build/services/ScenarioGenerationService.integration.test.js +4 -0
- package/build/services/ScenarioGenerationService.test.d.ts +1 -0
- package/build/services/TestDiscoveryService.d.ts +128 -0
- package/build/services/TestDiscoveryService.js +22 -12
- package/build/services/TestDiscoveryService.test.d.ts +1 -0
- package/build/services/TestDiscoveryService.test.js +4 -3
- package/build/services/TestExecutionService.d.ts +55 -0
- package/build/services/TestExecutionService.js +158 -26
- package/build/services/TestExecutionService.test.d.ts +1 -0
- package/build/services/TestExecutionService.test.js +339 -25
- package/build/services/TestGenerationService.d.ts +56 -0
- package/build/services/TestGenerationService.test.d.ts +1 -0
- package/build/services/TestGenerationService.test.js +10 -8
- package/build/services/containerEnv.d.ts +14 -0
- package/build/tool-phase-coverage.test.d.ts +1 -0
- package/build/tool-phase-coverage.test.js +2 -0
- package/build/tool-phases.d.ts +38 -0
- package/build/tools/auth/loginTool.d.ts +2 -0
- package/build/tools/auth/logoutTool.d.ts +2 -0
- package/build/tools/code-refactor/codeReuseTool.d.ts +2 -0
- package/build/tools/code-refactor/enhanceAssertionsTool.d.ts +2 -0
- package/build/tools/code-refactor/modularizationTool.d.ts +2 -0
- package/build/tools/executeSkyrampTestTool.d.ts +2 -0
- package/build/tools/executeSkyrampTestTool.js +17 -4
- package/build/tools/fixErrorTool.d.ts +2 -0
- package/build/tools/generate-tests/generateBatchScenarioRestTool.d.ts +45 -0
- package/build/tools/generate-tests/generateBatchScenarioRestTool.js +1 -1
- package/build/tools/generate-tests/generateBatchScenarioRestTool.test.d.ts +1 -0
- package/build/tools/generate-tests/generateBatchScenarioRestTool.test.js +11 -9
- package/build/tools/generate-tests/generateContractRestTool.d.ts +31 -0
- package/build/tools/generate-tests/generateE2ERestTool.d.ts +13 -0
- package/build/tools/generate-tests/generateFuzzRestTool.d.ts +10 -0
- package/build/tools/generate-tests/generateIntegrationRestTool.d.ts +16 -0
- package/build/tools/generate-tests/generateLoadRestTool.d.ts +18 -0
- package/build/tools/generate-tests/generateLoadRestTool.test.d.ts +1 -0
- package/build/tools/generate-tests/generateMockRestTool.d.ts +64 -0
- package/build/tools/generate-tests/generateSmokeRestTool.d.ts +8 -0
- package/build/tools/generate-tests/generateUIRestTool.d.ts +14 -0
- package/build/tools/generate-tests/generateUIRestTool.js +1 -1
- package/build/tools/generate-tests/loadTestSchema.d.ts +39 -0
- package/build/tools/one-click/oneClickTool.d.ts +11 -0
- package/build/tools/submitReportTool.d.ts +384 -0
- package/build/tools/submitReportTool.js +225 -37
- package/build/tools/submitReportTool.test.d.ts +1 -0
- package/build/tools/submitReportTool.test.js +479 -55
- package/build/tools/test-management/actionsTool.d.ts +10 -0
- package/build/tools/test-management/actionsTool.js +10 -0
- package/build/tools/test-management/analyzeChangesTool.d.ts +26 -0
- package/build/tools/test-management/analyzeChangesTool.js +128 -48
- package/build/tools/test-management/analyzeChangesTool.test.d.ts +1 -0
- package/build/tools/test-management/analyzeChangesTool.test.js +80 -73
- package/build/tools/test-management/analyzeTestHealthTool.d.ts +2 -0
- package/build/tools/test-management/analyzeTestHealthTool.js +6 -3
- package/build/tools/test-management/index.d.ts +3 -0
- package/build/tools/test-management/index.js +0 -1
- package/build/tools/trace/resolveSaveStoragePath.d.ts +7 -0
- package/build/tools/trace/resolveSaveStoragePath.test.d.ts +1 -0
- package/build/tools/trace/resolveSessionPaths.d.ts +40 -0
- package/build/tools/trace/resolveSessionPaths.test.d.ts +1 -0
- package/build/tools/trace/sessionState.d.ts +2 -0
- package/build/tools/trace/sessionState.test.d.ts +1 -0
- package/build/tools/trace/startTraceCollectionTool.d.ts +2 -0
- package/build/tools/trace/stopTraceCollectionTool.d.ts +2 -0
- package/build/tools/workspace/initScanWorkspaceTool.d.ts +4 -0
- package/build/tools/workspace/initializeWorkspaceTool.d.ts +2 -0
- package/build/tools/workspace/initializeWorkspaceTool.test.d.ts +1 -0
- package/build/tools/workspace/initializeWorkspaceTool.test.js +134 -0
- package/build/types/OneClickCommands.d.ts +68 -0
- package/build/types/RepositoryAnalysis.d.ts +3004 -0
- package/build/types/TestAnalysis.d.ts +97 -0
- package/build/types/TestExecution.d.ts +63 -0
- package/build/types/TestExecution.js +11 -1
- package/build/types/TestRecommendation.d.ts +12 -0
- package/build/types/TestTypes.d.ts +234 -0
- package/build/types/TestbotReport.d.ts +68 -0
- package/build/types/TestbotReport.js +1 -0
- package/build/types/index.d.ts +4 -0
- package/build/types/index.js +3 -0
- package/build/utils/AnalysisStateManager.d.ts +182 -0
- package/build/utils/AnalysisStateManager.js +10 -1
- package/build/utils/AnalysisStateManager.test.d.ts +1 -0
- package/build/utils/analyze-openapi.d.ts +1 -0
- package/build/utils/branchDiff.d.ts +18 -0
- package/build/utils/dartRouteExtractor.d.ts +45 -0
- package/build/utils/dartRouteExtractor.test.d.ts +1 -0
- package/build/utils/docker.d.ts +19 -0
- package/build/utils/docker.test.d.ts +1 -0
- package/build/utils/docker.test.js +10 -9
- package/build/utils/featureFlags.d.ts +37 -0
- package/build/utils/featureFlags.test.d.ts +1 -0
- package/build/utils/gitStaging.d.ts +24 -0
- package/build/utils/gitStaging.test.d.ts +1 -0
- package/build/utils/gitStaging.test.js +13 -7
- package/build/utils/httpDefaults.d.ts +10 -0
- package/build/utils/httpDefaults.test.d.ts +1 -0
- package/build/utils/initAgent.d.ts +36 -0
- package/build/utils/language-helper.d.ts +6 -0
- package/build/utils/logger.d.ts +11 -0
- package/build/utils/normalizeParams.d.ts +14 -0
- package/build/utils/normalizeSkyrampImports.d.ts +13 -0
- package/build/utils/pr-comment-parser.d.ts +31 -0
- package/build/utils/pr-comment-parser.test.d.ts +1 -0
- package/build/utils/pr-comment-parser.test.js +6 -5
- package/build/utils/projectMetadata.d.ts +15 -0
- package/build/utils/projectMetadata.test.d.ts +1 -0
- package/build/utils/proxy-terminal.d.ts +2 -0
- package/build/utils/repoScanner.d.ts +27 -0
- package/build/utils/repoScanner.test.d.ts +1 -0
- package/build/utils/routeParsers.d.ts +53 -0
- package/build/utils/routeParsers.js +31 -38
- package/build/utils/routeParsers.test.d.ts +1 -0
- package/build/utils/scenarioDrafting.d.ts +71 -0
- package/build/utils/scenarioDrafting.js +23 -1
- package/build/utils/scenarioDrafting.test.d.ts +1 -0
- package/build/utils/skyrampMdContent.d.ts +5 -0
- package/build/utils/sourceRouteExtractor.d.ts +48 -0
- package/build/utils/sourceRouteExtractor.test.d.ts +1 -0
- package/build/utils/telemetry.d.ts +32 -0
- package/build/utils/telemetry.test.d.ts +1 -0
- package/build/utils/trace-parser.d.ts +32 -0
- package/build/utils/trace-parser.test.d.ts +6 -0
- package/build/utils/uiPageEnumerator.d.ts +146 -0
- package/build/utils/uiPageEnumerator.js +58 -14
- package/build/utils/uiPageEnumerator.test.d.ts +1 -0
- package/build/utils/uiPageEnumerator.test.js +223 -43
- package/build/utils/utils.d.ts +45 -0
- package/build/utils/utils.js +10 -0
- package/build/utils/utils.test.d.ts +1 -0
- package/build/utils/versions.d.ts +3 -0
- package/build/utils/versions.js +1 -1
- package/build/utils/workspaceAuth.d.ts +127 -0
- package/build/utils/workspaceAuth.test.d.ts +1 -0
- package/build/utils/workspaceAuth.test.js +25 -25
- package/build/workspace/index.d.ts +1 -0
- package/build/workspace/workspace.d.ts +390 -0
- package/build/workspace/workspace.test.d.ts +1 -0
- package/node_modules/playwright/LICENSE +202 -0
- package/node_modules/playwright/NOTICE +5 -0
- package/node_modules/playwright/README.md +168 -0
- package/node_modules/playwright/lib/mcp/skyramp/traceRecordingBackend.js +13 -9
- package/node_modules/playwright/lib/mcp/test/skyRampExport.js +4 -3
- package/node_modules/playwright/node_modules/playwright-core/LICENSE +202 -0
- package/node_modules/playwright/node_modules/playwright-core/NOTICE +5 -0
- package/node_modules/playwright/node_modules/playwright-core/ThirdPartyNotices.txt +23 -126
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/{codeMirrorModule-B0JOjboO.js → codeMirrorModule-B5kqh2EV.js} +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/{defaultSettingsView-1anWeyDf.js → defaultSettingsView-CZ9npQ3N.js} +79 -79
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/{index.Cc5029a3.js → index.BCnxj-_b.js} +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.html +2 -2
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/{uiMode.Wo5yvvVh.js → uiMode.1Ym0Ivn8.js} +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.html +2 -2
- package/node_modules/playwright/node_modules/playwright-core/package.json +1 -1
- package/node_modules/playwright/package.json +1 -1
- package/package.json +16 -4
- package/build/tools/test-management/uiAnalyzeChangesTool.js +0 -155
- package/build/tools/test-management/uiAnalyzeChangesTool.test.js +0 -147
- package/node_modules/playwright/node_modules/playwright-core/.DS_Store +0 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/.bin/node-which +0 -52
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/.bin/is-docker +0 -5
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/.bin/mime +0 -46
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/.bin/yaml +0 -11
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.CP3Y8Zsb.js +0 -2
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
jest
|
|
1
|
+
import { jest } from "@jest/globals";
|
|
2
|
+
jest.unstable_mockModule("../../workspace/workspace.js", () => ({
|
|
2
3
|
WorkspaceConfigManager: jest.fn(),
|
|
3
4
|
}));
|
|
4
|
-
jest.
|
|
5
|
+
jest.unstable_mockModule("../../services/AnalyticsService.js", () => ({
|
|
5
6
|
AnalyticsService: { pushMCPToolEvent: jest.fn() },
|
|
6
7
|
}));
|
|
7
|
-
jest.
|
|
8
|
+
jest.unstable_mockModule("../../playwright/traceRecordingPrompt.js", () => ({
|
|
8
9
|
getTraceRecordingPromptText: () => "",
|
|
9
10
|
}));
|
|
10
|
-
|
|
11
|
+
const { getTestbotPrompt, buildWorkspaceRecoveryPrefix } = await import("./testbot-prompts.js");
|
|
11
12
|
// Minimal args to invoke getTestbotPrompt — only services matter for these tests
|
|
12
13
|
const baseArgs = {
|
|
13
14
|
prTitle: "Test PR",
|
|
@@ -24,26 +25,6 @@ function callWithServices(services) {
|
|
|
24
25
|
undefined, // userPrompt
|
|
25
26
|
services);
|
|
26
27
|
}
|
|
27
|
-
function callWithStateOutputFile(stateOutputFile) {
|
|
28
|
-
return getTestbotPrompt(baseArgs.prTitle, baseArgs.prDescription, baseArgs.summaryOutputFile, baseArgs.repositoryPath, undefined, // baseBranch
|
|
29
|
-
undefined, // maxRecommendations
|
|
30
|
-
undefined, // maxGenerate
|
|
31
|
-
undefined, // maxCritical
|
|
32
|
-
undefined, // prNumber
|
|
33
|
-
undefined, // userPrompt
|
|
34
|
-
undefined, // services
|
|
35
|
-
stateOutputFile);
|
|
36
|
-
}
|
|
37
|
-
function callFollowUpWithStateOutputFile(stateOutputFile) {
|
|
38
|
-
return getTestbotPrompt(baseArgs.prTitle, baseArgs.prDescription, baseArgs.summaryOutputFile, baseArgs.repositoryPath, undefined, // baseBranch
|
|
39
|
-
undefined, // maxRecommendations
|
|
40
|
-
undefined, // maxGenerate
|
|
41
|
-
undefined, // maxCritical
|
|
42
|
-
undefined, // prNumber
|
|
43
|
-
"add more tests", // userPrompt — triggers follow-up path
|
|
44
|
-
undefined, // services
|
|
45
|
-
stateOutputFile);
|
|
46
|
-
}
|
|
47
28
|
describe("buildServiceContext (via getTestbotPrompt)", () => {
|
|
48
29
|
it("renders full service with all fields", () => {
|
|
49
30
|
const prompt = callWithServices([
|
|
@@ -121,27 +102,6 @@ describe("buildServiceContext (via getTestbotPrompt)", () => {
|
|
|
121
102
|
expect(prompt).toContain("</REPOSITORY PATH>\nUse the Skyramp MCP server tools");
|
|
122
103
|
});
|
|
123
104
|
});
|
|
124
|
-
describe("stateOutputFile in getTestbotPrompt", () => {
|
|
125
|
-
it("includes stateOutputFile in skyramp_analyze_changes call for first-run prompt", () => {
|
|
126
|
-
const stateFile = "/tmp/skyramp/analyze-changes-state.json";
|
|
127
|
-
const prompt = callWithStateOutputFile(stateFile);
|
|
128
|
-
// The prompt must pass stateOutputFile to skyramp_analyze_changes
|
|
129
|
-
expect(prompt).toContain(`\`stateOutputFile\`: "${stateFile}"`);
|
|
130
|
-
});
|
|
131
|
-
it("includes stateOutputFile in skyramp_analyze_changes call for follow-up prompt", () => {
|
|
132
|
-
const stateFile = "/tmp/skyramp/analyze-changes-state.json";
|
|
133
|
-
const prompt = callFollowUpWithStateOutputFile(stateFile);
|
|
134
|
-
expect(prompt).toContain(`\`stateOutputFile\`: "${stateFile}"`);
|
|
135
|
-
});
|
|
136
|
-
it("omits stateOutputFile from skyramp_analyze_changes call when not provided", () => {
|
|
137
|
-
const prompt = callWithStateOutputFile(undefined);
|
|
138
|
-
expect(prompt).not.toContain("stateOutputFile");
|
|
139
|
-
});
|
|
140
|
-
it("omits stateOutputFile from follow-up prompt when not provided", () => {
|
|
141
|
-
const prompt = callFollowUpWithStateOutputFile(undefined);
|
|
142
|
-
expect(prompt).not.toContain("stateOutputFile");
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
105
|
describe("uiCredentials in getTestbotPrompt", () => {
|
|
146
106
|
function callWithUiCredentials(uiCredentials) {
|
|
147
107
|
return getTestbotPrompt(baseArgs.prTitle, baseArgs.prDescription, baseArgs.summaryOutputFile, baseArgs.repositoryPath, undefined, // baseBranch
|
|
@@ -151,7 +111,6 @@ describe("uiCredentials in getTestbotPrompt", () => {
|
|
|
151
111
|
undefined, // prNumber
|
|
152
112
|
undefined, // userPrompt
|
|
153
113
|
undefined, // services
|
|
154
|
-
undefined, // stateOutputFile
|
|
155
114
|
uiCredentials);
|
|
156
115
|
}
|
|
157
116
|
// The instructions text references `<ui-credentials>` in prose (backticked);
|
|
@@ -216,13 +175,11 @@ describe("drift analysis — runtime tool call (step 3)", () => {
|
|
|
216
175
|
const prompt = basePrompt();
|
|
217
176
|
expect(prompt).toContain("skyramp_actions");
|
|
218
177
|
});
|
|
219
|
-
it("
|
|
178
|
+
it("skyramp_analyze_test_health is referenced in the prompt", () => {
|
|
179
|
+
// After the unified maintenance refactor, analyze_test_health is referenced
|
|
180
|
+
// in the testMaintenance submission guidance rather than as an explicit step.
|
|
220
181
|
const prompt = basePrompt();
|
|
221
|
-
|
|
222
|
-
const healthPos = prompt.indexOf("skyramp_analyze_test_health");
|
|
223
|
-
const task2Pos = prompt.indexOf("## Task 2");
|
|
224
|
-
expect(healthPos).toBeGreaterThan(task1Pos);
|
|
225
|
-
expect(healthPos).toBeLessThan(task2Pos);
|
|
182
|
+
expect(prompt).toContain("skyramp_analyze_test_health");
|
|
226
183
|
});
|
|
227
184
|
it("does not contain the build-time embedded drift_analysis_rules content (Action Decision Tree)", () => {
|
|
228
185
|
// The rules are now fetched at runtime via skyramp_analyze_test_health —
|
|
@@ -237,57 +194,7 @@ describe("drift analysis — runtime tool call (step 3)", () => {
|
|
|
237
194
|
expect(prompt).not.toContain("You are acting as a Skyramp Integration Architect");
|
|
238
195
|
});
|
|
239
196
|
});
|
|
240
|
-
describe("UI grounding via Task 2 capture-act-capture", () => {
|
|
241
|
-
it("surfaces uiContext as guidance, not a contract", () => {
|
|
242
|
-
const prompt = getTestbotPrompt(baseArgs.prTitle, baseArgs.prDescription, baseArgs.summaryOutputFile, baseArgs.repositoryPath);
|
|
243
|
-
// uiContext fields are explained inline so the agent knows what to do with
|
|
244
|
-
// them. Step 1 provides candidate URLs but gives fallback instructions
|
|
245
|
-
// ("navigate from the workspace baseUrl and explore") for 404s/redirects,
|
|
246
|
-
// treating candidates as guidance not a rigid contract.
|
|
247
|
-
expect(prompt).toContain("uiContext");
|
|
248
|
-
expect(prompt).toContain("candidateUiPages");
|
|
249
|
-
expect(prompt).toContain("changedFrontendFiles");
|
|
250
|
-
expect(prompt).toMatch(/navigate from the workspace baseUrl and explore/i);
|
|
251
|
-
});
|
|
252
|
-
it("step 5 enforces Blueprint Citation Invariant in natural prose", () => {
|
|
253
|
-
const prompt = getTestbotPrompt(baseArgs.prTitle, baseArgs.prDescription, baseArgs.summaryOutputFile, baseArgs.repositoryPath);
|
|
254
|
-
// Step 5 is the citation-invariant guardrail, not a "fill in tuples"
|
|
255
|
-
// post-processing step (slice 4 cleanup: recs are grounded upstream).
|
|
256
|
-
expect(prompt).toContain("Blueprint Citation Invariant");
|
|
257
|
-
// Reasoning must be natural prose, NOT internal-identifier syntax.
|
|
258
|
-
expect(prompt).toMatch(/natural prose/i);
|
|
259
|
-
expect(prompt).toMatch(/internal-identifier syntax/i);
|
|
260
|
-
});
|
|
261
|
-
it("Task 2 no longer instructs the agent to fill in tuples post-hoc", () => {
|
|
262
|
-
const prompt = getTestbotPrompt(baseArgs.prTitle, baseArgs.prDescription, baseArgs.summaryOutputFile, baseArgs.repositoryPath);
|
|
263
|
-
// After slice 4 cleanup: Task 2 captures are for trace recording's own
|
|
264
|
-
// assertions, not for retroactively rewriting recommendation reasoning.
|
|
265
|
-
// The phrase "fill in tuples" must NOT appear anywhere in the prompt.
|
|
266
|
-
expect(prompt).not.toMatch(/fill in tuples/i);
|
|
267
|
-
expect(prompt).not.toMatch(/return to step 5 and fill/i);
|
|
268
|
-
});
|
|
269
|
-
it("Task 2 step 5 mentions possibleAssertions as available, NOT as required (slice 5.5 softening)", () => {
|
|
270
|
-
const prompt = getTestbotPrompt(baseArgs.prTitle, baseArgs.prDescription, baseArgs.summaryOutputFile, baseArgs.repositoryPath);
|
|
271
|
-
// Slice 5: AFTER-action browser_blueprint response includes
|
|
272
|
-
// possibleAssertions[] — mechanically translated candidates.
|
|
273
|
-
expect(prompt).toContain("possibleAssertions");
|
|
274
|
-
// Slice 5.5: prompt explicitly tells the agent NOT to feel obligated.
|
|
275
|
-
// Two P09 runs with the prior "emit at least one" directive showed the
|
|
276
|
-
// agent over-using shallow visibility assertions at the expense of
|
|
277
|
-
// integration-test depth. The softened version says: read them, use
|
|
278
|
-
// when they happen to match what you'd write anyway, ignore otherwise.
|
|
279
|
-
expect(prompt).toMatch(/do not feel obligated/i);
|
|
280
|
-
expect(prompt).toMatch(/biased toward visibility/i);
|
|
281
|
-
// The candidate format is still documented.
|
|
282
|
-
expect(prompt).toMatch(/\bcode\b.*\brationale\b.*\btier\b/i);
|
|
283
|
-
// The pre-existing "at least one browser_assert per page navigated"
|
|
284
|
-
// rule should be preserved (it's about meaningful business-outcome
|
|
285
|
-
// assertions, not about possibleAssertions).
|
|
286
|
-
expect(prompt).toMatch(/at least one .browser_assert. per page navigated/i);
|
|
287
|
-
});
|
|
288
|
-
});
|
|
289
197
|
describe("buildWorkspaceRecoveryPrefix", () => {
|
|
290
|
-
const { buildWorkspaceRecoveryPrefix } = require("./testbot-prompts.js");
|
|
291
198
|
it("includes repositoryPath in both init_scan and init_workspace instructions", () => {
|
|
292
199
|
const prefix = buildWorkspaceRecoveryPrefix("/home/user/repo");
|
|
293
200
|
expect(prefix).toContain('skyramp_init_scan with workspacePath "/home/user/repo"');
|
|
@@ -312,7 +219,6 @@ describe("testsRepoDir in getTestbotPrompt", () => {
|
|
|
312
219
|
undefined, // prNumber
|
|
313
220
|
undefined, // userPrompt
|
|
314
221
|
undefined, // services
|
|
315
|
-
undefined, // stateOutputFile
|
|
316
222
|
undefined, // uiCredentials
|
|
317
223
|
testsRepoDir);
|
|
318
224
|
}
|
|
@@ -324,7 +230,6 @@ describe("testsRepoDir in getTestbotPrompt", () => {
|
|
|
324
230
|
undefined, // prNumber
|
|
325
231
|
"add more tests", // userPrompt — triggers follow-up path
|
|
326
232
|
undefined, // services
|
|
327
|
-
undefined, // stateOutputFile
|
|
328
233
|
undefined, // uiCredentials
|
|
329
234
|
testsRepoDir);
|
|
330
235
|
}
|
|
@@ -348,20 +253,13 @@ describe("testsRepoDir in getTestbotPrompt", () => {
|
|
|
348
253
|
});
|
|
349
254
|
});
|
|
350
255
|
describe("testbot prompt blueprint-grounded recommendations (slice 4)", () => {
|
|
351
|
-
it("
|
|
352
|
-
const prompt = getTestbotPrompt(baseArgs.prTitle, baseArgs.prDescription, baseArgs.summaryOutputFile, baseArgs.repositoryPath);
|
|
353
|
-
const uiacIdx = prompt.indexOf("skyramp_ui_analyze_changes");
|
|
354
|
-
const acIdx = prompt.indexOf("skyramp_analyze_changes");
|
|
355
|
-
expect(uiacIdx).toBeGreaterThan(-1);
|
|
356
|
-
expect(acIdx).toBeGreaterThan(uiacIdx);
|
|
357
|
-
});
|
|
358
|
-
it("Task 1 step 1 instructs the agent to capture blueprints (without threading them through a param)", () => {
|
|
256
|
+
it("uses a single skyramp_analyze_changes call (no separate pre-flight tool, no blueprint threading)", () => {
|
|
359
257
|
const prompt = getTestbotPrompt(baseArgs.prTitle, baseArgs.prDescription, baseArgs.summaryOutputFile, baseArgs.repositoryPath);
|
|
360
|
-
//
|
|
361
|
-
|
|
362
|
-
expect(prompt).
|
|
363
|
-
|
|
364
|
-
//
|
|
258
|
+
// The standalone pre-flight tool is gone — its work folded into analyze_changes.
|
|
259
|
+
expect(prompt).not.toContain("skyramp_ui_analyze_changes");
|
|
260
|
+
expect(prompt).toContain("skyramp_analyze_changes");
|
|
261
|
+
// Captures stay in tool-result history — the old capturedBlueprints
|
|
262
|
+
// threading directive must be gone.
|
|
365
263
|
expect(prompt).not.toMatch(/capturedBlueprints/);
|
|
366
264
|
});
|
|
367
265
|
// Flutter support — both the generalised UI trigger wording and the
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
export declare const ANALYSIS_URI_PREFIX = "skyramp://analysis";
|
|
3
|
+
/**
|
|
4
|
+
* Register MCP Resources for analysis data access.
|
|
5
|
+
*
|
|
6
|
+
* Resources provide read-only, token-efficient access to analysis data
|
|
7
|
+
* via sessionId. The state file is an internal backing store.
|
|
8
|
+
*
|
|
9
|
+
* URI scheme:
|
|
10
|
+
* skyramp://analysis/{sessionId}/summary
|
|
11
|
+
* skyramp://analysis/{sessionId}/endpoints
|
|
12
|
+
* skyramp://analysis/{sessionId}/endpoints/{+path}
|
|
13
|
+
* skyramp://analysis/{sessionId}/endpoints/{+path}/{method}
|
|
14
|
+
* skyramp://analysis/{sessionId}/scenarios
|
|
15
|
+
* skyramp://analysis/{sessionId}/diff
|
|
16
|
+
*/
|
|
17
|
+
export declare function registerAnalysisResources(server: McpServer): void;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ResourceTemplate, } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { logger } from "../utils/logger.js";
|
|
3
|
+
import { resourceText } from "../utils/utils.js";
|
|
4
|
+
import { AnalyticsService } from "../services/AnalyticsService.js";
|
|
5
|
+
import { getAdaptWorkflowPrompt } from "../prompts/sut-setup/modes/adaptWorkflowPrompt.js";
|
|
6
|
+
import { getDockerComposePrompt } from "../prompts/sut-setup/modes/dockerComposePrompt.js";
|
|
7
|
+
import { SutSetupMode } from "../prompts/sut-setup/shared.js";
|
|
8
|
+
export function registerSutSetupResource(server) {
|
|
9
|
+
logger.info("Registering SUT setup resource");
|
|
10
|
+
// RFC 6570 {+rest} (reserved expansion) captures the entire query string
|
|
11
|
+
// including the leading "?". This avoids the SDK's per-param regex which
|
|
12
|
+
// fails on empty query-param values.
|
|
13
|
+
const template = new ResourceTemplate("skyramp://prompts/skyramp_testbot_sut{+rest}", { list: undefined });
|
|
14
|
+
server.registerResource("skyramp_testbot_sut", template, {
|
|
15
|
+
title: "Skyramp Testbot SUT Setup",
|
|
16
|
+
description: "Returns mode-specific instructions for SUT (System Under Test) setup. " +
|
|
17
|
+
"Modes: none, adapt_workflow, docker_compose.",
|
|
18
|
+
mimeType: "text/plain",
|
|
19
|
+
}, async (uri) => {
|
|
20
|
+
const param = (name, fallback) => uri.searchParams.get(name) ?? fallback;
|
|
21
|
+
const mode = param("sutSetupMode", SutSetupMode.None);
|
|
22
|
+
const args = {
|
|
23
|
+
repositoryPath: param("repositoryPath", "."),
|
|
24
|
+
sutSetupMode: mode,
|
|
25
|
+
sutSourceWorkflowFile: param("sutSourceWorkflowFile", ""),
|
|
26
|
+
sutSourceDockerComposeFile: param("sutSourceDockerComposeFile", ""),
|
|
27
|
+
};
|
|
28
|
+
let prompt;
|
|
29
|
+
switch (mode) {
|
|
30
|
+
case SutSetupMode.AdaptWorkflow:
|
|
31
|
+
prompt = getAdaptWorkflowPrompt(args);
|
|
32
|
+
break;
|
|
33
|
+
case SutSetupMode.DockerCompose:
|
|
34
|
+
prompt = getDockerComposePrompt(args);
|
|
35
|
+
break;
|
|
36
|
+
case SutSetupMode.None:
|
|
37
|
+
prompt = "sutSetupMode is 'none'. No SUT setup required.";
|
|
38
|
+
break;
|
|
39
|
+
default:
|
|
40
|
+
prompt = `Unknown SUT setup mode: '${mode}'. Valid modes: none, adapt_workflow, docker_compose.`;
|
|
41
|
+
}
|
|
42
|
+
AnalyticsService.pushMCPToolEvent("skyramp_testbot_sut_resource", undefined, { mode }).catch(() => { });
|
|
43
|
+
return resourceText(uri.toString(), prompt);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
@@ -25,7 +25,7 @@ export function registerTestbotResource(server) {
|
|
|
25
25
|
const maxCrit = parseInt(uri.searchParams.get("maxCritical") || "", 10);
|
|
26
26
|
const repositoryPath = param("repositoryPath", ".");
|
|
27
27
|
const services = await readWorkspaceServices(repositoryPath);
|
|
28
|
-
const prompt = getTestbotPrompt(param("prTitle", ""), param("prDescription", ""), param("summaryOutputFile", ""), repositoryPath, uri.searchParams.get("baseBranch") || undefined, isNaN(maxRec) ? MAX_RECOMMENDATIONS : maxRec, isNaN(maxGen) ? MAX_TESTS_TO_GENERATE : maxGen, isNaN(maxCrit) ? MAX_CRITICAL_TESTS : maxCrit, isNaN(prNum) ? undefined : prNum, uri.searchParams.get("userPrompt") || undefined, services.length ? services : undefined, uri.searchParams.get("
|
|
28
|
+
const prompt = getTestbotPrompt(param("prTitle", ""), param("prDescription", ""), param("summaryOutputFile", ""), repositoryPath, uri.searchParams.get("baseBranch") || undefined, isNaN(maxRec) ? MAX_RECOMMENDATIONS : maxRec, isNaN(maxGen) ? MAX_TESTS_TO_GENERATE : maxGen, isNaN(maxCrit) ? MAX_CRITICAL_TESTS : maxCrit, isNaN(prNum) ? undefined : prNum, uri.searchParams.get("userPrompt") || undefined, services.length ? services : undefined, uri.searchParams.get("uiCredentials") || undefined, uri.searchParams.get("testsRepoDir") || undefined);
|
|
29
29
|
AnalyticsService.pushMCPToolEvent("skyramp_testbot_prompt", undefined, {}).catch(() => { });
|
|
30
30
|
// Return the original URI — clients may use it to re-fetch the resource,
|
|
31
31
|
// and the caller already has these params. Credentials never appear in
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
export declare class AnalyticsService {
|
|
3
|
+
static pushTestGenerationToolEvent(toolName: string, result: CallToolResult, params: Record<string, any>): Promise<void>;
|
|
4
|
+
static pushMCPToolEvent(toolName: string, result: CallToolResult | undefined, params: Record<string, string>): Promise<void>;
|
|
5
|
+
/**
|
|
6
|
+
* Track server crash events
|
|
7
|
+
*/
|
|
8
|
+
static pushServerCrashEvent(crashType: string, errorMessage: string, errorStack?: string): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* Track tool timeout events
|
|
11
|
+
*/
|
|
12
|
+
static pushToolTimeoutEvent(toolName: string, timeoutMs: number, params: Record<string, string>): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// @ts-nocheck - Jest ESM type inference issues
|
|
2
|
+
import { jest } from "@jest/globals";
|
|
3
|
+
import * as fs from "fs";
|
|
4
|
+
import * as path from "path";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
// AnalyticsService resolves the MCP version with
|
|
7
|
+
// `fileURLToPath(import.meta.url)` at module scope. Under ts-jest's old
|
|
8
|
+
// CommonJS transform that top-level import.meta failed to compile with TS1343,
|
|
9
|
+
// so this module — and therefore this test — could not exist. The native-ESM
|
|
10
|
+
// Jest config (SKYR-3799) is what makes it loadable.
|
|
11
|
+
// pushToolEvent lives in @skyramp/skyramp, which pulls the native dylib. Mock
|
|
12
|
+
// it so we can assert on the event payload without loading the binary. Under
|
|
13
|
+
// native ESM jest.mock is not hoisted — use unstable_mockModule + dynamic
|
|
14
|
+
// import of the subject below.
|
|
15
|
+
const pushToolEvent = jest.fn();
|
|
16
|
+
jest.unstable_mockModule("@skyramp/skyramp", () => ({ pushToolEvent }));
|
|
17
|
+
jest.unstable_mockModule("../utils/telemetry.js", () => ({
|
|
18
|
+
getEntryPoint: jest.fn(() => "mcp"),
|
|
19
|
+
getCIPlatform: jest.fn(() => undefined),
|
|
20
|
+
getRepositoryInfo: jest.fn(async () => ({})),
|
|
21
|
+
}));
|
|
22
|
+
jest.unstable_mockModule("../utils/logger.js", () => ({
|
|
23
|
+
logger: { info: jest.fn(), error: jest.fn(), debug: jest.fn(), warn: jest.fn() },
|
|
24
|
+
}));
|
|
25
|
+
const { AnalyticsService } = await import("./AnalyticsService.js");
|
|
26
|
+
const telemetry = await import("../utils/telemetry.js");
|
|
27
|
+
// The version the production code should resolve: package.json two levels up
|
|
28
|
+
// from this module's own location — the same lookup getMCPPackageVersion does
|
|
29
|
+
// via import.meta.url. Computing it the same way here proves the test harness
|
|
30
|
+
// itself supports import.meta now.
|
|
31
|
+
const expectedVersion = JSON.parse(fs.readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), "../../package.json"), "utf8")).version;
|
|
32
|
+
describe("AnalyticsService — import.meta-based version resolution", () => {
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
jest.clearAllMocks();
|
|
35
|
+
telemetry.getEntryPoint.mockReturnValue("mcp");
|
|
36
|
+
telemetry.getCIPlatform.mockReturnValue(undefined);
|
|
37
|
+
telemetry.getRepositoryInfo.mockResolvedValue({});
|
|
38
|
+
});
|
|
39
|
+
it("stamps the package.json version (resolved via import.meta.url) into the event params", async () => {
|
|
40
|
+
const params = {};
|
|
41
|
+
await AnalyticsService.pushMCPToolEvent("skyramp_smoke_test_generation", undefined, params);
|
|
42
|
+
expect(pushToolEvent).toHaveBeenCalledTimes(1);
|
|
43
|
+
const [, toolName, , sentParams] = pushToolEvent.mock.calls[0];
|
|
44
|
+
expect(toolName).toBe("skyramp_smoke_test_generation");
|
|
45
|
+
expect(sentParams.mcpServerVersion).toBe(expectedVersion);
|
|
46
|
+
// Sanity: a real semver-ish string, not an empty/undefined fallback.
|
|
47
|
+
expect(sentParams.mcpServerVersion).toMatch(/^\d+\.\d+\.\d+/);
|
|
48
|
+
});
|
|
49
|
+
it("concatenates error text from an isError result into the event error message", async () => {
|
|
50
|
+
const result = {
|
|
51
|
+
isError: true,
|
|
52
|
+
content: [
|
|
53
|
+
{ type: "text", text: "first failure" },
|
|
54
|
+
{ type: "text", text: "second failure" },
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
await AnalyticsService.pushMCPToolEvent("skyramp_execute_test", result, {});
|
|
58
|
+
const [, , errorMessage] = pushToolEvent.mock.calls[0];
|
|
59
|
+
expect(errorMessage).toBe("first failure, second failure");
|
|
60
|
+
});
|
|
61
|
+
it("sends an empty error message for a successful result", async () => {
|
|
62
|
+
const result = { isError: false, content: [{ type: "text", text: "ok" }] };
|
|
63
|
+
await AnalyticsService.pushMCPToolEvent("skyramp_execute_test", result, {});
|
|
64
|
+
const [, , errorMessage] = pushToolEvent.mock.calls[0];
|
|
65
|
+
expect(errorMessage).toBe("");
|
|
66
|
+
});
|
|
67
|
+
it("includes ciPlatform in the params when running in CI", async () => {
|
|
68
|
+
telemetry.getCIPlatform.mockReturnValue("github_actions");
|
|
69
|
+
const params = {};
|
|
70
|
+
await AnalyticsService.pushMCPToolEvent("skyramp_init_workspace", undefined, params);
|
|
71
|
+
const [, , , sentParams] = pushToolEvent.mock.calls[0];
|
|
72
|
+
expect(sentParams.ciPlatform).toBe("github_actions");
|
|
73
|
+
});
|
|
74
|
+
it("merges repository info into the params", async () => {
|
|
75
|
+
telemetry.getRepositoryInfo.mockResolvedValue({ repoName: "letsramp/mcp", repoOwner: "letsramp" });
|
|
76
|
+
const params = { repositoryPath: "/repo" };
|
|
77
|
+
await AnalyticsService.pushMCPToolEvent("skyramp_analyze_changes", undefined, params);
|
|
78
|
+
expect(telemetry.getRepositoryInfo).toHaveBeenCalledWith("/repo");
|
|
79
|
+
const [, , , sentParams] = pushToolEvent.mock.calls[0];
|
|
80
|
+
expect(sentParams.repoName).toBe("letsramp/mcp");
|
|
81
|
+
});
|
|
82
|
+
it("swallows errors from pushToolEvent (telemetry must never break a tool call)", async () => {
|
|
83
|
+
pushToolEvent.mockRejectedValueOnce(new Error("network down"));
|
|
84
|
+
await expect(AnalyticsService.pushMCPToolEvent("skyramp_smoke_test_generation", undefined, {})).resolves.toBeUndefined();
|
|
85
|
+
});
|
|
86
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
export interface ModularizationParams {
|
|
3
|
+
testFile: string;
|
|
4
|
+
testType?: string;
|
|
5
|
+
language?: string;
|
|
6
|
+
isTraceBased?: boolean;
|
|
7
|
+
prompt?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class ModularizationService {
|
|
10
|
+
processModularizationRequest(params: ModularizationParams): Promise<CallToolResult>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
export interface TraceRequest {
|
|
3
|
+
Source: string;
|
|
4
|
+
Destination: string;
|
|
5
|
+
RequestBody: string;
|
|
6
|
+
ResponseBody: string;
|
|
7
|
+
RequestHeaders: Record<string, string[]>;
|
|
8
|
+
ResponseHeaders: Record<string, string[]>;
|
|
9
|
+
Method: string;
|
|
10
|
+
Path: string;
|
|
11
|
+
QueryParams: Record<string, string[]>;
|
|
12
|
+
StatusCode: number;
|
|
13
|
+
Port: number;
|
|
14
|
+
Timestamp: string;
|
|
15
|
+
Scheme: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ScenarioParams {
|
|
18
|
+
scenarioName: string;
|
|
19
|
+
destination: string;
|
|
20
|
+
apiSchema?: string;
|
|
21
|
+
baseURL?: string;
|
|
22
|
+
method: string;
|
|
23
|
+
path: string;
|
|
24
|
+
requestBody?: string;
|
|
25
|
+
queryParams?: string;
|
|
26
|
+
responseBody?: string;
|
|
27
|
+
statusCode?: number;
|
|
28
|
+
outputDir: string;
|
|
29
|
+
authHeader?: string;
|
|
30
|
+
authScheme?: string;
|
|
31
|
+
authToken?: string;
|
|
32
|
+
responseHeaders?: Record<string, string[]>;
|
|
33
|
+
}
|
|
34
|
+
export declare class ScenarioGenerationService {
|
|
35
|
+
parseScenario(params: ScenarioParams): Promise<CallToolResult>;
|
|
36
|
+
generateTraceRequestFromInput(params: ScenarioParams): TraceRequest | null;
|
|
37
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -4,10 +4,14 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Requires: @skyramp/skyramp native dylib (skips if not available)
|
|
6
6
|
*/
|
|
7
|
+
import { jest } from "@jest/globals";
|
|
7
8
|
import fs from "fs";
|
|
8
9
|
import path from "path";
|
|
9
10
|
import os from "os";
|
|
11
|
+
import { createRequire } from "module";
|
|
10
12
|
import { ScenarioGenerationService } from "./ScenarioGenerationService.js";
|
|
13
|
+
// Native dylib is a CommonJS addon — load it via createRequire under ESM.
|
|
14
|
+
const require = createRequire(import.meta.url);
|
|
11
15
|
let SkyrampClient;
|
|
12
16
|
try {
|
|
13
17
|
SkyrampClient = require("@skyramp/skyramp").SkyrampClient;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { TestAnalysisResult } from "../types/TestAnalysis.js";
|
|
2
|
+
interface TestDiscoveryResult {
|
|
3
|
+
tests: TestAnalysisResult[];
|
|
4
|
+
/** Paths of external files that were deemed relevant to the PR (score > 0). */
|
|
5
|
+
relevantExternalTestPaths: string[];
|
|
6
|
+
}
|
|
7
|
+
export interface TestDiscoveryOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Resource names derived from endpoints in changed files (e.g. ["orders", "products"]).
|
|
10
|
+
* - Non-empty array: external files partitioned by relevance; only relevant files
|
|
11
|
+
* get full endpoint extraction. May be the sentinel `["unknown"]` when endpoints
|
|
12
|
+
* exist but resource names are unresolvable — treated as "endpoints present" to
|
|
13
|
+
* avoid skipping external coverage. Also used for "add field" PRs where the changed
|
|
14
|
+
* files have no endpoint definitions but the scanner found related endpoints nearby.
|
|
15
|
+
* - Empty array `[]`: PR mode with no endpoints from diff or scanner — external
|
|
16
|
+
* tests are skipped entirely to avoid flooding context.
|
|
17
|
+
* - `undefined`: full-repo mode — external tests capped at MAX_EXTERNAL_FULL_REPO.
|
|
18
|
+
*/
|
|
19
|
+
changedResources?: string[];
|
|
20
|
+
}
|
|
21
|
+
export declare class TestDiscoveryService {
|
|
22
|
+
private readonly EXCLUDED_DIRS;
|
|
23
|
+
private readonly SKYRAMP_MARKER;
|
|
24
|
+
private readonly SUPPORTED_EXTENSIONS;
|
|
25
|
+
private readonly MAX_CONCURRENT_OPERATIONS;
|
|
26
|
+
private readonly MAX_EXTERNAL_FULL_REPO;
|
|
27
|
+
private readonly TEST_FILE_PATTERNS;
|
|
28
|
+
private readonly TEST_DIR_PATTERNS;
|
|
29
|
+
/**
|
|
30
|
+
* Discover all tests under testDir — both Skyramp-generated and external (user-written).
|
|
31
|
+
* Uses fast-glob for cross-platform file scanning, then classifies discovered files
|
|
32
|
+
* as Skyramp-generated tests, external tests, or not-a-test during processing.
|
|
33
|
+
*
|
|
34
|
+
* External test handling depends on `options.changedResources`:
|
|
35
|
+
* - `string[]` with entries (PR mode, endpoints detected): partition by relevance.
|
|
36
|
+
* - `[]` empty array (PR mode, scanner found no endpoints): skip external tests entirely
|
|
37
|
+
* rather than flooding context with irrelevant files.
|
|
38
|
+
* - `undefined` (full-repo mode, no diff): cap at MAX_EXTERNAL_FULL_REPO.
|
|
39
|
+
*/
|
|
40
|
+
discoverTests(testDir: string, options?: TestDiscoveryOptions): Promise<TestDiscoveryResult>;
|
|
41
|
+
/**
|
|
42
|
+
* Score an external test file's relevance to a set of changed resource names.
|
|
43
|
+
* Tokenises the last two segments of the file path (split by /, \, -, _, .)
|
|
44
|
+
* and counts overlapping tokens with the changed resources.
|
|
45
|
+
* Example: "test_orders_api.py" vs ["orders"] → score 1.
|
|
46
|
+
*/
|
|
47
|
+
private scoreRelevance;
|
|
48
|
+
/**
|
|
49
|
+
* Partition external test files into relevant (score > 0) and low-relevance (score = 0).
|
|
50
|
+
* Signal: path/name token overlap with changedResources.
|
|
51
|
+
*/
|
|
52
|
+
private partitionByRelevance;
|
|
53
|
+
/**
|
|
54
|
+
* Process test files in parallel batches with concurrency control
|
|
55
|
+
* @param isExternal When true, uses external test metadata extraction
|
|
56
|
+
* @param contentCache Optional pre-read file contents from classification pass
|
|
57
|
+
*/
|
|
58
|
+
private processFilesInBatches;
|
|
59
|
+
/**
|
|
60
|
+
* Classify candidate files as skyramp (has marker), external (test file without
|
|
61
|
+
* marker), or not-a-test. Caches file contents so downstream metadata extraction
|
|
62
|
+
* doesn't need to re-read from disk.
|
|
63
|
+
*/
|
|
64
|
+
private classifyTestFiles;
|
|
65
|
+
/**
|
|
66
|
+
* Check if a file is an external (non-Skyramp) test file based on naming convention
|
|
67
|
+
* or directory placement.
|
|
68
|
+
*/
|
|
69
|
+
private isExternalTestFile;
|
|
70
|
+
/**
|
|
71
|
+
* Extract metadata from a test file
|
|
72
|
+
* File is already confirmed to contain Skyramp marker by file search
|
|
73
|
+
* @param cachedContent Optional pre-read content from classification pass
|
|
74
|
+
*/
|
|
75
|
+
private extractTestMetadata;
|
|
76
|
+
/**
|
|
77
|
+
* Extract the HTTP methods and paths covered by this test file.
|
|
78
|
+
* Returns a comma-separated string like "GET /orders/{id}, DELETE /orders/{id}".
|
|
79
|
+
* Handles Python (send_request / check_schema) and TypeScript/JS (sendRequest).
|
|
80
|
+
*/
|
|
81
|
+
private extractCoveredEndpoints;
|
|
82
|
+
/**
|
|
83
|
+
* Extract metadata from an external (non-Skyramp) test file.
|
|
84
|
+
* Uses heuristic patterns for endpoint extraction, test type, and framework detection.
|
|
85
|
+
* @param cachedContent Optional pre-read content from classification pass
|
|
86
|
+
*/
|
|
87
|
+
private extractExternalTestMetadata;
|
|
88
|
+
/**
|
|
89
|
+
* Extract HTTP endpoints from external (non-Skyramp) test files.
|
|
90
|
+
* Matches common patterns: requests.get, axios.post, fetch, supertest, RestAssured.
|
|
91
|
+
*/
|
|
92
|
+
private extractExternalEndpoints;
|
|
93
|
+
/**
|
|
94
|
+
* Normalize an endpoint path extracted from test code.
|
|
95
|
+
* Strips base URL prefixes and returns only the path portion.
|
|
96
|
+
* Returns null if the path doesn't look like an API endpoint.
|
|
97
|
+
*/
|
|
98
|
+
private normalizeEndpointPath;
|
|
99
|
+
/**
|
|
100
|
+
* Detect test type from external test file path and content.
|
|
101
|
+
* Falls back to directory/filename heuristics since external tests lack Skyramp command lines.
|
|
102
|
+
*/
|
|
103
|
+
private detectExternalTestType;
|
|
104
|
+
/**
|
|
105
|
+
* Detect test framework from external test file content by checking imports.
|
|
106
|
+
*/
|
|
107
|
+
private detectExternalFramework;
|
|
108
|
+
/**
|
|
109
|
+
* Detect programming language from file extension
|
|
110
|
+
*/
|
|
111
|
+
private detectLanguage;
|
|
112
|
+
/**
|
|
113
|
+
* Detect test type from file content and name
|
|
114
|
+
* Checks Skyramp command line, filename, and content patterns
|
|
115
|
+
*/
|
|
116
|
+
private detectTestType;
|
|
117
|
+
/**
|
|
118
|
+
* Extract API schema path from test content
|
|
119
|
+
* Looks for Skyramp command line first, then fallback to other patterns
|
|
120
|
+
*/
|
|
121
|
+
private extractApiSchema;
|
|
122
|
+
/**
|
|
123
|
+
* Extract Framework from test content
|
|
124
|
+
* Looks for Skyramp command line first, then fallback to other patterns
|
|
125
|
+
*/
|
|
126
|
+
private extractFramework;
|
|
127
|
+
}
|
|
128
|
+
export {};
|