@skyramp/mcp 0.3.8 → 0.4.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/build/commands/commandLibrary.d.ts +1 -1
  2. package/build/commands/commandLibrary.js +3 -3
  3. package/build/commands/recommendTestsAndExecuteCommand.d.ts +1 -1
  4. package/build/commands/recommendTestsAndExecuteCommand.js +35 -20
  5. package/build/commands/testThisEndpointCommand.js +35 -19
  6. package/build/index.js +9 -3
  7. package/build/playwright/blueprintDigest.d.ts +15 -0
  8. package/build/playwright/blueprintDigest.js +152 -0
  9. package/build/playwright/blueprintDigestStore.d.ts +31 -0
  10. package/build/playwright/blueprintDigestStore.js +117 -0
  11. package/build/playwright/registerPlaywrightTools.js +60 -12
  12. package/build/playwright/traceRecordingPrompt.js +8 -7
  13. package/build/prompts/enhance-assertions/sharedAssertionRules.js +9 -8
  14. package/build/prompts/enhance-assertions/uiAssertionsPrompt.js +24 -2
  15. package/build/prompts/promptAssets.d.ts +20 -0
  16. package/build/prompts/promptAssets.js +55 -0
  17. package/build/prompts/sut-setup/modes/dockerComposePrompt.js +19 -5
  18. package/build/prompts/test-maintenance/actionsInstructions.d.ts +4 -0
  19. package/build/prompts/test-maintenance/actionsInstructions.js +14 -2
  20. package/build/prompts/test-maintenance/drift-analysis-prompt.d.ts +0 -10
  21. package/build/prompts/test-maintenance/drift-analysis-prompt.js +2 -11
  22. package/build/prompts/test-maintenance/uiDriftAnalysisSections.js +8 -4
  23. package/build/prompts/test-recommendation/diffExecutionPlan.d.ts +5 -22
  24. package/build/prompts/test-recommendation/diffExecutionPlan.js +37 -465
  25. package/build/prompts/test-recommendation/recommendationSections.d.ts +7 -17
  26. package/build/prompts/test-recommendation/recommendationSections.js +67 -309
  27. package/build/prompts/test-recommendation/recommendationShared.d.ts +19 -47
  28. package/build/prompts/test-recommendation/recommendationShared.js +49 -155
  29. package/build/prompts/test-recommendation/registerRecommendTestsPrompt.d.ts +0 -5
  30. package/build/prompts/test-recommendation/registerRecommendTestsPrompt.js +10 -153
  31. package/build/prompts/test-recommendation/test-recommendation-prompt.d.ts +2 -29
  32. package/build/prompts/test-recommendation/test-recommendation-prompt.js +32 -457
  33. package/build/prompts/testbot/planDeclarations.d.ts +6 -0
  34. package/build/prompts/testbot/planDeclarations.js +9 -0
  35. package/build/prompts/testbot/testbot-prompts.d.ts +8 -0
  36. package/build/prompts/testbot/testbot-prompts.js +256 -381
  37. package/build/recommendation/answers.d.ts +35 -0
  38. package/build/recommendation/answers.js +96 -0
  39. package/build/recommendation/registerPlan.d.ts +49 -0
  40. package/build/recommendation/registerPlan.js +117 -0
  41. package/build/recommendation/runVerifiers.d.ts +10 -0
  42. package/build/recommendation/runVerifiers.js +49 -0
  43. package/build/recommendation/subjectStep.d.ts +42 -0
  44. package/build/recommendation/subjectStep.js +86 -0
  45. package/build/recommendation/types.d.ts +163 -0
  46. package/build/recommendation/types.js +20 -0
  47. package/build/recommendation/verifierContracts.d.ts +382 -0
  48. package/build/recommendation/verifierContracts.js +263 -0
  49. package/build/recommendation/verifiers/changedFile.d.ts +2 -0
  50. package/build/recommendation/verifiers/changedFile.js +82 -0
  51. package/build/recommendation/verifiers/citedPath.d.ts +12 -0
  52. package/build/recommendation/verifiers/citedPath.js +35 -0
  53. package/build/recommendation/verifiers/coverage.d.ts +7 -0
  54. package/build/recommendation/verifiers/coverage.js +617 -0
  55. package/build/recommendation/verifiers/deliveredMatchesPlan.d.ts +11 -0
  56. package/build/recommendation/verifiers/deliveredMatchesPlan.js +33 -0
  57. package/build/recommendation/verifiers/endpointGrounded.d.ts +17 -0
  58. package/build/recommendation/verifiers/endpointGrounded.js +128 -0
  59. package/build/recommendation/verifiers/existingCoverage.d.ts +6 -0
  60. package/build/recommendation/verifiers/existingCoverage.js +51 -0
  61. package/build/recommendation/verifiers/expectedOutcome.d.ts +31 -0
  62. package/build/recommendation/verifiers/expectedOutcome.js +105 -0
  63. package/build/recommendation/verifiers/removedElementGuarded.d.ts +2 -0
  64. package/build/recommendation/verifiers/removedElementGuarded.js +57 -0
  65. package/build/recommendation/verifiers/reportedCategory.d.ts +26 -0
  66. package/build/recommendation/verifiers/reportedCategory.js +84 -0
  67. package/build/recommendation/verifiers/screenRoute.d.ts +10 -0
  68. package/build/recommendation/verifiers/screenRoute.js +118 -0
  69. package/build/recommendation/verifiers/statedDifference.d.ts +6 -0
  70. package/build/recommendation/verifiers/statedDifference.js +140 -0
  71. package/build/recommendation/verifiers/uiElementGrounded.d.ts +7 -0
  72. package/build/recommendation/verifiers/uiElementGrounded.js +318 -0
  73. package/build/resources/analysisResources.js +1 -114
  74. package/build/resources/testbotResource.js +23 -13
  75. package/build/services/ModularizationService.js +2 -1
  76. package/build/services/TestDiscoveryService.d.ts +3 -72
  77. package/build/services/TestDiscoveryService.js +10 -303
  78. package/build/services/containerEnv.d.ts +1 -1
  79. package/build/services/containerEnv.js +12 -0
  80. package/build/skills/fixTestImportErrorsSkill.d.ts +13 -0
  81. package/build/skills/fixTestImportErrorsSkill.js +20 -0
  82. package/build/toolNames.d.ts +1 -0
  83. package/build/toolNames.js +1 -0
  84. package/build/tools/code-refactor/enhanceAssertionsTool.js +3 -3
  85. package/build/tools/code-refactor/modularizationTool.js +2 -1
  86. package/build/tools/executeSkyrampTestTool.d.ts +80 -0
  87. package/build/tools/executeSkyrampTestTool.js +246 -19
  88. package/build/tools/generate-tests/generateBatchScenarioRestTool.js +6 -0
  89. package/build/tools/generate-tests/generateContractRestTool.js +3 -3
  90. package/build/tools/generate-tests/planGuard.d.ts +2 -2
  91. package/build/tools/generate-tests/planGuard.js +78 -18
  92. package/build/tools/one-click/oneClickTool.d.ts +0 -1
  93. package/build/tools/one-click/oneClickTool.js +0 -5
  94. package/build/tools/submitReportTool.d.ts +48 -42
  95. package/build/tools/submitReportTool.js +576 -193
  96. package/build/tools/test-management/actionsTool.js +72 -4
  97. package/build/tools/test-management/analyzeChangesTool.d.ts +144 -48
  98. package/build/tools/test-management/analyzeChangesTool.js +212 -1219
  99. package/build/tools/test-management/analyzeTestHealthTool.js +13 -24
  100. package/build/tools/test-management/index.d.ts +1 -0
  101. package/build/tools/test-management/index.js +1 -0
  102. package/build/tools/test-management/registerTestPlanTool.d.ts +795 -172
  103. package/build/tools/test-management/registerTestPlanTool.js +609 -542
  104. package/build/tools/test-management/resolveScreenTool.d.ts +75 -0
  105. package/build/tools/test-management/resolveScreenTool.js +289 -0
  106. package/build/types/BlueprintDigest.d.ts +34 -0
  107. package/build/types/BlueprintDigest.js +1 -0
  108. package/build/types/RepositoryAnalysis.d.ts +20 -1559
  109. package/build/types/RepositoryAnalysis.js +2 -58
  110. package/build/types/StepMethod.d.ts +40 -0
  111. package/build/types/StepMethod.js +77 -0
  112. package/build/types/TestAnalysis.d.ts +12 -0
  113. package/build/types/TestExecution.d.ts +4 -0
  114. package/build/types/TestRecommendation.d.ts +24 -24
  115. package/build/types/TestRecommendation.js +91 -89
  116. package/build/types/TestbotPromptOptions.d.ts +0 -4
  117. package/build/types/TestbotReport.d.ts +64 -2
  118. package/build/utils/AnalysisStateManager.d.ts +79 -113
  119. package/build/utils/AnalysisStateManager.js +147 -57
  120. package/build/utils/assertion-verify/api-shared-lints.js +1 -1
  121. package/build/utils/assertion-verify/metrics.js +85 -36
  122. package/build/utils/assertion-verify/ui-lints.d.ts +0 -5
  123. package/build/utils/assertion-verify/ui-lints.js +32 -0
  124. package/build/utils/branchDiff.d.ts +63 -31
  125. package/build/utils/branchDiff.js +242 -94
  126. package/build/utils/containedPath.d.ts +18 -0
  127. package/build/utils/containedPath.js +73 -0
  128. package/build/utils/dartRouteExtractor.d.ts +18 -34
  129. package/build/utils/dartRouteExtractor.js +101 -173
  130. package/build/utils/featureFlags.d.ts +12 -0
  131. package/build/utils/featureFlags.js +14 -0
  132. package/build/utils/frontendSelectors.d.ts +48 -27
  133. package/build/utils/frontendSelectors.js +241 -80
  134. package/build/utils/pathMatching.d.ts +2 -4
  135. package/build/utils/pathMatching.js +2 -4
  136. package/build/utils/planMatchKeys.d.ts +38 -47
  137. package/build/utils/planMatchKeys.js +143 -81
  138. package/build/utils/rebaselineSnapshots.d.ts +24 -0
  139. package/build/utils/rebaselineSnapshots.js +65 -0
  140. package/build/utils/removedUiElements.d.ts +22 -0
  141. package/build/utils/removedUiElements.js +106 -0
  142. package/build/utils/reportVerification.d.ts +2 -6
  143. package/build/utils/reportVerification.js +61 -2
  144. package/build/utils/screenRoutes.d.ts +66 -0
  145. package/build/utils/screenRoutes.js +727 -0
  146. package/build/utils/sourceRouteExtractor.js +320 -112
  147. package/build/utils/testFileClassification.d.ts +11 -2
  148. package/build/utils/testFileClassification.js +44 -2
  149. package/build/utils/testFixtures.d.ts +5 -0
  150. package/build/utils/testFixtures.js +13 -0
  151. package/build/utils/utils.d.ts +0 -1
  152. package/build/utils/utils.js +0 -11
  153. package/build/utils/versions.d.ts +3 -3
  154. package/build/utils/versions.js +1 -1
  155. package/build/workspace/workspace.d.ts +12 -12
  156. package/node_modules/playwright/lib/mcp/skyramp/assertHiddenTool.js +56 -0
  157. package/node_modules/playwright/lib/mcp/skyramp/assertTool.js +2 -1
  158. package/node_modules/playwright/lib/mcp/skyramp/loadTraceTool.js +10 -0
  159. package/node_modules/playwright/lib/mcp/skyramp/skyRampImport.js +4 -1
  160. package/node_modules/playwright/lib/mcp/skyramp/traceRecordingBackend.js +160 -1
  161. package/node_modules/playwright/lib/mcp/test/skyRampExport.js +4 -2
  162. package/node_modules/playwright/node_modules/playwright-core/lib/server/codegen/skyramp/jsonlReader.js +1 -0
  163. package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/recorderSignalProcessor.js +2 -0
  164. package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder.js +5 -1
  165. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/{index.-Id052Lr.js → index.B7KbSQcC.js} +1 -1
  166. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.html +1 -1
  167. package/node_modules/playwright/node_modules/playwright-core/package.json +1 -1
  168. package/node_modules/playwright/node_modules/playwright-core/src/server/codegen/skyramp/jsonlReader.ts +1 -1
  169. package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/recorderSignalProcessor.ts +7 -0
  170. package/node_modules/playwright/node_modules/playwright-core/src/server/recorder.ts +6 -1
  171. package/node_modules/playwright/package.json +1 -1
  172. package/package.json +4 -3
  173. package/plugin/.claude-plugin/plugin.json +8 -0
  174. package/plugin/plugin.json +6 -0
  175. package/plugin/prompts/declaring-a-plan.md +20 -0
  176. package/plugin/prompts/generate-tests/context-fetching.md +4 -0
  177. package/plugin/prompts/generate-tests/execution-plan.md +63 -0
  178. package/plugin/prompts/generate-tests/generation.md +108 -0
  179. package/plugin/prompts/generate-tests/path-parameters.md +1 -0
  180. package/plugin/prompts/generate-tests/reasoning-protocol.md +17 -0
  181. package/plugin/prompts/generate-tests/tool-workflow-variants.md +61 -0
  182. package/plugin/prompts/generate-tests/tool-workflows.md +65 -0
  183. package/plugin/prompts/plan-tests.md +42 -0
  184. package/plugin/prompts/testbot-task1.md +82 -0
  185. package/plugin/skills/fix-test-import-errors/SKILL.md +98 -0
  186. package/build/prompts/test-recommendation/analysisOutputPrompt.d.ts +0 -84
  187. package/build/prompts/test-recommendation/analysisOutputPrompt.js +0 -369
  188. package/build/prompts/test-recommendation/fullRepoCatalog.d.ts +0 -7
  189. package/build/prompts/test-recommendation/fullRepoCatalog.js +0 -283
  190. package/build/prompts/test-recommendation/scopeAssessment.d.ts +0 -81
  191. package/build/prompts/test-recommendation/scopeAssessment.js +0 -359
  192. package/build/recommendation/budgeters/diversityBalancedBudgeter.d.ts +0 -7
  193. package/build/recommendation/budgeters/diversityBalancedBudgeter.js +0 -105
  194. package/build/recommendation/budgeters/fixedNBudgeter.d.ts +0 -7
  195. package/build/recommendation/budgeters/fixedNBudgeter.js +0 -11
  196. package/build/recommendation/budgeters/shared.d.ts +0 -32
  197. package/build/recommendation/budgeters/shared.js +0 -246
  198. package/build/recommendation/discriminators.d.ts +0 -37
  199. package/build/recommendation/discriminators.js +0 -379
  200. package/build/recommendation/diversity.d.ts +0 -47
  201. package/build/recommendation/diversity.js +0 -101
  202. package/build/recommendation/planRanker.d.ts +0 -65
  203. package/build/recommendation/planRanker.js +0 -83
  204. package/build/recommendation/testFixtures.d.ts +0 -25
  205. package/build/recommendation/testFixtures.js +0 -45
  206. package/build/types/FrontendIntegration.d.ts +0 -28
  207. package/build/types/FrontendIntegration.js +0 -22
  208. package/build/types/Recommendation.d.ts +0 -146
  209. package/build/types/Recommendation.js +0 -74
  210. package/build/utils/changedRoutes.d.ts +0 -29
  211. package/build/utils/changedRoutes.js +0 -87
  212. package/build/utils/frontendIntegration.d.ts +0 -9
  213. package/build/utils/frontendIntegration.js +0 -243
  214. package/build/utils/importerHop.d.ts +0 -135
  215. package/build/utils/importerHop.js +0 -489
  216. package/build/utils/pathAffinityClassification.d.ts +0 -49
  217. package/build/utils/pathAffinityClassification.js +0 -180
  218. package/build/utils/pythonMountPrefixes.d.ts +0 -25
  219. package/build/utils/pythonMountPrefixes.js +0 -347
  220. package/build/utils/repoScanner.d.ts +0 -34
  221. package/build/utils/repoScanner.js +0 -300
  222. package/build/utils/routeParsers.d.ts +0 -95
  223. package/build/utils/routeParsers.js +0 -951
  224. package/build/utils/scenarioDrafting.d.ts +0 -92
  225. package/build/utils/scenarioDrafting.js +0 -951
  226. package/build/utils/subjectEndpoints.d.ts +0 -19
  227. package/build/utils/subjectEndpoints.js +0 -98
  228. package/build/utils/uiPageEnumerator.d.ts +0 -172
  229. package/build/utils/uiPageEnumerator.js +0 -474
@@ -7,8 +7,9 @@ import * as fs from "fs";
7
7
  import * as path from "path";
8
8
  import { AnalyticsService } from "../../services/AnalyticsService.js";
9
9
  import { dualChannelResult, toolError } from "../../utils/utils.js";
10
- import { isTestFile } from "../../prompts/test-recommendation/scopeAssessment.js";
11
- import { buildRenameStrategy, buildFileRenameStrategy, buildUpdateStrategy, buildRegenerateStrategy, buildDeleteStrategy, buildUpdateFileInstruction, buildRegenerateFileInstruction, } from "../../prompts/test-maintenance/actionsInstructions.js";
10
+ import { isTestFile } from "../../utils/testFileClassification.js";
11
+ import { REBASELINE_SNAPSHOT_NAME_RE, looksLikeOnDiskBaselineName } from "../../utils/rebaselineSnapshots.js";
12
+ import { buildRenameStrategy, buildFileRenameStrategy, buildUpdateStrategy, buildRebaselineStrategy, buildRegenerateStrategy, buildDeleteStrategy, buildUpdateFileInstruction, buildRegenerateFileInstruction, } from "../../prompts/test-maintenance/actionsInstructions.js";
12
13
  /**
13
14
  * Compute a suggested new filename when an endpoint is renamed.
14
15
  */
@@ -102,6 +103,15 @@ const recommendationSchema = z.object({
102
103
  .optional()
103
104
  .describe("For a large UPDATE file, the concrete per-site edits you already located while reading it — one entry per place that must change, with a verbatim anchor. " +
104
105
  "Surfaced to the apply step as a checklist so it edits each site directly instead of re-grepping/re-paging the file. Provide this whenever an UPDATE touches more than a couple of sites."),
106
+ rebaselineSnapshots: z
107
+ // Loose here on purpose: one malformed name must not reject the whole batch and
108
+ // lose every other verdict. Entries are validated per item below; invalid ones
109
+ // are dropped and surfaced in the response.
110
+ .array(z.string())
111
+ .optional()
112
+ .describe("UPDATE only — the toHaveScreenshot() baseline filenames (e.g. [\"page-001.png\"]) whose captured page/element/region the diff visibly changed, so the committed PNG is stale (SKYR-4298). " +
113
+ "List only the baselines the change reaches; leave unaffected ones out. These are refreshed at the final skyramp_execute_test run via its rebaselineSnapshots parameter, never by editing the assertion, its maxDiffPixelRatio, or the PNG. " +
114
+ "Omit when the diff does not explain a screenshot mismatch — that failure stays red."),
105
115
  renamedEndpoints: z
106
116
  .array(z.object({
107
117
  oldPath: z.string().describe("Previous endpoint path"),
@@ -182,6 +192,7 @@ export function registerActionsTool(server) {
182
192
  // and passes results here directly — analyzeTestHealthTool never writes assessment
183
193
  // data back to the state file.
184
194
  const recommendations = [];
195
+ const droppedRebaselineNotes = [];
185
196
  (args.recommendations ?? []).forEach((rec) => {
186
197
  // Schema requires absolute paths; resolve any relative paths defensively
187
198
  // against repoRoot in case the LLM sends a relative path despite the schema.
@@ -294,6 +305,26 @@ export function registerActionsTool(server) {
294
305
  resolvedPomFile = undefined;
295
306
  }
296
307
  }
308
+ if (rec.action !== DriftAction.Update && rec.rebaselineSnapshots?.length) {
309
+ droppedRebaselineNotes.push(`${rec.testFilePath}: rebaselineSnapshots [${rec.rebaselineSnapshots.join(", ")}] ignored on ${rec.action} — a baseline refresh is only meaningful on UPDATE.`);
310
+ }
311
+ // Per-entry validation (the schema is deliberately loose, see above).
312
+ const validBaselines = [];
313
+ for (const raw of rec.rebaselineSnapshots ?? []) {
314
+ const name = raw.trim();
315
+ if (!REBASELINE_SNAPSHOT_NAME_RE.test(name)) {
316
+ droppedRebaselineNotes.push(`${rec.testFilePath}: rebaselineSnapshots entry ${JSON.stringify(raw)} dropped — must be the bare .png name the test passes to toHaveScreenshot(), e.g. "page-001.png" (no path, commas, or whitespace).`);
317
+ continue;
318
+ }
319
+ if (looksLikeOnDiskBaselineName(name)) {
320
+ // Kept — a test can legitimately pass a name like this — but flagged: the
321
+ // on-disk file carries Playwright's project/platform suffix, and passing it
322
+ // by mistake refreshes nothing (the execution result will say NOT refreshed).
323
+ droppedRebaselineNotes.push(`${rec.testFilePath}: rebaselineSnapshots entry "${name}" kept but looks like an on-disk filename (Playwright's project/platform suffix). If the test passes "${name.replace(/-(?:[^-]+-)?(?:darwin|linux|win32)\.png$/i, ".png")}" to toHaveScreenshot(), pass that instead.`);
324
+ }
325
+ if (!validBaselines.includes(name))
326
+ validBaselines.push(name);
327
+ }
297
328
  recommendations.push({
298
329
  testFilePath: resolvedFile,
299
330
  pomFile: resolvedPomFile,
@@ -306,6 +337,19 @@ export function registerActionsTool(server) {
306
337
  updateInstructions: rec.updateInstructions ?? "",
307
338
  renamedEndpoints: rec.renamedEndpoints ?? [],
308
339
  ...(rec.editSites?.length ? { editSites: rec.editSites } : {}),
340
+ // Only an UPDATE refreshes a baseline. A REGENERATEd spec that reuses a
341
+ // baseline name still compares against the committed PNG, and DELETE
342
+ // removes the spec — neither is a refresh, so the list is dropped (and
343
+ // surfaced in the response below rather than silently discarded).
344
+ ...(rec.action === DriftAction.Update && validBaselines.length
345
+ ? {
346
+ rebaselineSnapshots: validBaselines,
347
+ // No updateInstructions → the refresh is the whole maintenance and
348
+ // the report gate must not expect a spec/POM edit. With
349
+ // updateInstructions the gate holds the UPDATE to both.
350
+ rebaselineOnly: !rec.updateInstructions,
351
+ }
352
+ : {}),
309
353
  });
310
354
  });
311
355
  // Derive the no-action set here instead of asking the LLM to enumerate it.
@@ -340,6 +384,11 @@ export function registerActionsTool(server) {
340
384
  rationale: r.rationale,
341
385
  testType: r.testType,
342
386
  endpoint: r.endpoint,
387
+ // Persisted so the report-time working-tree check knows this UPDATE's
388
+ // change is the refreshed PNG, not the spec (SKYR-4298).
389
+ ...(r.rebaselineSnapshots?.length
390
+ ? { rebaselineSnapshots: r.rebaselineSnapshots, rebaselineOnly: r.rebaselineOnly === true }
391
+ : {}),
343
392
  })),
344
393
  }, { repo: args.repository, repositoryPath, step: "actions" });
345
394
  }
@@ -449,6 +498,7 @@ export function registerActionsTool(server) {
449
498
  suggestedNewFile,
450
499
  updateInstructions: rec.updateInstructions,
451
500
  rationale: rec.rationale,
501
+ rebaselineSnapshots: rec.rebaselineSnapshots,
452
502
  }));
453
503
  }
454
504
  // ── REGENERATE: emit overwrite instructions ──
@@ -500,6 +550,10 @@ export function registerActionsTool(server) {
500
550
  deleteRecommendations.length === 0) {
501
551
  sections.push(`No action required. All existing tests appear healthy.`);
502
552
  }
553
+ if (droppedRebaselineNotes.length > 0) {
554
+ sections.push(`## rebaselineSnapshots notes (${droppedRebaselineNotes.length})\n\n` +
555
+ droppedRebaselineNotes.map((n) => `- ${n}`).join("\n"));
556
+ }
503
557
  sections.push(`**This tool is currently in Early Preview stage. Please verify the results.**`);
504
558
  const responseText = sections.join("\n\n");
505
559
  // ── Build LLM instructions ──
@@ -534,18 +588,32 @@ export function registerActionsTool(server) {
534
588
  // Update context: per-file guidance + current content for the downstream LLM.
535
589
  // Including file content avoids re-reads on each Edit turn, reducing token usage.
536
590
  const updateContext = updateRecommendations
537
- .filter((rec) => !!rec.updateInstructions)
591
+ .filter((rec) => !!rec.updateInstructions || !!rec.rebaselineSnapshots?.length)
538
592
  .map((rec) => {
539
593
  const editTarget = rec.pomFile ?? rec.testFilePath;
594
+ const hasEdit = !!rec.updateInstructions;
540
595
  return {
541
596
  file: editTarget,
542
- context: rec.updateInstructions,
597
+ // A rebaseline-only entry has nothing to edit: no context, and an
598
+ // explicit edit_required: false so the strategy's "make the changes
599
+ // described in context" cannot apply to it (rationale is always set,
600
+ // so it must not stand in for edit instructions here).
601
+ ...(hasEdit ? { context: rec.updateInstructions } : { edit_required: false }),
543
602
  ...(rec.editSites?.length ? { edit_sites: rec.editSites } : {}),
603
+ // The baselines to pass as skyramp_execute_test's rebaselineSnapshots for
604
+ // the SPEC (testFilePath, which is what runs) — never `file`, which is
605
+ // the page object for a POM-backed UPDATE.
606
+ ...(rec.rebaselineSnapshots?.length
607
+ ? { spec_file: rec.testFilePath, rebaseline_snapshots: rec.rebaselineSnapshots }
608
+ : {}),
544
609
  };
545
610
  });
546
611
  if (updateContext.length > 0) {
547
612
  llmInstructionsObj.update_context = updateContext;
548
613
  llmInstructionsObj.update_strategy = buildUpdateStrategy();
614
+ if (updateContext.some((u) => "rebaseline_snapshots" in u)) {
615
+ llmInstructionsObj.rebaseline_strategy = buildRebaselineStrategy();
616
+ }
549
617
  }
550
618
  // REGENERATE context: existing file content gives the generation tool the
551
619
  // endpoint URL, auth pattern, test type, and language to replicate.
@@ -1,71 +1,167 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import { z } from "zod";
3
3
  import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
4
- import { CandidateUiPage } from "../../utils/uiPageEnumerator.js";
5
- import type { FrontendFileIntegration } from "../../types/FrontendIntegration.js";
6
4
  import { TraceFile } from "../../types/RepositoryAnalysis.js";
7
- import { BranchDiffData } from "../../utils/branchDiff.js";
8
- import { ScannedEndpoint } from "../../utils/repoScanner.js";
5
+ import { ChangedFileName } from "../../utils/branchDiff.js";
6
+ import { RemovedUiElement } from "../../utils/removedUiElements.js";
9
7
  import { TraceParseResult } from "../../utils/trace-parser.js";
10
8
  /** Exported for testing: maps a parsed trace result to a TraceFile. */
11
9
  export declare function buildTraceFileEntry(tracePath: string, result: TraceParseResult): TraceFile;
12
- export declare function isSecurityRelevantDiff(diffContent: string): boolean;
13
- export declare function filterEndpointsBySpec(scannedEndpoints: ScannedEndpoint[], specPaths: Set<string>, specPathItems: Record<string, any>, diffChangedPaths: Set<string>): ScannedEndpoint[];
14
10
  export declare function isGraphQLFile(filePath: string, repositoryPath: string): Promise<boolean>;
15
- export declare function filterUnsupportedGraphQLEndpoints(endpoints: ScannedEndpoint[], repositoryPath: string): Promise<ScannedEndpoint[]>;
16
11
  export declare const analyzeChangesInputSchema: {
17
12
  repositoryPath: z.ZodString;
18
13
  scope: z.ZodOptional<z.ZodDefault<z.ZodEnum<["full_repo", "branch_diff"]>>>;
19
14
  baseBranch: z.ZodOptional<z.ZodString>;
20
15
  testDirectory: z.ZodOptional<z.ZodString>;
21
- topN: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
22
- maxGenerate: z.ZodOptional<z.ZodNumber>;
23
16
  prNumber: z.ZodOptional<z.ZodNumber>;
24
17
  repository: z.ZodOptional<z.ZodString>;
18
+ primaryRepository: z.ZodOptional<z.ZodString>;
25
19
  testsRepoDir: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
26
20
  includeUncommitted: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
27
21
  };
28
- export declare const NO_UI_INSTRUCTIONS = "No UI changes detected \u2014 no blueprint capture needed.";
29
- export declare const NO_RESOLVABLE_URLS_INSTRUCTIONS = "Frontend changes detected but no candidate URLs could be resolved (no route files matched the changed files or their importers, and no frontend baseUrl to fall back to). UI recommendations will be source-grounded only.";
30
- export declare function buildCaptureInstructions(pages: CandidateUiPage[]): string;
31
22
  /**
32
- * Instruction block for changed frontend files the server determined have no
33
- * production importer (SKYR-3855) — dead/orphaned components. Used both to
34
- * replace the capture instructions entirely (every changed frontend file is
35
- * unintegrated) and to append a scoped note when only some files are
36
- * (`buildCaptureInstructions` still runs for the rest in that case).
23
+ * Everything `skyramp_analyze_changes` returns: facts about the repository and
24
+ * the change, and no instruction text. The agent reads the diff and the files
25
+ * itself and decides what the change warrants, so anything the server used to
26
+ * say ABOUT these facts has been removed rather than reworded.
37
27
  */
38
- export declare function buildUnintegratedInstructions(results: FrontendFileIntegration[]): string;
39
- /**
40
- * Assemble the tool result. See `dualChannelResult` for why the payload is
41
- * carried on both result channels.
42
- */
43
- export declare function buildAnalyzeChangesResult(parts: {
44
- structuredSummary: string;
45
- uiInstructions: string;
46
- outputText: string;
47
- recommendationPrompt: string;
48
- }): CallToolResult;
28
+ export interface AnalyzeChangesData {
29
+ sessionId?: string;
30
+ stateFile?: string;
31
+ repositoryPath: string;
32
+ repositoryName: string;
33
+ /** owner/repo, when the caller supplied it. */
34
+ repository?: string;
35
+ /** Other repositories already analyzed into this run's state file. */
36
+ relatedRepositories?: string[];
37
+ analysisScope: string;
38
+ /** The application is not running, so nothing can be captured from it. */
39
+ planOnly: boolean;
40
+ currentBranch?: string;
41
+ baseBranch?: string;
42
+ /** The same listing `skyramp_register_test_plan` verifies a candidate's
43
+ * `changedFile` against, so the agent sees exactly what the check reads.
44
+ * A rename appears as the new path plus the old one marked deleted. */
45
+ changedFiles: ChangedFileName[];
46
+ existingTestFiles?: {
47
+ /** Repo-relative paths of tests Skyramp generated. */
48
+ skyramp: string[];
49
+ /** Repo-relative paths of tests the repository owns. */
50
+ external: string[];
51
+ /** The subset of `external` discovery scored relevant to this change. */
52
+ relevantExternal: string[];
53
+ };
54
+ workspace?: {
55
+ baseUrl: string;
56
+ authMethod: string;
57
+ authHeader?: string;
58
+ openApiSpecPath?: string;
59
+ /** Whether the spec loaded and carried usable path entries. */
60
+ openApiSpecLoaded: boolean;
61
+ };
62
+ /**
63
+ * Identifying `data-*` attributes the diff removed from files that survive it
64
+ * (SKYR-4305). No blueprint can hold a removed element, so this list is the
65
+ * only record that they were there.
66
+ */
67
+ uiContext?: {
68
+ removedElements?: RemovedUiElement[];
69
+ };
70
+ /** Set when the call returned before analysis, and why. */
71
+ /** The one instruction the result keeps: which tool comes next. */
72
+ nextStep?: string;
73
+ }
74
+ /** SKYR-4182: structuredContent needs a declared outputSchema, and the schema
75
+ * has to accept the early exit as well as a full analysis — hence the optional
76
+ * fields. */
77
+ export declare const analyzeChangesOutputSchema: {
78
+ sessionId: z.ZodOptional<z.ZodString>;
79
+ stateFile: z.ZodOptional<z.ZodString>;
80
+ repositoryPath: z.ZodString;
81
+ repositoryName: z.ZodString;
82
+ repository: z.ZodOptional<z.ZodString>;
83
+ relatedRepositories: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
84
+ analysisScope: z.ZodString;
85
+ planOnly: z.ZodBoolean;
86
+ currentBranch: z.ZodOptional<z.ZodString>;
87
+ baseBranch: z.ZodOptional<z.ZodString>;
88
+ changedFiles: z.ZodArray<z.ZodObject<{
89
+ path: z.ZodString;
90
+ deleted: z.ZodBoolean;
91
+ }, "strip", z.ZodTypeAny, {
92
+ path: string;
93
+ deleted: boolean;
94
+ }, {
95
+ path: string;
96
+ deleted: boolean;
97
+ }>, "many">;
98
+ existingTestFiles: z.ZodOptional<z.ZodObject<{
99
+ skyramp: z.ZodArray<z.ZodString, "many">;
100
+ external: z.ZodArray<z.ZodString, "many">;
101
+ relevantExternal: z.ZodArray<z.ZodString, "many">;
102
+ }, "strip", z.ZodTypeAny, {
103
+ skyramp: string[];
104
+ external: string[];
105
+ relevantExternal: string[];
106
+ }, {
107
+ skyramp: string[];
108
+ external: string[];
109
+ relevantExternal: string[];
110
+ }>>;
111
+ workspace: z.ZodOptional<z.ZodObject<{
112
+ baseUrl: z.ZodString;
113
+ authMethod: z.ZodString;
114
+ authHeader: z.ZodOptional<z.ZodString>;
115
+ openApiSpecPath: z.ZodOptional<z.ZodString>;
116
+ openApiSpecLoaded: z.ZodBoolean;
117
+ }, "strip", z.ZodTypeAny, {
118
+ baseUrl: string;
119
+ authMethod: string;
120
+ openApiSpecLoaded: boolean;
121
+ authHeader?: string | undefined;
122
+ openApiSpecPath?: string | undefined;
123
+ }, {
124
+ baseUrl: string;
125
+ authMethod: string;
126
+ openApiSpecLoaded: boolean;
127
+ authHeader?: string | undefined;
128
+ openApiSpecPath?: string | undefined;
129
+ }>>;
130
+ uiContext: z.ZodOptional<z.ZodObject<{
131
+ removedElements: z.ZodOptional<z.ZodArray<z.ZodObject<{
132
+ attribute: z.ZodString;
133
+ value: z.ZodString;
134
+ file: z.ZodString;
135
+ }, "strip", z.ZodTypeAny, {
136
+ value: string;
137
+ file: string;
138
+ attribute: string;
139
+ }, {
140
+ value: string;
141
+ file: string;
142
+ attribute: string;
143
+ }>, "many">>;
144
+ }, "strip", z.ZodTypeAny, {
145
+ removedElements?: {
146
+ value: string;
147
+ file: string;
148
+ attribute: string;
149
+ }[] | undefined;
150
+ }, {
151
+ removedElements?: {
152
+ value: string;
153
+ file: string;
154
+ attribute: string;
155
+ }[] | undefined;
156
+ }>>;
157
+ nextStep: z.ZodOptional<z.ZodString>;
158
+ };
49
159
  /**
50
- * Coverage is discovered from the working tree, so a test file the PR itself adds looks
51
- * identical to pre-existing coverage. This is what the budgeter reads to decide whether
52
- * an empty plan is a dedup artifact or the author's own coverage.
53
- *
54
- * No diff means no answer, so it reports `true` and the reserve stays shut. `diffData` is
55
- * absent in full-repo scope — where fullRepoCatalog deliberately drops externally covered
56
- * scenarios, and promoting them back would contradict the prompt the agent reads — and
57
- * after a branch-diff failure, where nothing is known about the changed files at all.
58
- *
59
- * Classification comes from discovery, not from `isTestFile`: the flag has to agree with
60
- * whatever built the coverage keys it guards.
61
- *
62
- * `userChangedFiles` is the bot-filtered list. The bot commits its generated tests onto
63
- * the branch it analyzed, and those filenames are exactly what the discovery patterns
64
- * exist to match — so reading the raw base..HEAD list shut the reserve on every re-run
65
- * of a branch: run 1 generates the tests, run 2 sees them. When the filter cannot answer
66
- * (no bot commit yet, or a git failure) the raw list stands. That is safe in the same
67
- * direction as the `!diffData` case: the raw list can only hold MORE files, so the
68
- * fallback shuts the reserve rather than opening it.
160
+ * Assemble the tool result. The payload is carried on BOTH channels because
161
+ * each agent CLI reads a different one and none falls back: Claude Code takes
162
+ * `structuredContent`, Cursor takes `content[]`. `content[]` must be the
163
+ * literal JSON serialization of `structuredContent` — that exact form is what
164
+ * GitHub Copilot CLI de-duplicates on.
69
165
  */
70
- export declare function computeDiffChangesTestFiles(diffData: BranchDiffData | undefined, userChangedFiles?: string[] | null): boolean;
166
+ export declare function buildAnalyzeChangesResult(data: AnalyzeChangesData): CallToolResult;
71
167
  export declare function registerAnalyzeChangesTool(server: McpServer): void;