@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
@@ -1,66 +0,0 @@
1
- import { fixedNBudgeter } from "./fixedNBudgeter.js";
2
- import { mkCandidate } from "../testFixtures.js";
3
- import { externalDedupKey } from "../../prompts/test-recommendation/recommendationShared.js";
4
- function ctx(over = {}) {
5
- return {
6
- maxGenerate: 3,
7
- maxTotal: 20,
8
- isUIOnlyPR: false,
9
- hasFrontendChanges: false,
10
- externalCoverage: new Set(),
11
- ...over,
12
- };
13
- }
14
- const gen = (r) => r.generate.map((c) => c.scenario.scenarioName);
15
- describe("fixedNBudgeter", () => {
16
- it("backend-only PR fills maxGenerate slots via round-robin across test types", () => {
17
- const ranked = [
18
- mkCandidate("i1", { testType: "integration" }),
19
- mkCandidate("i2", { testType: "integration" }),
20
- mkCandidate("i3", { testType: "integration" }),
21
- mkCandidate("c1", { testType: "contract" }),
22
- mkCandidate("c2", { testType: "contract" }),
23
- ];
24
- const res = fixedNBudgeter.select(ranked, ctx());
25
- expect(res.generate.length).toBe(3);
26
- expect(res.reservedUISlots).toBe(0);
27
- // buckets [integration, contract]; round 1 → i1, c1; round 2 → i2
28
- expect(gen(res)).toEqual(["i1", "c1", "i2"]);
29
- });
30
- it("mixed (frontend) PR reserves one UI slot → backend count = maxGenerate - 1", () => {
31
- const ranked = [
32
- mkCandidate("i1", { testType: "integration" }),
33
- mkCandidate("i2", { testType: "integration" }),
34
- mkCandidate("c1", { testType: "contract" }),
35
- ];
36
- const res = fixedNBudgeter.select(ranked, ctx({ hasFrontendChanges: true }));
37
- expect(res.generate.length).toBe(2);
38
- expect(res.reservedUISlots).toBe(1);
39
- });
40
- it("UI-only PR selects no backend generate items", () => {
41
- const res = fixedNBudgeter.select([mkCandidate("i1", { testType: "integration" })], ctx({ isUIOnlyPR: true }));
42
- expect(res.generate.length).toBe(0);
43
- });
44
- it("additional = leftover candidates (rank order), excluding anything generated", () => {
45
- const ranked = [
46
- mkCandidate("i1", { testType: "integration" }),
47
- mkCandidate("c1", { testType: "contract" }),
48
- mkCandidate("i2", { testType: "integration" }),
49
- mkCandidate("c2", { testType: "contract" }),
50
- ];
51
- const res = fixedNBudgeter.select(ranked, ctx());
52
- const generated = new Set(gen(res));
53
- for (const a of res.additional) {
54
- expect(generated.has(a.scenario.scenarioName)).toBe(false);
55
- }
56
- expect(res.additional.length).toBe(1);
57
- });
58
- it("drops an ordinary candidate already covered by an external test", () => {
59
- const covered = mkCandidate("covered", { testType: "contract" });
60
- const fresh = mkCandidate("fresh", { testType: "integration" });
61
- const res = fixedNBudgeter.select([covered, fresh], ctx({ maxGenerate: 5, externalCoverage: new Set([externalDedupKey(covered.scenario)]) }));
62
- const all = [...res.generate, ...res.additional].map((c) => c.scenario.scenarioName);
63
- expect(all).toContain("fresh");
64
- expect(all).not.toContain("covered");
65
- });
66
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,324 +0,0 @@
1
- import { validateDiscriminator } from "./discriminators.js";
2
- import { DiscriminatorKind } from "../types/Recommendation.js";
3
- // A diff containing the verbatim anchors each valid claim below points at.
4
- const DIFF = [
5
- "@@ netbox/circuits/models.py",
6
- "+ if install_date == termination_date:",
7
- "+ raise ValidationError('same-day circuit')",
8
- "+ provider.account_count = len(accounts)",
9
- "+ results = Provider.objects.filter(physical_address=query)",
10
- '+ circuit.status = "active"',
11
- ].join("\n");
12
- function step(over = {}) {
13
- return {
14
- order: 0,
15
- method: "GET",
16
- path: "/r",
17
- description: "",
18
- interactionType: "success",
19
- expectedStatusCode: 200,
20
- ...over,
21
- };
22
- }
23
- function scenario(steps) {
24
- return {
25
- scenarioName: "s",
26
- description: "s",
27
- category: "business_rule",
28
- priority: "high",
29
- steps,
30
- chainingKeys: [],
31
- requiresAuth: false,
32
- estimatedComplexity: "moderate",
33
- };
34
- }
35
- const claim = (kind, anchor) => ({
36
- kind,
37
- changedCodeAnchor: anchor,
38
- });
39
- describe("validateDiscriminator — boundary_equality", () => {
40
- const anchor = "install_date == termination_date";
41
- it("verifies a same-day accept-side boundary (two distinct fields, equal value, 2xx)", () => {
42
- const s = scenario([
43
- step({
44
- method: "POST",
45
- path: "/api/circuits",
46
- interactionType: "success",
47
- expectedStatusCode: 201,
48
- requestBody: { install_date: "2024-01-15", termination_date: "2024-01-15" },
49
- }),
50
- ]);
51
- expect(validateDiscriminator(s, claim(DiscriminatorKind.BOUNDARY_EQUALITY, anchor), DIFF).verified).toBe(true);
52
- });
53
- it("verifies the mirrored reject side (4xx + interactionType error)", () => {
54
- const s = scenario([
55
- step({
56
- method: "POST",
57
- path: "/api/circuits",
58
- interactionType: "error",
59
- expectedStatusCode: 422,
60
- requestBody: { install_date: "2024-01-15", termination_date: "2024-01-15" },
61
- }),
62
- ]);
63
- expect(validateDiscriminator(s, claim(DiscriminatorKind.BOUNDARY_EQUALITY, anchor), DIFF).verified).toBe(true);
64
- });
65
- it("demotes a gaming attempt (happy-path GET, no equal-value fields)", () => {
66
- const s = scenario([step({ method: "GET", path: "/api/circuits", expectedStatusCode: 200 })]);
67
- const res = validateDiscriminator(s, claim(DiscriminatorKind.BOUNDARY_EQUALITY, anchor), DIFF);
68
- expect(res.verified).toBe(false);
69
- expect(res.reason).toMatch(/boundary_equality/);
70
- });
71
- it("returns unverified (no throw) on malformed input with no steps", () => {
72
- const res = validateDiscriminator({}, claim(DiscriminatorKind.BOUNDARY_EQUALITY, anchor), DIFF);
73
- expect(res.verified).toBe(false);
74
- expect(res.reason).toBeDefined();
75
- });
76
- it("demotes when the anchor is absent from the diff", () => {
77
- const s = scenario([
78
- step({
79
- method: "POST",
80
- path: "/api/circuits",
81
- expectedStatusCode: 201,
82
- requestBody: { install_date: "2024-01-15", termination_date: "2024-01-15" },
83
- }),
84
- ]);
85
- const res = validateDiscriminator(s, claim(DiscriminatorKind.BOUNDARY_EQUALITY, "absent_anchor_symbol"), DIFF);
86
- expect(res.verified).toBe(false);
87
- expect(res.reason).toMatch(/absent_anchor_symbol/);
88
- expect(res.reason).toMatch(/diff/);
89
- });
90
- });
91
- describe("validateDiscriminator — multi_record_aggregate", () => {
92
- const anchor = "provider.account_count = len(accounts)";
93
- it("verifies an explicit numeric-count assertion (account_count == 2)", () => {
94
- const s = scenario([
95
- step({ order: 0, method: "POST", path: "/api/providers", expectedStatusCode: 201 }),
96
- step({
97
- order: 1,
98
- method: "GET",
99
- path: "/api/providers/summary",
100
- expectedStatusCode: 200,
101
- expectedResponseFields: ["account_count == 2"],
102
- }),
103
- ]);
104
- expect(validateDiscriminator(s, claim(DiscriminatorKind.MULTI_RECORD_AGGREGATE, anchor), DIFF).verified).toBe(true);
105
- });
106
- it("verifies >= 2 same-path POSTs before an asserting step", () => {
107
- const s = scenario([
108
- step({ order: 0, method: "POST", path: "/api/providers/1/accounts", expectedStatusCode: 201 }),
109
- step({ order: 1, method: "POST", path: "/api/providers/1/accounts", expectedStatusCode: 201 }),
110
- step({
111
- order: 2,
112
- method: "GET",
113
- path: "/api/providers/1/summary",
114
- expectedStatusCode: 200,
115
- expectedResponseFields: ["accounts"],
116
- }),
117
- ]);
118
- expect(validateDiscriminator(s, claim(DiscriminatorKind.MULTI_RECORD_AGGREGATE, anchor), DIFF).verified).toBe(true);
119
- });
120
- it("demotes a gaming attempt (single create + read, count 1)", () => {
121
- const s = scenario([
122
- step({ order: 0, method: "POST", path: "/api/providers", expectedStatusCode: 201 }),
123
- step({
124
- order: 1,
125
- method: "GET",
126
- path: "/api/providers/1",
127
- expectedStatusCode: 200,
128
- expectedResponseFields: ["name"],
129
- }),
130
- ]);
131
- const res = validateDiscriminator(s, claim(DiscriminatorKind.MULTI_RECORD_AGGREGATE, anchor), DIFF);
132
- expect(res.verified).toBe(false);
133
- expect(res.reason).toMatch(/multi_record_aggregate/);
134
- });
135
- it("returns unverified (no throw) on malformed input with null steps", () => {
136
- const res = validateDiscriminator({ steps: null }, claim(DiscriminatorKind.MULTI_RECORD_AGGREGATE, anchor), DIFF);
137
- expect(res.verified).toBe(false);
138
- });
139
- it("demotes when the anchor is absent from the diff", () => {
140
- const s = scenario([
141
- step({ method: "GET", path: "/x", expectedStatusCode: 200, expectedResponseFields: ["account_count == 2"] }),
142
- ]);
143
- expect(validateDiscriminator(s, claim(DiscriminatorKind.MULTI_RECORD_AGGREGATE, "not_in_diff_anchor"), DIFF).verified).toBe(false);
144
- });
145
- });
146
- describe("validateDiscriminator — negative_match", () => {
147
- const anchor = "physical_address=query";
148
- it("verifies a substring near-miss asserting empty results", () => {
149
- const s = scenario([
150
- step({
151
- order: 0,
152
- method: "POST",
153
- path: "/api/providers",
154
- expectedStatusCode: 201,
155
- requestBody: { physical_address: "123 Main Street, Building A" },
156
- }),
157
- step({
158
- order: 1,
159
- method: "GET",
160
- path: "/api/providers",
161
- expectedStatusCode: 200,
162
- queryParams: { physical_address: "123 Main Street" },
163
- expectedResponseFields: ["count == 0"],
164
- }),
165
- ]);
166
- expect(validateDiscriminator(s, claim(DiscriminatorKind.NEGATIVE_MATCH, anchor), DIFF).verified).toBe(true);
167
- });
168
- it("verifies a 404 near-miss lookup", () => {
169
- const s = scenario([
170
- step({
171
- order: 0,
172
- method: "POST",
173
- path: "/api/providers",
174
- expectedStatusCode: 201,
175
- requestBody: { slug: "acme-corp-provider" },
176
- }),
177
- step({
178
- order: 1,
179
- method: "GET",
180
- path: "/api/providers/acme-corp",
181
- expectedStatusCode: 404,
182
- interactionType: "error",
183
- queryParams: { slug: "acme-corp" },
184
- }),
185
- ]);
186
- expect(validateDiscriminator(s, claim(DiscriminatorKind.NEGATIVE_MATCH, anchor), DIFF).verified).toBe(true);
187
- });
188
- it("demotes a gaming attempt (exact match, non-empty 200 result)", () => {
189
- const s = scenario([
190
- step({
191
- order: 0,
192
- method: "POST",
193
- path: "/api/providers",
194
- expectedStatusCode: 201,
195
- requestBody: { physical_address: "123 Main Street" },
196
- }),
197
- step({
198
- order: 1,
199
- method: "GET",
200
- path: "/api/providers",
201
- expectedStatusCode: 200,
202
- queryParams: { physical_address: "123 Main Street" },
203
- expectedResponseFields: ["results"],
204
- }),
205
- ]);
206
- const res = validateDiscriminator(s, claim(DiscriminatorKind.NEGATIVE_MATCH, anchor), DIFF);
207
- expect(res.verified).toBe(false);
208
- expect(res.reason).toMatch(/negative_match/);
209
- });
210
- it("returns unverified (no throw) on malformed input with no steps", () => {
211
- const res = validateDiscriminator({}, claim(DiscriminatorKind.NEGATIVE_MATCH, anchor), DIFF);
212
- expect(res.verified).toBe(false);
213
- });
214
- it("demotes when the anchor is absent from the diff", () => {
215
- const s = scenario([
216
- step({ method: "GET", path: "/x", expectedStatusCode: 404, queryParams: { q: "abc" } }),
217
- ]);
218
- expect(validateDiscriminator(s, claim(DiscriminatorKind.NEGATIVE_MATCH, "missing_anchor_xyz"), DIFF).verified).toBe(false);
219
- });
220
- });
221
- describe("validateDiscriminator — state_transition", () => {
222
- const anchor = 'circuit.status = "active"';
223
- it("verifies two same-resource mutations with divergent outcomes", () => {
224
- const s = scenario([
225
- step({
226
- order: 0,
227
- method: "PATCH",
228
- path: "/api/circuits/5",
229
- interactionType: "success",
230
- expectedStatusCode: 200,
231
- requestBody: { status: "active" },
232
- }),
233
- step({
234
- order: 1,
235
- method: "DELETE",
236
- path: "/api/circuits/5",
237
- interactionType: "error",
238
- expectedStatusCode: 409,
239
- }),
240
- ]);
241
- expect(validateDiscriminator(s, claim(DiscriminatorKind.STATE_TRANSITION, anchor), DIFF).verified).toBe(true);
242
- });
243
- it("verifies divergent mutations linked via chainsFrom", () => {
244
- const s = scenario([
245
- step({
246
- order: 0,
247
- method: "POST",
248
- path: "/api/circuits",
249
- interactionType: "success",
250
- expectedStatusCode: 201,
251
- }),
252
- step({
253
- order: 1,
254
- method: "PATCH",
255
- path: "/api/circuits/{id}",
256
- interactionType: "success",
257
- expectedStatusCode: 200,
258
- chainsFrom: { sourceStep: 0, sourceField: "id", sourceLocation: "body", targetParam: "id", targetLocation: "path" },
259
- }),
260
- ]);
261
- expect(validateDiscriminator(s, claim(DiscriminatorKind.STATE_TRANSITION, anchor), DIFF).verified).toBe(true);
262
- });
263
- it("demotes a gaming attempt (two identical-outcome POSTs)", () => {
264
- const s = scenario([
265
- step({ order: 0, method: "POST", path: "/api/circuits", interactionType: "success", expectedStatusCode: 201 }),
266
- step({ order: 1, method: "POST", path: "/api/circuits", interactionType: "success", expectedStatusCode: 201 }),
267
- ]);
268
- const res = validateDiscriminator(s, claim(DiscriminatorKind.STATE_TRANSITION, anchor), DIFF);
269
- expect(res.verified).toBe(false);
270
- expect(res.reason).toMatch(/state_transition/);
271
- });
272
- it("returns unverified (no throw) on malformed input with no steps", () => {
273
- const res = validateDiscriminator({}, claim(DiscriminatorKind.STATE_TRANSITION, anchor), DIFF);
274
- expect(res.verified).toBe(false);
275
- });
276
- it("demotes when the anchor is absent from the diff", () => {
277
- const s = scenario([
278
- step({ method: "PATCH", path: "/api/circuits/5", expectedStatusCode: 200 }),
279
- step({ method: "DELETE", path: "/api/circuits/5", expectedStatusCode: 409, interactionType: "error" }),
280
- ]);
281
- expect(validateDiscriminator(s, claim(DiscriminatorKind.STATE_TRANSITION, "anchor_not_present"), DIFF).verified).toBe(false);
282
- });
283
- });
284
- describe("validateDiscriminator — anchor gate", () => {
285
- it("demotes a too-short anchor before any structural check", () => {
286
- const s = scenario([step()]);
287
- const res = validateDiscriminator(s, claim(DiscriminatorKind.BOUNDARY_EQUALITY, "short"), DIFF);
288
- expect(res.verified).toBe(false);
289
- expect(res.reason).toMatch(/too short/);
290
- });
291
- it("never throws on wholly malformed input", () => {
292
- expect(() => validateDiscriminator(undefined, undefined, DIFF)).not.toThrow();
293
- const res = validateDiscriminator(undefined, undefined, DIFF);
294
- expect(res.verified).toBe(false);
295
- });
296
- });
297
- describe("verifyAnchor whitespace normalization (seed-2 multi-line anchor regression)", () => {
298
- const multiLineDiff = [
299
- "--- a/circuits.py",
300
- "+++ b/circuits.py",
301
- "+ raise ValidationError({",
302
- "+ 'termination_date': _(",
303
- "+ \"Termination date cannot precede install date.\")",
304
- "+ })",
305
- ].join("\n");
306
- it("verifies an anchor that spans wrapped diff lines (collapsed whitespace, markers stripped)", () => {
307
- const s = scenario([
308
- step({ requestBody: { install_date: "2024-06-01", termination_date: "2024-06-01" }, expectedStatusCode: 201, interactionType: "success" }),
309
- ]);
310
- const result = validateDiscriminator(s, {
311
- kind: DiscriminatorKind.BOUNDARY_EQUALITY,
312
- changedCodeAnchor: "raise ValidationError({ 'termination_date': _( \"Termination date cannot precede install date.\") })",
313
- }, multiLineDiff);
314
- expect(result.verified).toBe(true);
315
- });
316
- it("still rejects an anchor that occurs nowhere in the diff", () => {
317
- const s = scenario([
318
- step({ requestBody: { install_date: "2024-06-01", termination_date: "2024-06-01" }, expectedStatusCode: 201, interactionType: "success" }),
319
- ]);
320
- const result = validateDiscriminator(s, { kind: DiscriminatorKind.BOUNDARY_EQUALITY, changedCodeAnchor: "this snippet is not in the diff at all" }, multiLineDiff);
321
- expect(result.verified).toBe(false);
322
- expect(result.reason).toContain("does not occur verbatim");
323
- });
324
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,77 +0,0 @@
1
- import { roundRobinByType, prioritizeAttackSurfaceBundles } from "./diversity.js";
2
- import { PriorityTier } from "../types/TestRecommendation.js";
3
- // Minimal DraftedScenario factory — only the fields the diversity helpers read
4
- // (category, description, steps.length, testType) matter here.
5
- function scen(name, opts = {}) {
6
- return {
7
- scenarioName: name,
8
- description: opts.description ?? name,
9
- category: opts.category ?? "workflow",
10
- priority: "high",
11
- steps: Array.from({ length: opts.steps ?? 2 }, () => ({})),
12
- chainingKeys: [],
13
- requiresAuth: false,
14
- estimatedComplexity: "moderate",
15
- testType: opts.testType,
16
- };
17
- }
18
- function cand(name, priority, opts = {}) {
19
- return { scenario: scen(name, opts), priority };
20
- }
21
- const names = (items) => items.map((i) => i.scenario.scenarioName);
22
- describe("roundRobinByType", () => {
23
- it("returns [] when count <= 0", () => {
24
- const items = [cand("a", PriorityTier.HIGH), cand("b", PriorityTier.HIGH)];
25
- expect(roundRobinByType(items, 0)).toEqual([]);
26
- expect(roundRobinByType(items, -1)).toEqual([]);
27
- });
28
- it("returns the full list in rank order when count >= length (degenerate == slice)", () => {
29
- const items = [cand("a", PriorityTier.HIGH), cand("b", PriorityTier.HIGH), cand("c", PriorityTier.HIGH)];
30
- expect(names(roundRobinByType(items, 3))).toEqual(["a", "b", "c"]);
31
- expect(names(roundRobinByType(items, 5))).toEqual(["a", "b", "c"]);
32
- });
33
- it("with a single test type present, returns the first `count` by rank", () => {
34
- const items = [
35
- cand("i1", PriorityTier.HIGH, { testType: "integration" }),
36
- cand("i2", PriorityTier.HIGH, { testType: "integration" }),
37
- cand("i3", PriorityTier.HIGH, { testType: "integration" }),
38
- ];
39
- expect(names(roundRobinByType(items, 2))).toEqual(["i1", "i2"]);
40
- });
41
- it("distributes one slot per present test type before a second of any type", () => {
42
- const items = [
43
- cand("i1", PriorityTier.HIGH, { testType: "integration" }),
44
- cand("i2", PriorityTier.HIGH, { testType: "integration" }),
45
- cand("c1", PriorityTier.HIGH, { testType: "contract" }),
46
- cand("i3", PriorityTier.HIGH, { testType: "integration" }),
47
- ];
48
- // First-appearance bucket order is [integration, contract]; round 1 picks one of each.
49
- expect(names(roundRobinByType(items, 2))).toEqual(["i1", "c1"]);
50
- });
51
- it("selects protected (CRITICAL) items first, regardless of type or rank position", () => {
52
- const items = [
53
- cand("i1", PriorityTier.HIGH, { testType: "integration" }),
54
- cand("i2", PriorityTier.HIGH, { testType: "integration" }),
55
- cand("c1", PriorityTier.CRITICAL, { testType: "contract" }),
56
- ];
57
- const result = names(roundRobinByType(items, 2));
58
- expect(result[0]).toBe("c1");
59
- expect(result).toContain("i1");
60
- });
61
- });
62
- describe("prioritizeAttackSurfaceBundles", () => {
63
- it("moves an attack-surface security_boundary item ahead of the first ordinary direct-auth boundary", () => {
64
- const items = [
65
- cand("ordinary", PriorityTier.HIGH, { category: "security_boundary", description: "Auth boundary: GET /x" }),
66
- cand("attack", PriorityTier.HIGH, {
67
- category: "security_boundary",
68
- description: "Attack-surface auth boundary: DELETE /x",
69
- }),
70
- ];
71
- expect(names(prioritizeAttackSurfaceBundles(items))).toEqual(["attack", "ordinary"]);
72
- });
73
- it("leaves ordering unchanged when there is no attack-surface item", () => {
74
- const items = [cand("a", PriorityTier.HIGH), cand("b", PriorityTier.HIGH)];
75
- expect(names(prioritizeAttackSurfaceBundles(items))).toEqual(["a", "b"]);
76
- });
77
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,110 +0,0 @@
1
- import { rankCandidates, selectPlan } from "./planRanker.js";
2
- import { Novelty, PriorityTier } from "../types/TestRecommendation.js";
3
- import { CandidateSource, DiscriminatorKind, computeCandidateId } from "../types/Recommendation.js";
4
- function cand(name, opts = {}) {
5
- const steps = [
6
- { order: 0, method: "GET", path: `/${name}`, description: "", interactionType: "success", expectedStatusCode: 200 },
7
- { order: 1, method: "POST", path: `/${name}`, description: "", interactionType: "success", expectedStatusCode: 201 },
8
- ];
9
- const scenario = {
10
- scenarioName: name,
11
- description: name,
12
- category: opts.category ?? "workflow",
13
- priority: opts.agentPriority ?? "high",
14
- steps,
15
- chainingKeys: [],
16
- requiresAuth: false,
17
- estimatedComplexity: "moderate",
18
- testType: opts.testType ?? "integration",
19
- };
20
- return {
21
- scenario,
22
- priority: PriorityTier.HIGH,
23
- novelty: Novelty.EXISTING,
24
- source: CandidateSource.AGENT,
25
- candidateId: computeCandidateId(scenario),
26
- verifiedDiscriminator: opts.verified,
27
- };
28
- }
29
- const names = (cs) => cs.map((c) => c.scenario.scenarioName);
30
- const ids = (cs) => cs.map((c) => c.candidateId);
31
- describe("rankCandidates", () => {
32
- it("floats a verified discriminator (agent priority 'low') above an unverified security_boundary (agent priority 'high') — the round-1 miscalibration regression", () => {
33
- const verifiedLow = cand("verified-boundary", {
34
- category: "business_rule",
35
- agentPriority: "low",
36
- verified: DiscriminatorKind.BOUNDARY_EQUALITY,
37
- });
38
- const unverifiedHigh = cand("generic-authz", {
39
- category: "security_boundary",
40
- agentPriority: "high",
41
- });
42
- const ranked = rankCandidates([unverifiedHigh, verifiedLow]);
43
- expect(names(ranked)).toEqual(["verified-boundary", "generic-authz"]);
44
- });
45
- it("keeps bug_caught / CRITICAL carve-out first, even ahead of a verified discriminator", () => {
46
- const bug = cand("bug-catcher", { category: "bug_caught" });
47
- const verified = cand("verified-agg", { category: "business_rule", verified: DiscriminatorKind.MULTI_RECORD_AGGREGATE });
48
- const ranked = rankCandidates([verified, bug]);
49
- expect(names(ranked)[0]).toBe("bug-catcher");
50
- });
51
- it("orders by category priority when carve-out and verification are equal", () => {
52
- const high = cand("high-cat", { category: "security_boundary" }); // HIGH
53
- const low = cand("low-cat", { category: "crud" }); // LOW
54
- const medium = cand("medium-cat", { category: "workflow" }); // MEDIUM
55
- expect(names(rankCandidates([low, medium, high]))).toEqual(["high-cat", "medium-cat", "low-cat"]);
56
- });
57
- it("is deterministic: identical input and any shuffle yield the same order", () => {
58
- const a = cand("alpha", { category: "business_rule", verified: DiscriminatorKind.BOUNDARY_EQUALITY });
59
- const b = cand("bravo", { category: "security_boundary" });
60
- const c = cand("charlie", { category: "bug_caught" });
61
- const d = cand("delta", { category: "crud", agentPriority: "high" });
62
- const e = cand("echo", { category: "workflow", verified: DiscriminatorKind.STATE_TRANSITION });
63
- const order1 = ids(rankCandidates([a, b, c, d, e]));
64
- const order2 = ids(rankCandidates([a, b, c, d, e]));
65
- const shuffled = ids(rankCandidates([e, c, a, d, b]));
66
- expect(order1).toEqual(order2);
67
- expect(shuffled).toEqual(order1);
68
- });
69
- it("does not let the agent priority tag break a tie (candidateId is the stable tiebreak)", () => {
70
- // Same category, same verification → agent priority is irrelevant; order is by candidateId.
71
- const hi = cand("zeta", { category: "workflow", agentPriority: "high" });
72
- const lo = cand("alfa", { category: "workflow", agentPriority: "low" });
73
- const forward = ids(rankCandidates([hi, lo]));
74
- const backward = ids(rankCandidates([lo, hi]));
75
- expect(forward).toEqual(backward);
76
- });
77
- it("does not mutate the input array", () => {
78
- const input = [cand("b", { category: "crud" }), cand("a", { category: "bug_caught" })];
79
- const before = names(input);
80
- rankCandidates(input);
81
- expect(names(input)).toEqual(before);
82
- });
83
- });
84
- describe("selectPlan", () => {
85
- const ctx = (over = {}) => ({
86
- maxGenerate: 3,
87
- maxTotal: 20,
88
- isUIOnlyPR: false,
89
- hasFrontendChanges: false,
90
- externalCoverage: new Set(),
91
- ...over,
92
- });
93
- it("ranks then budgets, surfacing the supplied demotions on the result", () => {
94
- const candidates = [
95
- cand("gen-a", { category: "business_rule", verified: DiscriminatorKind.BOUNDARY_EQUALITY }),
96
- cand("gen-b", { category: "security_boundary" }),
97
- cand("gen-c", { category: "crud" }),
98
- ];
99
- const demotions = [{ candidateId: "faked-claim-abc12345", reason: "boundary_equality unverified" }];
100
- const res = selectPlan(candidates, ctx({ demotions }));
101
- expect(res.generate.length).toBeGreaterThan(0);
102
- expect(res.demotions).toEqual(demotions);
103
- // The verified discriminator is ranked first and lands in GENERATE.
104
- expect(res.generate[0].scenario.scenarioName).toBe("gen-a");
105
- });
106
- it("defaults demotions to an empty array when none are supplied", () => {
107
- const res = selectPlan([cand("solo", { category: "workflow" })], ctx());
108
- expect(res.demotions).toEqual([]);
109
- });
110
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,44 +0,0 @@
1
- // @ts-nocheck - Jest ESM type inference issues
2
- import { jest } from "@jest/globals";
3
- import * as os from "os";
4
- import * as path from "path";
5
- jest.unstable_mockModule("../utils/logger.js", () => ({
6
- logger: { info: jest.fn(), error: jest.fn(), warning: jest.fn(), debug: jest.fn() },
7
- }));
8
- jest.unstable_mockModule("../services/AnalyticsService.js", () => ({
9
- AnalyticsService: { pushMCPToolEvent: jest.fn().mockResolvedValue(undefined) },
10
- }));
11
- const { registerTestbotResource } = await import("./testbotResource.js");
12
- function captureResourceHandler() {
13
- let handler;
14
- const fakeServer = {
15
- registerResource: (_name, _template, _meta, fn) => {
16
- handler = fn;
17
- },
18
- };
19
- registerTestbotResource(fakeServer);
20
- return (uri) => handler(uri);
21
- }
22
- describe("registerTestbotResource", () => {
23
- // No .skyramp/workspace.yml under a fresh tmp dir, so readWorkspaceServices
24
- // resolves to [] without touching the filesystem in an unexpected way.
25
- const repositoryPath = path.join(os.tmpdir(), "skyr-4023-resource-test");
26
- function makeUri(params) {
27
- const uri = new URL("skyramp://prompts/testbot");
28
- uri.searchParams.set("repositoryPath", repositoryPath);
29
- for (const [key, value] of Object.entries(params)) {
30
- uri.searchParams.set(key, value);
31
- }
32
- return uri;
33
- }
34
- it("includes the report-language instruction when the URI has ?language=ja", async () => {
35
- const handle = captureResourceHandler();
36
- const result = await handle(makeUri({ language: "ja" }));
37
- expect(result.contents[0].text).toContain("**Report language: Japanese.**");
38
- });
39
- it("omits the report-language instruction when language is absent", async () => {
40
- const handle = captureResourceHandler();
41
- const result = await handle(makeUri({}));
42
- expect(result.contents[0].text).not.toContain("**Report language:");
43
- });
44
- });
@@ -1 +0,0 @@
1
- export {};