@skyramp/mcp 0.2.6 → 0.2.8-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (248) 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 +6 -4
  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/enhance-assertions/uiAssertionsPrompt.js +24 -5
  18. package/build/prompts/fix-error-prompt.d.ts +1 -0
  19. package/build/prompts/initialize-workspace/initializeWorkspacePrompt.d.ts +1 -0
  20. package/build/prompts/modularization/integration-test-modularization.d.ts +1 -0
  21. package/build/prompts/modularization/ui-test-modularization.d.ts +1 -0
  22. package/build/prompts/personas.d.ts +21 -0
  23. package/build/prompts/pom-aware-code-reuse.d.ts +1 -0
  24. package/build/prompts/startTraceCollectionPrompts.d.ts +2 -0
  25. package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.d.ts +2 -0
  26. package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.js +114 -0
  27. package/build/prompts/sut-setup/modes/dockerComposePrompt.d.ts +2 -0
  28. package/build/prompts/sut-setup/modes/dockerComposePrompt.js +292 -0
  29. package/build/prompts/sut-setup/shared.d.ts +39 -0
  30. package/build/prompts/sut-setup/shared.js +132 -0
  31. package/build/prompts/test-maintenance/actionsInstructions.d.ts +35 -0
  32. package/build/prompts/test-maintenance/drift-analysis-prompt.d.ts +4 -0
  33. package/build/prompts/test-maintenance/driftAnalysisSections.d.ts +13 -0
  34. package/build/prompts/test-maintenance/driftAnalysisSections.js +9 -3
  35. package/build/prompts/test-recommendation/analysisOutputPrompt.d.ts +84 -0
  36. package/build/prompts/test-recommendation/analysisOutputPrompt.js +1 -1
  37. package/build/prompts/test-recommendation/analysisOutputPrompt.test.d.ts +1 -0
  38. package/build/prompts/test-recommendation/analysisOutputPrompt.test.js +1 -0
  39. package/build/prompts/test-recommendation/diffExecutionPlan.d.ts +17 -0
  40. package/build/prompts/test-recommendation/diffExecutionPlan.js +83 -18
  41. package/build/prompts/test-recommendation/fullRepoCatalog.d.ts +7 -0
  42. package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.d.ts +1 -0
  43. package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.js +1 -0
  44. package/build/prompts/test-recommendation/promptPlan.d.ts +203 -0
  45. package/build/prompts/test-recommendation/promptPlan.test.d.ts +1 -0
  46. package/build/prompts/test-recommendation/recommendationSections.d.ts +35 -0
  47. package/build/prompts/test-recommendation/recommendationShared.d.ts +31 -0
  48. package/build/prompts/test-recommendation/registerRecommendTestsPrompt.d.ts +7 -0
  49. package/build/prompts/test-recommendation/scopeAssessment.d.ts +55 -0
  50. package/build/prompts/test-recommendation/scopeAssessment.js +2 -2
  51. package/build/prompts/test-recommendation/scopeAssessment.test.d.ts +1 -0
  52. package/build/prompts/test-recommendation/scopeAssessment.test.js +1 -0
  53. package/build/prompts/test-recommendation/test-recommendation-prompt.d.ts +6 -0
  54. package/build/prompts/test-recommendation/test-recommendation-prompt.js +4 -4
  55. package/build/prompts/test-recommendation/test-recommendation-prompt.test.d.ts +1 -0
  56. package/build/prompts/test-recommendation/test-recommendation-prompt.test.js +97 -99
  57. package/build/prompts/testbot/testbot-prompts.d.ts +26 -0
  58. package/build/prompts/testbot/testbot-prompts.js +301 -46
  59. package/build/prompts/testbot/testbot-prompts.test.d.ts +1 -0
  60. package/build/prompts/testbot/testbot-prompts.test.js +109 -117
  61. package/build/resources/analysisResources.d.ts +17 -0
  62. package/build/resources/progressResource.d.ts +2 -0
  63. package/build/resources/sutSetupResource.d.ts +2 -0
  64. package/build/resources/sutSetupResource.js +45 -0
  65. package/build/resources/testbotResource.d.ts +2 -0
  66. package/build/resources/testbotResource.js +2 -2
  67. package/build/services/AnalyticsService.d.ts +13 -0
  68. package/build/services/AnalyticsService.test.d.ts +1 -0
  69. package/build/services/AnalyticsService.test.js +86 -0
  70. package/build/services/ModularizationService.d.ts +11 -0
  71. package/build/services/ScenarioGenerationService.d.ts +37 -0
  72. package/build/services/ScenarioGenerationService.integration.test.d.ts +1 -0
  73. package/build/services/ScenarioGenerationService.integration.test.js +4 -0
  74. package/build/services/ScenarioGenerationService.test.d.ts +1 -0
  75. package/build/services/TestDiscoveryService.d.ts +128 -0
  76. package/build/services/TestDiscoveryService.js +22 -12
  77. package/build/services/TestDiscoveryService.test.d.ts +1 -0
  78. package/build/services/TestDiscoveryService.test.js +4 -3
  79. package/build/services/TestExecutionService.d.ts +55 -0
  80. package/build/services/TestExecutionService.js +158 -26
  81. package/build/services/TestExecutionService.test.d.ts +1 -0
  82. package/build/services/TestExecutionService.test.js +339 -25
  83. package/build/services/TestGenerationService.d.ts +56 -0
  84. package/build/services/TestGenerationService.test.d.ts +1 -0
  85. package/build/services/TestGenerationService.test.js +10 -8
  86. package/build/services/containerEnv.d.ts +14 -0
  87. package/build/tool-phase-coverage.test.d.ts +1 -0
  88. package/build/tool-phase-coverage.test.js +2 -0
  89. package/build/tool-phases.d.ts +38 -0
  90. package/build/tools/auth/loginTool.d.ts +2 -0
  91. package/build/tools/auth/logoutTool.d.ts +2 -0
  92. package/build/tools/code-refactor/codeReuseTool.d.ts +2 -0
  93. package/build/tools/code-refactor/enhanceAssertionsTool.d.ts +2 -0
  94. package/build/tools/code-refactor/modularizationTool.d.ts +2 -0
  95. package/build/tools/executeSkyrampTestTool.d.ts +2 -0
  96. package/build/tools/executeSkyrampTestTool.js +26 -7
  97. package/build/tools/fixErrorTool.d.ts +2 -0
  98. package/build/tools/generate-tests/generateBatchScenarioRestTool.d.ts +45 -0
  99. package/build/tools/generate-tests/generateBatchScenarioRestTool.js +1 -1
  100. package/build/tools/generate-tests/generateBatchScenarioRestTool.test.d.ts +1 -0
  101. package/build/tools/generate-tests/generateBatchScenarioRestTool.test.js +11 -9
  102. package/build/tools/generate-tests/generateContractRestTool.d.ts +31 -0
  103. package/build/tools/generate-tests/generateE2ERestTool.d.ts +13 -0
  104. package/build/tools/generate-tests/generateFuzzRestTool.d.ts +10 -0
  105. package/build/tools/generate-tests/generateIntegrationRestTool.d.ts +16 -0
  106. package/build/tools/generate-tests/generateLoadRestTool.d.ts +18 -0
  107. package/build/tools/generate-tests/generateLoadRestTool.test.d.ts +1 -0
  108. package/build/tools/generate-tests/generateMockRestTool.d.ts +64 -0
  109. package/build/tools/generate-tests/generateSmokeRestTool.d.ts +8 -0
  110. package/build/tools/generate-tests/generateUIRestTool.d.ts +14 -0
  111. package/build/tools/generate-tests/generateUIRestTool.js +1 -1
  112. package/build/tools/generate-tests/loadTestSchema.d.ts +39 -0
  113. package/build/tools/one-click/oneClickTool.d.ts +11 -0
  114. package/build/tools/submitReportTool.d.ts +394 -0
  115. package/build/tools/submitReportTool.js +250 -41
  116. package/build/tools/submitReportTool.test.d.ts +1 -0
  117. package/build/tools/submitReportTool.test.js +511 -55
  118. package/build/tools/test-management/actionsTool.d.ts +10 -0
  119. package/build/tools/test-management/actionsTool.js +21 -7
  120. package/build/tools/test-management/analyzeChangesTool.d.ts +27 -0
  121. package/build/tools/test-management/analyzeChangesTool.js +150 -48
  122. package/build/tools/test-management/analyzeChangesTool.test.d.ts +1 -0
  123. package/build/tools/test-management/analyzeChangesTool.test.js +95 -78
  124. package/build/tools/test-management/analyzeTestHealthTool.d.ts +2 -0
  125. package/build/tools/test-management/analyzeTestHealthTool.js +16 -9
  126. package/build/tools/test-management/index.d.ts +3 -0
  127. package/build/tools/test-management/index.js +0 -1
  128. package/build/tools/trace/resolveSaveStoragePath.d.ts +7 -0
  129. package/build/tools/trace/resolveSaveStoragePath.test.d.ts +1 -0
  130. package/build/tools/trace/resolveSessionPaths.d.ts +40 -0
  131. package/build/tools/trace/resolveSessionPaths.test.d.ts +1 -0
  132. package/build/tools/trace/sessionState.d.ts +2 -0
  133. package/build/tools/trace/sessionState.test.d.ts +1 -0
  134. package/build/tools/trace/startTraceCollectionTool.d.ts +2 -0
  135. package/build/tools/trace/stopTraceCollectionTool.d.ts +2 -0
  136. package/build/tools/workspace/initScanWorkspaceTool.d.ts +4 -0
  137. package/build/tools/workspace/initializeWorkspaceTool.d.ts +2 -0
  138. package/build/tools/workspace/initializeWorkspaceTool.js +39 -22
  139. package/build/tools/workspace/initializeWorkspaceTool.test.d.ts +1 -0
  140. package/build/tools/workspace/initializeWorkspaceTool.test.js +134 -0
  141. package/build/tools/workspace/serviceUpsert.d.ts +12 -0
  142. package/build/tools/workspace/serviceUpsert.js +23 -0
  143. package/build/tools/workspace/serviceUpsert.test.d.ts +1 -0
  144. package/build/tools/workspace/serviceUpsert.test.js +50 -0
  145. package/build/types/OneClickCommands.d.ts +68 -0
  146. package/build/types/RepositoryAnalysis.d.ts +3004 -0
  147. package/build/types/TestAnalysis.d.ts +97 -0
  148. package/build/types/TestExecution.d.ts +63 -0
  149. package/build/types/TestExecution.js +11 -1
  150. package/build/types/TestRecommendation.d.ts +12 -0
  151. package/build/types/TestTypes.d.ts +234 -0
  152. package/build/types/TestbotReport.d.ts +68 -0
  153. package/build/types/TestbotReport.js +1 -0
  154. package/build/types/index.d.ts +4 -0
  155. package/build/types/index.js +3 -0
  156. package/build/utils/AnalysisStateManager.d.ts +242 -0
  157. package/build/utils/AnalysisStateManager.js +144 -3
  158. package/build/utils/AnalysisStateManager.test.d.ts +1 -0
  159. package/build/utils/AnalysisStateManager.test.js +98 -0
  160. package/build/utils/analyze-openapi.d.ts +1 -0
  161. package/build/utils/branchDiff.d.ts +18 -0
  162. package/build/utils/dartRouteExtractor.d.ts +45 -0
  163. package/build/utils/dartRouteExtractor.test.d.ts +1 -0
  164. package/build/utils/docker.d.ts +19 -0
  165. package/build/utils/docker.test.d.ts +1 -0
  166. package/build/utils/docker.test.js +10 -9
  167. package/build/utils/featureFlags.d.ts +37 -0
  168. package/build/utils/featureFlags.test.d.ts +1 -0
  169. package/build/utils/gitStaging.d.ts +24 -0
  170. package/build/utils/gitStaging.test.d.ts +1 -0
  171. package/build/utils/gitStaging.test.js +13 -7
  172. package/build/utils/httpDefaults.d.ts +10 -0
  173. package/build/utils/httpDefaults.test.d.ts +1 -0
  174. package/build/utils/initAgent.d.ts +36 -0
  175. package/build/utils/language-helper.d.ts +6 -0
  176. package/build/utils/logger.d.ts +11 -0
  177. package/build/utils/normalizeParams.d.ts +14 -0
  178. package/build/utils/normalizeSkyrampImports.d.ts +13 -0
  179. package/build/utils/pr-comment-parser.d.ts +31 -0
  180. package/build/utils/pr-comment-parser.test.d.ts +1 -0
  181. package/build/utils/pr-comment-parser.test.js +6 -5
  182. package/build/utils/projectMetadata.d.ts +15 -0
  183. package/build/utils/projectMetadata.test.d.ts +1 -0
  184. package/build/utils/proxy-terminal.d.ts +2 -0
  185. package/build/utils/repoScanner.d.ts +27 -0
  186. package/build/utils/repoScanner.test.d.ts +1 -0
  187. package/build/utils/routeParsers.d.ts +53 -0
  188. package/build/utils/routeParsers.js +31 -38
  189. package/build/utils/routeParsers.test.d.ts +1 -0
  190. package/build/utils/scenarioDrafting.d.ts +71 -0
  191. package/build/utils/scenarioDrafting.js +23 -1
  192. package/build/utils/scenarioDrafting.test.d.ts +1 -0
  193. package/build/utils/skyrampMdContent.d.ts +5 -0
  194. package/build/utils/sourceRouteExtractor.d.ts +48 -0
  195. package/build/utils/sourceRouteExtractor.test.d.ts +1 -0
  196. package/build/utils/telemetry.d.ts +32 -0
  197. package/build/utils/telemetry.test.d.ts +1 -0
  198. package/build/utils/trace-parser.d.ts +32 -0
  199. package/build/utils/trace-parser.test.d.ts +6 -0
  200. package/build/utils/uiPageEnumerator.d.ts +146 -0
  201. package/build/utils/uiPageEnumerator.js +58 -14
  202. package/build/utils/uiPageEnumerator.test.d.ts +1 -0
  203. package/build/utils/uiPageEnumerator.test.js +223 -43
  204. package/build/utils/utils.d.ts +45 -0
  205. package/build/utils/utils.js +10 -0
  206. package/build/utils/utils.test.d.ts +1 -0
  207. package/build/utils/versions.d.ts +3 -0
  208. package/build/utils/versions.js +1 -1
  209. package/build/utils/workspaceAuth.d.ts +127 -0
  210. package/build/utils/workspaceAuth.test.d.ts +1 -0
  211. package/build/utils/workspaceAuth.test.js +25 -25
  212. package/build/workspace/index.d.ts +1 -0
  213. package/build/workspace/workspace.d.ts +390 -0
  214. package/build/workspace/workspace.js +7 -7
  215. package/build/workspace/workspace.test.d.ts +1 -0
  216. package/build/workspace/workspace.test.js +6 -6
  217. package/node_modules/playwright/lib/mcp/skyramp/loadTraceTool.js +31 -13
  218. package/node_modules/playwright/lib/mcp/skyramp/traceRecordingBackend.js +88 -15
  219. package/node_modules/playwright/lib/mcp/test/skyRampExport.js +4 -3
  220. package/node_modules/playwright/node_modules/playwright-core/ThirdPartyNotices.txt +23 -126
  221. package/node_modules/playwright/node_modules/playwright-core/lib/generated/injectedScriptSource.js +1 -1
  222. package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/recorderApp.js +79 -19
  223. package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/skyramp/aliasRemapper.js +84 -0
  224. package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/skyramp/replayEngine.js +15 -4
  225. package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/{codeMirrorModule-CPZKmjFR.js → codeMirrorModule-D0BjbCb7.js} +1 -1
  226. package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/index-lvTRGFx-.js +193 -0
  227. package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/index.html +1 -1
  228. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/{codeMirrorModule-B0JOjboO.js → codeMirrorModule-Cqp3cwEJ.js} +1 -1
  229. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/{defaultSettingsView-1anWeyDf.js → defaultSettingsView-CYf9adZh.js} +79 -79
  230. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/{index.Cc5029a3.js → index.B_7ywgmr.js} +1 -1
  231. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.html +2 -2
  232. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.html +2 -2
  233. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/{uiMode.Wo5yvvVh.js → uiMode.u4_8VnCV.js} +1 -1
  234. package/node_modules/playwright/node_modules/playwright-core/package.json +1 -1
  235. package/node_modules/playwright/node_modules/playwright-core/src/generated/injectedScriptSource.ts +1 -1
  236. package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/recorderApp.ts +129 -43
  237. package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/skyramp/aliasRemapper.ts +119 -0
  238. package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/skyramp/replayEngine.ts +33 -10
  239. package/node_modules/playwright/package.json +1 -1
  240. package/package.json +16 -4
  241. package/build/tools/test-management/uiAnalyzeChangesTool.js +0 -155
  242. package/build/tools/test-management/uiAnalyzeChangesTool.test.js +0 -147
  243. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/.bin/node-which +0 -52
  244. package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/.bin/is-docker +0 -5
  245. package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/.bin/mime +0 -46
  246. package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/.bin/yaml +0 -11
  247. package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/index-CsgPR2wy.js +0 -193
  248. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.CP3Y8Zsb.js +0 -2
@@ -1,5 +1,12 @@
1
+ // @ts-nocheck - Jest ESM type inference issues
2
+ import { jest } from "@jest/globals";
1
3
  // Mock logger before importing docker module
2
- jest.mock("./logger.js", () => ({
4
+ const mockInspect = jest.fn();
5
+ const mockGetImage = jest.fn(() => ({ inspect: mockInspect }));
6
+ const mockFollowProgress = jest.fn();
7
+ const mockPull = jest.fn();
8
+ const mockModem = { followProgress: mockFollowProgress };
9
+ jest.unstable_mockModule("./logger.js", () => ({
3
10
  logger: {
4
11
  debug: jest.fn(),
5
12
  info: jest.fn(),
@@ -7,18 +14,12 @@ jest.mock("./logger.js", () => ({
7
14
  warning: jest.fn(),
8
15
  },
9
16
  }));
10
- // Mock dockerode before importing docker module
11
- const mockInspect = jest.fn();
12
- const mockGetImage = jest.fn(() => ({ inspect: mockInspect }));
13
- const mockFollowProgress = jest.fn();
14
- const mockPull = jest.fn();
15
- const mockModem = { followProgress: mockFollowProgress };
16
17
  jest.mock("dockerode", () => jest.fn().mockImplementation(() => ({
17
18
  getImage: mockGetImage,
18
19
  pull: mockPull,
19
20
  modem: mockModem,
20
21
  })));
21
- import { dockerImageExistsLocally, pullDockerImage } from "./docker.js";
22
+ const { dockerImageExistsLocally, pullDockerImage } = await import("./docker.js");
22
23
  // Helper: make docker.pull succeed (stream ends without error)
23
24
  function mockPullSuccess() {
24
25
  const fakeStream = {};
@@ -54,7 +55,7 @@ describe("dockerImageExistsLocally", () => {
54
55
  });
55
56
  });
56
57
  describe("pullDockerImage", () => {
57
- const IMAGE = "skyramp/executor:v1.3.27";
58
+ const IMAGE = "skyramp/executor:v1.3.29";
58
59
  beforeEach(() => jest.clearAllMocks());
59
60
  describe("on amd64 host", () => {
60
61
  const originalArch = process.arch;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Feature flag helpers.
3
+ *
4
+ * Each helper in this module reads a `SKYRAMP_FEATURE_*` env var and returns
5
+ * a boolean. These helpers treat a flag as ON only when the env var is
6
+ * exactly `"1"`; anything else (unset, empty, "0", "true", "false", etc.) is
7
+ * treated as OFF.
8
+ */
9
+ /**
10
+ * Gates BOTH consumer-side contract tests AND the SDK's "default mode"
11
+ * fallback (where omitting both `providerMode` and `consumerMode` causes the
12
+ * SDK to generate BOTH provider and consumer tests).
13
+ *
14
+ * `providerMode` itself is exposed regardless of this flag.
15
+ *
16
+ * When OFF (default):
17
+ * - `skyramp_contract_test_generation` only exposes provider-mode
18
+ * parameters in its input schema, and the tool description, validation,
19
+ * and post-generation instructions all assume provider-only behavior.
20
+ * - The SDK is always invoked with `providerMode: true`, so the
21
+ * "neither mode set ⇒ generate both" default cannot leak through. Only
22
+ * a provider contract test is ever generated.
23
+ * - Testbot recommendation prompts no longer suggest `consumerMode: true`
24
+ * contract tests.
25
+ *
26
+ * When ON (`SKYRAMP_FEATURE_CONTRACT_CONSUMER_MODE=1`):
27
+ * - Restores the previous behavior: `consumerMode` / `consumerOutput` are
28
+ * exposed on the input schema, recommendation prompts mention consumer
29
+ * contract tests, and the SDK's "no mode set ⇒ generate both" default
30
+ * is preserved.
31
+ */
32
+ export declare function isContractConsumerModeEnabled(): boolean;
33
+ /**
34
+ * Returns true when running inside a TestBot environment
35
+ * (SKYRAMP_FEATURE_TESTBOT=1).
36
+ */
37
+ export declare function isTestbotEnabled(): boolean;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Check whether `child` is inside `parent` using resolved paths with
3
+ * a trailing separator to avoid prefix false positives (e.g. /tmp/test-repo2
4
+ * should not match /tmp/test-repo).
5
+ */
6
+ export declare function isInsideDir(child: string, parent: string): boolean;
7
+ /**
8
+ * In cross-repo mode, redirects an outputDir to be under the test repo clone
9
+ * if it isn't already. Returns the original path unchanged when testsRepoDir
10
+ * is unset or the path is already inside it.
11
+ */
12
+ export declare function resolveOutputDir(outputDir: string, testsRepoDir: string | undefined): string;
13
+ /**
14
+ * Stages a file path an MCP tool just wrote into the git index by
15
+ * running `git add -- <path>`.
16
+ *
17
+ * Automatically detects the git root of the target path so that staging
18
+ * works correctly in cross-repo mode (test repo clone separate from the
19
+ * source repo).
20
+ *
21
+ * Gated by the SKYRAMP_FEATURE_TESTBOT=1 env var, which is set only
22
+ * inside a testbot CI run.
23
+ */
24
+ export declare function stageGeneratedPaths(filePath: string, cwd?: string): Promise<void>;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,7 @@
1
- jest.mock("./logger.js", () => ({
1
+ import { jest } from "@jest/globals";
2
+ const execFileMock = jest.fn();
3
+ const execFileSyncMock = jest.fn();
4
+ jest.unstable_mockModule("./logger.js", () => ({
2
5
  logger: {
3
6
  debug: jest.fn(),
4
7
  info: jest.fn(),
@@ -6,14 +9,17 @@ jest.mock("./logger.js", () => ({
6
9
  error: jest.fn(),
7
10
  },
8
11
  }));
9
- jest.mock("fs", () => ({
12
+ jest.unstable_mockModule("fs", () => ({
13
+ default: {
14
+ statSync: (p) => ({
15
+ isDirectory: () => !p.includes("."),
16
+ }),
17
+ },
10
18
  statSync: (p) => ({
11
19
  isDirectory: () => !p.includes("."),
12
20
  }),
13
21
  }));
14
- const execFileMock = jest.fn();
15
- const execFileSyncMock = jest.fn();
16
- jest.mock("child_process", () => ({
22
+ jest.unstable_mockModule("child_process", () => ({
17
23
  execFile: (cmd, args, opts, cb) => {
18
24
  const result = execFileMock(cmd, args, opts);
19
25
  const cbErr = result && typeof result === "object" && "err" in result
@@ -26,8 +32,8 @@ jest.mock("child_process", () => ({
26
32
  },
27
33
  execFileSync: (cmd, args, opts) => execFileSyncMock(cmd, args, opts),
28
34
  }));
29
- import { stageGeneratedPaths } from "./gitStaging.js";
30
- import { logger } from "./logger.js";
35
+ const { stageGeneratedPaths } = await import("./gitStaging.js");
36
+ const { logger } = await import("./logger.js");
31
37
  const loggerInfoMock = logger.info;
32
38
  let originalTestbotEnv;
33
39
  beforeAll(() => {
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Shared HTTP method defaults used across scenario drafting and test generation.
3
+ */
4
+ /**
5
+ * Returns the conventional success status code for a given HTTP method.
6
+ * POST → 201 Created
7
+ * DELETE → 204 No Content
8
+ * other → 200 OK
9
+ */
10
+ export declare function inferExpectedStatus(method: string): number;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,36 @@
1
+ import { WORKER_DOCKER_IMAGE } from "./versions.js";
2
+ export { WORKER_DOCKER_IMAGE };
3
+ /**
4
+ * Install or refresh SKYRAMP_MD_CONTENT at global skill discovery paths only (~/.claude, ~/.cursor, ~/.github/skills).
5
+ * No workspace path required. Creates files if missing; overwrites if content differs.
6
+ */
7
+ export declare function ensureSkyrampMdInstalled(): Promise<void>;
8
+ /**
9
+ * Skyramp init:
10
+ * install/refresh global skill files (~/.claude, ~/.cursor, ~/.github/skills) (errors logged but do not block init),
11
+ * check which images are missing, then kick off any needed pulls in the background and return immediately.
12
+ * Deduplication for the MCP oninitialized path is handled by registerInitTriggerOnMCPInitialized in this module.
13
+ *
14
+ * Pull improvements over the previous SkyrampClient.initAgent() FFI approach:
15
+ * - Skip-if-present: each image is checked independently via a fast daemon inspect (~5ms)
16
+ * before any pull is attempted, avoiding unnecessary network calls.
17
+ * - Pull only what is missing: if one image is already present, only the other is pulled.
18
+ * Previously both images were always pulled regardless.
19
+ * - Parallel pulls: missing images are pulled concurrently via Promise.all, halving
20
+ * wall-clock time when both need to be downloaded.
21
+ * - Arch-aware: pull platform is detected from process.arch (linux/arm64 on Apple Silicon,
22
+ * linux/amd64 otherwise) with an automatic amd64 fallback if no arm64 manifest exists
23
+ * (e.g. skyramp/executor is amd64-only; skyramp/worker supports both).
24
+ * - No FFI overhead: direct Dockerode calls replace the Go shared-library bridge,
25
+ * removing the cost of loading the .so and marshalling output through a C string.
26
+ * - Cleaner error propagation: structured errors from Dockerode replace parsing a
27
+ * stringified Go output from the C FFI boundary.
28
+ */
29
+ export declare function initCheck(): Promise<void>;
30
+ /**
31
+ * Runs initCheck asynchronously after the MCP handshake completes.
32
+ * Prevents duplicate concurrent runs and skips future runs after a successful init.
33
+ * If initCheck fails, a later call can retry within the same process.
34
+ * Assign to server.server.oninitialized in main().
35
+ */
36
+ export declare function registerInitTriggerOnMCPInitialized(): Promise<void>;
@@ -0,0 +1,6 @@
1
+ export interface LanguageStepsParams {
2
+ language: string;
3
+ testType?: string;
4
+ framework?: string;
5
+ }
6
+ export declare function getLanguageSteps(params: LanguageStepsParams): string;
@@ -0,0 +1,11 @@
1
+ export declare class McpLogger {
2
+ private loggerName;
3
+ constructor(loggerName?: string);
4
+ private sendLogMessage;
5
+ debug(message: string, data?: any): void;
6
+ info(message: string, data?: any): void;
7
+ warning(message: string, data?: any): void;
8
+ error(message: string, data?: any): void;
9
+ critical(message: string, data?: any): void;
10
+ }
11
+ export declare const logger: McpLogger;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Normalize tool parameters to handle common LLM mistakes:
3
+ * - Case-insensitive language/framework values
4
+ * - Common parameter name aliases
5
+ */
6
+ /**
7
+ * Normalize language and framework to lowercase accepted values.
8
+ */
9
+ export declare function normalizeLanguageParams(params: Record<string, any>): void;
10
+ /**
11
+ * Resolve common parameter name aliases that LLMs use.
12
+ * e.g., zipPath -> playwrightInput, testFilePath -> testFile
13
+ */
14
+ export declare function resolveParamAliases(params: Record<string, any>, aliases: Record<string, string>): void;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Ensure `expect` is imported from `@skyramp/skyramp` rather than `@playwright/test`.
3
+ * - Strips `expect` from any `@playwright/test` import (keeps other identifiers).
4
+ * - If the file uses `expect(...)`, ensures an `@skyramp/skyramp` import carries `expect`.
5
+ * Returns the original string if no rewrite was needed.
6
+ */
7
+ export declare function normalizeSkyrampExpectImport(source: string): string;
8
+ /**
9
+ * Normalize the `expect` import in a file on disk. No-op if the file is missing,
10
+ * unreadable, or already correct. Errors are swallowed — this is a safety net,
11
+ * not a blocking step.
12
+ */
13
+ export declare function normalizeSkyrampImportsInFile(testFile: string | undefined): void;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * PR Comment Parser — extracts TestBot history from GitHub PR comments.
3
+ *
4
+ * Parses previous Skyramp TestBot comments on a PR to build context
5
+ * about what has already been recommended, implemented, and tested.
6
+ * This prevents re-recommendations and enables contextual awareness
7
+ * across the PR lifecycle.
8
+ */
9
+ export interface PRTestContext {
10
+ prNumber: number;
11
+ previousRecommendations: Array<{
12
+ testType: string;
13
+ endpoint: string;
14
+ scenarioName?: string;
15
+ status: "recommended" | "implemented" | "dismissed";
16
+ commentId: string;
17
+ }>;
18
+ implementedTestFiles: string[];
19
+ executionResults: Array<{
20
+ testFile: string;
21
+ status: "pass" | "fail" | "skipped";
22
+ timestamp: string;
23
+ }>;
24
+ }
25
+ /**
26
+ * Fetch and parse PR comments to build TestBot history context.
27
+ *
28
+ * Uses the `gh` CLI (available in CI and local dev environments with
29
+ * GitHub CLI installed). Falls back gracefully if `gh` is unavailable.
30
+ */
31
+ export declare function parsePRComments(repoOwner: string, repoName: string, prNumber: number, _token?: string): Promise<PRTestContext>;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,9 +1,10 @@
1
- import { parsePRComments } from "./pr-comment-parser.js";
2
- import { execFileSync } from "child_process";
3
- jest.mock("child_process", () => ({
4
- execFileSync: jest.fn(),
1
+ import { jest } from "@jest/globals";
2
+ // Mock child_process before importing the module under test
3
+ const mockedExecFileSync = jest.fn();
4
+ jest.unstable_mockModule("child_process", () => ({
5
+ execFileSync: mockedExecFileSync,
5
6
  }));
6
- const mockedExecFileSync = execFileSync;
7
+ const { parsePRComments } = await import("./pr-comment-parser.js");
7
8
  // ---------------------------------------------------------------------------
8
9
  // Fixture helpers — build PR comment bodies matching the real renderReport()
9
10
  // output wrapped in the progress comment from testbot/src/progress.ts.
@@ -0,0 +1,15 @@
1
+ export type ProjectType = "rest-api" | "frontend" | "full-stack" | "microservices" | "library" | "cli" | "other";
2
+ export type DeploymentPattern = "microservices" | "full-stack" | "containerized-monolith" | "traditional" | "unknown";
3
+ export interface ProjectMeta {
4
+ projectType: ProjectType;
5
+ primaryLanguage: string;
6
+ primaryFramework: string;
7
+ deploymentPattern: DeploymentPattern;
8
+ languages: string[];
9
+ frameworks: string[];
10
+ runtime: string;
11
+ isContainerized: boolean;
12
+ hasDockerCompose: boolean;
13
+ hasCiCd: boolean;
14
+ }
15
+ export declare function detectProjectMetadata(repositoryPath: string): ProjectMeta;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export default function openProxyTerminal(): Promise<void>;
2
+ export declare function closeProxyTerminal(): Promise<void>;
@@ -0,0 +1,27 @@
1
+ export interface ScannedEndpoint {
2
+ path: string;
3
+ methods: string[];
4
+ sourceFile: string;
5
+ }
6
+ /**
7
+ * Returns the relative paths of entry-point files that define the routing
8
+ * hierarchy for this repository. The LLM reads these files in Step 1.5 to
9
+ * trace router/module nesting and build an authoritative path resolution table.
10
+ *
11
+ * Intentionally returns only file paths — no extracted lines. Static regex
12
+ * extraction is fragile and framework-specific; the LLM reads the files directly
13
+ * and understands any framework's routing syntax.
14
+ */
15
+ export declare function grepRouterMountingContext(repositoryPath: string): string[];
16
+ /**
17
+ * Return relative paths of all source files that are likely to define API
18
+ * routes. Two-pass strategy:
19
+ * 1. Fast: filename matches ROUTE_FILE_PATTERN (no file I/O needed).
20
+ * 2. Content: files not matched by name are read and checked for both a
21
+ * URL-path literal AND an HTTP method registration. This covers any
22
+ * framework the filename filter misses — Axum, Ktor, .NET, Hono, etc.
23
+ * Result is capped at MAX_CANDIDATE_FILES to keep the LLM prompt bounded.
24
+ */
25
+ export declare function findCandidateRouteFiles(repositoryPath: string): string[];
26
+ export declare function scanAllRepoEndpoints(repositoryPath: string): ScannedEndpoint[];
27
+ export declare function scanRelatedEndpoints(repositoryPath: string, changedFiles: string[]): ScannedEndpoint[];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,53 @@
1
+ import { BranchDiffData } from "./branchDiff.js";
2
+ import type { ScannedEndpoint } from "./repoScanner.js";
3
+ export interface ParsedDiffEndpoint {
4
+ method: string;
5
+ path: string;
6
+ sourceFile: string;
7
+ }
8
+ export declare function nextjsFileToApiPath(filePath: string): string | null;
9
+ export declare const UI_FILE_EXTENSIONS: readonly ["tsx", "jsx", "vue", "svelte", "html", "xml"];
10
+ export declare const UI_FILE_GIT_PATHSPEC: string;
11
+ export declare const UI_FILE_EXTENSIONS_PIPED: string;
12
+ export declare function parseRouteLine(line: string, sourceFile: string): ParsedDiffEndpoint | null;
13
+ /**
14
+ * Scan all route definitions in a single source file, combining prefix declarations
15
+ * with method-level annotations. Two orthogonal state machines run in parallel:
16
+ *
17
+ * 1. Class-prefix (Spring, NestJS, ASP.NET, Kotlin):
18
+ * @Controller/@RestController/@RequestMapping (class level) + class declaration →
19
+ * activates classPrefix, applied to all @Get/@Post/@GetMapping etc. below.
20
+ *
21
+ * 2. Router-variable prefix (FastAPI, Flask Blueprint):
22
+ * varName = APIRouter(prefix=...) or Blueprint(url_prefix=...) — handles both
23
+ * single-line and multi-line declarations — maps the variable name to its prefix.
24
+ * Applied when @varName.method(...) is seen.
25
+ *
26
+ * Falls back to pure parseRouteLine for all other frameworks (Express inline, Gin,
27
+ * Rails, Laravel, Actix, Hapi, Go stdlib, etc.), which remain unaffected.
28
+ */
29
+ export declare function parseFileEndpoints(content: string, sourceFile: string): ParsedDiffEndpoint[];
30
+ export declare const SKIP_PATH_SEGMENTS: Set<string>;
31
+ /**
32
+ * Extract the primary resource key from an endpoint path for use as a dedup key.
33
+ *
34
+ * For top-level resources (e.g. "/api/v1/orders/{id}") returns the resource name ("orders").
35
+ * For sub-resources (e.g. "/orders/{id}/items") returns "orders_items" — including the
36
+ * parent prevents "/orders/{id}/items" and "/products/{id}/items" from colliding on "items".
37
+ */
38
+ export declare function extractResourceFromPath(endpointPath: string): string;
39
+ export interface ClassifiedEndpoints {
40
+ /** Endpoints in scanned catalog whose sourceFile is in changedFiles (not new/deleted). */
41
+ changedEndpoints: ScannedEndpoint[];
42
+ /** Endpoints whose sourceFile is in a newly-created file. */
43
+ newEndpoints: ScannedEndpoint[];
44
+ /** Endpoints whose sourceFile is in a deleted file (recovered from base branch). */
45
+ removedEndpoints: ScannedEndpoint[];
46
+ /** Changed files that don't map to any scanned endpoint. */
47
+ unmatchedFiles: string[];
48
+ changedFiles: string[];
49
+ currentBranch: string;
50
+ baseBranch: string;
51
+ affectedServices: string[];
52
+ }
53
+ export declare function classifyEndpointsByChangedFiles(diffData: BranchDiffData, scannedEndpoints: ScannedEndpoint[], deletedFileEndpoints?: ScannedEndpoint[]): ClassifiedEndpoints;
@@ -406,21 +406,36 @@ const GENERIC_ROUTE_BASENAMES = new Set(["api", "app", "handler", "handlers", "i
406
406
  function normalizeSourcePath(filePath) {
407
407
  return filePath.replace(/\\/g, "/");
408
408
  }
409
- /**
410
- * Classify endpoints by cross-referencing `changedFiles` against `scannedEndpoints[].sourceFile`.
411
- *
412
- * This replaces `parseEndpointsFromDiff` — instead of regex-parsing diff hunks for route
413
- * annotations (fragile for 15+ frameworks), it uses the already-scanned endpoint catalog
414
- * which has full, resolved paths and concrete HTTP methods.
415
- *
416
- * For deleted files, the caller must supply endpoints recovered from the base branch
417
- * (via `parseFileEndpoints` on `git show base:<file>`) in `deletedFileEndpoints`.
418
- */
409
+ function staticPathSegments(urlPath) {
410
+ return urlPath.split("/").filter(s => s && !/^[:{[]/.test(s)).map(s => s.toLowerCase());
411
+ }
412
+ function endpointSourceResource(ep) {
413
+ const sourceSegments = ep.sourceFile.split(/[\\/]/).filter(Boolean);
414
+ const filename = sourceSegments.at(-1)?.replace(/\.[^.]+$/, "") ?? "";
415
+ const normalizedFilename = filename.replace(/^(?:old|new)[-_]/i, "").toLowerCase();
416
+ const isDynamic = /^\[.*\]$/.test(normalizedFilename) || /^\{.*\}$/.test(normalizedFilename);
417
+ if (!isDynamic && !GENERIC_ROUTE_BASENAMES.has(normalizedFilename) && normalizedFilename) {
418
+ return normalizedFilename;
419
+ }
420
+ else if (GENERIC_ROUTE_BASENAMES.has(normalizedFilename)) {
421
+ // Generic filename: walk up the directory tree for a more specific ancestor name.
422
+ const parentSegments = sourceSegments.slice(0, -1).reverse();
423
+ const contextSegment = parentSegments
424
+ .map(s => s.replace(/\.[^.]+$/, "").replace(/^(?:old|new)[-_]/i, "").toLowerCase())
425
+ .find(s => s && !GENERIC_ROUTE_BASENAMES.has(s) && !/^\[.*\]$/.test(s) && !/^\{.*\}$/.test(s));
426
+ if (contextSegment)
427
+ return `${contextSegment}/${normalizedFilename}`;
428
+ }
429
+ // Fall back to the last static segment of the endpoint's URL path.
430
+ const segments = staticPathSegments(ep.path);
431
+ return segments.at(-1) ?? normalizedFilename;
432
+ }
433
+ function endpointMovedKey(path, resource, method) {
434
+ return method ? `${path}::${resource}::${method}` : `${path}::${resource}`;
435
+ }
419
436
  export function classifyEndpointsByChangedFiles(diffData, scannedEndpoints, deletedFileEndpoints) {
420
437
  const newFileSet = new Set(diffData.newFiles.map(normalizeSourcePath));
421
438
  const deletedFileSet = new Set(diffData.deletedFiles.map(normalizeSourcePath));
422
- // Build sourceFile -> ScannedEndpoint[] map from the post-change catalog.
423
- // Git diffs use POSIX separators; scanner output can reflect OS-native paths.
424
439
  const bySourceFile = new Map();
425
440
  for (const ep of scannedEndpoints) {
426
441
  const sourceKey = normalizeSourcePath(ep.sourceFile);
@@ -435,7 +450,6 @@ export function classifyEndpointsByChangedFiles(diffData, scannedEndpoints, dele
435
450
  const unmatchedFiles = [];
436
451
  for (const file of diffData.changedFiles) {
437
452
  const fileKey = normalizeSourcePath(file);
438
- // Deleted files won't appear in scanned catalog — handled separately below
439
453
  if (deletedFileSet.has(fileKey))
440
454
  continue;
441
455
  const eps = bySourceFile.get(fileKey);
@@ -454,47 +468,26 @@ export function classifyEndpointsByChangedFiles(diffData, scannedEndpoints, dele
454
468
  // Filter out endpoints that still exist in the current catalog as moved/refactored.
455
469
  // Same router-relative paths can exist in sibling files, so only treat them as moved
456
470
  // when the source resource also matches.
457
- function endpointSourceResource(ep) {
458
- const sourceSegments = ep.sourceFile.split(/[\\/]/).filter(Boolean);
459
- const base = sourceSegments.at(-1)?.replace(/\.[^.]+$/, "") ?? "";
460
- const normalizedBase = base.replace(/^(?:old|new)[-_]/i, "").toLowerCase();
461
- const isDynamicBase = /^\[.*\]$/.test(normalizedBase) || /^\{.*\}$/.test(normalizedBase);
462
- if (normalizedBase && !isDynamicBase && !GENERIC_ROUTE_BASENAMES.has(normalizedBase)) {
463
- return normalizedBase;
464
- }
465
- if (normalizedBase && GENERIC_ROUTE_BASENAMES.has(normalizedBase)) {
466
- const contextSegment = [...sourceSegments]
467
- .slice(0, -1)
468
- .reverse()
469
- .map((segment) => segment.replace(/\.[^.]+$/, "").replace(/^(?:old|new)[-_]/i, "").toLowerCase())
470
- .find((segment) => segment && !GENERIC_ROUTE_BASENAMES.has(segment) && !/^\[.*\]$/.test(segment) && !/^\{.*\}$/.test(segment));
471
- if (contextSegment)
472
- return `${contextSegment}/${normalizedBase}`;
473
- }
474
- const staticSegments = ep.path.split("/").filter(Boolean).filter((segment) => !/^[:{[]/.test(segment));
475
- return staticSegments[staticSegments.length - 1]?.toLowerCase() ?? normalizedBase;
476
- }
477
471
  const currentMethodKeys = new Set();
478
472
  const currentPathResourceKeys = new Set();
479
473
  const currentMultiKeys = new Set();
480
- const movedKey = (path, resource, method) => method ? `${path}::${resource}::${method}` : `${path}::${resource}`;
481
474
  for (const current of scannedEndpoints) {
482
475
  const currentResource = endpointSourceResource(current);
483
- const pathResourceKey = movedKey(current.path, currentResource);
476
+ const pathResourceKey = endpointMovedKey(current.path, currentResource);
484
477
  currentPathResourceKeys.add(pathResourceKey);
485
478
  for (const method of current.methods) {
486
479
  if (method === "MULTI")
487
480
  currentMultiKeys.add(pathResourceKey);
488
- currentMethodKeys.add(movedKey(current.path, currentResource, method));
481
+ currentMethodKeys.add(endpointMovedKey(current.path, currentResource, method));
489
482
  }
490
483
  }
491
484
  function isMovedEndpoint(deleted, method) {
492
485
  const deletedResource = endpointSourceResource(deleted);
493
- const pathResourceKey = movedKey(deleted.path, deletedResource);
486
+ const pathResourceKey = endpointMovedKey(deleted.path, deletedResource);
494
487
  if (method === "MULTI")
495
488
  return currentPathResourceKeys.has(pathResourceKey);
496
489
  return currentMultiKeys.has(pathResourceKey) ||
497
- currentMethodKeys.has(movedKey(deleted.path, deletedResource, method));
490
+ currentMethodKeys.has(endpointMovedKey(deleted.path, deletedResource, method));
498
491
  }
499
492
  const removedEndpoints = (deletedFileEndpoints ?? [])
500
493
  .map((ep) => ({
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,71 @@
1
+ import { DraftedScenario } from "../types/RepositoryAnalysis.js";
2
+ import { WorkspaceAuthType } from "./workspaceAuth.js";
3
+ export declare function isRealResource(r: string): boolean;
4
+ type MethodInput = string | {
5
+ method: string;
6
+ sourceFile?: string;
7
+ interactions?: Array<{
8
+ request?: {
9
+ body?: Record<string, unknown>;
10
+ };
11
+ }>;
12
+ };
13
+ type EndpointInput = {
14
+ path: string;
15
+ methods: Array<MethodInput>;
16
+ };
17
+ type EndpointRef = {
18
+ method: string;
19
+ path: string;
20
+ sourceFile?: string;
21
+ };
22
+ type ScenarioDraftOptions = {
23
+ /** Existing endpoints touched by a security/destructive diff; used only for attack-surface expansion. */
24
+ changedEndpoints?: Array<EndpointRef>;
25
+ /** Gate sibling destructive expansion to diffs with auth/permission/admin-key signals. */
26
+ securityRelevantDiff?: boolean;
27
+ };
28
+ export type ResourceRelationships = Map<string, Set<string>>;
29
+ /**
30
+ * Infer parent→child resource relationships from two signals already present
31
+ * in the endpoint data — no source code scanning required.
32
+ *
33
+ * Signal 1 — path nesting (always available):
34
+ * /collections/{id}/links → links depends on collections
35
+ *
36
+ * Signal 2 — request body FK fields (available when trace data is merged):
37
+ * POST /orders body: { product_id: "..." } → orders depends on products
38
+ *
39
+ * Returns a map of `dependent → Set<parent>`. Only confirmed, real-resource
40
+ * pairs are included. When no signal is found the map is empty, which tells
41
+ * the caller to fall back to heuristic pairing.
42
+ */
43
+ export declare function inferResourceRelationships(endpoints: Array<EndpointInput>): ResourceRelationships;
44
+ export declare function draftScenariosFromEndpoints(endpoints: Array<EndpointInput>, newEndpoints?: Array<EndpointRef>, wsAuthType?: WorkspaceAuthType, options?: ScenarioDraftOptions, removedEndpoints?: Array<EndpointRef>): DraftedScenario[];
45
+ /**
46
+ * Draft scenarios that directly test each new endpoint in the branch diff.
47
+ *
48
+ * For each new endpoint, method-specific scenarios are produced:
49
+ * PUT/PATCH → mutation-recalc integration, boundary-values integration, contract, not-found
50
+ * POST → lifecycle integration (create + optional GET), contract, validation error
51
+ * DELETE → lifecycle integration (create + delete + 404), contract
52
+ * GET /{id} → contract, not-found
53
+ * GET /coll → contract + collection-list integration (create-then-GET) or contract-only
54
+ *
55
+ * Additionally, PUT/PATCH/DELETE methods get an auth-boundary scenario
56
+ * (category "security_boundary" → HIGH priority, not CRITICAL) so it
57
+ * lands in ADDITIONAL deterministically instead of depending on LLM
58
+ * supplement. GET is excluded (often public); POST is excluded because
59
+ * the security-boundary supplement tier covers it. Exception: execution
60
+ * endpoints (/execute, /run, /trigger, etc.) include auth-boundary for
61
+ * all non-GET methods (including POST) since they are high-value targets.
62
+ */
63
+ export declare function draftDiffDirectScenarios(newEndpoints: Array<{
64
+ method: string;
65
+ path: string;
66
+ }>, resourceGroups: Map<string, {
67
+ basePath: string;
68
+ methods: Set<string>;
69
+ paramPath?: string;
70
+ }>, wsAuthType?: WorkspaceAuthType): DraftedScenario[];
71
+ export {};
@@ -142,7 +142,7 @@ export function inferResourceRelationships(endpoints) {
142
142
  }
143
143
  return relationships;
144
144
  }
145
- export function draftScenariosFromEndpoints(endpoints, newEndpoints = [], wsAuthType, options = {}) {
145
+ export function draftScenariosFromEndpoints(endpoints, newEndpoints = [], wsAuthType, options = {}, removedEndpoints = []) {
146
146
  const scenarios = [];
147
147
  const resourceGroups = new Map();
148
148
  for (const ep of endpoints) {
@@ -191,6 +191,28 @@ export function draftScenariosFromEndpoints(endpoints, newEndpoints = [], wsAuth
191
191
  }
192
192
  scenarios.push(...draftDiffDirectScenarios(newEndpoints, resourceGroups, wsAuthType));
193
193
  scenarios.push(...draftAttackSurfaceExpansionScenarios(endpoints, options.changedEndpoints ?? [], wsAuthType, options.securityRelevantDiff ?? false));
194
+ // 404-guard scenarios for removed endpoints — absence assertions confirming
195
+ // the endpoint is gone. Single-step contract tests, no chaining needed.
196
+ for (const ep of removedEndpoints) {
197
+ scenarios.push({
198
+ scenarioName: `verify-removed-${ep.method.toLowerCase()}-${ep.path.replace(/[^a-z0-9]+/gi, "-").replace(/^-|-$/g, "")}`,
199
+ description: `Verify ${ep.method} ${ep.path} returns 404 — endpoint was removed in this PR`,
200
+ category: "breaking_change",
201
+ priority: "high",
202
+ steps: [{
203
+ order: 1,
204
+ method: ep.method,
205
+ path: ep.path,
206
+ description: `${ep.method} ${ep.path} → 404 (endpoint removed)`,
207
+ interactionType: "error",
208
+ expectedStatusCode: 404,
209
+ }],
210
+ chainingKeys: [],
211
+ requiresAuth: false,
212
+ estimatedComplexity: "simple",
213
+ source: ScenarioSource.CodeInferred,
214
+ });
215
+ }
194
216
  return capScenarios(scenarios);
195
217
  }
196
218
  const MAX_TOTAL_SCENARIOS = 30;
@@ -0,0 +1 @@
1
+ export {};