@skyramp/mcp 0.2.6 → 0.2.8-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 +12 -0
- package/build/commands/recommendTestsAndExecuteCommand.d.ts +2 -0
- package/build/commands/testThisEndpointCommand.d.ts +2 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +6 -4
- package/build/playwright/PlaywrightTraceService.d.ts +32 -0
- package/build/playwright/index.d.ts +3 -0
- package/build/playwright/registerPlaywrightTools.d.ts +8 -0
- package/build/playwright/registerPlaywrightTools.js +12 -11
- package/build/playwright/traceRecordingPrompt.d.ts +13 -0
- package/build/playwright/traceRecordingPrompt.js +3 -11
- package/build/prompts/code-reuse.d.ts +1 -0
- package/build/prompts/enhance-assertions/contractProviderAssertionsPrompt.d.ts +2 -0
- package/build/prompts/enhance-assertions/integrationAssertionsPrompt.d.ts +2 -0
- package/build/prompts/enhance-assertions/sharedAssertionRules.d.ts +15 -0
- package/build/prompts/enhance-assertions/uiAssertionsPrompt.d.ts +2 -0
- package/build/prompts/enhance-assertions/uiAssertionsPrompt.js +24 -5
- package/build/prompts/fix-error-prompt.d.ts +1 -0
- package/build/prompts/initialize-workspace/initializeWorkspacePrompt.d.ts +1 -0
- package/build/prompts/modularization/integration-test-modularization.d.ts +1 -0
- package/build/prompts/modularization/ui-test-modularization.d.ts +1 -0
- package/build/prompts/personas.d.ts +21 -0
- package/build/prompts/pom-aware-code-reuse.d.ts +1 -0
- package/build/prompts/startTraceCollectionPrompts.d.ts +2 -0
- package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.d.ts +2 -0
- package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.js +114 -0
- package/build/prompts/sut-setup/modes/dockerComposePrompt.d.ts +2 -0
- package/build/prompts/sut-setup/modes/dockerComposePrompt.js +292 -0
- package/build/prompts/sut-setup/shared.d.ts +39 -0
- package/build/prompts/sut-setup/shared.js +132 -0
- package/build/prompts/test-maintenance/actionsInstructions.d.ts +35 -0
- package/build/prompts/test-maintenance/drift-analysis-prompt.d.ts +4 -0
- package/build/prompts/test-maintenance/driftAnalysisSections.d.ts +13 -0
- package/build/prompts/test-maintenance/driftAnalysisSections.js +9 -3
- package/build/prompts/test-recommendation/analysisOutputPrompt.d.ts +84 -0
- package/build/prompts/test-recommendation/analysisOutputPrompt.js +1 -1
- package/build/prompts/test-recommendation/analysisOutputPrompt.test.d.ts +1 -0
- package/build/prompts/test-recommendation/analysisOutputPrompt.test.js +1 -0
- package/build/prompts/test-recommendation/diffExecutionPlan.d.ts +17 -0
- package/build/prompts/test-recommendation/diffExecutionPlan.js +83 -18
- package/build/prompts/test-recommendation/fullRepoCatalog.d.ts +7 -0
- package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.d.ts +1 -0
- package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.js +1 -0
- package/build/prompts/test-recommendation/promptPlan.d.ts +203 -0
- package/build/prompts/test-recommendation/promptPlan.test.d.ts +1 -0
- package/build/prompts/test-recommendation/recommendationSections.d.ts +35 -0
- package/build/prompts/test-recommendation/recommendationShared.d.ts +31 -0
- package/build/prompts/test-recommendation/registerRecommendTestsPrompt.d.ts +7 -0
- package/build/prompts/test-recommendation/scopeAssessment.d.ts +55 -0
- package/build/prompts/test-recommendation/scopeAssessment.js +2 -2
- package/build/prompts/test-recommendation/scopeAssessment.test.d.ts +1 -0
- package/build/prompts/test-recommendation/scopeAssessment.test.js +1 -0
- package/build/prompts/test-recommendation/test-recommendation-prompt.d.ts +6 -0
- package/build/prompts/test-recommendation/test-recommendation-prompt.js +4 -4
- package/build/prompts/test-recommendation/test-recommendation-prompt.test.d.ts +1 -0
- package/build/prompts/test-recommendation/test-recommendation-prompt.test.js +97 -99
- package/build/prompts/testbot/testbot-prompts.d.ts +26 -0
- package/build/prompts/testbot/testbot-prompts.js +301 -46
- package/build/prompts/testbot/testbot-prompts.test.d.ts +1 -0
- package/build/prompts/testbot/testbot-prompts.test.js +109 -117
- package/build/resources/analysisResources.d.ts +17 -0
- package/build/resources/progressResource.d.ts +2 -0
- package/build/resources/sutSetupResource.d.ts +2 -0
- package/build/resources/sutSetupResource.js +45 -0
- package/build/resources/testbotResource.d.ts +2 -0
- package/build/resources/testbotResource.js +2 -2
- package/build/services/AnalyticsService.d.ts +13 -0
- package/build/services/AnalyticsService.test.d.ts +1 -0
- package/build/services/AnalyticsService.test.js +86 -0
- package/build/services/ModularizationService.d.ts +11 -0
- package/build/services/ScenarioGenerationService.d.ts +37 -0
- package/build/services/ScenarioGenerationService.integration.test.d.ts +1 -0
- package/build/services/ScenarioGenerationService.integration.test.js +4 -0
- package/build/services/ScenarioGenerationService.test.d.ts +1 -0
- package/build/services/TestDiscoveryService.d.ts +128 -0
- package/build/services/TestDiscoveryService.js +22 -12
- package/build/services/TestDiscoveryService.test.d.ts +1 -0
- package/build/services/TestDiscoveryService.test.js +4 -3
- package/build/services/TestExecutionService.d.ts +55 -0
- package/build/services/TestExecutionService.js +158 -26
- package/build/services/TestExecutionService.test.d.ts +1 -0
- package/build/services/TestExecutionService.test.js +339 -25
- package/build/services/TestGenerationService.d.ts +56 -0
- package/build/services/TestGenerationService.test.d.ts +1 -0
- package/build/services/TestGenerationService.test.js +10 -8
- package/build/services/containerEnv.d.ts +14 -0
- package/build/tool-phase-coverage.test.d.ts +1 -0
- package/build/tool-phase-coverage.test.js +2 -0
- package/build/tool-phases.d.ts +38 -0
- package/build/tools/auth/loginTool.d.ts +2 -0
- package/build/tools/auth/logoutTool.d.ts +2 -0
- package/build/tools/code-refactor/codeReuseTool.d.ts +2 -0
- package/build/tools/code-refactor/enhanceAssertionsTool.d.ts +2 -0
- package/build/tools/code-refactor/modularizationTool.d.ts +2 -0
- package/build/tools/executeSkyrampTestTool.d.ts +2 -0
- package/build/tools/executeSkyrampTestTool.js +26 -7
- package/build/tools/fixErrorTool.d.ts +2 -0
- package/build/tools/generate-tests/generateBatchScenarioRestTool.d.ts +45 -0
- package/build/tools/generate-tests/generateBatchScenarioRestTool.js +1 -1
- package/build/tools/generate-tests/generateBatchScenarioRestTool.test.d.ts +1 -0
- package/build/tools/generate-tests/generateBatchScenarioRestTool.test.js +11 -9
- package/build/tools/generate-tests/generateContractRestTool.d.ts +31 -0
- package/build/tools/generate-tests/generateE2ERestTool.d.ts +13 -0
- package/build/tools/generate-tests/generateFuzzRestTool.d.ts +10 -0
- package/build/tools/generate-tests/generateIntegrationRestTool.d.ts +16 -0
- package/build/tools/generate-tests/generateLoadRestTool.d.ts +18 -0
- package/build/tools/generate-tests/generateLoadRestTool.test.d.ts +1 -0
- package/build/tools/generate-tests/generateMockRestTool.d.ts +64 -0
- package/build/tools/generate-tests/generateSmokeRestTool.d.ts +8 -0
- package/build/tools/generate-tests/generateUIRestTool.d.ts +14 -0
- package/build/tools/generate-tests/generateUIRestTool.js +1 -1
- package/build/tools/generate-tests/loadTestSchema.d.ts +39 -0
- package/build/tools/one-click/oneClickTool.d.ts +11 -0
- package/build/tools/submitReportTool.d.ts +394 -0
- package/build/tools/submitReportTool.js +250 -41
- package/build/tools/submitReportTool.test.d.ts +1 -0
- package/build/tools/submitReportTool.test.js +511 -55
- package/build/tools/test-management/actionsTool.d.ts +10 -0
- package/build/tools/test-management/actionsTool.js +21 -7
- package/build/tools/test-management/analyzeChangesTool.d.ts +27 -0
- package/build/tools/test-management/analyzeChangesTool.js +150 -48
- package/build/tools/test-management/analyzeChangesTool.test.d.ts +1 -0
- package/build/tools/test-management/analyzeChangesTool.test.js +95 -78
- package/build/tools/test-management/analyzeTestHealthTool.d.ts +2 -0
- package/build/tools/test-management/analyzeTestHealthTool.js +16 -9
- package/build/tools/test-management/index.d.ts +3 -0
- package/build/tools/test-management/index.js +0 -1
- package/build/tools/trace/resolveSaveStoragePath.d.ts +7 -0
- package/build/tools/trace/resolveSaveStoragePath.test.d.ts +1 -0
- package/build/tools/trace/resolveSessionPaths.d.ts +40 -0
- package/build/tools/trace/resolveSessionPaths.test.d.ts +1 -0
- package/build/tools/trace/sessionState.d.ts +2 -0
- package/build/tools/trace/sessionState.test.d.ts +1 -0
- package/build/tools/trace/startTraceCollectionTool.d.ts +2 -0
- package/build/tools/trace/stopTraceCollectionTool.d.ts +2 -0
- package/build/tools/workspace/initScanWorkspaceTool.d.ts +4 -0
- package/build/tools/workspace/initializeWorkspaceTool.d.ts +2 -0
- package/build/tools/workspace/initializeWorkspaceTool.js +39 -22
- package/build/tools/workspace/initializeWorkspaceTool.test.d.ts +1 -0
- package/build/tools/workspace/initializeWorkspaceTool.test.js +134 -0
- package/build/tools/workspace/serviceUpsert.d.ts +12 -0
- package/build/tools/workspace/serviceUpsert.js +23 -0
- package/build/tools/workspace/serviceUpsert.test.d.ts +1 -0
- package/build/tools/workspace/serviceUpsert.test.js +50 -0
- package/build/types/OneClickCommands.d.ts +68 -0
- package/build/types/RepositoryAnalysis.d.ts +3004 -0
- package/build/types/TestAnalysis.d.ts +97 -0
- package/build/types/TestExecution.d.ts +63 -0
- package/build/types/TestExecution.js +11 -1
- package/build/types/TestRecommendation.d.ts +12 -0
- package/build/types/TestTypes.d.ts +234 -0
- package/build/types/TestbotReport.d.ts +68 -0
- package/build/types/TestbotReport.js +1 -0
- package/build/types/index.d.ts +4 -0
- package/build/types/index.js +3 -0
- package/build/utils/AnalysisStateManager.d.ts +242 -0
- package/build/utils/AnalysisStateManager.js +144 -3
- package/build/utils/AnalysisStateManager.test.d.ts +1 -0
- package/build/utils/AnalysisStateManager.test.js +98 -0
- package/build/utils/analyze-openapi.d.ts +1 -0
- package/build/utils/branchDiff.d.ts +18 -0
- package/build/utils/dartRouteExtractor.d.ts +45 -0
- package/build/utils/dartRouteExtractor.test.d.ts +1 -0
- package/build/utils/docker.d.ts +19 -0
- package/build/utils/docker.test.d.ts +1 -0
- package/build/utils/docker.test.js +10 -9
- package/build/utils/featureFlags.d.ts +37 -0
- package/build/utils/featureFlags.test.d.ts +1 -0
- package/build/utils/gitStaging.d.ts +24 -0
- package/build/utils/gitStaging.test.d.ts +1 -0
- package/build/utils/gitStaging.test.js +13 -7
- package/build/utils/httpDefaults.d.ts +10 -0
- package/build/utils/httpDefaults.test.d.ts +1 -0
- package/build/utils/initAgent.d.ts +36 -0
- package/build/utils/language-helper.d.ts +6 -0
- package/build/utils/logger.d.ts +11 -0
- package/build/utils/normalizeParams.d.ts +14 -0
- package/build/utils/normalizeSkyrampImports.d.ts +13 -0
- package/build/utils/pr-comment-parser.d.ts +31 -0
- package/build/utils/pr-comment-parser.test.d.ts +1 -0
- package/build/utils/pr-comment-parser.test.js +6 -5
- package/build/utils/projectMetadata.d.ts +15 -0
- package/build/utils/projectMetadata.test.d.ts +1 -0
- package/build/utils/proxy-terminal.d.ts +2 -0
- package/build/utils/repoScanner.d.ts +27 -0
- package/build/utils/repoScanner.test.d.ts +1 -0
- package/build/utils/routeParsers.d.ts +53 -0
- package/build/utils/routeParsers.js +31 -38
- package/build/utils/routeParsers.test.d.ts +1 -0
- package/build/utils/scenarioDrafting.d.ts +71 -0
- package/build/utils/scenarioDrafting.js +23 -1
- package/build/utils/scenarioDrafting.test.d.ts +1 -0
- package/build/utils/skyrampMdContent.d.ts +5 -0
- package/build/utils/sourceRouteExtractor.d.ts +48 -0
- package/build/utils/sourceRouteExtractor.test.d.ts +1 -0
- package/build/utils/telemetry.d.ts +32 -0
- package/build/utils/telemetry.test.d.ts +1 -0
- package/build/utils/trace-parser.d.ts +32 -0
- package/build/utils/trace-parser.test.d.ts +6 -0
- package/build/utils/uiPageEnumerator.d.ts +146 -0
- package/build/utils/uiPageEnumerator.js +58 -14
- package/build/utils/uiPageEnumerator.test.d.ts +1 -0
- package/build/utils/uiPageEnumerator.test.js +223 -43
- package/build/utils/utils.d.ts +45 -0
- package/build/utils/utils.js +10 -0
- package/build/utils/utils.test.d.ts +1 -0
- package/build/utils/versions.d.ts +3 -0
- package/build/utils/versions.js +1 -1
- package/build/utils/workspaceAuth.d.ts +127 -0
- package/build/utils/workspaceAuth.test.d.ts +1 -0
- package/build/utils/workspaceAuth.test.js +25 -25
- package/build/workspace/index.d.ts +1 -0
- package/build/workspace/workspace.d.ts +390 -0
- package/build/workspace/workspace.js +7 -7
- package/build/workspace/workspace.test.d.ts +1 -0
- package/build/workspace/workspace.test.js +6 -6
- package/node_modules/playwright/lib/mcp/skyramp/loadTraceTool.js +31 -13
- package/node_modules/playwright/lib/mcp/skyramp/traceRecordingBackend.js +88 -15
- package/node_modules/playwright/lib/mcp/test/skyRampExport.js +4 -3
- package/node_modules/playwright/node_modules/playwright-core/ThirdPartyNotices.txt +23 -126
- package/node_modules/playwright/node_modules/playwright-core/lib/generated/injectedScriptSource.js +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/recorderApp.js +79 -19
- package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/skyramp/aliasRemapper.js +84 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/skyramp/replayEngine.js +15 -4
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/{codeMirrorModule-CPZKmjFR.js → codeMirrorModule-D0BjbCb7.js} +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/index-lvTRGFx-.js +193 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/index.html +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/{codeMirrorModule-B0JOjboO.js → codeMirrorModule-Cqp3cwEJ.js} +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/{defaultSettingsView-1anWeyDf.js → defaultSettingsView-CYf9adZh.js} +79 -79
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/{index.Cc5029a3.js → index.B_7ywgmr.js} +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.html +2 -2
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.html +2 -2
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/{uiMode.Wo5yvvVh.js → uiMode.u4_8VnCV.js} +1 -1
- package/node_modules/playwright/node_modules/playwright-core/package.json +1 -1
- package/node_modules/playwright/node_modules/playwright-core/src/generated/injectedScriptSource.ts +1 -1
- package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/recorderApp.ts +129 -43
- package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/skyramp/aliasRemapper.ts +119 -0
- package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/skyramp/replayEngine.ts +33 -10
- package/node_modules/playwright/package.json +1 -1
- package/package.json +16 -4
- package/build/tools/test-management/uiAnalyzeChangesTool.js +0 -155
- package/build/tools/test-management/uiAnalyzeChangesTool.test.js +0 -147
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/.bin/node-which +0 -52
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/.bin/is-docker +0 -5
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/.bin/mime +0 -46
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/.bin/yaml +0 -11
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/index-CsgPR2wy.js +0 -193
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.CP3Y8Zsb.js +0 -2
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
/**
|
|
3
|
+
* Compute a suggested new filename when an endpoint is renamed.
|
|
4
|
+
*/
|
|
5
|
+
export declare function computeRenamedTestFile(testFile: string, renames: Array<{
|
|
6
|
+
oldPath: string;
|
|
7
|
+
newPath: string;
|
|
8
|
+
method: string;
|
|
9
|
+
}>): string | null;
|
|
10
|
+
export declare function registerActionsTool(server: McpServer): void;
|
|
@@ -6,6 +6,7 @@ import * as fs from "fs";
|
|
|
6
6
|
import * as path from "path";
|
|
7
7
|
import { AnalyticsService } from "../../services/AnalyticsService.js";
|
|
8
8
|
import { toolError } from "../../utils/utils.js";
|
|
9
|
+
import { stageGeneratedPaths } from "../../utils/gitStaging.js";
|
|
9
10
|
import { buildRenameStrategy, buildFileRenameStrategy, buildUpdateStrategy, buildRegenerateStrategy, buildUpdateFileInstruction, buildRegenerateFileInstruction, } from "../../prompts/test-maintenance/actionsInstructions.js";
|
|
10
11
|
/**
|
|
11
12
|
* Compute a suggested new filename when an endpoint is renamed.
|
|
@@ -87,6 +88,10 @@ const actionsSchema = {
|
|
|
87
88
|
.string()
|
|
88
89
|
.refine((p) => path.isAbsolute(p), { message: "stateFile must be an absolute path" })
|
|
89
90
|
.describe("Path to state file from skyramp_analyze_changes"),
|
|
91
|
+
repository: z
|
|
92
|
+
.string()
|
|
93
|
+
.optional()
|
|
94
|
+
.describe("The owner/repo whose analysis section to act on (e.g. 'letsramp/api-insight'). In a multi-repo run, ALWAYS set it — the primary's owner/repo for the primary repo's tests, or a related repo's owner/repo for that repo's section — within the run-scoped stateFile. Omit only for a single-repo run."),
|
|
90
95
|
recommendations: z
|
|
91
96
|
.array(recommendationSchema)
|
|
92
97
|
.optional()
|
|
@@ -106,12 +111,12 @@ export function registerActionsTool(server) {
|
|
|
106
111
|
}, async (args) => {
|
|
107
112
|
let errorResult;
|
|
108
113
|
try {
|
|
109
|
-
logger.info(
|
|
110
|
-
// Load UnifiedAnalysisState
|
|
114
|
+
logger.info(`Performing Actions (unified test-management)${args.repository ? ` for repository ${args.repository}` : ""}`);
|
|
115
|
+
// Load UnifiedAnalysisState for the requested repo section (primary when
|
|
116
|
+
// repository omitted/matches the root) from the run-scoped state file.
|
|
111
117
|
const stateManager = StateManager.fromStatePath(args.stateFile);
|
|
112
|
-
const stateData = await stateManager.
|
|
113
|
-
const
|
|
114
|
-
const repositoryPath = fullState?.metadata.repositoryPath || "";
|
|
118
|
+
const stateData = await stateManager.readRepoData(args.repository);
|
|
119
|
+
const repositoryPath = (await stateManager.getRepoRepositoryPath(args.repository)) || "";
|
|
115
120
|
if (!stateData) {
|
|
116
121
|
errorResult = toolError(`State file is empty or invalid: ${args.stateFile}. Call skyramp_analyze_changes first to generate a valid state file.`);
|
|
117
122
|
return errorResult;
|
|
@@ -365,6 +370,15 @@ export function registerActionsTool(server) {
|
|
|
365
370
|
});
|
|
366
371
|
llmInstructionsObj.regenerate_strategy = buildRegenerateStrategy();
|
|
367
372
|
}
|
|
373
|
+
// Stage UPDATE and REGENERATE target paths so testbot's re-stage step
|
|
374
|
+
// commits the agent's edits even when files are outside testDirectory.
|
|
375
|
+
const stagedPaths = [
|
|
376
|
+
...updateRecommendations.map((r) => r.testFile),
|
|
377
|
+
...regenerateRecommendations.map((r) => r.testFile),
|
|
378
|
+
];
|
|
379
|
+
for (const p of stagedPaths) {
|
|
380
|
+
await stageGeneratedPaths(p).catch((e) => logger.warning(`Failed to stage maintained file ${p}: ${e.message}`));
|
|
381
|
+
}
|
|
368
382
|
const llmInstructions = JSON.stringify(llmInstructionsObj, null, 2);
|
|
369
383
|
const contentBlocks = [
|
|
370
384
|
{
|
|
@@ -394,8 +408,8 @@ export function registerActionsTool(server) {
|
|
|
394
408
|
finally {
|
|
395
409
|
let repositoryPath = "";
|
|
396
410
|
try {
|
|
397
|
-
|
|
398
|
-
|
|
411
|
+
repositoryPath =
|
|
412
|
+
(await StateManager.fromStatePath(args.stateFile).getRepoRepositoryPath(args.repository)) || "";
|
|
399
413
|
}
|
|
400
414
|
catch (analyticsError) {
|
|
401
415
|
logger.error(`Failed to read state for analytics in actions tool: ${analyticsError?.message ?? analyticsError}`, analyticsError);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { CandidateUiPage } from "../../utils/uiPageEnumerator.js";
|
|
4
|
+
import { TraceFile } from "../../types/RepositoryAnalysis.js";
|
|
5
|
+
import { ScannedEndpoint } from "../../utils/repoScanner.js";
|
|
6
|
+
import { TraceParseResult } from "../../utils/trace-parser.js";
|
|
7
|
+
/** Exported for testing: maps a parsed trace result to a TraceFile. */
|
|
8
|
+
export declare function buildTraceFileEntry(tracePath: string, result: TraceParseResult): TraceFile;
|
|
9
|
+
export declare function isSecurityRelevantDiff(diffContent: string): boolean;
|
|
10
|
+
export declare function filterEndpointsBySpec(scannedEndpoints: ScannedEndpoint[], specPaths: Set<string>, specPathItems: Record<string, any>, diffChangedPaths: Set<string>): ScannedEndpoint[];
|
|
11
|
+
export declare function isGraphQLFile(filePath: string, repositoryPath: string): Promise<boolean>;
|
|
12
|
+
export declare function filterUnsupportedGraphQLEndpoints(endpoints: ScannedEndpoint[], repositoryPath: string): Promise<ScannedEndpoint[]>;
|
|
13
|
+
export declare const analyzeChangesInputSchema: {
|
|
14
|
+
repositoryPath: z.ZodString;
|
|
15
|
+
scope: z.ZodOptional<z.ZodDefault<z.ZodEnum<["full_repo", "branch_diff"]>>>;
|
|
16
|
+
baseBranch: z.ZodOptional<z.ZodString>;
|
|
17
|
+
testDirectory: z.ZodOptional<z.ZodString>;
|
|
18
|
+
topN: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
|
19
|
+
maxGenerate: z.ZodOptional<z.ZodNumber>;
|
|
20
|
+
prNumber: z.ZodOptional<z.ZodNumber>;
|
|
21
|
+
repository: z.ZodOptional<z.ZodString>;
|
|
22
|
+
testsRepoDir: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
23
|
+
};
|
|
24
|
+
export declare const NO_UI_INSTRUCTIONS = "No UI changes detected \u2014 no blueprint capture needed.";
|
|
25
|
+
export declare const NO_RESOLVABLE_URLS_INSTRUCTIONS = "Frontend changes detected but no candidate URLs could be resolved (workspace baseUrl missing or no router files matched). UI recommendations will be source-grounded only.";
|
|
26
|
+
export declare function buildCaptureInstructions(pages: CandidateUiPage[]): string;
|
|
27
|
+
export declare function registerAnalyzeChangesTool(server: McpServer): void;
|
|
@@ -8,7 +8,7 @@ import { simpleGit } from "simple-git";
|
|
|
8
8
|
import { logger } from "../../utils/logger.js";
|
|
9
9
|
import { parseWorkspaceAuthType, getDefaultAuthHeader, WorkspaceAuthType, readWorkspaceConfigRaw } from "../../utils/workspaceAuth.js";
|
|
10
10
|
import { AnalyticsService } from "../../services/AnalyticsService.js";
|
|
11
|
-
import { StateManager, registerSession, storeSessionData, setTestsRepoDir, } from "../../utils/AnalysisStateManager.js";
|
|
11
|
+
import { StateManager, registerSession, storeSessionData, setTestsRepoDir, getActiveRunStatePath, setActiveRunStatePath, } from "../../utils/AnalysisStateManager.js";
|
|
12
12
|
import { buildRecommendationPrompt } from "../../prompts/test-recommendation/test-recommendation-prompt.js";
|
|
13
13
|
import { hasFlutterSdkDep, isFrontendFile, isTestFile } from "../../prompts/test-recommendation/scopeAssessment.js";
|
|
14
14
|
import { enumerateCandidateUiPages } from "../../utils/uiPageEnumerator.js";
|
|
@@ -24,6 +24,32 @@ import { buildAnalysisOutputText } from "../../prompts/test-recommendation/analy
|
|
|
24
24
|
import { parseTraceFile, discoverTraceFiles, discoverPlaywrightZips, } from "../../utils/trace-parser.js";
|
|
25
25
|
import { TestSource } from "../../types/TestAnalysis.js";
|
|
26
26
|
import { parsePRComments } from "../../utils/pr-comment-parser.js";
|
|
27
|
+
// Generic module names that appear as imports in virtually every router file.
|
|
28
|
+
// Matching against these would extract ALL prefix= tokens from mount files,
|
|
29
|
+
// flooding changedResources with unrelated resources.
|
|
30
|
+
const GENERIC_MODULE_NAMES = new Set([
|
|
31
|
+
"models", "utils", "helpers", "schemas", "types", "constants",
|
|
32
|
+
"config", "settings", "exceptions", "errors", "base", "common",
|
|
33
|
+
"app", "main", "index", "server", "init", "deps", "dependencies",
|
|
34
|
+
]);
|
|
35
|
+
function resolveMountPrefixTokens(mountFileContents, changedFiles) {
|
|
36
|
+
const tokens = changedFiles.flatMap((file) => {
|
|
37
|
+
const mod = path.basename(file).replace(/\.[^.]+$/, "").toLowerCase();
|
|
38
|
+
if (GENERIC_MODULE_NAMES.has(mod))
|
|
39
|
+
return [];
|
|
40
|
+
const modRe = new RegExp(`\\b${mod.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`);
|
|
41
|
+
return mountFileContents.flatMap((content) => {
|
|
42
|
+
if (!modRe.test(content.toLowerCase()))
|
|
43
|
+
return [];
|
|
44
|
+
const matches = [...content.matchAll(/prefix\s*=\s*["'](\/?[^"']+)/g)];
|
|
45
|
+
return matches.flatMap((m) => {
|
|
46
|
+
const token = extractResourceFromPath(m[1]);
|
|
47
|
+
return token !== "unknown" ? [token] : [];
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
return [...new Set(tokens)];
|
|
52
|
+
}
|
|
27
53
|
/** Exported for testing: maps a parsed trace result to a TraceFile. */
|
|
28
54
|
export function buildTraceFileEntry(tracePath, result) {
|
|
29
55
|
return {
|
|
@@ -339,17 +365,44 @@ export const analyzeChangesInputSchema = {
|
|
|
339
365
|
.number()
|
|
340
366
|
.optional()
|
|
341
367
|
.describe("GitHub PR number. When provided, fetches previous TestBot comments on this PR and skips re-recommending tests already suggested in earlier commits — reduces duplicate recommendations across multiple pushes to the same PR."),
|
|
342
|
-
|
|
368
|
+
repository: z
|
|
343
369
|
.string()
|
|
344
|
-
.refine((v) => path.isAbsolute(v), { message: "stateOutputFile must be an absolute path" })
|
|
345
370
|
.optional()
|
|
346
|
-
.describe("
|
|
371
|
+
.describe("The owner/repo this call analyzes (e.g. 'letsramp/api-insight'). In a multi-repo run, ALWAYS set it — for the primary AND every related repo. All calls in one Testbot run share ONE state file automatically (you do NOT pass a file path); each repo's analysis is stored as its own section within it. The primary's analysis is kept at the root and tagged with its owner/repo; related repos are stored as keyed sections. Omit only for a single-repo run."),
|
|
347
372
|
testsRepoDir: z
|
|
348
373
|
.string()
|
|
349
374
|
.refine((v) => path.isAbsolute(v), { message: "testsRepoDir must be an absolute path" })
|
|
350
375
|
.optional()
|
|
351
376
|
.describe("Absolute path to a separate test repository clone. When set, existing test discovery scans this directory instead of repositoryPath. Used in cross-repo test delivery mode where tests live in a separate repo."),
|
|
352
377
|
};
|
|
378
|
+
// ── UI blueprint-capture instructions ──
|
|
379
|
+
// Moved here from the former skyramp_ui_analyze_changes pre-flight tool. These
|
|
380
|
+
// strings + buildCaptureInstructions are appended to the tool output so the
|
|
381
|
+
// agent captures browser_blueprints on the candidate UI pages after this call.
|
|
382
|
+
// The captures stay in its tool-result history and serve as element vocabulary
|
|
383
|
+
// for UI recommendation reasoning (enforced at submit time by the Blueprint
|
|
384
|
+
// Citation Invariant in the testbot prompt).
|
|
385
|
+
export const NO_UI_INSTRUCTIONS = `No UI changes detected — no blueprint capture needed.`;
|
|
386
|
+
export const NO_RESOLVABLE_URLS_INSTRUCTIONS = `Frontend changes detected but no candidate URLs could be resolved (workspace baseUrl missing or no router files matched). UI recommendations will be source-grounded only.`;
|
|
387
|
+
export function buildCaptureInstructions(pages) {
|
|
388
|
+
const pagesYaml = pages
|
|
389
|
+
.map((p, i) => ` ${i + 1}. ${p.url} (sourcedFrom: ${p.sourcedFrom.join(", ") || "(none)"}, strategy: ${p.strategy})`)
|
|
390
|
+
.join("\n");
|
|
391
|
+
return `Frontend changes detected. **Before writing any UI recommendation \`reasoning\`, capture blueprints on the candidate UI pages below.** Those captures stay in your tool-result history and serve as element vocabulary — the recommendation catalog further down gives you the authoring rules; you bring the observed elements.
|
|
392
|
+
|
|
393
|
+
**Candidate URLs:**
|
|
394
|
+
${pagesYaml}
|
|
395
|
+
|
|
396
|
+
**For each candidate URL:**
|
|
397
|
+
- \`browser_navigate\` to the URL
|
|
398
|
+
- \`browser_blueprint\` to capture the page
|
|
399
|
+
|
|
400
|
+
You don't need to thread the blueprints back into a tool call — they're in your context once captured.
|
|
401
|
+
|
|
402
|
+
If a candidate URL 404s or redirects unexpectedly, navigate from the workspace baseUrl and explore (admin apps mount routes under base prefixes the source extraction can't see). If the page rendered but lacks the changed feature (gated UI: modal, dropdown, accordion), do NOT iterate further during this step — UI recs will fall back to source-grounded prose for those, and the agent's later trace recording (Task 2) will navigate into the gate via capture-act-capture.
|
|
403
|
+
|
|
404
|
+
If \`browser_blueprint\` fails on every candidate URL (app unreachable, all 404s), proceed and log an \`issuesFound\` info entry. Recommendations will be source-grounded; non-UI work is unaffected.`;
|
|
405
|
+
}
|
|
353
406
|
export function registerAnalyzeChangesTool(server) {
|
|
354
407
|
server.registerTool(TOOL_NAME, {
|
|
355
408
|
annotations: {
|
|
@@ -540,6 +593,30 @@ export function registerAnalyzeChangesTool(server) {
|
|
|
540
593
|
// testsRepoDir is a cross-repo path override — honour it when set.
|
|
541
594
|
// Otherwise always scan the full repo root.
|
|
542
595
|
const testDir = params.testsRepoDir ?? undefined;
|
|
596
|
+
const routerMountContext = grepRouterMountingContext(params.repositoryPath);
|
|
597
|
+
// Read contents once — used for token extraction and LLM prompt injection.
|
|
598
|
+
const ROUTER_INLINE_LIMIT = 4096;
|
|
599
|
+
const routerMountContextContents = routerMountContext.map((f) => {
|
|
600
|
+
try {
|
|
601
|
+
const abs = path.isAbsolute(f) ? f : path.join(params.repositoryPath, f);
|
|
602
|
+
if (fs.statSync(abs).size > ROUTER_INLINE_LIMIT * 10)
|
|
603
|
+
return ""; // skip very large files
|
|
604
|
+
return fs.readFileSync(abs, "utf-8");
|
|
605
|
+
}
|
|
606
|
+
catch {
|
|
607
|
+
return "";
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
// Size-capped subset for LLM prompt injection.
|
|
611
|
+
const ROUTER_INLINE_MAX_FILES = 3;
|
|
612
|
+
const routerFileContents = routerMountContext
|
|
613
|
+
.slice(0, ROUTER_INLINE_MAX_FILES)
|
|
614
|
+
.flatMap((f, i) => {
|
|
615
|
+
const content = routerMountContextContents[i] ?? "";
|
|
616
|
+
if (!content || content.length > ROUTER_INLINE_LIMIT)
|
|
617
|
+
return [];
|
|
618
|
+
return [{ file: f, content: content.trimEnd() }];
|
|
619
|
+
});
|
|
543
620
|
// Compute changedResources from classified endpoints for test discovery filtering.
|
|
544
621
|
// undefined → full-repo mode (no diff context)
|
|
545
622
|
// [] → PR mode, no endpoints found → skip external tests
|
|
@@ -568,14 +645,22 @@ export function registerAnalyzeChangesTool(server) {
|
|
|
568
645
|
}
|
|
569
646
|
else {
|
|
570
647
|
// All endpoints resolved to "unknown" (e.g. NestJS relative paths) —
|
|
571
|
-
// extract resource names from
|
|
572
|
-
const
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
648
|
+
// first try to extract resource names from router mount prefixes.
|
|
649
|
+
const changedSourceFiles = classifiedEndpoints.changedFiles ?? [];
|
|
650
|
+
const mountedResources = resolveMountPrefixTokens(routerMountContextContents, changedSourceFiles);
|
|
651
|
+
if (mountedResources.length > 0) {
|
|
652
|
+
changedResources = mountedResources;
|
|
653
|
+
}
|
|
654
|
+
else {
|
|
655
|
+
// Fall back to extracting resource names from changed file paths.
|
|
656
|
+
const candidateFiles = classifiedEndpoints.unmatchedFiles.length > 0
|
|
657
|
+
? classifiedEndpoints.unmatchedFiles
|
|
658
|
+
: classifiedEndpoints.changedFiles ?? [];
|
|
659
|
+
const fromFiles = candidateFiles
|
|
660
|
+
.map((f) => extractResourceFromPath(f.replace(/\.[^./]+$/, "").replace(FRAMEWORK_SUFFIX_RE, "")))
|
|
661
|
+
.filter((r, i, arr) => r !== "unknown" && arr.indexOf(r) === i);
|
|
662
|
+
changedResources = fromFiles.length > 0 ? fromFiles : ["unknown"];
|
|
663
|
+
}
|
|
579
664
|
}
|
|
580
665
|
}
|
|
581
666
|
else if (classifiedEndpoints.unmatchedFiles.length > 0) {
|
|
@@ -594,7 +679,15 @@ export function registerAnalyzeChangesTool(server) {
|
|
|
594
679
|
changedResources = fromFiles.length > 0 ? fromFiles : ["unknown"];
|
|
595
680
|
}
|
|
596
681
|
else {
|
|
597
|
-
|
|
682
|
+
// No endpoints and no unmatched files — the diff touches only non-route
|
|
683
|
+
// files (e.g. schema, model, DTO). Extract resource tokens from the
|
|
684
|
+
// changed file paths so tests that import the changed symbol are still
|
|
685
|
+
// surfaced for drift assessment. Fall back to [] only if extraction
|
|
686
|
+
// yields nothing (e.g. a file with a non-resource name like utils.py).
|
|
687
|
+
const fromChangedFiles = (classifiedEndpoints.changedFiles ?? [])
|
|
688
|
+
.map((f) => extractResourceFromPath(f.replace(/\.[^./]+$/, "").replace(FRAMEWORK_SUFFIX_RE, "")))
|
|
689
|
+
.filter((r, i, arr) => r !== "unknown" && arr.indexOf(r) === i);
|
|
690
|
+
changedResources = fromChangedFiles.length > 0 ? fromChangedFiles : [];
|
|
598
691
|
}
|
|
599
692
|
}
|
|
600
693
|
let existingTests = [];
|
|
@@ -875,10 +968,15 @@ export function registerAnalyzeChangesTool(server) {
|
|
|
875
968
|
sourceFile: m.sourceFile ?? "",
|
|
876
969
|
})))
|
|
877
970
|
: [];
|
|
971
|
+
const removedEndpointsForDrafting = classifiedEndpoints?.removedEndpoints.flatMap((ep) => ep.methods.map((m) => ({
|
|
972
|
+
method: m,
|
|
973
|
+
path: ep.path,
|
|
974
|
+
sourceFile: ep.sourceFile,
|
|
975
|
+
}))) ?? [];
|
|
878
976
|
const codeInferredScenarios = draftScenariosFromEndpoints(skeletonEndpoints, scenarioDraftSeed, wsAuthType, {
|
|
879
977
|
changedEndpoints: changedEndpointsForSecurityExpansion,
|
|
880
978
|
securityRelevantDiff,
|
|
881
|
-
});
|
|
979
|
+
}, removedEndpointsForDrafting);
|
|
882
980
|
let allDraftedScenarios = codeInferredScenarios;
|
|
883
981
|
if (traceResult && traceResult.userFlows.length > 0) {
|
|
884
982
|
const traceScenarios = traceResult.userFlows
|
|
@@ -1081,7 +1179,6 @@ export function registerAnalyzeChangesTool(server) {
|
|
|
1081
1179
|
// can be persisted to the state file for downstream tools (health, drift).
|
|
1082
1180
|
// Without them, analyzeTestHealth would work only off the static catalog
|
|
1083
1181
|
// which has wrong paths for nested resources and unsupported frameworks.
|
|
1084
|
-
const routerMountContext = grepRouterMountingContext(params.repositoryPath);
|
|
1085
1182
|
const routeLikeUnmatchedFiles = [];
|
|
1086
1183
|
for (const file of classifiedEndpoints?.unmatchedFiles ?? []) {
|
|
1087
1184
|
const routeLike = SOURCE_EXTS.test(file) &&
|
|
@@ -1110,25 +1207,6 @@ export function registerAnalyzeChangesTool(server) {
|
|
|
1110
1207
|
diffFilePath = path.join(os.tmpdir(), `skyramp-diff-${sessionId}.diff`);
|
|
1111
1208
|
await fs.promises.writeFile(diffFilePath, diffData.diffContent, { encoding: "utf-8", mode: 0o600 });
|
|
1112
1209
|
}
|
|
1113
|
-
// Read router mount files server-side (size-capped) so the LLM has them
|
|
1114
|
-
// inline and doesn't need an extra read step when no spec is available.
|
|
1115
|
-
const ROUTER_INLINE_LIMIT = 4096; // bytes — skip files larger than ~4 KB
|
|
1116
|
-
const ROUTER_INLINE_MAX_FILES = 3;
|
|
1117
|
-
const routerFileContents = routerMountContext
|
|
1118
|
-
.slice(0, ROUTER_INLINE_MAX_FILES)
|
|
1119
|
-
.flatMap((f) => {
|
|
1120
|
-
try {
|
|
1121
|
-
const absPath = path.isAbsolute(f) ? f : path.join(params.repositoryPath, f);
|
|
1122
|
-
const stat = fs.statSync(absPath);
|
|
1123
|
-
if (stat.size > ROUTER_INLINE_LIMIT)
|
|
1124
|
-
return [];
|
|
1125
|
-
const content = fs.readFileSync(absPath, "utf-8").trimEnd();
|
|
1126
|
-
return [{ file: f, content }];
|
|
1127
|
-
}
|
|
1128
|
-
catch {
|
|
1129
|
-
return [];
|
|
1130
|
-
}
|
|
1131
|
-
});
|
|
1132
1210
|
// Compute UI context from the diff's changed files using the shared
|
|
1133
1211
|
// `isFrontendFile` classifier. Persisting this in the stateFile lets
|
|
1134
1212
|
// skyramp_analyze_test_health and the recommendation prompt consume the
|
|
@@ -1136,9 +1214,9 @@ export function registerAnalyzeChangesTool(server) {
|
|
|
1136
1214
|
//
|
|
1137
1215
|
// candidateUiPages is enumerated programmatically via the strategy
|
|
1138
1216
|
// ladder in uiPageEnumerator (framework route grep, source-grounded
|
|
1139
|
-
// routes, root fallback). The
|
|
1140
|
-
//
|
|
1141
|
-
//
|
|
1217
|
+
// routes, root fallback). The agent uses these to capture
|
|
1218
|
+
// browser_blueprints — see uiInstructions below, which this tool returns
|
|
1219
|
+
// so the agent captures element vocabulary for UI rec reasoning.
|
|
1142
1220
|
const uiContext = await (async () => {
|
|
1143
1221
|
const changedFiles = classifiedEndpoints?.changedFiles ?? [];
|
|
1144
1222
|
if (changedFiles.length === 0)
|
|
@@ -1149,9 +1227,8 @@ export function registerAnalyzeChangesTool(server) {
|
|
|
1149
1227
|
// enumeration in.
|
|
1150
1228
|
// Compute hasFlutterSdkDep once and pass it through so .dart files
|
|
1151
1229
|
// in a Flutter project are recognised as frontend. See Confluence
|
|
1152
|
-
// "Flutter support in Testbot" — this is the
|
|
1153
|
-
//
|
|
1154
|
-
// uiAnalyzeChangesTool). Both must agree to avoid silent divergence.
|
|
1230
|
+
// "Flutter support in Testbot" — this is the budget-driving call site
|
|
1231
|
+
// that must thread the flag so a Flutter PR enters the UI pipeline.
|
|
1155
1232
|
const flutterSdk = hasFlutterSdkDep(params.repositoryPath);
|
|
1156
1233
|
const frontendFiles = changedFiles.filter((f) => isFrontendFile(f, { hasFlutterSdkDep: flutterSdk }) && !isTestFile(f));
|
|
1157
1234
|
if (frontendFiles.length === 0)
|
|
@@ -1162,6 +1239,16 @@ export function registerAnalyzeChangesTool(server) {
|
|
|
1162
1239
|
candidateUiPages,
|
|
1163
1240
|
};
|
|
1164
1241
|
})();
|
|
1242
|
+
// Derive the UI blueprint-capture instructions the agent acts on after
|
|
1243
|
+
// this call. Mirrors the branching of the former skyramp_ui_analyze_changes
|
|
1244
|
+
// pre-flight tool, now folded in here so the agent makes one analysis call
|
|
1245
|
+
// instead of two. The captures stay in the agent's tool-result history and
|
|
1246
|
+
// serve as element vocabulary when it writes UI recommendation reasoning.
|
|
1247
|
+
const uiInstructions = !uiContext || uiContext.changedFrontendFiles.length === 0
|
|
1248
|
+
? NO_UI_INSTRUCTIONS
|
|
1249
|
+
: uiContext.candidateUiPages.length === 0
|
|
1250
|
+
? NO_RESOLVABLE_URLS_INSTRUCTIONS
|
|
1251
|
+
: buildCaptureInstructions(uiContext.candidateUiPages);
|
|
1165
1252
|
const unifiedState = {
|
|
1166
1253
|
existingTests,
|
|
1167
1254
|
newEndpoints: newEndpointsForDrafting,
|
|
@@ -1215,22 +1302,37 @@ export function registerAnalyzeChangesTool(server) {
|
|
|
1215
1302
|
relevantExternalTestPaths,
|
|
1216
1303
|
},
|
|
1217
1304
|
};
|
|
1218
|
-
// Clean up old state files (>24 hours) before creating new one
|
|
1219
|
-
const stateDir = params.stateOutputFile
|
|
1220
|
-
? path.dirname(path.resolve(params.stateOutputFile))
|
|
1221
|
-
: undefined;
|
|
1305
|
+
// Clean up old state files (>24 hours) before creating new one.
|
|
1222
1306
|
try {
|
|
1223
|
-
await StateManager.cleanupOldFiles(24
|
|
1307
|
+
await StateManager.cleanupOldFiles(24);
|
|
1224
1308
|
}
|
|
1225
1309
|
catch (error) {
|
|
1226
1310
|
logger.warning(`Failed to cleanup old state files: ${error.message}`);
|
|
1227
1311
|
}
|
|
1228
|
-
|
|
1229
|
-
|
|
1312
|
+
// Resolve the state file. Multi-repo (`repository` set): all calls in one
|
|
1313
|
+
// Testbot run share ONE state file — the first call creates it and records
|
|
1314
|
+
// the run anchor; later related-repo calls reuse it (no agent-provided path,
|
|
1315
|
+
// which previously caused filename hallucinations). Single-repo (`repository`
|
|
1316
|
+
// absent): always a fresh per-call file — byte-identical to prior behavior.
|
|
1317
|
+
const activeRunPath = params.repository
|
|
1318
|
+
? getActiveRunStatePath()
|
|
1319
|
+
: undefined;
|
|
1320
|
+
const stateManager = activeRunPath
|
|
1321
|
+
? StateManager.fromStatePath(activeRunPath)
|
|
1322
|
+
: new StateManager("analysis", sessionId);
|
|
1323
|
+
// `repository` identifies which repo this analysis belongs to. The primary
|
|
1324
|
+
// (first write of the run, or matching the root's recorded repository) is
|
|
1325
|
+
// stored at the root; a related repo is stored as a keyed section within the
|
|
1326
|
+
// same run-scoped stateFile.
|
|
1327
|
+
await stateManager.writeRepoData(unifiedState, {
|
|
1328
|
+
repo: params.repository,
|
|
1230
1329
|
repositoryPath: params.repositoryPath,
|
|
1231
1330
|
step: "analyze_changes",
|
|
1232
1331
|
});
|
|
1233
1332
|
const stateFile = stateManager.getStatePath();
|
|
1333
|
+
// Anchor the run's state file so subsequent related-repo calls reuse it.
|
|
1334
|
+
if (params.repository)
|
|
1335
|
+
setActiveRunStatePath(stateFile);
|
|
1234
1336
|
registerSession(sessionId, stateFile);
|
|
1235
1337
|
try {
|
|
1236
1338
|
await server.server.sendResourceListChanged();
|
|
@@ -1348,7 +1450,7 @@ export function registerAnalyzeChangesTool(server) {
|
|
|
1348
1450
|
content: [
|
|
1349
1451
|
{
|
|
1350
1452
|
type: "text",
|
|
1351
|
-
text: `\`\`\`json\n${structuredSummary}\n\`\`\`\n\n${outputText}\n\n---\n\n## Pre-built Test Catalog — Fill in placeholders from source code, then display verbatim\n⚠️ Do NOT reformat, rename sections, or generate a new catalog. Replace \`<…from source>\` values, then show this output exactly as-is, grouped by test type.\n\n${recommendationPrompt}`,
|
|
1453
|
+
text: `\`\`\`json\n${structuredSummary}\n\`\`\`\n\n## UI Blueprint Capture — do this BEFORE writing UI recommendation reasoning\n${uiInstructions}\n\n${outputText}\n\n---\n\n## Pre-built Test Catalog — Fill in placeholders from source code, then display verbatim\n⚠️ Do NOT reformat, rename sections, or generate a new catalog. Replace \`<…from source>\` values, then show this output exactly as-is, grouped by test type.\n\n${recommendationPrompt}`,
|
|
1352
1454
|
},
|
|
1353
1455
|
],
|
|
1354
1456
|
isError: false,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|