@skyramp/mcp 0.4.4 → 0.5.0-rc.10

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 (144) hide show
  1. package/build/entitlements/entitlementGate.d.ts +8 -0
  2. package/build/entitlements/entitlementGate.js +57 -0
  3. package/build/entitlements/runCodes.d.ts +18 -0
  4. package/build/entitlements/runCodes.js +16 -0
  5. package/build/index.js +32 -6
  6. package/build/playwright/PlaywrightTraceService.d.ts +17 -0
  7. package/build/playwright/PlaywrightTraceService.js +29 -1
  8. package/build/playwright/dataSafetyConfig.d.ts +74 -0
  9. package/build/playwright/dataSafetyConfig.js +109 -0
  10. package/build/playwright/essentialTools.d.ts +1 -0
  11. package/build/playwright/essentialTools.js +44 -0
  12. package/build/playwright/registerPlaywrightTools.d.ts +36 -1
  13. package/build/playwright/registerPlaywrightTools.js +87 -43
  14. package/build/playwright/safeResolveDataSafety.d.ts +24 -0
  15. package/build/playwright/safeResolveDataSafety.js +33 -0
  16. package/build/prompts/initialize-workspace/initializeWorkspacePrompt.d.ts +17 -0
  17. package/build/prompts/initialize-workspace/initializeWorkspacePrompt.js +46 -177
  18. package/build/prompts/modularization/ui-test-modularization.d.ts +1 -0
  19. package/build/prompts/modularization/ui-test-modularization.js +9 -2
  20. package/build/prompts/test-maintenance/driftAnalysisShared.js +1 -1
  21. package/build/services/FleetExecutionService.d.ts +87 -16
  22. package/build/services/FleetExecutionService.js +487 -48
  23. package/build/services/FleetRunRegistry.d.ts +49 -0
  24. package/build/services/FleetRunRegistry.js +178 -0
  25. package/build/services/containerEnv.js +8 -2
  26. package/build/services/fleetLimitConfirmation.d.ts +19 -0
  27. package/build/services/fleetLimitConfirmation.js +126 -0
  28. package/build/tool-phases.d.ts +14 -8
  29. package/build/tool-phases.js +88 -43
  30. package/build/tools/code-refactor/assertion-state.js +3 -1
  31. package/build/tools/code-refactor/codeReuseTool.js +2 -1
  32. package/build/tools/code-refactor/utils-verify-gates.js +1 -1
  33. package/build/tools/executeFleetTool.d.ts +6 -4
  34. package/build/tools/executeFleetTool.js +67 -23
  35. package/build/tools/fixErrorTool.js +2 -1
  36. package/build/tools/fleetLifecycleTools.d.ts +20 -0
  37. package/build/tools/fleetLifecycleTools.js +124 -0
  38. package/build/tools/generate-tests/generateIntegrationRestTool.d.ts +38 -0
  39. package/build/tools/generate-tests/generateIntegrationRestTool.js +7 -1
  40. package/build/tools/generate-tests/generateUILoadRestTool.d.ts +19 -1
  41. package/build/tools/generate-tests/generateUILoadRestTool.js +316 -50
  42. package/build/tools/submitReportTool.js +4 -122
  43. package/build/tools/test-management/registerTestPlanTool.js +22 -6
  44. package/build/tools/workspace/initScanWorkspaceTool.d.ts +11 -1
  45. package/build/tools/workspace/initScanWorkspaceTool.js +111 -9
  46. package/build/tools/workspace/initializeWorkspaceTool.js +40 -4
  47. package/build/types/AssertionOutcome.d.ts +3 -0
  48. package/build/types/TestbotReport.d.ts +0 -37
  49. package/build/types/TestbotReport.js +0 -22
  50. package/build/types/index.d.ts +1 -1
  51. package/build/types/index.js +1 -1
  52. package/build/utils/assertion-verify/created-add-guard.d.ts +12 -0
  53. package/build/utils/assertion-verify/created-add-guard.js +173 -0
  54. package/build/utils/assertion-verify/index.d.ts +1 -0
  55. package/build/utils/assertion-verify/index.js +1 -0
  56. package/build/utils/assertion-verify/verify.d.ts +7 -3
  57. package/build/utils/assertion-verify/verify.js +9 -3
  58. package/build/utils/featureFlags.js +6 -3
  59. package/build/utils/repositorySlug.d.ts +14 -0
  60. package/build/utils/repositorySlug.js +46 -1
  61. package/build/utils/telemetry.d.ts +2 -0
  62. package/build/utils/telemetry.js +12 -0
  63. package/build/utils/utils-verify/action-key.d.ts +59 -2
  64. package/build/utils/utils-verify/action-key.js +162 -6
  65. package/build/utils/utils-verify/action-sites.d.ts +7 -0
  66. package/build/utils/utils-verify/action-sites.js +277 -35
  67. package/build/utils/utils-verify/call-sites.d.ts +8 -2
  68. package/build/utils/utils-verify/language-spec.js +1 -1
  69. package/build/utils/utils-verify/parse.d.ts +4 -0
  70. package/build/utils/utils-verify/parse.js +2 -1
  71. package/build/utils/versions.d.ts +3 -3
  72. package/build/utils/versions.js +1 -1
  73. package/build/workspace/workspace.d.ts +63 -121
  74. package/build/workspace/workspace.js +45 -48
  75. package/build/workspace/workspaceVerifier.d.ts +22 -0
  76. package/build/workspace/workspaceVerifier.js +65 -0
  77. package/node_modules/playwright/lib/dom-analyzer/blueprint.js +7 -6
  78. package/node_modules/playwright/lib/dom-analyzer/dynamicId.js +5 -4
  79. package/node_modules/playwright/lib/dom-analyzer/dynamicId.test.js +12 -0
  80. package/node_modules/playwright/lib/mcp/skyramp/dataSafetyGuard.js +822 -0
  81. package/node_modules/playwright/lib/mcp/skyramp/dataSafetySession.js +372 -0
  82. package/node_modules/playwright/lib/mcp/skyramp/exportTool.js +101 -8
  83. package/node_modules/playwright/lib/mcp/skyramp/finishTestSetupTool.js +45 -0
  84. package/node_modules/playwright/lib/mcp/skyramp/index.js +16 -0
  85. package/node_modules/playwright/lib/mcp/skyramp/recordingPhase.js +65 -0
  86. package/node_modules/playwright/lib/mcp/skyramp/skyRampImport.js +1 -0
  87. package/node_modules/playwright/lib/mcp/skyramp/traceRecordingBackend.js +598 -127
  88. package/node_modules/playwright/lib/mcp/test/skyRampExport.js +85 -31
  89. package/node_modules/playwright/lib/mcp/test/skyRampExport.test.js +132 -5
  90. package/node_modules/playwright/node_modules/playwright-core/lib/cli/program.js +2 -0
  91. package/node_modules/playwright/node_modules/playwright-core/lib/client/browserContext.js +4 -2
  92. package/node_modules/playwright/node_modules/playwright-core/lib/generated/injectedScriptSource.js +1 -1
  93. package/node_modules/playwright/node_modules/playwright-core/lib/generated/pollingRecorderSource.js +1 -1
  94. package/node_modules/playwright/node_modules/playwright-core/lib/protocol/validator.js +2 -1
  95. package/node_modules/playwright/node_modules/playwright-core/lib/server/browserContext.js +17 -1
  96. package/node_modules/playwright/node_modules/playwright-core/lib/server/codegen/skyramp/jsonlReader.js +1 -0
  97. package/node_modules/playwright/node_modules/playwright-core/lib/server/har/harRecorder.js +1 -0
  98. package/node_modules/playwright/node_modules/playwright-core/lib/server/har/harTracer.js +1 -1
  99. package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/recorderRunner.js +2 -1
  100. package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/recorderSignalProcessor.js +2 -1
  101. package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/skyramp/clickExpandedState.js +75 -0
  102. package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder.js +4 -2
  103. package/node_modules/playwright/node_modules/playwright-core/lib/utils/isomorphic/volatileDate.js +85 -0
  104. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/{codeMirrorModule-Bou8kKzE.js → codeMirrorModule-BuhAdckO.js} +1 -1
  105. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-COAHN430.js +809 -0
  106. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/{index.0MJW0uG7.js → index.7AU8h0PZ.js} +1 -1
  107. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.html +2 -2
  108. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/{uiMode.GLqsx5cI.js → uiMode.Dl7smBJn.js} +1 -1
  109. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.html +2 -2
  110. package/node_modules/playwright/node_modules/playwright-core/package.json +1 -1
  111. package/node_modules/playwright/node_modules/playwright-core/src/cli/program.ts +5 -0
  112. package/node_modules/playwright/node_modules/playwright-core/src/client/browserContext.ts +3 -1
  113. package/node_modules/playwright/node_modules/playwright-core/src/client/types.ts +2 -0
  114. package/node_modules/playwright/node_modules/playwright-core/src/generated/injectedScriptSource.ts +1 -1
  115. package/node_modules/playwright/node_modules/playwright-core/src/generated/pollingRecorderSource.ts +1 -1
  116. package/node_modules/playwright/node_modules/playwright-core/src/protocol/validator.ts +1 -0
  117. package/node_modules/playwright/node_modules/playwright-core/src/server/browserContext.ts +25 -1
  118. package/node_modules/playwright/node_modules/playwright-core/src/server/codegen/skyramp/jsonlReader.ts +2 -0
  119. package/node_modules/playwright/node_modules/playwright-core/src/server/har/harRecorder.ts +1 -0
  120. package/node_modules/playwright/node_modules/playwright-core/src/server/har/harTracer.ts +3 -1
  121. package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/recorderRunner.ts +3 -1
  122. package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/recorderSignalProcessor.ts +1 -0
  123. package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/skyramp/clickExpandedState.ts +82 -0
  124. package/node_modules/playwright/node_modules/playwright-core/src/server/recorder.ts +2 -0
  125. package/node_modules/playwright/node_modules/playwright-core/src/utils/isomorphic/volatileDate.ts +137 -1
  126. package/node_modules/playwright/package.json +1 -1
  127. package/package.json +4 -4
  128. package/plugin/prompts/plan-tests.md +2 -2
  129. package/plugin/prompts/testbot-task1.md +1 -1
  130. package/plugin/skills/enhance-assertions/reference/integration.md +1 -0
  131. package/plugin/skills/setup-testbot-target-sut/SKILL.md +60 -0
  132. package/plugin/skills/setup-testbot-target-sut/reference/ci-workflow.md +26 -0
  133. package/plugin/skills/setup-testbot-target-sut/reference/deployed-environment.md +105 -0
  134. package/plugin/skills/setup-testbot-target-sut/reference/existing-tests.md +14 -0
  135. package/plugin/skills/setup-testbot-target-sut/reference/troubleshooting.md +20 -0
  136. package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.d.ts +0 -2
  137. package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.js +0 -178
  138. package/build/prompts/sut-setup/modes/dockerComposePrompt.d.ts +0 -2
  139. package/build/prompts/sut-setup/modes/dockerComposePrompt.js +0 -311
  140. package/build/prompts/sut-setup/shared.d.ts +0 -62
  141. package/build/prompts/sut-setup/shared.js +0 -196
  142. package/build/resources/sutSetupResource.d.ts +0 -2
  143. package/build/resources/sutSetupResource.js +0 -63
  144. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-DTp2-8Si.js +0 -809
@@ -1,24 +1,38 @@
1
1
  import { z } from "zod";
2
- import { executeFleet, JAVA_CLASS_NAME, } from "../services/FleetExecutionService.js";
2
+ import { FLEET_ENTRY_NAME } from "../services/FleetExecutionService.js";
3
+ import { fleetRuns } from "../services/FleetRunRegistry.js";
4
+ import { assertFleetLimitsConfirmed } from "../services/fleetLimitConfirmation.js";
3
5
  import { logger } from "../utils/logger.js";
4
6
  import { toolError } from "../utils/utils.js";
5
7
  const TOOL_NAME = "skyramp_execute_fleet";
6
8
  export const fleetExecutionInputSchema = {
7
9
  directory: z
8
10
  .string()
9
- .describe("Directory holding a generated Java ui-load trio (the fleet, load and journey " +
10
- "classes) and, usually, its credentials.csv. Java only: a python, typescript or " +
11
- "javascript fleet manager is a script, run it directly."),
11
+ .describe("Directory holding a generated ui-load trio (the fleet manager, load and journey " +
12
+ "files) in java, python, typescript or javascript and, usually, its credentials.csv."),
12
13
  entryClass: z
13
14
  .string()
14
- .regex(JAVA_CLASS_NAME)
15
+ .regex(FLEET_ENTRY_NAME)
15
16
  .optional()
16
- .describe("The fleet class to run. Discovered from *FleetTest.java when omitted."),
17
+ .describe("The fleet manager to run: a Java class name, or a python/typescript/javascript file " +
18
+ "name (X_fleet.py, X_fleet.ts, X_fleet.js). Discovered from *FleetTest.java, " +
19
+ "*_fleet.py, *_fleet.ts or *_fleet.js when omitted."),
17
20
  certsDir: z
18
21
  .string()
19
- .describe("Docker client certificates for the remote engine (ca.pem, cert.pem, key.pem). " +
20
- "Required: the run needs a remote engine, and a remote engine is mTLS. Mounted " +
21
- "read-only and exported as SKYRAMP_DOCKER_CERTS."),
22
+ .optional()
23
+ .describe("Docker client certificates for a remote engine (ca.pem, cert.pem, key.pem). " +
24
+ "Required when a host of the fleet names a remote Docker engine, which is mTLS. " +
25
+ "Mounted read-only and exported as SKYRAMP_DOCKER_CERTS. A fleet whose hosts name " +
26
+ "no dockerHost deploys on the local Docker daemon and needs none. dockerHost is " +
27
+ "read from the file's text, so write each host's options inline with dockerHost " +
28
+ '(if any) as a string literal ("tcp://…:2376"), not a variable or a spread -- the ' +
29
+ "latter reads as no dockerHost found, which this tool refuses rather than guess."),
30
+ localDocker: z
31
+ .boolean()
32
+ .optional()
33
+ .describe("Allow a fleet that deploys on the local Docker daemon. The daemon's socket is " +
34
+ "mounted into the executor, which gives the fleet code root-level access to this " +
35
+ "host. Off by default: set it only after the user agreed to that."),
22
36
  credentials: z
23
37
  .string()
24
38
  .optional()
@@ -26,12 +40,19 @@ export const fleetExecutionInputSchema = {
26
40
  libraryJar: z
27
41
  .string()
28
42
  .optional()
29
- .describe("A branch-built skyramp-library jar to compile and run against, for a fix that is not " +
30
- "released yet. The executor image's own SDK is used when this is omitted."),
43
+ .describe("Java only: a branch-built skyramp-library jar to compile and run against, for a fix " +
44
+ "that is not released yet. The executor image's own SDK is used when this is omitted."),
45
+ libraryPackage: z
46
+ .string()
47
+ .optional()
48
+ .describe("Python, typescript or javascript: a branch-built SDK package to run against, for a " +
49
+ "fix that is not released yet -- a pip .whl or .tar.gz for python, an npm .tgz for " +
50
+ "typescript and javascript. Installed over the executor image's SDK before the " +
51
+ "fleet starts; the image's own SDK is used when this is omitted."),
31
52
  executorImage: z
32
53
  .string()
33
54
  .optional()
34
- .describe("Container image to compile and run in. Defaults to the released executor, or " +
55
+ .describe("Container image to run in. Defaults to the released executor, or " +
35
56
  "SKYRAMP_EXECUTOR_IMAGE. Name a branch-built one when its baked SDK is what you " +
36
57
  "are testing."),
37
58
  platform: z
@@ -49,6 +70,12 @@ export const fleetExecutionInputSchema = {
49
70
  .record(z.string(), z.string())
50
71
  .optional()
51
72
  .describe("Extra environment for the run, e.g. SKYRAMP_TEST_BASE_URL."),
73
+ confirmationToken: z
74
+ .string()
75
+ .optional()
76
+ .describe("Required when the fleet file sets limits: the token returned beside the echoed " +
77
+ "normalized limits. Pass it only after the user confirmed those limits. A fleet " +
78
+ "without limits needs none."),
52
79
  };
53
80
  /**
54
81
  * Runs a generated fleet test and reports what happened.
@@ -57,40 +84,57 @@ export const fleetExecutionInputSchema = {
57
84
  * executor container every other generated test runs in compiles the trio and starts the
58
85
  * fleet manager, and the caller gets the run's own report plus its result as data.
59
86
  *
60
- * The worker is deployed by the test, not by this tool, so the run needs a remote Docker
61
- * engine: inside a container, a locally deployed worker is not reachable at the localhost
62
- * address the fleet resolves for it.
87
+ * The worker is deployed by the test, not by this tool: on a remote Docker engine over mTLS,
88
+ * or, for a host that names no engine, on the local daemon through its socket.
63
89
  */
64
90
  export function registerExecuteFleetTool(server) {
65
91
  server.registerTool(TOOL_NAME, {
66
92
  title: "Execute a generated fleet test",
67
- description: "Compile and run a generated Java ui-load fleet trio in the Skyramp executor container, " +
68
- "against a remote Docker engine, and return the run's report, its verdict and its " +
69
- "structured result. Point it at the directory the generation wrote.",
93
+ description: "Run a generated ui-load fleet trio (java, python, typescript or javascript) in the Skyramp executor container " +
94
+ "and return the run's report, its verdict and its structured result. It blocks until " +
95
+ "the run ends and relays no limit events while it runs: prefer skyramp_start_fleet " +
96
+ "when the client can poll. The fleet deploys " +
97
+ "its workers on the Docker engines its hosts name: a remote engine needs certsDir, a " +
98
+ "host with no dockerHost deploys on the local Docker daemon and needs no " +
99
+ "certificates but needs localDocker: true, because the daemon's socket gives the run " +
100
+ "root-level access to this host. Point it at the directory the generation wrote. A fleet with limits " +
101
+ "needs the confirmationToken returned beside its echoed limits; pass it only after the " +
102
+ "user confirmed those limits. The token ties the run to the echoed limits, it does not " +
103
+ "record the user's confirmation.",
70
104
  inputSchema: z.object(fleetExecutionInputSchema),
71
- }, async (args) => {
105
+ }, async (args, extra) => {
72
106
  try {
73
- const run = await executeFleet({
107
+ assertFleetLimitsConfirmed(args);
108
+ // Through the registry, so a blocking run shares the one-run-per-directory guard.
109
+ const run = await fleetRuns.run({
74
110
  directory: args.directory,
75
111
  executorImage: args.executorImage,
76
112
  platform: args.platform,
77
113
  entryClass: args.entryClass,
78
114
  certsDir: args.certsDir,
115
+ localDocker: args.localDocker,
79
116
  credentials: args.credentials,
80
117
  libraryJar: args.libraryJar,
118
+ libraryPackage: args.libraryPackage,
81
119
  timeoutSec: args.timeoutSec,
82
120
  env: args.env,
83
- });
121
+ }, extra.mcpReq.signal);
84
122
  const headline = run.timedOut
85
123
  ? `Fleet run timed out after ${args.timeoutSec ?? 600}s`
86
- : `Fleet run ${run.passed ? "PASSED" : "FAILED"} (${run.entryClass} in ${run.executorImage}, exit ${run.exitCode})`;
124
+ : run.cancelled
125
+ ? "Fleet run cancelled"
126
+ : `Fleet run ${run.passed ? "PASSED" : "FAILED"} (${run.entryClass} in ${run.executorImage}, exit ${run.exitCode})`;
87
127
  const text = [
88
128
  headline,
89
129
  run.report || "(the run printed no report lines)",
90
130
  run.result
91
131
  ? "Structured result:\n" + JSON.stringify(run.result, null, 2)
92
132
  : "",
93
- run.passed ? "" : "Output:\n" + run.output.slice(-4000),
133
+ run.passed
134
+ ? ""
135
+ : "Output:\n" +
136
+ run.output.slice(-4000) +
137
+ (run.outputLog ? `\n(full log: ${run.outputLog})` : ""),
94
138
  ]
95
139
  .filter(Boolean)
96
140
  .join("\n\n");
@@ -58,8 +58,9 @@ export function registerFixErrorTool(server) {
58
58
  return errorResult;
59
59
  }
60
60
  finally {
61
+ // No prompt: it carries the user's test code, and PushToolEvent
62
+ // forwards every field verbatim.
61
63
  AnalyticsService.pushMCPToolEvent(TOOL_NAME, errorResult, {
62
- prompt: params.prompt,
63
64
  testFile: params.testFile,
64
65
  }).catch((err) => {
65
66
  logger.warning("Analytics event failed", { error: String(err) });
@@ -0,0 +1,20 @@
1
+ import { McpServer } from "@modelcontextprotocol/server";
2
+ import type { FleetExecutionResult } from "../services/FleetExecutionService.js";
3
+ /** The most run output a result carries; a multi-hour run's log stays on disk. */
4
+ export declare const MAX_RESULT_OUTPUT: number;
5
+ /** The result with its output cut to the last MAX_RESULT_OUTPUT characters, saying so. */
6
+ export declare function boundedResult(result: FleetExecutionResult): FleetExecutionResult | {
7
+ output: string;
8
+ outputTruncated: string;
9
+ passed: boolean;
10
+ executorImage: string;
11
+ platform: import("../services/FleetExecutionService.js").ContainerPlatform;
12
+ entryClass: string;
13
+ exitCode: number | null;
14
+ report: string;
15
+ result?: unknown;
16
+ timedOut?: boolean;
17
+ cancelled?: boolean;
18
+ outputLog?: string;
19
+ };
20
+ export declare function registerFleetLifecycleTools(server: McpServer): void;
@@ -0,0 +1,124 @@
1
+ import { z } from "zod";
2
+ import { SkyrampClient } from "@skyramp/skyramp";
3
+ import { fleetRuns } from "../services/FleetRunRegistry.js";
4
+ import { assertFleetLimitsConfirmed } from "../services/fleetLimitConfirmation.js";
5
+ import { fleetExecutionInputSchema } from "./executeFleetTool.js";
6
+ import { toolError } from "../utils/utils.js";
7
+ import { makeProgressReporter } from "../utils/progress.js";
8
+ const response = (value) => ({
9
+ content: [{ type: "text", text: JSON.stringify(value) }],
10
+ });
11
+ const errorResponse = (error) => toolError(error instanceof Error ? error.message : String(error));
12
+ /** The most run output a result carries; a multi-hour run's log stays on disk. */
13
+ export const MAX_RESULT_OUTPUT = 64 * 1024;
14
+ /** The result with its output cut to the last MAX_RESULT_OUTPUT characters, saying so. */
15
+ export function boundedResult(result) {
16
+ if (result.output.length <= MAX_RESULT_OUTPUT)
17
+ return result;
18
+ return {
19
+ ...result,
20
+ output: result.output.slice(-MAX_RESULT_OUTPUT),
21
+ outputTruncated: `output cut to its last ${MAX_RESULT_OUTPUT} of ${result.output.length} characters; ` +
22
+ (result.outputLog
23
+ ? `the full log is ${result.outputLog}`
24
+ : "the full log could not be written to disk"),
25
+ };
26
+ }
27
+ export function registerFleetLifecycleTools(server) {
28
+ server.registerTool("skyramp_kpi_catalog", {
29
+ title: "Read the fleet KPI catalogue",
30
+ description: "Read native limit KPI names, base units, valid aggregations, scopes, deferred features and site defaults. A unitless rate is a ratio (0..1). Translate latency in seconds to ms. Ask instead of inventing unknown metrics, scopes, ambiguous units or sustained-breach durations. No run is started.",
31
+ inputSchema: z.object({}),
32
+ annotations: { readOnlyHint: true },
33
+ }, async () => {
34
+ try {
35
+ const client = new SkyrampClient();
36
+ if (!client.getFleetLimitCatalogue)
37
+ throw new Error("installed SDK lacks the native limit catalogue; upgrade the SDK");
38
+ return response(client.getFleetLimitCatalogue());
39
+ }
40
+ catch (error) {
41
+ return errorResponse(error);
42
+ }
43
+ });
44
+ server.registerTool("skyramp_start_fleet", {
45
+ title: "Start a fleet and return its run id",
46
+ description: "Start a generated fleet asynchronously. A fleet with limits needs confirmationToken: the token returned beside the echoed normalized limits, passed only after the user confirmed them. The token ties the run to the echoed limits, it does not record the user's confirmation. A fleet on the local Docker daemon needs localDocker: true, because the daemon's socket gives the run root-level access to this host. Keep this MCP session open. Poll skyramp_fleet_status every few seconds, relay each tripped/cleared limit event immediately, then collect skyramp_fleet_result. The fleet core, not the agent, decides warnings, failure and stopping.",
47
+ inputSchema: z.object(fleetExecutionInputSchema),
48
+ }, async ({ confirmationToken, ...args }) => {
49
+ try {
50
+ assertFleetLimitsConfirmed({ ...args, confirmationToken });
51
+ return response({ runId: fleetRuns.start(args) });
52
+ }
53
+ catch (error) {
54
+ return errorResponse(error);
55
+ }
56
+ });
57
+ server.registerTool("skyramp_fleet_status", {
58
+ title: "Read new live fleet events",
59
+ description: "Poll the same MCP session with runId and the previous next cursor. Relay limit events while the run is in progress; do not wait for the final report. An event is emitted once per transition. A call returns at most 200 events; when more is true, call again at once with next. truncated means the caller fell behind retention.",
60
+ inputSchema: z.object({
61
+ runId: z
62
+ .string()
63
+ .describe("The run id returned by skyramp_start_fleet."),
64
+ since: z
65
+ .number()
66
+ .int()
67
+ .nonnegative()
68
+ .default(0)
69
+ .describe("The next cursor from the previous skyramp_fleet_status response; 0 on the first call. Not an elapsed time or event count."),
70
+ }),
71
+ annotations: { readOnlyHint: true },
72
+ }, async ({ runId, since }, ctx) => {
73
+ try {
74
+ const status = fleetRuns.status(runId, since);
75
+ const notify = makeProgressReporter(ctx);
76
+ for (const item of status.events)
77
+ await notify(item.sequence + 1, status.next, JSON.stringify(item.event));
78
+ return response(status);
79
+ }
80
+ catch (error) {
81
+ return errorResponse(error);
82
+ }
83
+ });
84
+ server.registerTool("skyramp_fleet_result", {
85
+ title: "Collect a completed fleet report",
86
+ description: "Read the completed fleet's deterministic report, verdict and structured result. release=true also removes the retained job; only use it after saving the result. A running job is never removed.",
87
+ inputSchema: z.object({
88
+ runId: z
89
+ .string()
90
+ .describe("The run id returned by skyramp_start_fleet."),
91
+ release: z
92
+ .boolean()
93
+ .default(false)
94
+ .describe("When true, also remove the retained job after reading it. Only use after saving the result; a running job is never removed."),
95
+ }),
96
+ }, async ({ runId, release }) => {
97
+ try {
98
+ const result = fleetRuns.result(runId, release);
99
+ return {
100
+ ...response(boundedResult(result)),
101
+ ...(result.passed ? {} : { isError: true }),
102
+ };
103
+ }
104
+ catch (error) {
105
+ return errorResponse(error);
106
+ }
107
+ });
108
+ server.registerTool("skyramp_fleet_cancel", {
109
+ title: "Cancel a running fleet",
110
+ description: "Cancel a fleet started with skyramp_start_fleet, by runId, when the user asks to stop it. The run is interrupted so the fleet can cancel its workers, and killed if it has not ended after a grace period. Poll skyramp_fleet_status until done, then collect skyramp_fleet_result. Cancelling a finished run changes nothing.",
111
+ inputSchema: z.object({
112
+ runId: z
113
+ .string()
114
+ .describe("The run id returned by skyramp_start_fleet."),
115
+ }),
116
+ }, async ({ runId }) => {
117
+ try {
118
+ return response(fleetRuns.cancel(runId));
119
+ }
120
+ catch (error) {
121
+ return errorResponse(error);
122
+ }
123
+ });
124
+ }
@@ -1,6 +1,43 @@
1
1
  import { McpServer, CallToolResult } from "@modelcontextprotocol/server";
2
+ import { z } from "zod";
2
3
  import { TestType } from "../../types/TestTypes.js";
3
4
  import { TestGenerationService, BaseTestParams } from "../../services/TestGenerationService.js";
5
+ export declare const integrationTestSchema: {
6
+ language: z.ZodEnum<typeof import("../../types/TestTypes.js").ProgrammingLanguage>;
7
+ framework: z.ZodString;
8
+ output: z.ZodOptional<z.ZodString>;
9
+ deployDashboard: z.ZodDefault<z.ZodBoolean>;
10
+ runtime: z.ZodDefault<z.ZodPreprocess<z.ZodEnum<typeof import("../../types/TestTypes.js").RuntimeEnvironment>, unknown>>;
11
+ dockerNetwork: z.ZodDefault<z.ZodString>;
12
+ dockerWorkerPort: z.ZodDefault<z.ZodNumber>;
13
+ k8sNamespace: z.ZodDefault<z.ZodString>;
14
+ k8sConfig: z.ZodDefault<z.ZodString>;
15
+ k8sContext: z.ZodDefault<z.ZodString>;
16
+ authHeader: z.ZodDefault<z.ZodString>;
17
+ authScheme: z.ZodDefault<z.ZodString>;
18
+ insecure: z.ZodDefault<z.ZodBoolean>;
19
+ outputDir: z.ZodString;
20
+ force: z.ZodDefault<z.ZodBoolean>;
21
+ mockPort: z.ZodDefault<z.ZodNumber>;
22
+ optionalFields: z.ZodDefault<z.ZodBoolean>;
23
+ prompt: z.ZodString;
24
+ trace: z.ZodOptional<z.ZodString>;
25
+ include: z.ZodOptional<z.ZodDefault<z.ZodArray<z.ZodString>>>;
26
+ exclude: z.ZodOptional<z.ZodDefault<z.ZodArray<z.ZodString>>>;
27
+ codeReuse: z.ZodDefault<z.ZodBoolean>;
28
+ modularizeCode: z.ZodDefault<z.ZodBoolean>;
29
+ pathParams: z.ZodDefault<z.ZodString>;
30
+ queryParams: z.ZodDefault<z.ZodString>;
31
+ formParams: z.ZodDefault<z.ZodString>;
32
+ enhanceAssertions: z.ZodDefault<z.ZodBoolean>;
33
+ endpointURL: z.ZodDefault<z.ZodString>;
34
+ apiSchema: z.ZodDefault<z.ZodString>;
35
+ requestData: z.ZodDefault<z.ZodString>;
36
+ responseStatusCode: z.ZodDefault<z.ZodString>;
37
+ chainingKey: z.ZodOptional<z.ZodString>;
38
+ scenarioFile: z.ZodOptional<z.ZodString>;
39
+ emitIntegrationTeardown: z.ZodDefault<z.ZodBoolean>;
40
+ };
4
41
  export declare class IntegrationTestService extends TestGenerationService {
5
42
  protected getTestType(): TestType;
6
43
  generateTest(params: BaseTestParams & Record<string, any>): Promise<CallToolResult>;
@@ -9,6 +46,7 @@ export declare class IntegrationTestService extends TestGenerationService {
9
46
  responseData?: string;
10
47
  playwrightInput?: string;
11
48
  scenarioFile?: string;
49
+ emitIntegrationTeardown?: boolean;
12
50
  }): any;
13
51
  protected handleApiAnalysis(_params: BaseTestParams): Promise<CallToolResult | null>;
14
52
  }
@@ -11,8 +11,13 @@ import { readScenarioNameFromFile } from "./scenarioFileIdentity.js";
11
11
  import { toolError } from "../../utils/utils.js";
12
12
  import { enhanceAssertionsStep } from "../../skills/enhanceAssertionsSkill.js";
13
13
  const ADD_ASSERTIONS_DEFAULT = isTestbotEnabled();
14
- const integrationTestSchema = z
14
+ export const integrationTestSchema = z
15
15
  .object({
16
+ emitIntegrationTeardown: z
17
+ .boolean()
18
+ .default(false)
19
+ .describe("Register every record the test creates with the client's created-resources scope so the library deletes them in reverse order when the test exits, on success and on failure. " +
20
+ "Use for tests that create data against a shared or long-lived target."),
16
21
  enhanceAssertions: z
17
22
  .boolean()
18
23
  .default(ADD_ASSERTIONS_DEFAULT)
@@ -80,6 +85,7 @@ ${enhanceAssertionsStep("integration", "generated test file")}
80
85
  responseData: params.responseData,
81
86
  playwrightInput: params.playwrightInput,
82
87
  scenarioFile: params.scenarioFile,
88
+ emitIntegrationTeardown: params.emitIntegrationTeardown ?? false,
83
89
  };
84
90
  }
85
91
  async handleApiAnalysis(_params) {
@@ -25,24 +25,33 @@ export declare const uiLoadTestSchema: {
25
25
  address: z.ZodDefault<z.ZodString>;
26
26
  workerImage: z.ZodDefault<z.ZodString>;
27
27
  workerTag: z.ZodDefault<z.ZodString>;
28
+ browserSessions: z.ZodDefault<z.ZodNumber>;
28
29
  }, z.core.$strip>>;
29
- browserCoverage: z.ZodDefault<z.ZodNumber>;
30
30
  loadDuration: z.ZodDefault<z.ZodNumber>;
31
31
  loadNumThreads: z.ZodDefault<z.ZodNumber>;
32
32
  loadCount: z.ZodDefault<z.ZodNumber>;
33
33
  loadTargetRPS: z.ZodDefault<z.ZodNumber>;
34
+ coresPerBrowser: z.ZodOptional<z.ZodNumber>;
34
35
  loadRampupDuration: z.ZodDefault<z.ZodNumber>;
35
36
  loadRampupInterval: z.ZodDefault<z.ZodNumber>;
37
+ limits: z.ZodOptional<z.ZodArray<z.ZodString>>;
36
38
  thresholds: z.ZodDefault<z.ZodString>;
37
39
  deployWorker: z.ZodDefault<z.ZodBoolean>;
38
40
  include: z.ZodDefault<z.ZodArray<z.ZodString>>;
39
41
  exclude: z.ZodDefault<z.ZodArray<z.ZodString>>;
40
42
  output: z.ZodDefault<z.ZodString>;
41
43
  outputDir: z.ZodString;
44
+ credentialsFile: z.ZodOptional<z.ZodString>;
42
45
  allowTraceReuse: z.ZodDefault<z.ZodBoolean>;
43
46
  force: z.ZodDefault<z.ZodBoolean>;
44
47
  };
45
48
  type UILoadParams = z.infer<z.ZodObject<typeof uiLoadTestSchema>>;
49
+ /**
50
+ * Legacy threshold keys in the limit form the fleet core maps them to (D7): inclusive
51
+ * bounds, evaluated per region and overall, CPU per host. For the echo only; the
52
+ * thresholds themselves still reach the generator unchanged.
53
+ */
54
+ export declare function legacyThresholdLimits(thresholds: string): string[];
46
55
  /**
47
56
  * Generate the three ui-load files from one Playwright trace.
48
57
  *
@@ -51,6 +60,15 @@ type UILoadParams = z.infer<z.ZodObject<typeof uiLoadTestSchema>>;
51
60
  * hosts and a browser/protocol split that the shared wrapper has no room for.
52
61
  */
53
62
  export declare function generateUILoadTest(params: UILoadParams): Promise<CallToolResult>;
63
+ /**
64
+ * Copy the credential pool (credentialsFile, else credentials.csv beside the recorded
65
+ * session) to credentials.csv beside the generated files, where the fleet reads it; an
66
+ * existing one is left alone. Returns a line for the tool's result, or "" when not needed.
67
+ */
68
+ export declare function placeCredentialPool(files: string[], outputDir: string, params: {
69
+ credentialsFile?: string;
70
+ playwrightStoragePath?: string;
71
+ }): string;
54
72
  /**
55
73
  * The tool's entry point: the trace-reuse guard and the usage event around the generation,
56
74
  * as skyramp_ui_test_generation has them.