@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.
- package/build/commands/commandLibrary.d.ts +1 -1
- package/build/commands/commandLibrary.js +3 -3
- package/build/commands/recommendTestsAndExecuteCommand.d.ts +1 -1
- package/build/commands/recommendTestsAndExecuteCommand.js +35 -20
- package/build/commands/testThisEndpointCommand.js +35 -19
- package/build/index.js +9 -3
- package/build/playwright/blueprintDigest.d.ts +15 -0
- package/build/playwright/blueprintDigest.js +152 -0
- package/build/playwright/blueprintDigestStore.d.ts +31 -0
- package/build/playwright/blueprintDigestStore.js +117 -0
- package/build/playwright/registerPlaywrightTools.js +60 -12
- package/build/playwright/traceRecordingPrompt.js +8 -7
- package/build/prompts/enhance-assertions/sharedAssertionRules.js +9 -8
- package/build/prompts/enhance-assertions/uiAssertionsPrompt.js +24 -2
- package/build/prompts/promptAssets.d.ts +20 -0
- package/build/prompts/promptAssets.js +55 -0
- package/build/prompts/sut-setup/modes/dockerComposePrompt.js +19 -5
- package/build/prompts/test-maintenance/actionsInstructions.d.ts +4 -0
- package/build/prompts/test-maintenance/actionsInstructions.js +14 -2
- package/build/prompts/test-maintenance/drift-analysis-prompt.d.ts +0 -10
- package/build/prompts/test-maintenance/drift-analysis-prompt.js +2 -11
- package/build/prompts/test-maintenance/uiDriftAnalysisSections.js +8 -4
- package/build/prompts/test-recommendation/diffExecutionPlan.d.ts +5 -22
- package/build/prompts/test-recommendation/diffExecutionPlan.js +37 -465
- package/build/prompts/test-recommendation/recommendationSections.d.ts +7 -17
- package/build/prompts/test-recommendation/recommendationSections.js +67 -309
- package/build/prompts/test-recommendation/recommendationShared.d.ts +19 -47
- package/build/prompts/test-recommendation/recommendationShared.js +49 -155
- package/build/prompts/test-recommendation/registerRecommendTestsPrompt.d.ts +0 -5
- package/build/prompts/test-recommendation/registerRecommendTestsPrompt.js +10 -153
- package/build/prompts/test-recommendation/test-recommendation-prompt.d.ts +2 -29
- package/build/prompts/test-recommendation/test-recommendation-prompt.js +32 -457
- package/build/prompts/testbot/planDeclarations.d.ts +6 -0
- package/build/prompts/testbot/planDeclarations.js +9 -0
- package/build/prompts/testbot/testbot-prompts.d.ts +8 -0
- package/build/prompts/testbot/testbot-prompts.js +256 -381
- package/build/recommendation/answers.d.ts +35 -0
- package/build/recommendation/answers.js +96 -0
- package/build/recommendation/registerPlan.d.ts +49 -0
- package/build/recommendation/registerPlan.js +117 -0
- package/build/recommendation/runVerifiers.d.ts +10 -0
- package/build/recommendation/runVerifiers.js +49 -0
- package/build/recommendation/subjectStep.d.ts +42 -0
- package/build/recommendation/subjectStep.js +86 -0
- package/build/recommendation/types.d.ts +163 -0
- package/build/recommendation/types.js +20 -0
- package/build/recommendation/verifierContracts.d.ts +382 -0
- package/build/recommendation/verifierContracts.js +263 -0
- package/build/recommendation/verifiers/changedFile.d.ts +2 -0
- package/build/recommendation/verifiers/changedFile.js +82 -0
- package/build/recommendation/verifiers/citedPath.d.ts +12 -0
- package/build/recommendation/verifiers/citedPath.js +35 -0
- package/build/recommendation/verifiers/coverage.d.ts +7 -0
- package/build/recommendation/verifiers/coverage.js +617 -0
- package/build/recommendation/verifiers/deliveredMatchesPlan.d.ts +11 -0
- package/build/recommendation/verifiers/deliveredMatchesPlan.js +33 -0
- package/build/recommendation/verifiers/endpointGrounded.d.ts +17 -0
- package/build/recommendation/verifiers/endpointGrounded.js +128 -0
- package/build/recommendation/verifiers/existingCoverage.d.ts +6 -0
- package/build/recommendation/verifiers/existingCoverage.js +51 -0
- package/build/recommendation/verifiers/expectedOutcome.d.ts +31 -0
- package/build/recommendation/verifiers/expectedOutcome.js +105 -0
- package/build/recommendation/verifiers/removedElementGuarded.d.ts +2 -0
- package/build/recommendation/verifiers/removedElementGuarded.js +57 -0
- package/build/recommendation/verifiers/reportedCategory.d.ts +26 -0
- package/build/recommendation/verifiers/reportedCategory.js +84 -0
- package/build/recommendation/verifiers/screenRoute.d.ts +10 -0
- package/build/recommendation/verifiers/screenRoute.js +118 -0
- package/build/recommendation/verifiers/statedDifference.d.ts +6 -0
- package/build/recommendation/verifiers/statedDifference.js +140 -0
- package/build/recommendation/verifiers/uiElementGrounded.d.ts +7 -0
- package/build/recommendation/verifiers/uiElementGrounded.js +318 -0
- package/build/resources/analysisResources.js +1 -114
- package/build/resources/testbotResource.js +23 -13
- package/build/services/ModularizationService.js +2 -1
- package/build/services/TestDiscoveryService.d.ts +3 -72
- package/build/services/TestDiscoveryService.js +10 -303
- package/build/services/containerEnv.d.ts +1 -1
- package/build/services/containerEnv.js +12 -0
- package/build/skills/fixTestImportErrorsSkill.d.ts +13 -0
- package/build/skills/fixTestImportErrorsSkill.js +20 -0
- package/build/toolNames.d.ts +1 -0
- package/build/toolNames.js +1 -0
- package/build/tools/code-refactor/enhanceAssertionsTool.js +3 -3
- package/build/tools/code-refactor/modularizationTool.js +2 -1
- package/build/tools/executeSkyrampTestTool.d.ts +80 -0
- package/build/tools/executeSkyrampTestTool.js +246 -19
- package/build/tools/generate-tests/generateBatchScenarioRestTool.js +6 -0
- package/build/tools/generate-tests/generateContractRestTool.js +3 -3
- package/build/tools/generate-tests/planGuard.d.ts +2 -2
- package/build/tools/generate-tests/planGuard.js +78 -18
- package/build/tools/one-click/oneClickTool.d.ts +0 -1
- package/build/tools/one-click/oneClickTool.js +0 -5
- package/build/tools/submitReportTool.d.ts +48 -42
- package/build/tools/submitReportTool.js +576 -193
- package/build/tools/test-management/actionsTool.js +72 -4
- package/build/tools/test-management/analyzeChangesTool.d.ts +144 -48
- package/build/tools/test-management/analyzeChangesTool.js +212 -1219
- package/build/tools/test-management/analyzeTestHealthTool.js +13 -24
- package/build/tools/test-management/index.d.ts +1 -0
- package/build/tools/test-management/index.js +1 -0
- package/build/tools/test-management/registerTestPlanTool.d.ts +795 -172
- package/build/tools/test-management/registerTestPlanTool.js +609 -542
- package/build/tools/test-management/resolveScreenTool.d.ts +75 -0
- package/build/tools/test-management/resolveScreenTool.js +289 -0
- package/build/types/BlueprintDigest.d.ts +34 -0
- package/build/types/BlueprintDigest.js +1 -0
- package/build/types/RepositoryAnalysis.d.ts +20 -1559
- package/build/types/RepositoryAnalysis.js +2 -58
- package/build/types/StepMethod.d.ts +40 -0
- package/build/types/StepMethod.js +77 -0
- package/build/types/TestAnalysis.d.ts +12 -0
- package/build/types/TestExecution.d.ts +4 -0
- package/build/types/TestRecommendation.d.ts +24 -24
- package/build/types/TestRecommendation.js +91 -89
- package/build/types/TestbotPromptOptions.d.ts +0 -4
- package/build/types/TestbotReport.d.ts +64 -2
- package/build/utils/AnalysisStateManager.d.ts +79 -113
- package/build/utils/AnalysisStateManager.js +147 -57
- package/build/utils/assertion-verify/api-shared-lints.js +1 -1
- package/build/utils/assertion-verify/metrics.js +85 -36
- package/build/utils/assertion-verify/ui-lints.d.ts +0 -5
- package/build/utils/assertion-verify/ui-lints.js +32 -0
- package/build/utils/branchDiff.d.ts +63 -31
- package/build/utils/branchDiff.js +242 -94
- package/build/utils/containedPath.d.ts +18 -0
- package/build/utils/containedPath.js +73 -0
- package/build/utils/dartRouteExtractor.d.ts +18 -34
- package/build/utils/dartRouteExtractor.js +101 -173
- package/build/utils/featureFlags.d.ts +12 -0
- package/build/utils/featureFlags.js +14 -0
- package/build/utils/frontendSelectors.d.ts +48 -27
- package/build/utils/frontendSelectors.js +241 -80
- package/build/utils/pathMatching.d.ts +2 -4
- package/build/utils/pathMatching.js +2 -4
- package/build/utils/planMatchKeys.d.ts +38 -47
- package/build/utils/planMatchKeys.js +143 -81
- package/build/utils/rebaselineSnapshots.d.ts +24 -0
- package/build/utils/rebaselineSnapshots.js +65 -0
- package/build/utils/removedUiElements.d.ts +22 -0
- package/build/utils/removedUiElements.js +106 -0
- package/build/utils/reportVerification.d.ts +2 -6
- package/build/utils/reportVerification.js +61 -2
- package/build/utils/screenRoutes.d.ts +66 -0
- package/build/utils/screenRoutes.js +727 -0
- package/build/utils/sourceRouteExtractor.js +320 -112
- package/build/utils/testFileClassification.d.ts +11 -2
- package/build/utils/testFileClassification.js +44 -2
- package/build/utils/testFixtures.d.ts +5 -0
- package/build/utils/testFixtures.js +13 -0
- package/build/utils/utils.d.ts +0 -1
- package/build/utils/utils.js +0 -11
- package/build/utils/versions.d.ts +3 -3
- package/build/utils/versions.js +1 -1
- package/build/workspace/workspace.d.ts +12 -12
- package/node_modules/playwright/lib/mcp/skyramp/assertHiddenTool.js +56 -0
- package/node_modules/playwright/lib/mcp/skyramp/assertTool.js +2 -1
- package/node_modules/playwright/lib/mcp/skyramp/loadTraceTool.js +10 -0
- package/node_modules/playwright/lib/mcp/skyramp/skyRampImport.js +4 -1
- package/node_modules/playwright/lib/mcp/skyramp/traceRecordingBackend.js +160 -1
- package/node_modules/playwright/lib/mcp/test/skyRampExport.js +4 -2
- package/node_modules/playwright/node_modules/playwright-core/lib/server/codegen/skyramp/jsonlReader.js +1 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/recorderSignalProcessor.js +2 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder.js +5 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/{index.-Id052Lr.js → index.B7KbSQcC.js} +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.html +1 -1
- package/node_modules/playwright/node_modules/playwright-core/package.json +1 -1
- package/node_modules/playwright/node_modules/playwright-core/src/server/codegen/skyramp/jsonlReader.ts +1 -1
- package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/recorderSignalProcessor.ts +7 -0
- package/node_modules/playwright/node_modules/playwright-core/src/server/recorder.ts +6 -1
- package/node_modules/playwright/package.json +1 -1
- package/package.json +4 -3
- package/plugin/.claude-plugin/plugin.json +8 -0
- package/plugin/plugin.json +6 -0
- package/plugin/prompts/declaring-a-plan.md +20 -0
- package/plugin/prompts/generate-tests/context-fetching.md +4 -0
- package/plugin/prompts/generate-tests/execution-plan.md +63 -0
- package/plugin/prompts/generate-tests/generation.md +108 -0
- package/plugin/prompts/generate-tests/path-parameters.md +1 -0
- package/plugin/prompts/generate-tests/reasoning-protocol.md +17 -0
- package/plugin/prompts/generate-tests/tool-workflow-variants.md +61 -0
- package/plugin/prompts/generate-tests/tool-workflows.md +65 -0
- package/plugin/prompts/plan-tests.md +42 -0
- package/plugin/prompts/testbot-task1.md +82 -0
- package/plugin/skills/fix-test-import-errors/SKILL.md +98 -0
- package/build/prompts/test-recommendation/analysisOutputPrompt.d.ts +0 -84
- package/build/prompts/test-recommendation/analysisOutputPrompt.js +0 -369
- package/build/prompts/test-recommendation/fullRepoCatalog.d.ts +0 -7
- package/build/prompts/test-recommendation/fullRepoCatalog.js +0 -283
- package/build/prompts/test-recommendation/scopeAssessment.d.ts +0 -81
- package/build/prompts/test-recommendation/scopeAssessment.js +0 -359
- package/build/recommendation/budgeters/diversityBalancedBudgeter.d.ts +0 -7
- package/build/recommendation/budgeters/diversityBalancedBudgeter.js +0 -105
- package/build/recommendation/budgeters/fixedNBudgeter.d.ts +0 -7
- package/build/recommendation/budgeters/fixedNBudgeter.js +0 -11
- package/build/recommendation/budgeters/shared.d.ts +0 -32
- package/build/recommendation/budgeters/shared.js +0 -246
- package/build/recommendation/discriminators.d.ts +0 -37
- package/build/recommendation/discriminators.js +0 -379
- package/build/recommendation/diversity.d.ts +0 -47
- package/build/recommendation/diversity.js +0 -101
- package/build/recommendation/planRanker.d.ts +0 -65
- package/build/recommendation/planRanker.js +0 -83
- package/build/recommendation/testFixtures.d.ts +0 -25
- package/build/recommendation/testFixtures.js +0 -45
- package/build/types/FrontendIntegration.d.ts +0 -28
- package/build/types/FrontendIntegration.js +0 -22
- package/build/types/Recommendation.d.ts +0 -146
- package/build/types/Recommendation.js +0 -74
- package/build/utils/changedRoutes.d.ts +0 -29
- package/build/utils/changedRoutes.js +0 -87
- package/build/utils/frontendIntegration.d.ts +0 -9
- package/build/utils/frontendIntegration.js +0 -243
- package/build/utils/importerHop.d.ts +0 -135
- package/build/utils/importerHop.js +0 -489
- package/build/utils/pathAffinityClassification.d.ts +0 -49
- package/build/utils/pathAffinityClassification.js +0 -180
- package/build/utils/pythonMountPrefixes.d.ts +0 -25
- package/build/utils/pythonMountPrefixes.js +0 -347
- package/build/utils/repoScanner.d.ts +0 -34
- package/build/utils/repoScanner.js +0 -300
- package/build/utils/routeParsers.d.ts +0 -95
- package/build/utils/routeParsers.js +0 -951
- package/build/utils/scenarioDrafting.d.ts +0 -92
- package/build/utils/scenarioDrafting.js +0 -951
- package/build/utils/subjectEndpoints.d.ts +0 -19
- package/build/utils/subjectEndpoints.js +0 -98
- package/build/utils/uiPageEnumerator.d.ts +0 -172
- 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 "../../
|
|
11
|
-
import {
|
|
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
|
-
|
|
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 {
|
|
8
|
-
import {
|
|
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
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
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
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
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
|
|
166
|
+
export declare function buildAnalyzeChangesResult(data: AnalyzeChangesData): CallToolResult;
|
|
71
167
|
export declare function registerAnalyzeChangesTool(server: McpServer): void;
|