@skyramp/mcp 0.3.2-rc.pom-4 → 0.3.3

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 (256) hide show
  1. package/build/adapters/jestAdapter.d.ts +14 -0
  2. package/build/adapters/jestAdapter.js +113 -0
  3. package/build/adapters/mochaAdapter.d.ts +13 -0
  4. package/build/adapters/mochaAdapter.js +87 -0
  5. package/build/adapters/playwrightAdapter.d.ts +17 -0
  6. package/build/adapters/playwrightAdapter.js +182 -0
  7. package/build/adapters/pytestAdapter.d.ts +15 -0
  8. package/build/adapters/pytestAdapter.js +108 -0
  9. package/build/commands/commandLibrary.d.ts +1 -0
  10. package/build/commands/commandLibrary.js +19 -13
  11. package/build/commands/localDevTestChangesCommand.d.ts +15 -0
  12. package/build/commands/localDevTestChangesCommand.js +201 -0
  13. package/build/index.js +129 -8
  14. package/build/playwright/PlaywrightTraceService.d.ts +8 -0
  15. package/build/playwright/PlaywrightTraceService.js +1 -0
  16. package/build/prompts/code-reuse.js +3 -0
  17. package/build/prompts/enhance-assertions/sharedAssertionRules.d.ts +1 -0
  18. package/build/prompts/enhance-assertions/sharedAssertionRules.js +17 -0
  19. package/build/prompts/initialize-workspace/initializeWorkspacePrompt.js +11 -9
  20. package/build/prompts/local-dev/local-dev-plan.d.ts +35 -0
  21. package/build/prompts/local-dev/local-dev-plan.js +429 -0
  22. package/build/prompts/local-dev/local-dev-prompts.d.ts +4 -0
  23. package/build/prompts/local-dev/local-dev-prompts.js +190 -0
  24. package/build/prompts/pom-aware-code-reuse.js +17 -8
  25. package/build/prompts/prompt-utils.d.ts +8 -0
  26. package/build/prompts/prompt-utils.js +33 -0
  27. package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.js +70 -7
  28. package/build/prompts/sut-setup/modes/dockerComposePrompt.js +1 -1
  29. package/build/prompts/sut-setup/shared.js +19 -17
  30. package/build/prompts/test-maintenance/drift-analysis-prompt.d.ts +10 -1
  31. package/build/prompts/test-maintenance/drift-analysis-prompt.js +54 -1
  32. package/build/prompts/test-recommendation/analysisOutputPrompt.js +21 -29
  33. package/build/prompts/test-recommendation/scopeAssessment.d.ts +5 -2
  34. package/build/prompts/test-recommendation/scopeAssessment.js +78 -6
  35. package/build/prompts/test-recommendation/test-recommendation-prompt.js +41 -4
  36. package/build/prompts/testbot/testbot-prompts.d.ts +2 -17
  37. package/build/prompts/testbot/testbot-prompts.js +63 -60
  38. package/build/recommendation/planRanker.d.ts +15 -2
  39. package/build/recommendation/planRanker.js +76 -5
  40. package/build/resources/testbotResource.js +23 -5
  41. package/build/services/AnalyticsService.d.ts +1 -1
  42. package/build/services/TestExecutionService.d.ts +15 -9
  43. package/build/services/TestExecutionService.js +56 -28
  44. package/build/services/TestGenerationService.d.ts +2 -2
  45. package/build/services/TestGenerationService.js +39 -21
  46. package/build/services/containerEnv.js +27 -1
  47. package/build/tool-phases.js +7 -0
  48. package/build/tools/code-refactor/codeReuseTool.js +43 -4
  49. package/build/tools/code-refactor/enhanceAssertionsTool.js +68 -18
  50. package/build/tools/code-refactor/reuse-outcome.d.ts +109 -0
  51. package/build/tools/code-refactor/reuse-outcome.js +158 -0
  52. package/build/tools/code-refactor/reuse-state.d.ts +45 -0
  53. package/build/tools/code-refactor/reuse-state.js +140 -0
  54. package/build/tools/enrichTestWithMocksTool.d.ts +28 -0
  55. package/build/tools/enrichTestWithMocksTool.js +726 -0
  56. package/build/tools/executeSkyrampTestTool.d.ts +11 -0
  57. package/build/tools/executeSkyrampTestTool.js +62 -21
  58. package/build/tools/generate-tests/batchMockGenerationTool.d.ts +106 -0
  59. package/build/tools/generate-tests/batchMockGenerationTool.js +545 -0
  60. package/build/tools/generate-tests/generateBatchScenarioRestTool.js +25 -23
  61. package/build/tools/generate-tests/generateContractRestTool.js +2 -2
  62. package/build/tools/generate-tests/generateE2ERestTool.d.ts +1 -1
  63. package/build/tools/generate-tests/generateE2ERestTool.js +1 -1
  64. package/build/tools/generate-tests/generateLoadRestTool.d.ts +1 -1
  65. package/build/tools/generate-tests/generateLoadRestTool.js +1 -1
  66. package/build/tools/generate-tests/generateMockRestTool.d.ts +179 -6
  67. package/build/tools/generate-tests/generateMockRestTool.js +391 -22
  68. package/build/tools/generate-tests/loadTestSchema.d.ts +1 -1
  69. package/build/tools/generate-tests/planGuard.js +2 -22
  70. package/build/tools/generateEnrichedIntegrationTestTool.d.ts +25 -0
  71. package/build/tools/generateEnrichedIntegrationTestTool.js +235 -0
  72. package/build/tools/localDevWorkerComposeTool.d.ts +24 -0
  73. package/build/tools/localDevWorkerComposeTool.js +264 -0
  74. package/build/tools/one-click/oneClickTool.d.ts +13 -0
  75. package/build/tools/one-click/oneClickTool.js +195 -24
  76. package/build/tools/preflightMockCheckTool.d.ts +2 -0
  77. package/build/tools/preflightMockCheckTool.js +96 -0
  78. package/build/tools/queryProxyMocksTool.d.ts +70 -0
  79. package/build/tools/queryProxyMocksTool.js +521 -0
  80. package/build/tools/runExistingTestsTool.d.ts +138 -0
  81. package/build/tools/runExistingTestsTool.js +644 -0
  82. package/build/tools/submitReportTool.js +40 -2
  83. package/build/tools/test-management/actionsTool.js +12 -2
  84. package/build/tools/test-management/analyzeChangesTool.d.ts +2 -1
  85. package/build/tools/test-management/analyzeChangesTool.js +63 -40
  86. package/build/tools/test-management/analyzeTestHealthTool.d.ts +11 -0
  87. package/build/tools/test-management/analyzeTestHealthTool.js +63 -1
  88. package/build/tools/test-management/registerTestPlanTool.js +55 -7
  89. package/build/tools/trace/startTraceCollectionTool.js +3 -3
  90. package/build/types/ExternalTestExecution.d.ts +67 -0
  91. package/build/types/ExternalTestExecution.js +8 -0
  92. package/build/types/OneClickCommands.d.ts +1 -1
  93. package/build/types/Recommendation.d.ts +20 -0
  94. package/build/types/Recommendation.js +32 -6
  95. package/build/types/RepositoryAnalysis.d.ts +131 -14
  96. package/build/types/RepositoryAnalysis.js +16 -2
  97. package/build/types/ReuseOutcome.d.ts +63 -0
  98. package/build/types/ReuseOutcome.js +33 -0
  99. package/build/types/TestAnalysis.d.ts +7 -3
  100. package/build/types/TestExecution.d.ts +1 -0
  101. package/build/types/TestTypes.d.ts +25 -7
  102. package/build/types/TestTypes.js +25 -7
  103. package/build/types/TestbotPromptOptions.d.ts +35 -0
  104. package/build/types/TestbotPromptOptions.js +1 -0
  105. package/build/types/TestbotReport.d.ts +7 -0
  106. package/build/types/index.d.ts +3 -0
  107. package/build/types/index.js +1 -0
  108. package/build/utils/AnalysisStateManager.d.ts +33 -0
  109. package/build/utils/AnalysisStateManager.js +36 -2
  110. package/build/utils/analyze-openapi.js +18 -1
  111. package/build/utils/branchDiff.d.ts +17 -1
  112. package/build/utils/branchDiff.js +99 -14
  113. package/build/utils/featureFlags.d.ts +31 -0
  114. package/build/utils/featureFlags.js +37 -0
  115. package/build/utils/frontendSelectors.js +0 -1
  116. package/build/utils/gitStaging.d.ts +5 -0
  117. package/build/utils/gitStaging.js +1 -1
  118. package/build/utils/grpcMockValidation.d.ts +1 -0
  119. package/build/utils/grpcMockValidation.js +49 -0
  120. package/build/utils/httpMethodValidation.d.ts +4 -0
  121. package/build/utils/httpMethodValidation.js +15 -0
  122. package/build/utils/logger.js +1 -1
  123. package/build/utils/mockCompatibility.d.ts +49 -0
  124. package/build/utils/mockCompatibility.js +82 -0
  125. package/build/utils/pom-catalog.d.ts +23 -0
  126. package/build/utils/pom-catalog.js +30 -0
  127. package/build/utils/pom-scope/pom-files.d.ts +14 -0
  128. package/build/utils/pom-scope/pom-files.js +32 -6
  129. package/build/utils/pom-scope/testIdDiscovery.d.ts +40 -0
  130. package/build/utils/pom-scope/testIdDiscovery.js +104 -0
  131. package/build/utils/pom-verify/verify.d.ts +5 -0
  132. package/build/utils/pom-verify/verify.js +1 -0
  133. package/build/utils/progress.js +10 -5
  134. package/build/utils/proxy-terminal.js +3 -3
  135. package/build/utils/reportVerification.d.ts +7 -2
  136. package/build/utils/reportVerification.js +9 -3
  137. package/build/utils/routeParsers.d.ts +3 -9
  138. package/build/utils/routeParsers.js +79 -4
  139. package/build/utils/utils.js +2 -2
  140. package/build/utils/versions.d.ts +4 -3
  141. package/build/utils/versions.js +3 -1
  142. package/build/utils/workspaceAuth.d.ts +46 -0
  143. package/build/utils/workspaceAuth.js +156 -1
  144. package/build/workspace/frameworks.d.ts +11 -0
  145. package/build/workspace/frameworks.js +22 -0
  146. package/build/workspace/testSuites.d.ts +20 -0
  147. package/build/workspace/testSuites.js +17 -0
  148. package/build/workspace/workspace.d.ts +206 -24
  149. package/build/workspace/workspace.js +52 -2
  150. package/node_modules/playwright/ThirdPartyNotices.txt +319 -266
  151. package/node_modules/playwright/lib/dom-analyzer/blueprint.js +154 -27
  152. package/node_modules/playwright/lib/dom-analyzer/crawler.js +2 -2
  153. package/node_modules/playwright/lib/mcp/browser/tools/pageBlueprint.js +1 -1
  154. package/node_modules/playwright/lib/mcp/browser/tools/sitemap.js +6 -2
  155. package/node_modules/playwright/lib/mcp/skyramp/loadTraceTool.js +3 -2
  156. package/node_modules/playwright/lib/mcp/skyramp/resultCode.js +4 -3
  157. package/node_modules/playwright/lib/mcp/skyramp/skyRampImport.js +15 -3
  158. package/node_modules/playwright/lib/mcp/skyramp/specImport.js +781 -0
  159. package/node_modules/playwright/lib/mcp/skyramp/traceRecordingBackend.js +14 -3
  160. package/node_modules/playwright/lib/mcp/test/resultCode.test.js +2 -1
  161. package/node_modules/playwright/lib/mcp/test/skyRampExport.js +1 -1
  162. package/node_modules/playwright/lib/mcp/test/skyRampExport.test.js +30 -0
  163. package/node_modules/playwright/lib/transform/babelBundleImpl.js +200 -199
  164. package/node_modules/playwright/node_modules/playwright-core/ThirdPartyNotices.txt +3 -3
  165. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/.package-lock.json +3 -3
  166. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/adapter/aws-lambda/handler.js +16 -25
  167. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/adapter/bun/websocket.js +3 -1
  168. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/adapter/lambda-edge/handler.js +20 -4
  169. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/adapter/aws-lambda/handler.js +16 -25
  170. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/adapter/bun/websocket.js +3 -1
  171. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/adapter/lambda-edge/handler.js +20 -4
  172. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/client/client.js +10 -1
  173. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/client/utils.js +1 -1
  174. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/helper/css/common.js +3 -1
  175. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/helper/css/index.js +9 -1
  176. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/jsx/base.js +8 -14
  177. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/jsx/components.js +41 -21
  178. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/jsx/context.js +131 -5
  179. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/jsx/streaming.js +9 -7
  180. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/bearer-auth/index.js +1 -1
  181. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/cache/index.js +1 -1
  182. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/compress/index.js +2 -1
  183. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/cors/index.js +2 -5
  184. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/etag/index.js +2 -1
  185. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/language/language.js +10 -32
  186. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/method-override/index.js +5 -3
  187. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/serve-static/index.js +2 -2
  188. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/timing/timing.js +3 -1
  189. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/router/trie-router/node.js +9 -0
  190. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/utils/body.js +12 -4
  191. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/utils/buffer.js +2 -1
  192. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/utils/ipaddr.js +6 -1
  193. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/validator/validator.js +3 -3
  194. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/client/client.js +10 -1
  195. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/client/utils.js +1 -1
  196. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/helper/css/common.js +3 -1
  197. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/helper/css/index.js +9 -1
  198. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/jsx/base.js +15 -15
  199. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/jsx/components.js +42 -22
  200. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/jsx/context.js +129 -5
  201. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/jsx/streaming.js +10 -8
  202. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/bearer-auth/index.js +1 -1
  203. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/cache/index.js +1 -1
  204. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/compress/index.js +2 -1
  205. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/cors/index.js +2 -5
  206. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/etag/index.js +2 -1
  207. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/language/language.js +10 -32
  208. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/method-override/index.js +5 -3
  209. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/serve-static/index.js +2 -2
  210. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/timing/timing.js +3 -1
  211. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/router/trie-router/node.js +9 -0
  212. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/adapter/aws-lambda/handler.d.ts +1 -1
  213. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/adapter/lambda-edge/handler.d.ts +1 -1
  214. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/helper/websocket/index.d.ts +1 -1
  215. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/jsx/base.d.ts +1 -3
  216. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/jsx/context.d.ts +39 -0
  217. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/middleware/context-storage/index.d.ts +2 -2
  218. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/middleware/language/language.d.ts +18 -0
  219. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/utils/body.d.ts +1 -1
  220. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/utils/types.d.ts +1 -1
  221. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/utils/body.js +12 -4
  222. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/utils/buffer.js +2 -1
  223. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/utils/ipaddr.js +6 -1
  224. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/validator/validator.js +3 -3
  225. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/package.json +29 -22
  226. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/package-lock.json +3 -3
  227. package/node_modules/playwright/node_modules/playwright-core/lib/generated/pollingRecorderSource.js +1 -1
  228. package/node_modules/playwright/node_modules/playwright-core/lib/server/codegen/skyramp/jsonlReader.js +5 -1
  229. package/node_modules/playwright/node_modules/playwright-core/lib/server/codegen/skyramp/specReader.js +781 -0
  230. package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/recorderApp.js +25 -6
  231. package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/skyramp/replayEngine.js +3 -1
  232. package/node_modules/playwright/node_modules/playwright-core/lib/utils.js +2 -0
  233. package/node_modules/playwright/node_modules/playwright-core/lib/vite/htmlReport/index.html +253 -27
  234. package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/{codeMirrorModule-D0BjbCb7.js → codeMirrorModule-DtudTj_v.js} +1 -1
  235. package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/index-BpDwp16L.js +422 -0
  236. package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/index.html +1 -1
  237. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/{codeMirrorModule-Bzd72-bG.js → codeMirrorModule-FNMuBzX1.js} +1 -1
  238. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-Co9upU5h.js +1035 -0
  239. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.DXNIQ_dx.js +2 -0
  240. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.html +2 -2
  241. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.CIKB3XSv.js +5 -0
  242. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.html +2 -2
  243. package/node_modules/playwright/node_modules/playwright-core/package.json +1 -1
  244. package/node_modules/playwright/node_modules/playwright-core/src/generated/pollingRecorderSource.ts +1 -1
  245. package/node_modules/playwright/node_modules/playwright-core/src/server/codegen/skyramp/jsonlReader.ts +4 -0
  246. package/node_modules/playwright/node_modules/playwright-core/src/server/codegen/skyramp/specReader.ts +1028 -0
  247. package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/recorderApp.ts +31 -8
  248. package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/skyramp/replayEngine.ts +1 -0
  249. package/node_modules/playwright/node_modules/playwright-core/src/utils.ts +1 -0
  250. package/node_modules/playwright/package.json +1 -1
  251. package/package.json +12 -6
  252. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/tsconfig.build.tsbuildinfo +0 -1
  253. package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/index-lvTRGFx-.js +0 -193
  254. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-DzxTioTK.js +0 -809
  255. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.BGc30U3S.js +0 -2
  256. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.IaDrb29A.js +0 -5
@@ -0,0 +1,521 @@
1
+ import { z } from "zod";
2
+ import { spawn, execFile } from "child_process";
3
+ import { promisify } from "util";
4
+ import { MockProtocol } from "../types/TestTypes.js";
5
+ import { logger } from "../utils/logger.js";
6
+ const execFileAsync = promisify(execFile);
7
+ const TOOL_NAME = "skyramp_query_proxy_mocks";
8
+ // Internal safety cap on total samples fetched per protocol, guards against a
9
+ // runaway pagination loop if the worker keeps reporting hasMore.
10
+ const MAX_SAMPLES_PER_PROTOCOL = 500;
11
+ // Default worker port inside the pod (management API). See skyramp3 mgmt_api.go.
12
+ const DEFAULT_REMOTE_PORT = 35142;
13
+ // How long to wait for `kubectl port-forward` to report a bound local port.
14
+ const PORT_FORWARD_READY_TIMEOUT_MS = 15_000;
15
+ // Grace period between SIGTERM and SIGKILL when tearing a forward down.
16
+ const PORT_FORWARD_KILL_GRACE_MS = 2_000;
17
+ // Per-request timeout for the samples query so a stalled proxy can't hang the tool.
18
+ const SAMPLES_FETCH_TIMEOUT_MS = 10_000;
19
+ // Default label used by the Skyramp worker Helm chart.
20
+ const WORKER_SERVICE_SELECTOR = "app.kubernetes.io/name=skyramp-worker";
21
+ const PROTOCOLS = ["rest", "grpc", "kafka"];
22
+ // ── Pure normalizer (unit tested, no network) ────────────────────────────────
23
+ /**
24
+ * Split a gRPC full method path like "/helloworld.Greeter/SayHello" into its
25
+ * service name ("helloworld.Greeter") and method ("SayHello").
26
+ */
27
+ function parseGrpcMethod(full) {
28
+ if (!full)
29
+ return {};
30
+ const trimmed = full.replace(/^\//, "");
31
+ const slash = trimmed.lastIndexOf("/");
32
+ if (slash === -1)
33
+ return { method: trimmed };
34
+ return { service: trimmed.slice(0, slash), method: trimmed.slice(slash + 1) };
35
+ }
36
+ /**
37
+ * Derive a Kafka topic from either explicit metadata.topic or the sample path
38
+ * ("kafka-protocol/topic/orders" -> "orders").
39
+ */
40
+ function parseKafkaTopic(meta) {
41
+ if (meta.topic)
42
+ return meta.topic;
43
+ if (meta.path) {
44
+ const parts = meta.path.split("/").filter(Boolean);
45
+ return parts[parts.length - 1];
46
+ }
47
+ return undefined;
48
+ }
49
+ /**
50
+ * Combine a bare destination hostname with the separately-reported port
51
+ * (`metadata.port`) into `host:port`, which is what mock generation expects for
52
+ * the endpoint origin. Leaves the destination untouched if it already carries a
53
+ * port or if no usable port was reported.
54
+ */
55
+ export function withPort(destination, port) {
56
+ if (destination.includes(":"))
57
+ return destination;
58
+ if (!port || port <= 0)
59
+ return destination;
60
+ return `${destination}:${port}`;
61
+ }
62
+ /**
63
+ * Convert raw proxy samples for a single protocol into deduplicated mock specs
64
+ * whose fields map 1:1 onto skyramp_batch_mock_generation. Deduplication keeps
65
+ * one representative per distinct (destination, method/path/topic, status).
66
+ */
67
+ export function normalizeSamplesToMockSpecs(protocol, samples) {
68
+ const byKey = new Map();
69
+ for (const sample of samples) {
70
+ const meta = sample.metadata ?? {};
71
+ const destination = meta.destination;
72
+ if (!destination)
73
+ continue;
74
+ const host = withPort(destination, meta.port);
75
+ if (protocol === "rest") {
76
+ const scheme = meta.scheme || "http";
77
+ const path = meta.path || "";
78
+ const method = (meta.method || "GET").toUpperCase();
79
+ const statusCode = sample.response?.statusCode !== undefined
80
+ ? String(sample.response.statusCode)
81
+ : "";
82
+ const key = `${method} ${host}${path} ${statusCode}`;
83
+ if (byKey.has(key))
84
+ continue;
85
+ const requestBody = sample.request?.body;
86
+ byKey.set(key, {
87
+ protocol: MockProtocol.Rest,
88
+ endpointURL: `${scheme}://${host}${path}`,
89
+ method,
90
+ responseData: sample.response?.body || undefined,
91
+ responseStatusCode: statusCode || undefined,
92
+ requestData: requestBody || undefined,
93
+ requestAware: Boolean(requestBody),
94
+ });
95
+ }
96
+ else if (protocol === "grpc") {
97
+ const { service, method } = parseGrpcMethod(meta.method);
98
+ const key = `${host} ${meta.method || ""}`;
99
+ if (byKey.has(key))
100
+ continue;
101
+ byKey.set(key, {
102
+ protocol: MockProtocol.Grpc,
103
+ endpointURL: host,
104
+ grpcServiceName: service || meta.service || undefined,
105
+ method: method || undefined,
106
+ responseData: sample.response?.body || undefined,
107
+ requestData: sample.request?.body || undefined,
108
+ });
109
+ }
110
+ else {
111
+ // kafka
112
+ const topic = parseKafkaTopic(meta);
113
+ const isProduce = (meta.method || "").toLowerCase().includes("produce");
114
+ const key = `${host} ${topic || ""} ${isProduce ? "produce" : "consume"}`;
115
+ if (byKey.has(key))
116
+ continue;
117
+ // Kafka mocks accept exactly one of requestData (producer) or responseData
118
+ // (consumer) — never both.
119
+ const spec = {
120
+ protocol: MockProtocol.Kafka,
121
+ endpointURL: host,
122
+ kafkaTopic: topic,
123
+ };
124
+ if (isProduce) {
125
+ spec.requestData =
126
+ sample.request?.data || sample.request?.body || undefined;
127
+ }
128
+ else {
129
+ spec.responseData =
130
+ sample.response?.data || sample.response?.body || undefined;
131
+ }
132
+ byKey.set(key, spec);
133
+ }
134
+ }
135
+ return Array.from(byKey.values());
136
+ }
137
+ // ── Proxy URL normalization ──────────────────────────────────────────────────
138
+ /** Normalize a user-supplied proxy address into a scheme://host:port base. */
139
+ export function normalizeProxyBaseUrl(proxyUrl) {
140
+ let url = proxyUrl.trim();
141
+ if (!/^https?:\/\//i.test(url))
142
+ url = `http://${url}`;
143
+ const parsed = new URL(url);
144
+ // Strip any path/query — the samples endpoint is appended by the caller.
145
+ return `${parsed.protocol}//${parsed.host}`;
146
+ }
147
+ // Registry of live port-forward stop callbacks so a process-level signal can
148
+ // sweep any that are still running (see registerExitSafetyNet).
149
+ const activeForwards = new Set();
150
+ let exitHandlersRegistered = false;
151
+ function registerExitSafetyNet() {
152
+ if (exitHandlersRegistered)
153
+ return;
154
+ exitHandlersRegistered = true;
155
+ const sweep = () => {
156
+ for (const stop of Array.from(activeForwards)) {
157
+ try {
158
+ stop();
159
+ }
160
+ catch {
161
+ /* best effort */
162
+ }
163
+ }
164
+ };
165
+ process.on("exit", sweep);
166
+ process.on("SIGINT", sweep);
167
+ process.on("SIGTERM", sweep);
168
+ }
169
+ async function discoverWorkerPod(kubeconfig, namespace) {
170
+ const { stdout } = await execFileAsync("kubectl", [
171
+ "--kubeconfig",
172
+ kubeconfig,
173
+ "-n",
174
+ namespace,
175
+ "get",
176
+ "pods",
177
+ "-l",
178
+ WORKER_SERVICE_SELECTOR,
179
+ "-o",
180
+ "jsonpath={.items[0].metadata.name}",
181
+ ]);
182
+ const name = stdout.trim();
183
+ if (!name) {
184
+ throw new Error(`No pod matching '${WORKER_SERVICE_SELECTOR}' found in namespace '${namespace}'. ` +
185
+ `Pass workerService explicitly.`);
186
+ }
187
+ return name;
188
+ }
189
+ /**
190
+ * Start `kubectl port-forward` to the given target (a pod name, or "svc/<name>")
191
+ * using an OS-chosen local port (":remotePort"), resolving once kubectl reports
192
+ * the bound local port. The returned stop() kills the whole process group and is
193
+ * idempotent. Forwarding to the pod on its container port avoids depending on how
194
+ * the worker Service maps its ports (the Helm chart exposes port 80 → 35142).
195
+ */
196
+ function startPortForward(kubeconfig, namespace, target, remotePort) {
197
+ registerExitSafetyNet();
198
+ const child = spawn("kubectl", [
199
+ "--kubeconfig",
200
+ kubeconfig,
201
+ "-n",
202
+ namespace,
203
+ "port-forward",
204
+ target,
205
+ `:${remotePort}`,
206
+ ], { detached: true, stdio: ["ignore", "pipe", "pipe"] });
207
+ let stopped = false;
208
+ const stop = () => {
209
+ if (stopped)
210
+ return;
211
+ stopped = true;
212
+ activeForwards.delete(stop);
213
+ const pid = child.pid;
214
+ if (!pid)
215
+ return;
216
+ const killGroup = (signal) => {
217
+ try {
218
+ process.kill(-pid, signal);
219
+ }
220
+ catch {
221
+ // Group may already be gone, or on platforms without group semantics
222
+ // fall back to killing the direct child.
223
+ try {
224
+ child.kill(signal);
225
+ }
226
+ catch {
227
+ /* already dead */
228
+ }
229
+ }
230
+ };
231
+ killGroup("SIGTERM");
232
+ // Escalate to SIGKILL only if the process hasn't exited. child.killed just
233
+ // records that a signal was *sent* (and stays false for process-group kills
234
+ // via process.kill(-pid)), so check exitCode/signalCode for actual exit.
235
+ const timer = setTimeout(() => {
236
+ if (child.exitCode === null && child.signalCode === null)
237
+ killGroup("SIGKILL");
238
+ }, PORT_FORWARD_KILL_GRACE_MS);
239
+ timer.unref?.();
240
+ };
241
+ activeForwards.add(stop);
242
+ return new Promise((resolve, reject) => {
243
+ const timeout = setTimeout(() => {
244
+ stop();
245
+ reject(new Error(`kubectl port-forward did not become ready within ${PORT_FORWARD_READY_TIMEOUT_MS}ms`));
246
+ }, PORT_FORWARD_READY_TIMEOUT_MS);
247
+ timeout.unref?.();
248
+ let stderr = "";
249
+ child.stdout?.on("data", (chunk) => {
250
+ const text = chunk.toString();
251
+ // kubectl prints "Forwarding from 127.0.0.1:<port>" and/or "[::1]:<port>";
252
+ // accept either (some environments emit only the IPv6 line).
253
+ const match = text.match(/Forwarding from (?:127\.0\.0\.1|\[::1\]):(\d+)/);
254
+ if (match) {
255
+ clearTimeout(timeout);
256
+ resolve({ localPort: Number(match[1]), stop });
257
+ }
258
+ });
259
+ child.stderr?.on("data", (chunk) => {
260
+ stderr += chunk.toString();
261
+ });
262
+ child.on("error", (err) => {
263
+ clearTimeout(timeout);
264
+ stop();
265
+ reject(err);
266
+ });
267
+ child.on("exit", (code) => {
268
+ clearTimeout(timeout);
269
+ stop();
270
+ reject(new Error(`kubectl port-forward exited early (code ${code}): ${stderr.trim() || "no output"}`));
271
+ });
272
+ });
273
+ }
274
+ // ── Sample querying ──────────────────────────────────────────────────────────
275
+ async function queryProtocolSamples(baseUrl, protocol, pageSize, destination) {
276
+ const collected = [];
277
+ let offset = 0;
278
+ while (true) {
279
+ const params = new URLSearchParams({
280
+ protocol,
281
+ limit: String(pageSize),
282
+ offset: String(offset),
283
+ });
284
+ if (destination)
285
+ params.set("destination", destination);
286
+ const url = `${baseUrl}/skyramp/proxy/samples?${params.toString()}`;
287
+ // Bound each request so a stalled proxy connection can't hang the tool.
288
+ const res = await fetch(url, {
289
+ signal: AbortSignal.timeout(SAMPLES_FETCH_TIMEOUT_MS),
290
+ });
291
+ if (!res.ok) {
292
+ const body = await res.text().catch(() => "");
293
+ throw new Error(`GET ${url} -> ${res.status} ${body.slice(0, 200)}`);
294
+ }
295
+ const data = (await res.json());
296
+ const batch = data.samples ?? [];
297
+ collected.push(...batch);
298
+ // Stop on an empty page, an explicit hasMore=false, the internal cap, or —
299
+ // ONLY when the server reports a totalCount — once we've collected them all.
300
+ // Do NOT derive `total` from collected.length: that would make the "reached
301
+ // total" check trivially true and break pagination when totalCount is absent.
302
+ const reachedReportedTotal = typeof data.totalCount === "number" &&
303
+ collected.length >= data.totalCount;
304
+ if (batch.length === 0 ||
305
+ data.hasMore === false ||
306
+ reachedReportedTotal ||
307
+ collected.length >= MAX_SAMPLES_PER_PROTOCOL) {
308
+ break;
309
+ }
310
+ offset += batch.length;
311
+ }
312
+ return collected.slice(0, MAX_SAMPLES_PER_PROTOCOL);
313
+ }
314
+ // ── Input schema ─────────────────────────────────────────────────────────────
315
+ const inputSchema = {
316
+ proxyUrl: z
317
+ .string()
318
+ .optional()
319
+ .describe("Direct HTTP address of the Skyramp worker proxy management API, as host:port or a full URL " +
320
+ "(e.g. 'localhost:35141' or 'https://skyramp.example.com'). Also covers an ingress-controller " +
321
+ "route. Mutually exclusive with kubeconfig/namespace."),
322
+ kubeconfig: z
323
+ .string()
324
+ .optional()
325
+ .describe("Absolute path to a kubeconfig file. When set (with namespace), the tool runs `kubectl port-forward` " +
326
+ "to reach the worker in-cluster. Mutually exclusive with proxyUrl."),
327
+ namespace: z
328
+ .string()
329
+ .optional()
330
+ .describe("Kubernetes namespace where the Skyramp worker is deployed. Required with kubeconfig."),
331
+ workerService: z
332
+ .string()
333
+ .optional()
334
+ .describe(`Name of the worker Kubernetes Service to port-forward to (forwards to 'svc/<name>' at remotePort). ` +
335
+ `Optional — when omitted, the tool discovers the worker POD by label '${WORKER_SERVICE_SELECTOR}' and ` +
336
+ `forwards to it directly (avoids depending on how the Service maps its ports).`),
337
+ remotePort: z
338
+ .number()
339
+ .int()
340
+ .optional()
341
+ .describe(`Worker management API port inside the pod. Defaults to ${DEFAULT_REMOTE_PORT}.`),
342
+ protocols: z
343
+ .array(z.enum(PROTOCOLS))
344
+ .optional()
345
+ .describe("Which protocols to query. Defaults to all of rest, grpc, kafka."),
346
+ destination: z
347
+ .string()
348
+ .optional()
349
+ .describe("Optional destination filter (e.g. 'ams:4000') passed through to the samples query."),
350
+ limit: z
351
+ .number()
352
+ .int()
353
+ .positive()
354
+ .optional()
355
+ .describe("Page size per samples request (default 50). Total is capped internally."),
356
+ };
357
+ const mockSpecOutputSchema = z.object({
358
+ protocol: z.nativeEnum(MockProtocol),
359
+ endpointURL: z.string(),
360
+ method: z.string().optional(),
361
+ responseData: z.string().optional(),
362
+ responseStatusCode: z.string().optional(),
363
+ requestData: z.string().optional(),
364
+ requestAware: z.boolean().optional(),
365
+ grpcServiceName: z.string().optional(),
366
+ kafkaTopic: z.string().optional(),
367
+ });
368
+ const outputSchema = {
369
+ proxyReachable: z
370
+ .boolean()
371
+ .describe("True if the proxy was reached and queried. When false, fall back to code/OpenAPI inference."),
372
+ sampleCount: z
373
+ .number()
374
+ .describe("Total raw samples retrieved across all queried protocols."),
375
+ endpointsDiscovered: z
376
+ .number()
377
+ .describe("Number of deduplicated mock specs produced."),
378
+ mockSpecs: z
379
+ .array(mockSpecOutputSchema)
380
+ .describe("Normalized mock specs ready to pass to skyramp_batch_mock_generation."),
381
+ message: z
382
+ .string()
383
+ .optional()
384
+ .describe("Human-readable status or error detail."),
385
+ };
386
+ /**
387
+ * Validate that exactly one access mode was provided and return a normalized
388
+ * descriptor. Throws a user-facing error otherwise.
389
+ */
390
+ export function resolveAccessMode(params) {
391
+ const hasUrl = Boolean(params.proxyUrl);
392
+ const hasKube = Boolean(params.kubeconfig || params.namespace);
393
+ if (hasUrl && hasKube) {
394
+ throw new Error("Provide either proxyUrl OR kubeconfig+namespace, not both.");
395
+ }
396
+ if (!hasUrl && !hasKube) {
397
+ throw new Error("No proxy access provided. Pass proxyUrl, or kubeconfig+namespace.");
398
+ }
399
+ if (hasUrl)
400
+ return { mode: "url", proxyUrl: params.proxyUrl };
401
+ if (!params.kubeconfig || !params.namespace) {
402
+ throw new Error("Kubernetes access requires both kubeconfig and namespace.");
403
+ }
404
+ return {
405
+ mode: "kube",
406
+ kubeconfig: params.kubeconfig,
407
+ namespace: params.namespace,
408
+ };
409
+ }
410
+ export function registerQueryProxyMocksTool(server) {
411
+ server.registerTool(TOOL_NAME, {
412
+ description: "Query a running Skyramp worker proxy for recorded downstream traffic and return normalized mock specs. " +
413
+ "Use during local-dev dependency discovery when a proxy is recording real traffic: the returned mockSpecs " +
414
+ "map directly onto skyramp_batch_mock_generation (real request/response bodies and status codes) instead " +
415
+ "of code/OpenAPI inference. Access the proxy via proxyUrl (host:port or full URL, including an ingress " +
416
+ "route) OR kubeconfig+namespace (the tool runs kubectl port-forward and always tears it down). If the " +
417
+ "proxy is unreachable, proxyReachable is false and you should fall back to inference — the workflow is not " +
418
+ "aborted.",
419
+ inputSchema,
420
+ outputSchema,
421
+ }, async (params) => {
422
+ const protocols = params.protocols ?? [
423
+ ...PROTOCOLS,
424
+ ];
425
+ const pageSize = params.limit ?? 50;
426
+ const destination = params.destination;
427
+ let access;
428
+ try {
429
+ access = resolveAccessMode(params);
430
+ }
431
+ catch (err) {
432
+ const message = err instanceof Error ? err.message : String(err);
433
+ return unreachable(message);
434
+ }
435
+ let baseUrl;
436
+ let portForward;
437
+ try {
438
+ if (access.mode === "url") {
439
+ baseUrl = normalizeProxyBaseUrl(access.proxyUrl);
440
+ }
441
+ else {
442
+ // If a service name is given, forward to it (remotePort must be that
443
+ // service's port). Otherwise forward to the worker pod on its container
444
+ // port, which is independent of how the Service maps its ports.
445
+ const explicitService = params.workerService;
446
+ const target = explicitService
447
+ ? `svc/${explicitService}`
448
+ : await discoverWorkerPod(access.kubeconfig, access.namespace);
449
+ const remotePort = params.remotePort ?? DEFAULT_REMOTE_PORT;
450
+ portForward = await startPortForward(access.kubeconfig, access.namespace, target, remotePort);
451
+ baseUrl = `http://localhost:${portForward.localPort}`;
452
+ }
453
+ const allSpecs = [];
454
+ let sampleCount = 0;
455
+ for (const protocol of protocols) {
456
+ const samples = await queryProtocolSamples(baseUrl, protocol, pageSize, destination);
457
+ sampleCount += samples.length;
458
+ allSpecs.push(...normalizeSamplesToMockSpecs(protocol, samples));
459
+ }
460
+ return {
461
+ structuredContent: {
462
+ proxyReachable: true,
463
+ sampleCount,
464
+ endpointsDiscovered: allSpecs.length,
465
+ mockSpecs: allSpecs,
466
+ },
467
+ content: [
468
+ { type: "text", text: formatSummary(allSpecs, sampleCount) },
469
+ ],
470
+ };
471
+ }
472
+ catch (err) {
473
+ const message = err instanceof Error ? err.message : String(err);
474
+ logger.warning("skyramp_query_proxy_mocks failed to reach proxy", {
475
+ error: message,
476
+ });
477
+ return unreachable(message);
478
+ }
479
+ finally {
480
+ // Guaranteed teardown of the port-forward on every path.
481
+ portForward?.stop();
482
+ }
483
+ });
484
+ }
485
+ function unreachable(message) {
486
+ return {
487
+ structuredContent: {
488
+ proxyReachable: false,
489
+ sampleCount: 0,
490
+ endpointsDiscovered: 0,
491
+ mockSpecs: [],
492
+ message,
493
+ },
494
+ content: [
495
+ {
496
+ type: "text",
497
+ text: `⚠️ Proxy not queried: ${message}\n\n` +
498
+ "Fall back to OpenAPI spec / implementation-code inference for downstream mock shapes.",
499
+ },
500
+ ],
501
+ };
502
+ }
503
+ function formatSummary(specs, sampleCount) {
504
+ if (specs.length === 0) {
505
+ return `Proxy reachable but no samples recorded (queried ${sampleCount}). Fall back to code/OpenAPI inference.`;
506
+ }
507
+ const lines = specs.map((s) => {
508
+ if (s.protocol === MockProtocol.Rest) {
509
+ return ` • [rest] ${s.method} ${s.endpointURL} → ${s.responseStatusCode ?? "?"}`;
510
+ }
511
+ if (s.protocol === MockProtocol.Grpc) {
512
+ return ` • [grpc] ${s.endpointURL} ${s.grpcServiceName ?? ""}/${s.method ?? ""}`;
513
+ }
514
+ return ` • [kafka] ${s.endpointURL} topic=${s.kafkaTopic ?? "?"} ${s.requestData ? "(produce)" : "(consume)"}`;
515
+ });
516
+ return [
517
+ `✅ Proxy queried: ${sampleCount} sample(s) → ${specs.length} mock spec(s).`,
518
+ "Secrets are redacted by the proxy. Pass these specs to skyramp_batch_mock_generation:",
519
+ ...lines,
520
+ ].join("\n");
521
+ }
@@ -0,0 +1,138 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { WorkspaceConfig } from "../workspace/workspace.js";
3
+ import { ParsedExternalRun } from "../types/ExternalTestExecution.js";
4
+ import { SUPPORTED_FRAMEWORKS } from "../workspace/frameworks.js";
5
+ /** Test-run lifecycle resolved from a service's workspace.yml runtimeDetails. */
6
+ export interface ResolvedRunConfig {
7
+ serviceName: string;
8
+ framework: Framework;
9
+ testRunCommand: string;
10
+ testEnv?: Record<string, string>;
11
+ /** Repo-relative globs this suite owns; empty/absent means it accepts any selector. */
12
+ pathGlobs?: string[];
13
+ }
14
+ type Framework = (typeof SUPPORTED_FRAMEWORKS)[number];
15
+ /** Binds a framework to its pure parse/buildArgs pair + how its report is
16
+ * obtained. The generic IO shell {@link runExternalSuite} is the only place
17
+ * that spawns a process; adding a framework is a new ReaderSpec + registry entry. */
18
+ interface ReaderSpec {
19
+ framework: Framework;
20
+ /** Where the machine-readable report lands: a temp file, or the process stdout. */
21
+ outputVia: "file" | "stdout";
22
+ /** Env var pointing the reporter at the temp report path (e.g. Playwright). */
23
+ reportEnvVar?: string;
24
+ buildArgs(input: {
25
+ selectors: string[];
26
+ mode: "confirm" | "verify";
27
+ project?: string;
28
+ reportPath: string;
29
+ }): string[];
30
+ parse(report: unknown, opts: {
31
+ truncated: boolean;
32
+ }): ParsedExternalRun;
33
+ }
34
+ /** True when a framework has an execution reader (playwright/pytest/jest/vitest/mocha). */
35
+ export declare function frameworkHasReader(framework?: string): boolean;
36
+ /** Extract the last complete top-level JSON object from a stdout blob that may
37
+ * carry interleaved non-JSON (e.g. a test's console.log before mocha's json
38
+ * reporter dumps its object). Scans brace depth while respecting string/escape
39
+ * context so braces inside strings do not miscount. Throws if none found. */
40
+ export declare function extractLastJsonObject(s: string): string;
41
+ export interface RunExistingTestsParams {
42
+ workspacePath: string;
43
+ service?: string;
44
+ testSelectors?: string[];
45
+ mode?: "confirm" | "verify";
46
+ project?: string;
47
+ stateFile?: string;
48
+ repository?: string;
49
+ timeoutMs?: number;
50
+ maxTests?: number;
51
+ }
52
+ export interface PlaywrightRunOpts {
53
+ workspacePath: string;
54
+ selectors: string[];
55
+ mode: "confirm" | "verify";
56
+ project?: string;
57
+ timeoutMs?: number;
58
+ truncated: boolean;
59
+ }
60
+ /** Injectable IO seam so the orchestration in {@link runExternalTests} is unit
61
+ * testable without a real workspace file or Playwright process. */
62
+ export interface RunExistingTestsDeps {
63
+ readConfig: (workspacePath: string) => Promise<WorkspaceConfig>;
64
+ runner: (cfg: ResolvedRunConfig, opts: PlaywrightRunOpts) => Promise<ParsedExternalRun>;
65
+ now: () => string;
66
+ }
67
+ /** The routed suite list: every runnable suite to execute, plus the suites that
68
+ * were skipped (with a reason). A suite is runnable when its framework has a
69
+ * registered reader (its testRunCommand is required non-empty by the schema). */
70
+ export interface RunConfigResolution {
71
+ runs: ResolvedRunConfig[];
72
+ skips: {
73
+ service: string;
74
+ reason: string;
75
+ }[];
76
+ }
77
+ /**
78
+ * Resolves the runnable suites from workspace.yml (SKYR-4002). Enumerates every
79
+ * (service, suite) via resolveSuites; a suite is runnable when its framework has
80
+ * a registered reader (Playwright, pytest, jest, vitest, Mocha) — testRunCommand
81
+ * is required non-empty by the schema. Suites whose framework has no reader become
82
+ * skips-with-reason (never a throw). Every runnable suite runs. Throws only for an
83
+ * explicitly-named unknown service.
84
+ */
85
+ export declare function resolveRunConfig(config: WorkspaceConfig, opts?: {
86
+ service?: string;
87
+ }): RunConfigResolution;
88
+ /** Selectors partitioned into those this suite owns and those it does not. */
89
+ export interface SelectorRouting {
90
+ kept: string[];
91
+ dropped: string[];
92
+ }
93
+ /**
94
+ * Partitions `selectors` into the ones this suite owns and the ones it does not,
95
+ * using the suite's own `pathGlobs` from workspace.yml.
96
+ *
97
+ * One repo commonly hosts several runners (mocha for a core package, vitest for
98
+ * app packages, Playwright for e2e), and handing a runner another runner's spec is
99
+ * not a test failure — it is a loader crash that yields no report at all. Which
100
+ * suite owns which paths is a fact about the repo, so it is recorded as config the
101
+ * user can read and correct, rather than guessed at run time. Run 30297865488 is
102
+ * the cautionary case: routing on a guessed framework tag sent Ghost's Playwright
103
+ * specs away from the Playwright suite, and nothing ran.
104
+ *
105
+ * A suite with no globs owns everything. That is deliberate: absent globs means
106
+ * the suite is unscoped, not that it owns nothing, and narrowing on no
107
+ * information would silently shrink the run.
108
+ */
109
+ export declare function routeSelectorsToSuite(input: {
110
+ selectors: string[];
111
+ /** The suite's repo-relative globs; absent/empty means it accepts every selector. */
112
+ pathGlobs?: string[];
113
+ /** Absolute test-file paths from analyze_changes, used to canonicalize a selector. */
114
+ knownTestFiles?: string[];
115
+ workspacePath: string;
116
+ }): SelectorRouting;
117
+ /** Combines per-suite runs into one ParsedExternalRun for the tool's summary
118
+ * text: sums counts, concatenates results, ANDs environmentHealthy, joins the
119
+ * unhealthy details. */
120
+ export declare function aggregateRuns(parsed: ParsedExternalRun[]): ParsedExternalRun;
121
+ /**
122
+ * Generic IO shell for every framework reader: append the reporter + scoped
123
+ * selectors to the suite's `testRunCommand`, spawn it via bash (so a wrapper
124
+ * entrypoint's `exec "$@"` receives the flags), read the machine-readable
125
+ * report (temp file or captured stdout), and hand it to `spec.parse`. A missing
126
+ * or unparseable report is the exit-code rung: `environmentHealthy:false` with
127
+ * the stderr tail — never PR signal, never throws.
128
+ */
129
+ export declare function runExternalSuite(spec: ReaderSpec, cfg: ResolvedRunConfig, opts: PlaywrightRunOpts): Promise<ParsedExternalRun>;
130
+ export declare function runPlaywright(cfg: ResolvedRunConfig, opts: PlaywrightRunOpts): Promise<ParsedExternalRun>;
131
+ /**
132
+ * Orchestrates an external test run: resolve config → apply maxTests cap → run →
133
+ * persist a record to the state file. Pure of MCP/registration concerns and
134
+ * fully injectable for tests.
135
+ */
136
+ export declare function runExternalTests(params: RunExistingTestsParams, deps?: RunExistingTestsDeps): Promise<ParsedExternalRun>;
137
+ export declare function registerRunExistingTestsTool(server: McpServer): void;
138
+ export {};