@skyramp/mcp 0.2.6 → 0.2.7

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 (184) hide show
  1. package/build/commands/commandLibrary.d.ts +12 -0
  2. package/build/commands/recommendTestsAndExecuteCommand.d.ts +2 -0
  3. package/build/commands/testThisEndpointCommand.d.ts +2 -0
  4. package/build/index.d.ts +2 -0
  5. package/build/index.js +1 -2
  6. package/build/playwright/PlaywrightTraceService.d.ts +32 -0
  7. package/build/playwright/index.d.ts +3 -0
  8. package/build/playwright/registerPlaywrightTools.d.ts +8 -0
  9. package/build/playwright/registerPlaywrightTools.js +12 -11
  10. package/build/playwright/traceRecordingPrompt.d.ts +13 -0
  11. package/build/playwright/traceRecordingPrompt.js +3 -11
  12. package/build/prompts/code-reuse.d.ts +1 -0
  13. package/build/prompts/enhance-assertions/contractProviderAssertionsPrompt.d.ts +2 -0
  14. package/build/prompts/enhance-assertions/integrationAssertionsPrompt.d.ts +2 -0
  15. package/build/prompts/enhance-assertions/sharedAssertionRules.d.ts +15 -0
  16. package/build/prompts/enhance-assertions/uiAssertionsPrompt.d.ts +2 -0
  17. package/build/prompts/fix-error-prompt.d.ts +1 -0
  18. package/build/prompts/initialize-workspace/initializeWorkspacePrompt.d.ts +1 -0
  19. package/build/prompts/modularization/integration-test-modularization.d.ts +1 -0
  20. package/build/prompts/modularization/ui-test-modularization.d.ts +1 -0
  21. package/build/prompts/personas.d.ts +21 -0
  22. package/build/prompts/pom-aware-code-reuse.d.ts +1 -0
  23. package/build/prompts/startTraceCollectionPrompts.d.ts +2 -0
  24. package/build/prompts/test-maintenance/actionsInstructions.d.ts +35 -0
  25. package/build/prompts/test-maintenance/drift-analysis-prompt.d.ts +4 -0
  26. package/build/prompts/test-maintenance/driftAnalysisSections.d.ts +13 -0
  27. package/build/prompts/test-recommendation/analysisOutputPrompt.d.ts +84 -0
  28. package/build/prompts/test-recommendation/analysisOutputPrompt.test.d.ts +1 -0
  29. package/build/prompts/test-recommendation/analysisOutputPrompt.test.js +1 -0
  30. package/build/prompts/test-recommendation/diffExecutionPlan.d.ts +17 -0
  31. package/build/prompts/test-recommendation/diffExecutionPlan.js +7 -16
  32. package/build/prompts/test-recommendation/fullRepoCatalog.d.ts +7 -0
  33. package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.d.ts +1 -0
  34. package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.js +1 -0
  35. package/build/prompts/test-recommendation/promptPlan.d.ts +203 -0
  36. package/build/prompts/test-recommendation/promptPlan.test.d.ts +1 -0
  37. package/build/prompts/test-recommendation/recommendationSections.d.ts +35 -0
  38. package/build/prompts/test-recommendation/recommendationShared.d.ts +31 -0
  39. package/build/prompts/test-recommendation/registerRecommendTestsPrompt.d.ts +7 -0
  40. package/build/prompts/test-recommendation/scopeAssessment.d.ts +55 -0
  41. package/build/prompts/test-recommendation/scopeAssessment.js +2 -2
  42. package/build/prompts/test-recommendation/scopeAssessment.test.d.ts +1 -0
  43. package/build/prompts/test-recommendation/scopeAssessment.test.js +1 -0
  44. package/build/prompts/test-recommendation/test-recommendation-prompt.d.ts +6 -0
  45. package/build/prompts/test-recommendation/test-recommendation-prompt.js +4 -4
  46. package/build/prompts/test-recommendation/test-recommendation-prompt.test.d.ts +1 -0
  47. package/build/prompts/test-recommendation/test-recommendation-prompt.test.js +6 -99
  48. package/build/prompts/testbot/testbot-prompts.d.ts +11 -0
  49. package/build/prompts/testbot/testbot-prompts.js +198 -34
  50. package/build/prompts/testbot/testbot-prompts.test.d.ts +1 -0
  51. package/build/prompts/testbot/testbot-prompts.test.js +15 -73
  52. package/build/resources/analysisResources.d.ts +17 -0
  53. package/build/resources/progressResource.d.ts +2 -0
  54. package/build/resources/testbotResource.d.ts +2 -0
  55. package/build/services/AnalyticsService.d.ts +13 -0
  56. package/build/services/AnalyticsService.test.d.ts +1 -0
  57. package/build/services/AnalyticsService.test.js +86 -0
  58. package/build/services/ModularizationService.d.ts +11 -0
  59. package/build/services/ScenarioGenerationService.d.ts +37 -0
  60. package/build/services/ScenarioGenerationService.integration.test.d.ts +1 -0
  61. package/build/services/ScenarioGenerationService.integration.test.js +4 -0
  62. package/build/services/ScenarioGenerationService.test.d.ts +1 -0
  63. package/build/services/TestDiscoveryService.d.ts +128 -0
  64. package/build/services/TestDiscoveryService.test.d.ts +1 -0
  65. package/build/services/TestDiscoveryService.test.js +4 -3
  66. package/build/services/TestExecutionService.d.ts +46 -0
  67. package/build/services/TestExecutionService.test.d.ts +1 -0
  68. package/build/services/TestExecutionService.test.js +33 -25
  69. package/build/services/TestGenerationService.d.ts +56 -0
  70. package/build/services/TestGenerationService.test.d.ts +1 -0
  71. package/build/services/TestGenerationService.test.js +10 -8
  72. package/build/services/containerEnv.d.ts +14 -0
  73. package/build/tool-phase-coverage.test.d.ts +1 -0
  74. package/build/tool-phase-coverage.test.js +2 -0
  75. package/build/tool-phases.d.ts +38 -0
  76. package/build/tools/auth/loginTool.d.ts +2 -0
  77. package/build/tools/auth/logoutTool.d.ts +2 -0
  78. package/build/tools/code-refactor/codeReuseTool.d.ts +2 -0
  79. package/build/tools/code-refactor/enhanceAssertionsTool.d.ts +2 -0
  80. package/build/tools/code-refactor/modularizationTool.d.ts +2 -0
  81. package/build/tools/executeSkyrampTestTool.d.ts +2 -0
  82. package/build/tools/fixErrorTool.d.ts +2 -0
  83. package/build/tools/generate-tests/generateBatchScenarioRestTool.d.ts +45 -0
  84. package/build/tools/generate-tests/generateBatchScenarioRestTool.test.d.ts +1 -0
  85. package/build/tools/generate-tests/generateBatchScenarioRestTool.test.js +11 -9
  86. package/build/tools/generate-tests/generateContractRestTool.d.ts +31 -0
  87. package/build/tools/generate-tests/generateE2ERestTool.d.ts +13 -0
  88. package/build/tools/generate-tests/generateFuzzRestTool.d.ts +10 -0
  89. package/build/tools/generate-tests/generateIntegrationRestTool.d.ts +16 -0
  90. package/build/tools/generate-tests/generateLoadRestTool.d.ts +18 -0
  91. package/build/tools/generate-tests/generateLoadRestTool.test.d.ts +1 -0
  92. package/build/tools/generate-tests/generateMockRestTool.d.ts +64 -0
  93. package/build/tools/generate-tests/generateSmokeRestTool.d.ts +8 -0
  94. package/build/tools/generate-tests/generateUIRestTool.d.ts +14 -0
  95. package/build/tools/generate-tests/generateUIRestTool.js +1 -1
  96. package/build/tools/generate-tests/loadTestSchema.d.ts +39 -0
  97. package/build/tools/one-click/oneClickTool.d.ts +11 -0
  98. package/build/tools/submitReportTool.d.ts +384 -0
  99. package/build/tools/submitReportTool.js +144 -2
  100. package/build/tools/submitReportTool.test.d.ts +1 -0
  101. package/build/tools/submitReportTool.test.js +215 -5
  102. package/build/tools/test-management/actionsTool.d.ts +10 -0
  103. package/build/tools/test-management/analyzeChangesTool.d.ts +27 -0
  104. package/build/tools/test-management/analyzeChangesTool.js +44 -7
  105. package/build/tools/test-management/analyzeChangesTool.test.d.ts +1 -0
  106. package/build/tools/test-management/analyzeChangesTool.test.js +76 -39
  107. package/build/tools/test-management/analyzeTestHealthTool.d.ts +2 -0
  108. package/build/tools/test-management/index.d.ts +3 -0
  109. package/build/tools/test-management/index.js +0 -1
  110. package/build/tools/trace/resolveSaveStoragePath.d.ts +7 -0
  111. package/build/tools/trace/resolveSaveStoragePath.test.d.ts +1 -0
  112. package/build/tools/trace/resolveSessionPaths.d.ts +40 -0
  113. package/build/tools/trace/resolveSessionPaths.test.d.ts +1 -0
  114. package/build/tools/trace/sessionState.d.ts +2 -0
  115. package/build/tools/trace/sessionState.test.d.ts +1 -0
  116. package/build/tools/trace/startTraceCollectionTool.d.ts +2 -0
  117. package/build/tools/trace/stopTraceCollectionTool.d.ts +2 -0
  118. package/build/tools/workspace/initScanWorkspaceTool.d.ts +4 -0
  119. package/build/tools/workspace/initializeWorkspaceTool.d.ts +2 -0
  120. package/build/tools/workspace/initializeWorkspaceTool.test.d.ts +1 -0
  121. package/build/tools/workspace/initializeWorkspaceTool.test.js +134 -0
  122. package/build/types/OneClickCommands.d.ts +68 -0
  123. package/build/types/RepositoryAnalysis.d.ts +3004 -0
  124. package/build/types/TestAnalysis.d.ts +96 -0
  125. package/build/types/TestExecution.d.ts +53 -0
  126. package/build/types/TestRecommendation.d.ts +12 -0
  127. package/build/types/TestTypes.d.ts +234 -0
  128. package/build/utils/AnalysisStateManager.d.ts +182 -0
  129. package/build/utils/AnalysisStateManager.test.d.ts +1 -0
  130. package/build/utils/analyze-openapi.d.ts +1 -0
  131. package/build/utils/branchDiff.d.ts +18 -0
  132. package/build/utils/dartRouteExtractor.d.ts +45 -0
  133. package/build/utils/dartRouteExtractor.test.d.ts +1 -0
  134. package/build/utils/docker.d.ts +19 -0
  135. package/build/utils/docker.test.d.ts +1 -0
  136. package/build/utils/docker.test.js +10 -9
  137. package/build/utils/featureFlags.d.ts +37 -0
  138. package/build/utils/featureFlags.test.d.ts +1 -0
  139. package/build/utils/gitStaging.d.ts +24 -0
  140. package/build/utils/gitStaging.test.d.ts +1 -0
  141. package/build/utils/gitStaging.test.js +13 -7
  142. package/build/utils/httpDefaults.d.ts +10 -0
  143. package/build/utils/httpDefaults.test.d.ts +1 -0
  144. package/build/utils/initAgent.d.ts +36 -0
  145. package/build/utils/language-helper.d.ts +6 -0
  146. package/build/utils/logger.d.ts +11 -0
  147. package/build/utils/normalizeParams.d.ts +14 -0
  148. package/build/utils/normalizeSkyrampImports.d.ts +13 -0
  149. package/build/utils/pr-comment-parser.d.ts +31 -0
  150. package/build/utils/pr-comment-parser.test.d.ts +1 -0
  151. package/build/utils/pr-comment-parser.test.js +6 -5
  152. package/build/utils/projectMetadata.d.ts +15 -0
  153. package/build/utils/projectMetadata.test.d.ts +1 -0
  154. package/build/utils/proxy-terminal.d.ts +2 -0
  155. package/build/utils/repoScanner.d.ts +27 -0
  156. package/build/utils/repoScanner.test.d.ts +1 -0
  157. package/build/utils/routeParsers.d.ts +63 -0
  158. package/build/utils/routeParsers.test.d.ts +1 -0
  159. package/build/utils/scenarioDrafting.d.ts +71 -0
  160. package/build/utils/scenarioDrafting.test.d.ts +1 -0
  161. package/build/utils/skyrampMdContent.d.ts +5 -0
  162. package/build/utils/sourceRouteExtractor.d.ts +48 -0
  163. package/build/utils/sourceRouteExtractor.test.d.ts +1 -0
  164. package/build/utils/telemetry.d.ts +32 -0
  165. package/build/utils/telemetry.test.d.ts +1 -0
  166. package/build/utils/trace-parser.d.ts +32 -0
  167. package/build/utils/trace-parser.test.d.ts +6 -0
  168. package/build/utils/uiPageEnumerator.d.ts +146 -0
  169. package/build/utils/uiPageEnumerator.js +58 -14
  170. package/build/utils/uiPageEnumerator.test.d.ts +1 -0
  171. package/build/utils/uiPageEnumerator.test.js +223 -43
  172. package/build/utils/utils.d.ts +39 -0
  173. package/build/utils/utils.test.d.ts +1 -0
  174. package/build/utils/versions.d.ts +3 -0
  175. package/build/utils/versions.js +1 -1
  176. package/build/utils/workspaceAuth.d.ts +127 -0
  177. package/build/utils/workspaceAuth.test.d.ts +1 -0
  178. package/build/utils/workspaceAuth.test.js +25 -25
  179. package/build/workspace/index.d.ts +1 -0
  180. package/build/workspace/workspace.d.ts +390 -0
  181. package/build/workspace/workspace.test.d.ts +1 -0
  182. package/package.json +8 -3
  183. package/build/tools/test-management/uiAnalyzeChangesTool.js +0 -155
  184. package/build/tools/test-management/uiAnalyzeChangesTool.test.js +0 -147
@@ -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
+ }
@@ -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
+ * based on file path/name overlap with the changed resource names from the PR diff.
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 {};
@@ -0,0 +1 @@
1
+ export {};
@@ -1,10 +1,12 @@
1
+ // @ts-nocheck - Jest ESM type inference issues
2
+ import { jest } from "@jest/globals";
1
3
  // Mock heavy dependencies
2
4
  jest.mock("simple-git", () => ({
3
5
  simpleGit: jest.fn(() => ({
4
6
  checkIsRepo: jest.fn().mockResolvedValue(false),
5
7
  })),
6
8
  }));
7
- jest.mock("../utils/logger.js", () => ({
9
+ jest.unstable_mockModule("../utils/logger.js", () => ({
8
10
  logger: {
9
11
  info: jest.fn(),
10
12
  debug: jest.fn(),
@@ -14,12 +16,11 @@ jest.mock("../utils/logger.js", () => ({
14
16
  }));
15
17
  // fast-glob must return real file paths from the temp directory.
16
18
  // We use the real implementation by not mocking it.
17
- // Jest resolves .js → .ts via moduleNameMapper in jest.config.
18
19
  import * as fs from "fs";
19
20
  import * as path from "path";
20
21
  import * as os from "os";
21
- import { TestDiscoveryService } from "./TestDiscoveryService.js";
22
22
  import { TestSource } from "../types/TestAnalysis.js";
23
+ const { TestDiscoveryService } = await import("./TestDiscoveryService.js");
23
24
  describe("TestDiscoveryService", () => {
24
25
  let service;
25
26
  let tmpDir;
@@ -0,0 +1,46 @@
1
+ import { TestExecutionResult, BatchExecutionResult, TestExecutionOptions, ProgressCallback } from "../types/TestExecution.js";
2
+ export declare const EXECUTOR_DOCKER_IMAGE = "skyramp/executor:v1.3.28";
3
+ export declare const PLAYWRIGHT_CONFIG_FILES: string[];
4
+ export declare const EXCLUDED_MOUNT_ITEMS: string[];
5
+ export declare const MOUNT_NULL_ITEMS: string[];
6
+ /**
7
+ * Detect session file paths referenced in test files
8
+ * Looks for storageState patterns in TypeScript/JavaScript/Python/Java/C# test files
9
+ * Excludes matches found in comments
10
+ *
11
+ * Also handles the codegen pattern `path.join(__dirname, '<filename>')` (TS/JS) —
12
+ * the filename is resolved relative to the test file's directory on the host so
13
+ * the existing absolute-path mount branch makes it visible at the same path
14
+ * inside the container (Playwright's TS loader resolves __dirname to the host
15
+ * workspace path at runtime).
16
+ */
17
+ export declare function detectSessionFiles(testFilePath: string): string[];
18
+ export declare class TestExecutionService {
19
+ private docker;
20
+ private imageReady;
21
+ constructor();
22
+ /**
23
+ * Execute multiple tests in parallel batches
24
+ */
25
+ executeBatch(testOptions: TestExecutionOptions[]): Promise<BatchExecutionResult>;
26
+ /**
27
+ * Execute a single test
28
+ * @param options Test execution options
29
+ * @param onProgress Optional callback for progress updates
30
+ */
31
+ executeTest(options: TestExecutionOptions, onProgress?: ProgressCallback): Promise<TestExecutionResult>;
32
+ /**
33
+ * Ensure Docker image is available
34
+ * @param onProgress Optional callback for progress updates during pull
35
+ * @returns Object indicating whether image was cached or pulled
36
+ */
37
+ private ensureDockerImage;
38
+ /**
39
+ * Parse errors from test output
40
+ */
41
+ private parseErrors;
42
+ /**
43
+ * Parse warnings from test output
44
+ */
45
+ private parseWarnings;
46
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,28 +1,43 @@
1
+ // @ts-nocheck - Jest ESM type inference issues
2
+ import { jest } from "@jest/globals";
1
3
  import { buildContainerEnv, rewriteLocalhostForDocker } from "./containerEnv.js";
2
4
  // Mock dockerode before importing TestExecutionService
3
5
  const mockRun = jest.fn();
4
6
  const mockListImages = jest.fn();
5
- jest.mock("dockerode", () => {
6
- return jest.fn().mockImplementation(() => ({
7
+ jest.unstable_mockModule("dockerode", () => ({
8
+ default: jest.fn().mockImplementation(() => ({
7
9
  run: mockRun,
8
10
  listImages: mockListImages,
9
- }));
11
+ })),
12
+ }));
13
+ // Get actual fs for spreading, then mock specific methods
14
+ const actualFs = await import("fs");
15
+ const mockAccessSync = jest.fn();
16
+ const mockExistsSync = jest.fn().mockReturnValue(true);
17
+ const mockReaddirSync = jest.fn().mockImplementation((_path, options) => {
18
+ if (options?.withFileTypes) {
19
+ return [{ name: "test_file.py", isFile: () => true, isDirectory: () => false }];
20
+ }
21
+ return ["test_file.py"];
10
22
  });
11
- // Mock fs for workspace/file validation
12
- jest.mock("fs", () => ({
13
- ...jest.requireActual("fs"),
14
- accessSync: jest.fn(),
15
- existsSync: jest.fn().mockReturnValue(true),
16
- readdirSync: jest.fn().mockImplementation((_path, options) => {
17
- if (options?.withFileTypes) {
18
- return [{ name: "test_file.py", isFile: () => true, isDirectory: () => false }];
19
- }
20
- return ["test_file.py"];
21
- }),
22
- readFileSync: jest.fn().mockReturnValue(""),
23
+ const mockReadFileSync = jest.fn().mockReturnValue("");
24
+ jest.unstable_mockModule("fs", () => ({
25
+ ...actualFs,
26
+ default: {
27
+ ...actualFs.default,
28
+ accessSync: mockAccessSync,
29
+ existsSync: mockExistsSync,
30
+ readdirSync: mockReaddirSync,
31
+ readFileSync: mockReadFileSync,
32
+ constants: actualFs.default.constants,
33
+ },
34
+ accessSync: mockAccessSync,
35
+ existsSync: mockExistsSync,
36
+ readdirSync: mockReaddirSync,
37
+ readFileSync: mockReadFileSync,
23
38
  }));
24
39
  // Mock logger
25
- jest.mock("../utils/logger.js", () => ({
40
+ jest.unstable_mockModule("../utils/logger.js", () => ({
26
41
  logger: {
27
42
  debug: jest.fn(),
28
43
  info: jest.fn(),
@@ -145,12 +160,9 @@ describe("buildContainerEnv", () => {
145
160
  describe("detectSessionFiles", () => {
146
161
  // Import after mocks are set up so the fs mock applies
147
162
  let detectSessionFiles;
148
- let mockReadFileSync;
149
163
  beforeAll(async () => {
150
164
  const mod = await import("./TestExecutionService.js");
151
165
  detectSessionFiles = mod.detectSessionFiles;
152
- // eslint-disable-next-line @typescript-eslint/no-require-imports
153
- mockReadFileSync = require("fs").readFileSync;
154
166
  });
155
167
  it("detects string-literal storageState (TS/JS)", () => {
156
168
  mockReadFileSync.mockReturnValueOnce(`test.use({ storageState: '/abs/path/session.json' });`);
@@ -258,9 +270,7 @@ describe("TestExecutionService.executeTest - Docker env forwarding", () => {
258
270
  // resolve correctly inside the executor regardless of which path-shape the
259
271
  // codegen happens to emit.
260
272
  it("mirrors each workspace file mount at both /home/user/<f> and the host-absolute path", async () => {
261
- // eslint-disable-next-line @typescript-eslint/no-require-imports
262
- const fs = require("fs");
263
- fs.readdirSync.mockImplementation((_path, options) => {
273
+ mockReaddirSync.mockImplementation((_path, options) => {
264
274
  if (options?.withFileTypes) {
265
275
  return [
266
276
  { name: "xdr_dashboard.spec.ts", isFile: () => true, isDirectory: () => false },
@@ -288,9 +298,7 @@ describe("TestExecutionService.executeTest - Docker env forwarding", () => {
288
298
  expect(targets).toContain("/Users/pedro/projects/cisco-xdr-tests/skyramp_session_storage.json");
289
299
  });
290
300
  it("does not double-mount when workspacePath equals /home/user", async () => {
291
- // eslint-disable-next-line @typescript-eslint/no-require-imports
292
- const fs = require("fs");
293
- fs.readdirSync.mockImplementation((_path, options) => {
301
+ mockReaddirSync.mockImplementation((_path, options) => {
294
302
  if (options?.withFileTypes) {
295
303
  return [{ name: "test_file.py", isFile: () => true, isDirectory: () => false }];
296
304
  }
@@ -0,0 +1,56 @@
1
+ import { SkyrampClient } from "@skyramp/skyramp";
2
+ import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
3
+ import { TestType } from "../types/TestTypes.js";
4
+ export interface BaseTestParams {
5
+ endpointURL?: string;
6
+ method?: string;
7
+ apiSchema?: string;
8
+ language?: string;
9
+ framework?: string;
10
+ output?: string;
11
+ outputDir: string;
12
+ force: boolean;
13
+ deployDashboard?: boolean;
14
+ runtime?: string;
15
+ dockerNetwork?: string;
16
+ dockerWorkerPort?: number;
17
+ k8sNamespace?: string;
18
+ k8sConfig?: string;
19
+ k8sContext?: string;
20
+ authHeader?: string;
21
+ authScheme?: string;
22
+ pathParams?: string;
23
+ queryParams?: string;
24
+ formParams?: string;
25
+ requestData?: string;
26
+ responseStatusCode?: string;
27
+ trace?: string;
28
+ include?: string[];
29
+ exclude?: string[];
30
+ insecure?: boolean;
31
+ prompt?: string;
32
+ codeReuse?: boolean;
33
+ modularizeCode?: boolean;
34
+ chainingKey?: string;
35
+ scenarioFile?: string;
36
+ mockPort?: number;
37
+ optionalFields?: boolean;
38
+ }
39
+ export declare abstract class TestGenerationService {
40
+ protected client: SkyrampClient;
41
+ constructor();
42
+ generateTest(params: BaseTestParams & Record<string, any>): Promise<CallToolResult>;
43
+ protected validateInputs(params: BaseTestParams): CallToolResult;
44
+ protected abstract buildGenerationOptions(params: BaseTestParams & Record<string, any>): any;
45
+ protected abstract getTestType(): TestType;
46
+ protected handleApiAnalysis(params: BaseTestParams): Promise<CallToolResult | null>;
47
+ private static readonly STANDARD_HEADERS;
48
+ private static simpleWildcardMatch;
49
+ private static traceMatchesFilters;
50
+ protected extractAuthFromTrace(traceFilePath: string, include?: string[], exclude?: string[]): {
51
+ authHeader: string;
52
+ authScheme: string;
53
+ } | null;
54
+ protected executeGeneration(generateOptions: any): Promise<string>;
55
+ protected buildBaseGenerationOptions(params: BaseTestParams): any;
56
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,14 +1,18 @@
1
- // Mock @skyramp/skyramp before importing TestGenerationService to avoid
2
- // pulling in playwright (dynamic imports fail on Node 18 in CI).
3
- jest.mock("@skyramp/skyramp", () => ({
4
- SkyrampClient: jest.fn().mockImplementation(() => ({})),
5
- }));
6
- import { TestGenerationService } from "./TestGenerationService.js";
1
+ // @ts-nocheck - Jest ESM type inference issues
2
+ import { jest } from "@jest/globals";
7
3
  import { TestType } from "../types/TestTypes.js";
8
4
  import { AUTH_PLACEHOLDER_TOKEN } from "../types/TestTypes.js";
9
5
  import fs from "fs";
10
6
  import os from "os";
11
7
  import path from "path";
8
+ // Mock @skyramp/skyramp before importing TestGenerationService to avoid
9
+ // pulling in playwright (dynamic imports fail on Node 18 in CI). Under native
10
+ // ESM, jest.mock is not hoisted — use unstable_mockModule + dynamic import.
11
+ jest.unstable_mockModule("@skyramp/skyramp", () => ({
12
+ SkyrampClient: jest.fn().mockImplementation(() => ({})),
13
+ }));
14
+ const { TestGenerationService, BaseTestParams } = await import("./TestGenerationService.js");
15
+ const { SkyrampClient } = await import("@skyramp/skyramp");
12
16
  class StubService extends TestGenerationService {
13
17
  buildGenerationOptions() {
14
18
  return {};
@@ -87,7 +91,6 @@ describe("TestGenerationService — authType/authScheme not passed to library",
87
91
  let mockGenerateRestTest;
88
92
  beforeEach(() => {
89
93
  mockGenerateRestTest = jest.fn().mockResolvedValue("Test generation success");
90
- const { SkyrampClient } = require("@skyramp/skyramp");
91
94
  SkyrampClient.mockImplementation(() => ({
92
95
  generateRestTest: mockGenerateRestTest,
93
96
  }));
@@ -333,7 +336,6 @@ describe("TestGenerationService — trace-based auth in executeGeneration", () =
333
336
  let tmpDir;
334
337
  beforeEach(() => {
335
338
  mockGenerateRestTest = jest.fn().mockResolvedValue("Test generation success");
336
- const { SkyrampClient } = require("@skyramp/skyramp");
337
339
  SkyrampClient.mockImplementation(() => ({
338
340
  generateRestTest: mockGenerateRestTest,
339
341
  }));
@@ -0,0 +1,14 @@
1
+ import { TestExecutionOptions } from "../types/TestExecution.js";
2
+ /**
3
+ * Rewrite localhost / 127.0.0.1 URLs to host.docker.internal so the Docker
4
+ * executor container can reach services running on the host machine.
5
+ *
6
+ * Only applied when NOT using host networking (bridge mode), because in bridge
7
+ * mode the container's localhost is its own loopback, not the host's.
8
+ * host.docker.internal is mapped via ExtraHosts in TestExecutionService.
9
+ */
10
+ export declare function rewriteLocalhostForDocker(url: string): string;
11
+ /**
12
+ * Build the environment variable array for the Docker executor container.
13
+ */
14
+ export declare function buildContainerEnv(options: Pick<TestExecutionOptions, "token" | "language" | "useHostNetwork">, saveStoragePath?: string, hostEnv?: Record<string, string | undefined>): string[];
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,8 @@
1
1
  import { TOOL_PHASE_MAP, TOOLS_WITHOUT_PHASE } from "./tool-phases.js";
2
2
  import * as fs from "fs";
3
3
  import * as path from "path";
4
+ import { fileURLToPath } from "url";
5
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
4
6
  function findAllToolNames() {
5
7
  const toolNames = [];
6
8
  function walk(dir) {
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Canonical mapping of Skyramp MCP tool names to testbot progress phases.
3
+ *
4
+ * The testbot progress UI reads this map at runtime to know which tool calls
5
+ * correspond to which progress steps. When adding or renaming tools, update
6
+ * this map so the progress UI stays accurate.
7
+ *
8
+ * Tools not in this map must be listed in TOOLS_WITHOUT_PHASE.
9
+ *
10
+ * Phases: analyzing, generating, executing, maintaining, reporting
11
+ *
12
+ * ## Static vs context-dependent mappings
13
+ *
14
+ * - **Static** (`string`): the tool always maps to this phase.
15
+ * - **Context-dependent** (`{ before, after }`): the phase depends on whether
16
+ * the "generating" boundary has been crossed. The consumer tracks a boolean
17
+ * flag (`generationSeen`), initially `false`. When any tool in
18
+ * `GENERATING_TOOLS` is encountered, set `generationSeen = true`.
19
+ * - While `generationSeen` is `false`, resolve to the `before` phase.
20
+ * - Once `generationSeen` is `true`, resolve to the `after` phase.
21
+ *
22
+ * Example: `skyramp_execute_test` maps to `{ before: "maintaining", after: "executing" }`.
23
+ * Before any generation tool is seen, execution calls are part of
24
+ * maintenance (baseline runs). After generation, they are final test execution.
25
+ *
26
+ * Reset `generationSeen` to `false` at the start of each session/run.
27
+ */
28
+ export type PhaseMapping = string | {
29
+ before: string;
30
+ after: string;
31
+ };
32
+ export declare const TOOL_PHASE_MAP: Record<string, PhaseMapping>;
33
+ /** Tools whose phase depends on context — listed here for consumer discovery. */
34
+ export declare const CONTEXT_DEPENDENT_TOOLS: Set<string>;
35
+ /** All tools that belong to the "generating" phase — used as the boundary. */
36
+ export declare const GENERATING_TOOLS: Set<string>;
37
+ /** Tools that intentionally have no progress phase (infrastructure/utility). */
38
+ export declare const TOOLS_WITHOUT_PHASE: Set<string>;
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerLoginTool(server: McpServer): void;
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerLogoutTool(server: McpServer): void;
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerCodeReuseTool(server: McpServer): void;
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerEnhanceAssertionsTool(server: McpServer): void;
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerModularizationTool(server: McpServer): void;