@skyramp/mcp 0.3.2-rc.pom-3 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. package/build/commands/commandLibrary.d.ts +1 -0
  2. package/build/commands/commandLibrary.js +19 -13
  3. package/build/commands/localDevTestChangesCommand.d.ts +15 -0
  4. package/build/commands/localDevTestChangesCommand.js +201 -0
  5. package/build/index.js +80 -6
  6. package/build/prompts/code-reuse.js +3 -0
  7. package/build/prompts/enhance-assertions/sharedAssertionRules.d.ts +1 -0
  8. package/build/prompts/enhance-assertions/sharedAssertionRules.js +17 -0
  9. package/build/prompts/initialize-workspace/initializeWorkspacePrompt.js +11 -9
  10. package/build/prompts/local-dev/local-dev-plan.d.ts +35 -0
  11. package/build/prompts/local-dev/local-dev-plan.js +429 -0
  12. package/build/prompts/local-dev/local-dev-prompts.d.ts +4 -0
  13. package/build/prompts/local-dev/local-dev-prompts.js +190 -0
  14. package/build/prompts/pom-aware-code-reuse.js +12 -0
  15. package/build/prompts/prompt-utils.d.ts +8 -0
  16. package/build/prompts/prompt-utils.js +33 -0
  17. package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.js +37 -14
  18. package/build/prompts/sut-setup/shared.js +16 -12
  19. package/build/prompts/test-recommendation/analysisOutputPrompt.js +21 -29
  20. package/build/prompts/test-recommendation/scopeAssessment.d.ts +24 -7
  21. package/build/prompts/test-recommendation/scopeAssessment.js +111 -12
  22. package/build/prompts/test-recommendation/test-recommendation-prompt.js +41 -4
  23. package/build/prompts/testbot/testbot-prompts.d.ts +0 -5
  24. package/build/prompts/testbot/testbot-prompts.js +32 -52
  25. package/build/recommendation/planRanker.d.ts +15 -2
  26. package/build/recommendation/planRanker.js +76 -5
  27. package/build/resources/testbotResource.js +2 -1
  28. package/build/services/AnalyticsService.d.ts +1 -1
  29. package/build/services/TestExecutionService.d.ts +2 -1
  30. package/build/services/TestExecutionService.js +8 -3
  31. package/build/services/TestGenerationService.d.ts +2 -2
  32. package/build/services/TestGenerationService.js +39 -21
  33. package/build/services/containerEnv.js +3 -1
  34. package/build/tool-phases.js +6 -0
  35. package/build/tools/code-refactor/codeReuseTool.js +43 -4
  36. package/build/tools/code-refactor/enhanceAssertionsTool.js +68 -18
  37. package/build/tools/code-refactor/reuse-outcome.d.ts +109 -0
  38. package/build/tools/code-refactor/reuse-outcome.js +158 -0
  39. package/build/tools/code-refactor/reuse-state.d.ts +45 -0
  40. package/build/tools/code-refactor/reuse-state.js +140 -0
  41. package/build/tools/enrichTestWithMocksTool.d.ts +28 -0
  42. package/build/tools/enrichTestWithMocksTool.js +726 -0
  43. package/build/tools/executeSkyrampTestTool.d.ts +11 -0
  44. package/build/tools/executeSkyrampTestTool.js +62 -21
  45. package/build/tools/generate-tests/batchMockGenerationTool.d.ts +106 -0
  46. package/build/tools/generate-tests/batchMockGenerationTool.js +545 -0
  47. package/build/tools/generate-tests/generateBatchScenarioRestTool.js +25 -23
  48. package/build/tools/generate-tests/generateContractRestTool.js +2 -2
  49. package/build/tools/generate-tests/generateE2ERestTool.d.ts +1 -1
  50. package/build/tools/generate-tests/generateE2ERestTool.js +1 -1
  51. package/build/tools/generate-tests/generateLoadRestTool.d.ts +1 -1
  52. package/build/tools/generate-tests/generateLoadRestTool.js +1 -1
  53. package/build/tools/generate-tests/generateMockRestTool.d.ts +179 -6
  54. package/build/tools/generate-tests/generateMockRestTool.js +391 -22
  55. package/build/tools/generate-tests/loadTestSchema.d.ts +1 -1
  56. package/build/tools/generate-tests/planGuard.js +2 -22
  57. package/build/tools/generateEnrichedIntegrationTestTool.d.ts +25 -0
  58. package/build/tools/generateEnrichedIntegrationTestTool.js +235 -0
  59. package/build/tools/localDevWorkerComposeTool.d.ts +24 -0
  60. package/build/tools/localDevWorkerComposeTool.js +264 -0
  61. package/build/tools/one-click/oneClickTool.d.ts +13 -0
  62. package/build/tools/one-click/oneClickTool.js +195 -24
  63. package/build/tools/preflightMockCheckTool.d.ts +2 -0
  64. package/build/tools/preflightMockCheckTool.js +96 -0
  65. package/build/tools/queryProxyMocksTool.d.ts +70 -0
  66. package/build/tools/queryProxyMocksTool.js +522 -0
  67. package/build/tools/runExistingTestsTool.d.ts +31 -0
  68. package/build/tools/runExistingTestsTool.js +214 -13
  69. package/build/tools/submitReportTool.js +38 -3
  70. package/build/tools/test-management/analyzeChangesTool.d.ts +2 -1
  71. package/build/tools/test-management/analyzeChangesTool.js +63 -40
  72. package/build/tools/test-management/registerTestPlanTool.js +55 -7
  73. package/build/tools/trace/startTraceCollectionTool.js +3 -3
  74. package/build/types/FrontendIntegration.d.ts +3 -0
  75. package/build/types/FrontendIntegration.js +3 -0
  76. package/build/types/OneClickCommands.d.ts +1 -1
  77. package/build/types/Recommendation.d.ts +20 -0
  78. package/build/types/Recommendation.js +32 -6
  79. package/build/types/RepositoryAnalysis.d.ts +131 -14
  80. package/build/types/RepositoryAnalysis.js +16 -2
  81. package/build/types/ReuseOutcome.d.ts +63 -0
  82. package/build/types/ReuseOutcome.js +33 -0
  83. package/build/types/TestExecution.d.ts +1 -0
  84. package/build/types/TestTypes.d.ts +25 -7
  85. package/build/types/TestTypes.js +22 -6
  86. package/build/types/TestbotReport.d.ts +7 -0
  87. package/build/types/index.d.ts +2 -0
  88. package/build/types/index.js +1 -0
  89. package/build/utils/AnalysisStateManager.d.ts +26 -0
  90. package/build/utils/AnalysisStateManager.js +31 -1
  91. package/build/utils/analyze-openapi.js +18 -1
  92. package/build/utils/branchDiff.d.ts +17 -1
  93. package/build/utils/branchDiff.js +99 -14
  94. package/build/utils/featureFlags.d.ts +31 -0
  95. package/build/utils/featureFlags.js +37 -0
  96. package/build/utils/frontendIntegration.js +8 -1
  97. package/build/utils/grpcMockValidation.d.ts +1 -0
  98. package/build/utils/grpcMockValidation.js +49 -0
  99. package/build/utils/httpMethodValidation.d.ts +4 -0
  100. package/build/utils/httpMethodValidation.js +15 -0
  101. package/build/utils/logger.js +1 -1
  102. package/build/utils/mockCompatibility.d.ts +49 -0
  103. package/build/utils/mockCompatibility.js +82 -0
  104. package/build/utils/pom-scope/pom-files.js +7 -0
  105. package/build/utils/pom-verify/bindings.js +11 -1
  106. package/build/utils/pom-verify/re-exports.d.ts +10 -0
  107. package/build/utils/pom-verify/re-exports.js +61 -0
  108. package/build/utils/pom-verify/resolve.d.ts +4 -1
  109. package/build/utils/pom-verify/resolve.js +7 -4
  110. package/build/utils/pom-verify/verify.d.ts +5 -0
  111. package/build/utils/pom-verify/verify.js +25 -3
  112. package/build/utils/progress.js +10 -5
  113. package/build/utils/proxy-terminal.js +3 -3
  114. package/build/utils/routeParsers.d.ts +3 -9
  115. package/build/utils/routeParsers.js +79 -4
  116. package/build/utils/utils.js +2 -2
  117. package/build/utils/versions.d.ts +4 -3
  118. package/build/utils/versions.js +3 -1
  119. package/build/utils/workspaceAuth.d.ts +46 -0
  120. package/build/utils/workspaceAuth.js +156 -1
  121. package/build/workspace/testSuites.d.ts +2 -1
  122. package/build/workspace/testSuites.js +1 -1
  123. package/build/workspace/workspace.d.ts +108 -32
  124. package/build/workspace/workspace.js +32 -4
  125. package/package.json +5 -2
  126. package/build/adapters/jestAdapter.test.d.ts +0 -1
  127. package/build/adapters/jestAdapter.test.js +0 -93
  128. package/build/adapters/mochaAdapter.test.d.ts +0 -1
  129. package/build/adapters/mochaAdapter.test.js +0 -63
  130. package/build/adapters/playwrightAdapter.test.d.ts +0 -1
  131. package/build/adapters/playwrightAdapter.test.js +0 -169
  132. package/build/adapters/pytestAdapter.test.d.ts +0 -1
  133. package/build/adapters/pytestAdapter.test.js +0 -90
  134. package/build/prompts/code-reuse.test.d.ts +0 -1
  135. package/build/prompts/code-reuse.test.js +0 -62
  136. package/build/prompts/pom-aware-code-reuse.test.d.ts +0 -1
  137. package/build/prompts/pom-aware-code-reuse.test.js +0 -11
  138. package/build/prompts/test-maintenance/drift-analysis-prompt.test.d.ts +0 -1
  139. package/build/prompts/test-maintenance/drift-analysis-prompt.test.js +0 -51
  140. package/build/prompts/test-recommendation/analysisOutputPrompt.test.d.ts +0 -1
  141. package/build/prompts/test-recommendation/analysisOutputPrompt.test.js +0 -264
  142. package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.d.ts +0 -1
  143. package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.js +0 -126
  144. package/build/prompts/test-recommendation/promptPlan.test.d.ts +0 -1
  145. package/build/prompts/test-recommendation/promptPlan.test.js +0 -336
  146. package/build/prompts/test-recommendation/scopeAssessment.test.d.ts +0 -1
  147. package/build/prompts/test-recommendation/scopeAssessment.test.js +0 -371
  148. package/build/prompts/test-recommendation/test-recommendation-prompt.test.d.ts +0 -1
  149. package/build/prompts/test-recommendation/test-recommendation-prompt.test.js +0 -1925
  150. package/build/prompts/testbot/testbot-prompts.test.d.ts +0 -1
  151. package/build/prompts/testbot/testbot-prompts.test.js +0 -451
  152. package/build/recommendation/budgeters/diversityBalancedBudgeter.test.d.ts +0 -1
  153. package/build/recommendation/budgeters/diversityBalancedBudgeter.test.js +0 -138
  154. package/build/recommendation/budgeters/fixedNBudgeter.test.d.ts +0 -1
  155. package/build/recommendation/budgeters/fixedNBudgeter.test.js +0 -66
  156. package/build/recommendation/discriminators.test.d.ts +0 -1
  157. package/build/recommendation/discriminators.test.js +0 -324
  158. package/build/recommendation/diversity.test.d.ts +0 -1
  159. package/build/recommendation/diversity.test.js +0 -77
  160. package/build/recommendation/planRanker.test.d.ts +0 -1
  161. package/build/recommendation/planRanker.test.js +0 -110
  162. package/build/resources/testbotResource.test.d.ts +0 -1
  163. package/build/resources/testbotResource.test.js +0 -44
  164. package/build/services/AnalyticsService.test.d.ts +0 -1
  165. package/build/services/AnalyticsService.test.js +0 -86
  166. package/build/services/ScenarioGenerationService.integration.test.d.ts +0 -1
  167. package/build/services/ScenarioGenerationService.integration.test.js +0 -162
  168. package/build/services/ScenarioGenerationService.test.d.ts +0 -1
  169. package/build/services/ScenarioGenerationService.test.js +0 -414
  170. package/build/services/TestDiscoveryService.test.d.ts +0 -1
  171. package/build/services/TestDiscoveryService.test.js +0 -983
  172. package/build/services/TestExecutionService.test.d.ts +0 -1
  173. package/build/services/TestExecutionService.test.js +0 -1032
  174. package/build/services/TestGenerationService.test.d.ts +0 -1
  175. package/build/services/TestGenerationService.test.js +0 -578
  176. package/build/tool-phase-coverage.test.d.ts +0 -1
  177. package/build/tool-phase-coverage.test.js +0 -49
  178. package/build/tools/code-refactor/codeReuseTool.test.d.ts +0 -1
  179. package/build/tools/code-refactor/codeReuseTool.test.js +0 -572
  180. package/build/tools/generate-tests/generateBatchScenarioRestTool.test.d.ts +0 -1
  181. package/build/tools/generate-tests/generateBatchScenarioRestTool.test.js +0 -433
  182. package/build/tools/generate-tests/generateContractRestTool.test.d.ts +0 -1
  183. package/build/tools/generate-tests/generateContractRestTool.test.js +0 -142
  184. package/build/tools/generate-tests/generateIntegrationRestTool.test.d.ts +0 -1
  185. package/build/tools/generate-tests/generateIntegrationRestTool.test.js +0 -159
  186. package/build/tools/generate-tests/generateLoadRestTool.test.d.ts +0 -1
  187. package/build/tools/generate-tests/generateLoadRestTool.test.js +0 -169
  188. package/build/tools/generate-tests/generateUIRestTool.test.d.ts +0 -1
  189. package/build/tools/generate-tests/generateUIRestTool.test.js +0 -32
  190. package/build/tools/generate-tests/planGuard.test.d.ts +0 -1
  191. package/build/tools/generate-tests/planGuard.test.js +0 -185
  192. package/build/tools/generate-tests/scenarioLint.test.d.ts +0 -1
  193. package/build/tools/generate-tests/scenarioLint.test.js +0 -100
  194. package/build/tools/runExistingTestsTool.test.d.ts +0 -1
  195. package/build/tools/runExistingTestsTool.test.js +0 -379
  196. package/build/tools/submitReportTool.test.d.ts +0 -1
  197. package/build/tools/submitReportTool.test.js +0 -1428
  198. package/build/tools/test-management/actionsTool.test.d.ts +0 -1
  199. package/build/tools/test-management/actionsTool.test.js +0 -436
  200. package/build/tools/test-management/analyzeChangesTool.test.d.ts +0 -1
  201. package/build/tools/test-management/analyzeChangesTool.test.js +0 -522
  202. package/build/tools/test-management/analyzeTestHealthTool.test.d.ts +0 -1
  203. package/build/tools/test-management/analyzeTestHealthTool.test.js +0 -385
  204. package/build/tools/test-management/registerTestPlanTool.test.d.ts +0 -1
  205. package/build/tools/test-management/registerTestPlanTool.test.js +0 -296
  206. package/build/tools/trace/resolveSaveStoragePath.test.d.ts +0 -1
  207. package/build/tools/trace/resolveSaveStoragePath.test.js +0 -17
  208. package/build/tools/trace/resolveSessionPaths.test.d.ts +0 -1
  209. package/build/tools/trace/resolveSessionPaths.test.js +0 -104
  210. package/build/tools/trace/sessionState.test.d.ts +0 -1
  211. package/build/tools/trace/sessionState.test.js +0 -17
  212. package/build/tools/workspace/initializeWorkspaceTool.test.d.ts +0 -1
  213. package/build/tools/workspace/initializeWorkspaceTool.test.js +0 -139
  214. package/build/tools/workspace/serviceUpsert.test.d.ts +0 -1
  215. package/build/tools/workspace/serviceUpsert.test.js +0 -50
  216. package/build/utils/AnalysisStateManager.test.d.ts +0 -1
  217. package/build/utils/AnalysisStateManager.test.js +0 -134
  218. package/build/utils/dartRouteExtractor.test.d.ts +0 -1
  219. package/build/utils/dartRouteExtractor.test.js +0 -307
  220. package/build/utils/docker.test.d.ts +0 -1
  221. package/build/utils/docker.test.js +0 -114
  222. package/build/utils/featureFlags.test.d.ts +0 -1
  223. package/build/utils/featureFlags.test.js +0 -81
  224. package/build/utils/fileWalk.test.d.ts +0 -1
  225. package/build/utils/fileWalk.test.js +0 -252
  226. package/build/utils/frontendIntegration.test.d.ts +0 -1
  227. package/build/utils/frontendIntegration.test.js +0 -229
  228. package/build/utils/frontendSelectors.test.d.ts +0 -1
  229. package/build/utils/frontendSelectors.test.js +0 -118
  230. package/build/utils/gitStaging.test.d.ts +0 -1
  231. package/build/utils/gitStaging.test.js +0 -111
  232. package/build/utils/httpDefaults.test.d.ts +0 -1
  233. package/build/utils/httpDefaults.test.js +0 -21
  234. package/build/utils/importerHop.test.d.ts +0 -1
  235. package/build/utils/importerHop.test.js +0 -469
  236. package/build/utils/pathAffinityClassification.test.d.ts +0 -1
  237. package/build/utils/pathAffinityClassification.test.js +0 -208
  238. package/build/utils/planMatchKeys.test.d.ts +0 -1
  239. package/build/utils/planMatchKeys.test.js +0 -123
  240. package/build/utils/pom-scope/index.test.d.ts +0 -1
  241. package/build/utils/pom-scope/index.test.js +0 -278
  242. package/build/utils/pom-scope/pom-files.test.d.ts +0 -1
  243. package/build/utils/pom-scope/pom-files.test.js +0 -29
  244. package/build/utils/pom-scope/scoring.test.d.ts +0 -1
  245. package/build/utils/pom-scope/scoring.test.js +0 -39
  246. package/build/utils/pom-scope/selector-extractor.test.d.ts +0 -1
  247. package/build/utils/pom-scope/selector-extractor.test.js +0 -67
  248. package/build/utils/pom-verify/bindings.test.d.ts +0 -1
  249. package/build/utils/pom-verify/bindings.test.js +0 -164
  250. package/build/utils/pom-verify/calls.test.d.ts +0 -1
  251. package/build/utils/pom-verify/calls.test.js +0 -61
  252. package/build/utils/pom-verify/resolve.test.d.ts +0 -1
  253. package/build/utils/pom-verify/resolve.test.js +0 -114
  254. package/build/utils/pom-verify/verify.test.d.ts +0 -1
  255. package/build/utils/pom-verify/verify.test.js +0 -374
  256. package/build/utils/pr-comment-parser.test.d.ts +0 -1
  257. package/build/utils/pr-comment-parser.test.js +0 -428
  258. package/build/utils/progress.test.d.ts +0 -1
  259. package/build/utils/progress.test.js +0 -37
  260. package/build/utils/projectMetadata.test.d.ts +0 -1
  261. package/build/utils/projectMetadata.test.js +0 -172
  262. package/build/utils/pythonMountPrefixes.test.d.ts +0 -1
  263. package/build/utils/pythonMountPrefixes.test.js +0 -113
  264. package/build/utils/repoScanner.test.d.ts +0 -1
  265. package/build/utils/repoScanner.test.js +0 -190
  266. package/build/utils/reportVerification.test.d.ts +0 -1
  267. package/build/utils/reportVerification.test.js +0 -185
  268. package/build/utils/routeParsers.test.d.ts +0 -1
  269. package/build/utils/routeParsers.test.js +0 -1011
  270. package/build/utils/scenarioDrafting.test.d.ts +0 -1
  271. package/build/utils/scenarioDrafting.test.js +0 -876
  272. package/build/utils/sourceRouteExtractor.test.d.ts +0 -1
  273. package/build/utils/sourceRouteExtractor.test.js +0 -738
  274. package/build/utils/telemetry.test.d.ts +0 -1
  275. package/build/utils/telemetry.test.js +0 -70
  276. package/build/utils/trace-parser.test.d.ts +0 -6
  277. package/build/utils/trace-parser.test.js +0 -140
  278. package/build/utils/uiPageEnumerator.test.d.ts +0 -1
  279. package/build/utils/uiPageEnumerator.test.js +0 -824
  280. package/build/utils/utils.test.d.ts +0 -1
  281. package/build/utils/utils.test.js +0 -103
  282. package/build/utils/walkerCharacterization.test.d.ts +0 -1
  283. package/build/utils/walkerCharacterization.test.js +0 -233
  284. package/build/utils/workspaceAuth.test.d.ts +0 -1
  285. package/build/utils/workspaceAuth.test.js +0 -260
  286. package/build/workspace/testSuites.test.d.ts +0 -1
  287. package/build/workspace/testSuites.test.js +0 -23
  288. package/build/workspace/workspace.test.d.ts +0 -1
  289. package/build/workspace/workspace.test.js +0 -264
@@ -39,3 +39,40 @@ export function isContractConsumerModeEnabled() {
39
39
  export function isTestbotEnabled() {
40
40
  return process.env.SKYRAMP_FEATURE_TESTBOT === "1";
41
41
  }
42
+ /**
43
+ * Returns true when the local-dev workflow is enabled
44
+ * (SKYRAMP_FEATURE_LOCAL_DEV=1).
45
+ *
46
+ * The local-dev workflow registers the `skyramp_local_dev` prompt and
47
+ * one-click routing, which diffs from a base commit against the current
48
+ * working state, generates mock configurations and backend tests, executes
49
+ * them locally, and reports results — without requiring a pull request or
50
+ * CI environment.
51
+ */
52
+ export function isLocalDevEnabled() {
53
+ return process.env.SKYRAMP_FEATURE_LOCAL_DEV === "1";
54
+ }
55
+ /**
56
+ * Returns true when general one-click workflows are enabled
57
+ * (SKYRAMP_FEATURE_ONE_CLICK=1).
58
+ */
59
+ export function isOneClickEnabled() {
60
+ return process.env.SKYRAMP_FEATURE_ONE_CLICK === "1";
61
+ }
62
+ /**
63
+ * Gates the POM-aware path of `skyramp_reuse_code`
64
+ * (SKYRAMP_FEATURE_POM_REUSE=1).
65
+ *
66
+ * When OFF (default), TypeScript/JavaScript + Playwright targets are treated
67
+ * like every other target: `skyramp_reuse_code` returns the SkyrampUtils
68
+ * consolidation prompt, and none of the POM machinery runs — no deterministic
69
+ * POM pre-scoping, no POM catalog / mapping-table workflow, no `verify: true`
70
+ * compliance gates, and consequently no `reuse` summary on the report (nothing
71
+ * records an outcome to re-derive).
72
+ *
73
+ * When ON, the test is refactored against the repo's existing page objects and
74
+ * the verification gates apply.
75
+ */
76
+ export function isPomReuseEnabled() {
77
+ return process.env.SKYRAMP_FEATURE_POM_REUSE === "1";
78
+ }
@@ -26,7 +26,7 @@
26
26
  import { execFileSync } from "child_process";
27
27
  import * as fs from "fs";
28
28
  import * as path from "path";
29
- import { isTestFile } from "../prompts/test-recommendation/scopeAssessment.js";
29
+ import { isTestFile, isI18nLocaleFile } from "../prompts/test-recommendation/scopeAssessment.js";
30
30
  import { logger } from "./logger.js";
31
31
  import { walkDir } from "./fileWalk.js";
32
32
  import { buildPathSignatures } from "./pathSignatures.js";
@@ -166,6 +166,13 @@ function checkOneFile(repositoryPath, file) {
166
166
  if (isRouteOrEntrypoint(file)) {
167
167
  return { file, integrated: true, importers: [], reason: IntegrationReason.RouteOrEntrypoint };
168
168
  }
169
+ // i18n/locale content is commonly loaded via a runtime-templated path (e.g.
170
+ // i18next-http-backend's `loadPath: '/locales/{{lng}}/{{ns}}.json'`) rather
171
+ // than a static quoted import — the signature grep below would never find
172
+ // that reference and would misreport a real, live locale file as dead code.
173
+ if (isI18nLocaleFile(file)) {
174
+ return { file, integrated: true, importers: [], reason: IntegrationReason.I18nLocaleContent };
175
+ }
169
176
  // A missing changed file (e.g. deleted, or an unexpected diff shape) means
170
177
  // the classification can't be trusted — fail open rather than risk wrongly
171
178
  // suppressing UI test generation.
@@ -0,0 +1 @@
1
+ export declare function getGrpcMockResponseValidationError(responseData?: string): string | null;
@@ -0,0 +1,49 @@
1
+ const GRPC_STATUS_ERROR_NAMES = new Set([
2
+ "CANCELLED",
3
+ "UNKNOWN",
4
+ "INVALID_ARGUMENT",
5
+ "DEADLINE_EXCEEDED",
6
+ "NOT_FOUND",
7
+ "ALREADY_EXISTS",
8
+ "PERMISSION_DENIED",
9
+ "RESOURCE_EXHAUSTED",
10
+ "FAILED_PRECONDITION",
11
+ "ABORTED",
12
+ "OUT_OF_RANGE",
13
+ "UNIMPLEMENTED",
14
+ "INTERNAL",
15
+ "UNAVAILABLE",
16
+ "DATA_LOSS",
17
+ "UNAUTHENTICATED",
18
+ ]);
19
+ export function getGrpcMockResponseValidationError(responseData) {
20
+ if (!responseData || responseData.trim().startsWith("@"))
21
+ return null;
22
+ let parsed;
23
+ try {
24
+ parsed = JSON.parse(responseData);
25
+ }
26
+ catch {
27
+ return null;
28
+ }
29
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
30
+ return null;
31
+ }
32
+ const record = parsed;
33
+ const candidate = record.error;
34
+ if (typeof candidate !== "string")
35
+ return null;
36
+ const normalized = normalizeGrpcStatusName(candidate);
37
+ if (!GRPC_STATUS_ERROR_NAMES.has(normalized))
38
+ return null;
39
+ return `gRPC mock responseData cannot simulate gRPC status errors such as "${normalized}". Use grpcStatusCode/grpcStatusMessage for gRPC status errors, generate a successful protobuf-shaped response, use a real failing service, or record this scenario as blocked`;
40
+ }
41
+ function normalizeGrpcStatusName(value) {
42
+ return value
43
+ .replace(/^GRPC::Status(?:::|\.)?/i, "")
44
+ .replace(/^GRPC::/i, "")
45
+ .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
46
+ .replace(/[\s.:-]+/g, "_")
47
+ .replace(/^_+|_+$/g, "")
48
+ .toUpperCase();
49
+ }
@@ -0,0 +1,4 @@
1
+ import { HttpMethod } from "../types/TestTypes.js";
2
+ export declare const REST_MOCK_HTTP_METHODS: HttpMethod[];
3
+ export declare function normalizeRestMockMethod(method?: string): string;
4
+ export declare function getRestMockMethodValidationError(method?: string): string | null;
@@ -0,0 +1,15 @@
1
+ import { HttpMethod } from "../types/TestTypes.js";
2
+ export const REST_MOCK_HTTP_METHODS = Object.values(HttpMethod);
3
+ export function normalizeRestMockMethod(method) {
4
+ return method ? method.trim().toUpperCase() : "";
5
+ }
6
+ export function getRestMockMethodValidationError(method) {
7
+ if (!method)
8
+ return null;
9
+ const normalized = normalizeRestMockMethod(method);
10
+ if (!normalized)
11
+ return null; // whitespace-only → treated as empty (valid)
12
+ if (REST_MOCK_HTTP_METHODS.includes(normalized))
13
+ return null;
14
+ return `REST mock method must be one of ${REST_MOCK_HTTP_METHODS.join(", ")} or empty string (got "${method}")`;
15
+ }
@@ -22,7 +22,7 @@ export class McpLogger {
22
22
  try {
23
23
  console.error(JSON.stringify(logEntry));
24
24
  }
25
- catch (error) {
25
+ catch (_error) {
26
26
  // silently ignore
27
27
  }
28
28
  }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Mock Compatibility Pre-flight Check
3
+ *
4
+ * Validates mock protocol combinations BEFORE deployment to surface
5
+ * known incompatibilities early rather than at test execution time.
6
+ */
7
+ import { MockProtocol } from "../types/TestTypes.js";
8
+ export { MockProtocol };
9
+ /** Narrow view of a mock spec used only for protocol compatibility checking. */
10
+ export interface MockCompatibilitySpec {
11
+ protocol: MockProtocol;
12
+ endpointURL: string;
13
+ method?: string;
14
+ grpcServiceName?: string;
15
+ kafkaTopic?: string;
16
+ }
17
+ export interface CompatibilityWarning {
18
+ code: string;
19
+ message: string;
20
+ suggestion: string;
21
+ affectedMocks: string[];
22
+ /** When true, the affected mocks cannot intercept traffic and must not be generated or deployed. */
23
+ blocking?: boolean;
24
+ }
25
+ export interface CompatibilityResult {
26
+ compatible: boolean;
27
+ /** True when at least one warning is blocking — those mocks must be skipped entirely. */
28
+ hasBlockers: boolean;
29
+ warnings: CompatibilityWarning[];
30
+ }
31
+ export interface MockCompatibilityOptions {
32
+ /** Enable Docker local-dev checks that require mocks to intercept service DNS aliases. */
33
+ dockerLocalDev?: boolean;
34
+ }
35
+ /**
36
+ * Validates a set of mock specs for known protocol compatibility issues.
37
+ *
38
+ * Rules:
39
+ * - Any gRPC mock present → GRPC_PERSISTENT_CONN warning (DNS hijacking skips persistent conns)
40
+ * - Docker local-dev REST mock using loopback/host.docker.internal → REST_LOOPBACK_URL blocking warning
41
+ *
42
+ * REST mocks work correctly in Docker local-dev mode only when the mock URL uses
43
+ * the real Docker service hostname (e.g. "billing" from "http://billing:5001").
44
+ * The worker adds that hostname as a Docker network alias so DNS resolves to the mock server.
45
+ *
46
+ * `compatible` is false when any warning is blocking and the mock cannot intercept traffic.
47
+ * `hasBlockers` is true when at least one warning is blocking (mock must not be generated/deployed).
48
+ */
49
+ export declare function validateMockCompatibility(mocks: MockCompatibilitySpec[], options?: MockCompatibilityOptions): CompatibilityResult;
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Mock Compatibility Pre-flight Check
3
+ *
4
+ * Validates mock protocol combinations BEFORE deployment to surface
5
+ * known incompatibilities early rather than at test execution time.
6
+ */
7
+ import { MockProtocol } from "../types/TestTypes.js";
8
+ export { MockProtocol };
9
+ function parseRestHostname(endpointURL) {
10
+ try {
11
+ const hostname = new URL(endpointURL).hostname.toLowerCase();
12
+ return hostname.startsWith("[") && hostname.endsWith("]")
13
+ ? hostname.slice(1, -1)
14
+ : hostname;
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ }
20
+ function isLoopbackRestEndpoint(endpointURL) {
21
+ const hostname = parseRestHostname(endpointURL);
22
+ return (hostname === "localhost" ||
23
+ hostname === "127.0.0.1" ||
24
+ hostname === "0.0.0.0" ||
25
+ hostname === "::1" ||
26
+ hostname === "host.docker.internal");
27
+ }
28
+ /**
29
+ * Validates a set of mock specs for known protocol compatibility issues.
30
+ *
31
+ * Rules:
32
+ * - Any gRPC mock present → GRPC_PERSISTENT_CONN warning (DNS hijacking skips persistent conns)
33
+ * - Docker local-dev REST mock using loopback/host.docker.internal → REST_LOOPBACK_URL blocking warning
34
+ *
35
+ * REST mocks work correctly in Docker local-dev mode only when the mock URL uses
36
+ * the real Docker service hostname (e.g. "billing" from "http://billing:5001").
37
+ * The worker adds that hostname as a Docker network alias so DNS resolves to the mock server.
38
+ *
39
+ * `compatible` is false when any warning is blocking and the mock cannot intercept traffic.
40
+ * `hasBlockers` is true when at least one warning is blocking (mock must not be generated/deployed).
41
+ */
42
+ export function validateMockCompatibility(mocks, options = {}) {
43
+ const warnings = [];
44
+ const restMocks = mocks.filter((m) => m.protocol === MockProtocol.Rest);
45
+ const grpcMocks = mocks.filter((m) => m.protocol === MockProtocol.Grpc);
46
+ const loopbackRestMocks = options.dockerLocalDev
47
+ ? restMocks.filter((m) => isLoopbackRestEndpoint(m.endpointURL))
48
+ : [];
49
+ if (loopbackRestMocks.length > 0) {
50
+ warnings.push({
51
+ code: "REST_LOOPBACK_URL",
52
+ message: "REST mocks for Docker local-dev must use the original Docker service hostname. " +
53
+ "Loopback hosts such as localhost, 127.0.0.1, 0.0.0.0, ::1, or host.docker.internal " +
54
+ "do not give the Skyramp worker the downstream service DNS alias it needs to intercept traffic.",
55
+ suggestion: "Use the real Docker service origin in endpointURL, for example http://ams:4000 or " +
56
+ "http://billing:5001. Do not use localhost, host.docker.internal, or the Skyramp worker address " +
57
+ "for deployable REST mocks.",
58
+ affectedMocks: loopbackRestMocks.map((m) => m.endpointURL),
59
+ blocking: true,
60
+ });
61
+ }
62
+ // Rule: gRPC mocks use DNS hijacking that doesn't intercept persistent connections
63
+ if (grpcMocks.length > 0) {
64
+ warnings.push({
65
+ code: "GRPC_PERSISTENT_CONN",
66
+ message: "gRPC mocks use DNS hijacking which does not intercept persistent connections. " +
67
+ "If the service under test establishes a gRPC connection before mocks are applied, " +
68
+ "the existing connection will bypass the mock.",
69
+ suggestion: "Apply gRPC mocks before the service under test starts, or restart " +
70
+ "the service after applying mocks so it establishes a new connection through the mock DNS. " +
71
+ "For Docker local-dev, also verify the worker has the original downstream hostname alias " +
72
+ "from endpointURL (for example, partner-accounts for partner-accounts:50051).",
73
+ affectedMocks: grpcMocks.map((m) => m.grpcServiceName || m.endpointURL),
74
+ });
75
+ }
76
+ const hasBlockers = warnings.some((w) => w.blocking);
77
+ return {
78
+ compatible: !hasBlockers,
79
+ hasBlockers,
80
+ warnings,
81
+ };
82
+ }
@@ -8,6 +8,13 @@ const POM_GLOBS = [
8
8
  "**/*.page.{ts,js}",
9
9
  "**/*Page.{ts,js}",
10
10
  "**/pom/**/*.{ts,js}",
11
+ // Selector-owning helper libraries — the free-function convention (e.g. cal.com's
12
+ // playwright/lib/testUtils.ts exporting bookFirstEvent(page)). Bounded to helper
13
+ // modules inside test trees plus the explicit testUtils basename family: candidates
14
+ // are tiered by selector overlap downstream, so a non-owning match costs a scan,
15
+ // never a false substitution target.
16
+ "**/{test,tests,e2e,playwright}/**/{lib,utils,helpers,support}/**/*.{ts,js}",
17
+ "**/{testUtils,test-utils,testHelpers,test-helpers}.{ts,js}",
11
18
  ];
12
19
  const EXCLUDED_BASENAME = /\.(spec|test|cy)\.(ts|js|tsx|jsx|mjs|cjs)$/;
13
20
  const ALL_SOURCE_GLOBS = ["**/*.{ts,js,tsx,jsx,mjs,cjs}"];
@@ -33,7 +33,17 @@ function resolveAgainstPomSet(fromDir, ref, pomSet, aliasMap) {
33
33
  else {
34
34
  return undefined;
35
35
  }
36
- for (const cand of [base, `${base}.ts`, `${base}.js`, base.replace(/\.js$/, ".ts")]) {
36
+ // Directory imports are how barrels are consumed (`from '../helpers/pages/admin'` where the
37
+ // on-disk target is `admin/index.ts`) — without the index candidates, barrel-bound page objects
38
+ // never bind at all and every call through them degrades to unverifiable.
39
+ for (const cand of [
40
+ base,
41
+ `${base}.ts`,
42
+ `${base}.js`,
43
+ base.replace(/\.js$/, ".ts"),
44
+ path.join(base, "index.ts"),
45
+ path.join(base, "index.js"),
46
+ ]) {
37
47
  if (pomSet.has(cand))
38
48
  return cand;
39
49
  }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Transitive closure of a file's relative import/re-export refs within the POM set, in BFS
3
+ * order starting from `start` itself. This is the VERIFY-side expansion: a member reached
4
+ * through a barrel-of-barrels (`admin/index.ts` → `export * from './members'` →
5
+ * `members/index.ts` → `members-list-page.ts`) must be searchable from the binding's file, or
6
+ * every such member false-negatives with no way to remap. Distinct from pom-scope's
7
+ * `expandImports`, which stays one-hop by design for scoping (expansion inherits the referrer's
8
+ * score; a transitive walk would over-credit distant files).
9
+ */
10
+ export declare function expandReExportsTransitive(start: string, pomFiles: string[]): Promise<string[]>;
@@ -0,0 +1,61 @@
1
+ import { readFile } from "fs/promises";
2
+ import * as path from "path";
3
+ const REF_RE = /(?:from\s+["']([^"']+)["']|require\(\s*["']([^"']+)["']\s*\))/g;
4
+ /** Real-world barrel chains run 2-3 deep (Ghost: admin/index → members/index → members-list-page);
5
+ * the cap only exists to bound a pathological re-export cycle that the visited-set already breaks. */
6
+ const MAX_DEPTH = 6;
7
+ /** Resolves a relative `ref` from `fromFile` to a member of `pomSet`, trying the bare path,
8
+ * .ts/.js extensions, and directory index files — barrels are routinely imported as
9
+ * `from './members'` where the target on disk is `members/index.ts`. */
10
+ function resolveRef(fromFile, ref, pomSet) {
11
+ const base = path.resolve(path.dirname(fromFile), ref);
12
+ const candidates = [
13
+ base,
14
+ `${base}.ts`,
15
+ `${base}.js`,
16
+ base.replace(/\.js$/, ".ts"),
17
+ path.join(base, "index.ts"),
18
+ path.join(base, "index.js"),
19
+ ];
20
+ return candidates.find((c) => pomSet.has(c));
21
+ }
22
+ /**
23
+ * Transitive closure of a file's relative import/re-export refs within the POM set, in BFS
24
+ * order starting from `start` itself. This is the VERIFY-side expansion: a member reached
25
+ * through a barrel-of-barrels (`admin/index.ts` → `export * from './members'` →
26
+ * `members/index.ts` → `members-list-page.ts`) must be searchable from the binding's file, or
27
+ * every such member false-negatives with no way to remap. Distinct from pom-scope's
28
+ * `expandImports`, which stays one-hop by design for scoping (expansion inherits the referrer's
29
+ * score; a transitive walk would over-credit distant files).
30
+ */
31
+ export async function expandReExportsTransitive(start, pomFiles) {
32
+ const pomSet = new Set(pomFiles);
33
+ const visited = new Set([start]);
34
+ const out = [start];
35
+ let frontier = [start];
36
+ for (let depth = 0; depth < MAX_DEPTH && frontier.length > 0; depth++) {
37
+ const next = [];
38
+ for (const file of frontier) {
39
+ let content;
40
+ try {
41
+ content = await readFile(file, "utf8");
42
+ }
43
+ catch {
44
+ continue;
45
+ }
46
+ for (const m of content.matchAll(REF_RE)) {
47
+ const ref = m[1] ?? m[2];
48
+ if (!ref || !ref.startsWith("."))
49
+ continue;
50
+ const resolved = resolveRef(file, ref, pomSet);
51
+ if (resolved && !visited.has(resolved)) {
52
+ visited.add(resolved);
53
+ out.push(resolved);
54
+ next.push(resolved);
55
+ }
56
+ }
57
+ }
58
+ frontier = next;
59
+ }
60
+ return out;
61
+ }
@@ -1,7 +1,10 @@
1
1
  import { type PomBinding } from "./bindings.js";
2
2
  /** Checks `member` against member-DEFINITION shapes (not a bare `\bmember\b` token match, which
3
3
  * would also "find" a local variable or parameter that merely shares the member's name) in the
4
- * binding's class/source file and its one-hop relative imports that are themselves POM files. */
4
+ * binding's class/source file and the TRANSITIVE closure of its relative imports/re-exports that
5
+ * are themselves POM files. Transitivity matters: repos routinely bind through a barrel-of-barrels
6
+ * (Ghost's `admin/index.ts` → `./members` → `members-list-page.ts`), and stopping at one hop
7
+ * false-negatives every member of every class behind the second barrel. */
5
8
  export declare function resolveMemberSource(binding: PomBinding, member: string, pomFiles: string[]): Promise<{
6
9
  found: boolean;
7
10
  searched: string[];
@@ -1,8 +1,8 @@
1
1
  import { readFile } from "fs/promises";
2
- import { expandImports } from "../pom-scope/import-expansion.js";
3
2
  import { stripCommentsAndStrings } from "../pom-scope/strip.js";
4
3
  import { escapeRegExp } from "../regex.js";
5
4
  import { primaryFile } from "./bindings.js";
5
+ import { expandReExportsTransitive } from "./re-exports.js";
6
6
  // A definition site is either the very start of the file or just past a statement/block
7
7
  // delimiter -- this catches indented multi-line source AND single-line/minified class bodies
8
8
  // (`export class Foo { ctor(){...} bar(){...} }`) where a real method never lands at column 0.
@@ -26,12 +26,15 @@ function memberDefinitionRegexes(member) {
26
26
  }
27
27
  /** Checks `member` against member-DEFINITION shapes (not a bare `\bmember\b` token match, which
28
28
  * would also "find" a local variable or parameter that merely shares the member's name) in the
29
- * binding's class/source file and its one-hop relative imports that are themselves POM files. */
29
+ * binding's class/source file and the TRANSITIVE closure of its relative imports/re-exports that
30
+ * are themselves POM files. Transitivity matters: repos routinely bind through a barrel-of-barrels
31
+ * (Ghost's `admin/index.ts` → `./members` → `members-list-page.ts`), and stopping at one hop
32
+ * false-negatives every member of every class behind the second barrel. */
30
33
  export async function resolveMemberSource(binding, member, pomFiles) {
31
- const candidates = await expandImports([primaryFile(binding)], pomFiles);
34
+ const candidates = await expandReExportsTransitive(primaryFile(binding), pomFiles);
32
35
  const memberRes = memberDefinitionRegexes(member);
33
36
  const searched = [];
34
- for (const { file } of candidates) {
37
+ for (const file of candidates) {
35
38
  searched.push(file);
36
39
  let content;
37
40
  try {
@@ -10,5 +10,10 @@ export type VerifyResult = {
10
10
  unverifiable: string[];
11
11
  parseError?: string;
12
12
  checkedCalls: number;
13
+ /** Every POM call found in the spec, verifiable or not. NOT checkedCalls +
14
+ * unverifiable.length: `unverifiable` also absorbs `unrecognized` bindings,
15
+ * which are not calls at all, so that sum overcounts. This is the count of
16
+ * POM members the delivered spec actually reuses. */
17
+ reusedCalls: number;
13
18
  };
14
19
  export declare function verifyReuse(testFile: string, language: string): Promise<VerifyResult>;
@@ -4,7 +4,7 @@ import * as path from "path";
4
4
  import { promisify } from "util";
5
5
  import { findRoot } from "../pom-scope/index.js";
6
6
  import { globPomFiles, globAllSourceFiles } from "../pom-scope/pom-files.js";
7
- import { extractPomBindings, primaryFile } from "./bindings.js";
7
+ import { extractPomBindings } from "./bindings.js";
8
8
  import { extractPomCalls } from "./calls.js";
9
9
  import { resolveMemberSource } from "./resolve.js";
10
10
  import { stripComments, stripCommentsAndStrings } from "../pom-scope/strip.js";
@@ -34,7 +34,14 @@ async function listMembers(file) {
34
34
  return [];
35
35
  }
36
36
  const members = new Set();
37
- for (const re of [/^\s*(?:async\s+)?(\w+)\s*\(/gm, /this\.(\w+)\s*=/g, /get\s+(\w+)\s*\(/g]) {
37
+ for (const re of [
38
+ /^\s*(?:async\s+)?(\w+)\s*\(/gm,
39
+ /this\.(\w+)\s*=/g,
40
+ /get\s+(\w+)\s*\(/g,
41
+ // free-function helper modules: declarations and exported const arrows are members too
42
+ /\bfunction\s+(\w+)\s*\(/g,
43
+ /\bexport\s+const\s+(\w+)\s*=/g,
44
+ ]) {
38
45
  for (const m of content.matchAll(re)) {
39
46
  const name = m[1];
40
47
  if (name === "constructor" || NON_MEMBER_KEYWORDS.has(name))
@@ -139,7 +146,21 @@ export async function verifyReuse(testFile, language) {
139
146
  const member = call.chain[0] ?? binding.name;
140
147
  const { found, searched } = await resolveMemberSource(binding, member, pomFiles);
141
148
  if (!found) {
142
- violations.push({ binding: call.binding, member, searched, availableMembers: await listMembers(primaryFile(binding)) });
149
+ // Candidates come from the whole searched closure, not just the binding's file: a
150
+ // binding through a barrel has a member-less primary file, and the members the agent
151
+ // could remap to live in the leaf classes the barrel re-exports.
152
+ const availableMembers = [...new Set((await Promise.all(searched.map(listMembers))).flat())];
153
+ if (availableMembers.length === 0) {
154
+ // "Not found, and I can enumerate nothing to remap to" is evidence about the
155
+ // VERIFIER's reach, not the member's existence. Emitting a violation here starts a
156
+ // remap/demote loop the agent cannot win (no candidates to remap to → forced demote
157
+ // of possibly-correct reuse). Degrade to unverifiable — the fail-open contract at
158
+ // the reachability level, matching resolve.ts's permissive stance on shapes.
159
+ unverifiable.push([call.binding, ...call.chain].join("."));
160
+ checkedCalls--;
161
+ continue;
162
+ }
163
+ violations.push({ binding: call.binding, member, searched, availableMembers });
143
164
  }
144
165
  }
145
166
  for (const u of unrecognized)
@@ -161,5 +182,6 @@ export async function verifyReuse(testFile, language) {
161
182
  unverifiable,
162
183
  parseError,
163
184
  checkedCalls,
185
+ reusedCalls: calls.length,
164
186
  };
165
187
  }
@@ -10,11 +10,16 @@ export function makeProgressReporter(extra) {
10
10
  return async (progress, total, message) => {
11
11
  const progressToken = extra._meta?.progressToken;
12
12
  if (progressToken !== undefined) {
13
- const notification = {
14
- method: "notifications/progress",
15
- params: { progressToken, progress, total, message },
16
- };
17
- await extra.sendNotification(notification);
13
+ try {
14
+ const notification = {
15
+ method: "notifications/progress",
16
+ params: { progressToken, progress, total, message },
17
+ };
18
+ await extra.sendNotification(notification);
19
+ }
20
+ catch {
21
+ // Progress is best-effort; a disconnected client should not fail the tool.
22
+ }
18
23
  }
19
24
  };
20
25
  }
@@ -334,7 +334,7 @@ export async function closeProxyTerminal() {
334
334
  terminalPID,
335
335
  });
336
336
  }
337
- catch (killErr) {
337
+ catch (_killErr) {
338
338
  // Process is already dead, which is what we want
339
339
  logger.debug("Terminal process already terminated", {
340
340
  terminalPID,
@@ -384,14 +384,14 @@ export async function closeProxyTerminal() {
384
384
  terminalPID,
385
385
  });
386
386
  }
387
- catch (killErr) {
387
+ catch (_killErr) {
388
388
  // Process is already dead, which is what we want
389
389
  logger.debug("Terminal process already terminated", {
390
390
  terminalPID,
391
391
  });
392
392
  }
393
393
  }
394
- catch (pidErr) {
394
+ catch (_pidErr) {
395
395
  // Fallback to regular process kill
396
396
  try {
397
397
  process.kill(terminalPID, "SIGTERM");
@@ -59,15 +59,9 @@ export declare function isRouteLikeFile(filePath: string): boolean;
59
59
  * route that existed in the base branch.
60
60
  */
61
61
  export declare function selectRemovalCandidateFiles(diffData: BranchDiffData): string[];
62
- /**
63
- * Recover endpoints as they existed in the base branch, for the given candidate
64
- * files. `fetchBaseContent` returns a file's base-branch content (e.g. via
65
- * `git show base:<file>`); files that throw are skipped. Returns every endpoint
66
- * found in the base versions — callers pass the result to
67
- * `classifyEndpointsByChangedFiles`, whose moved/still-present filter drops any
68
- * endpoint that survives in the current catalog, leaving only genuine removals.
69
- */
70
- export declare function recoverRemovedEndpointsFromBase(candidateFiles: string[], fetchBaseContent: (file: string) => Promise<string>): Promise<ScannedEndpoint[]>;
62
+ export declare function recoverRemovedEndpointsFromBase(candidateFiles: string[], fetchBaseContent: (file: string) => Promise<string>, repositoryPath?: string, baseBranch?: string): Promise<ScannedEndpoint[]>;
63
+ /** Strip git's `a/` / `b/` diff-path prefix and normalize separators. */
64
+ export declare function normalizeDiffPath(spec: string): string;
71
65
  /**
72
66
  * Parse a unified diff into the set of new-side (post-change) line numbers that
73
67
  * were touched, keyed by normalized file path.