@skyramp/mcp 0.0.63-rc.7 → 0.0.63

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.
@@ -170,8 +170,8 @@ Call \`skyramp_submit_report\` with \`summaryOutputFile\`: "${summaryOutputFile}
170
170
 
171
171
  **nextSteps** — actionable next steps when test failures suggest misconfiguration.
172
172
  Each entry must be a single-line string (no embedded newlines).
173
- If multiple tests fail with 404 NOT_FOUND or connection refused on endpoints that ARE defined in the diff, add: "Some endpoints returned 404 — verify your \`target_setup_command\` deploys the PR branch and \`target_ready_check_command\` confirms the service is healthy."
174
- If tests fail with 401/403 on endpoints that require auth, add a step about \`auth_token_command\`.
173
+ If multiple tests fail with 404 NOT_FOUND or connection refused on endpoints that ARE defined in the diff, add: "Some endpoints returned 404 — verify your \`targetSetupCommand\` deploys the PR branch and \`targetReadyCheckCommand\` confirms the service is healthy."
174
+ If tests fail with 401/403 on endpoints that require auth, add a step about \`authTokenCommand\`.
175
175
  Only add next steps for systemic patterns (3+ tests with the same error class), not individual failures.
176
176
 
177
177
  **businessCaseAnalysis** — 1-2 sentences describing what user-facing interactions this PR
@@ -8,7 +8,7 @@ import { logger } from "../utils/logger.js";
8
8
  import { buildContainerEnv } from "./containerEnv.js";
9
9
  const DEFAULT_TIMEOUT = 300000; // 5 minutes
10
10
  const MAX_CONCURRENT_EXECUTIONS = 5;
11
- export const EXECUTOR_DOCKER_IMAGE = "skyramp/executor:v1.3.14";
11
+ export const EXECUTOR_DOCKER_IMAGE = "skyramp/executor:v1.3.15";
12
12
  const DOCKER_PLATFORM = "linux/amd64";
13
13
  const EXECUTION_PROGRESS_INTERVAL = 10000; // 10 seconds between progress updates during execution
14
14
  // Temp file with valid empty JSON — used instead of /dev/null for .json config files
@@ -1,3 +1,4 @@
1
+ import path from "path";
1
2
  import { z } from "zod";
2
3
  import { baseTestSchema, TestType } from "../../types/TestTypes.js";
3
4
  import { TestGenerationService, } from "../../services/TestGenerationService.js";
@@ -30,11 +31,31 @@ const contractTestSchema = {
30
31
  providerOutput: z
31
32
  .string()
32
33
  .optional()
33
- .describe("Absolute file path for the generated provider contract test file"),
34
+ .refine((val) => {
35
+ if (!val || val === "")
36
+ return true;
37
+ const validExtensions = [".py", ".ts", ".js", ".java"];
38
+ return validExtensions.some((ext) => val.endsWith(ext));
39
+ }, { message: "Output file must have one of these extensions: .py, .ts, .js, .java" })
40
+ .describe("Output file for the generated provider contract test. " +
41
+ "For Playwright framework, the file must match *.spec.ts so Playwright can discover it " +
42
+ "(e.g. contract_provider_orders.spec.ts). " +
43
+ "For other frameworks (pytest, junit), standard extensions are fine (.py, .java). " +
44
+ "Optional — when omitted, Skyramp generates a default name."),
34
45
  consumerOutput: z
35
46
  .string()
36
47
  .optional()
37
- .describe("Absolute file path for the generated consumer contract test file"),
48
+ .refine((val) => {
49
+ if (!val || val === "")
50
+ return true;
51
+ const validExtensions = [".py", ".ts", ".js", ".java"];
52
+ return validExtensions.some((ext) => val.endsWith(ext));
53
+ }, { message: "Output file must have one of these extensions: .py, .ts, .js, .java" })
54
+ .describe("Output file for the generated consumer contract test. " +
55
+ "For Playwright framework, the file must match *.spec.ts so Playwright can discover it " +
56
+ "(e.g. contract_consumer_orders.spec.ts). " +
57
+ "For other frameworks (pytest, junit), standard extensions are fine (.py, .java). " +
58
+ "Optional — when omitted, Skyramp generates a default name."),
38
59
  parentRequestData: z
39
60
  .record(z.string(), z.string())
40
61
  .optional()
@@ -55,6 +76,13 @@ const contractTestSchema = {
55
76
  "The value is the expected HTTP status code string for the provisioning call that creates that parent resource. " +
56
77
  "For example: {\"product_id\": \"201\"}. " +
57
78
  "Requires apiSchema. Not allowed with consumerMode or skipProvisionParents."),
79
+ parentFormParams: z
80
+ .record(z.string(), z.string())
81
+ .optional()
82
+ .describe("Map of form parameters for provisioning parent resources. " +
83
+ "Key is the path param variable name (e.g. 'product_id'); " +
84
+ "value is comma-separated key=value pairs (e.g. 'field1=val1,field2=val2'). " +
85
+ "Requires apiSchema. Not allowed with consumerMode or skipProvisionParents."),
58
86
  skipProvisionParents: z
59
87
  .boolean()
60
88
  .default(false)
@@ -126,9 +154,9 @@ ${sections.join("\n")}
126
154
  if (errList.isError)
127
155
  return errList;
128
156
  const errors = [];
129
- if ((params.parentRequestData || params.parentStatusCode) &&
157
+ if ((params.parentRequestData || params.parentStatusCode || params.parentFormParams) &&
130
158
  !params.apiSchema) {
131
- errors.push("parentRequestData and parentStatusCode are only allowed when apiSchema is provided.");
159
+ errors.push("parentRequestData, parentStatusCode, and parentFormParams are only allowed when apiSchema is provided.");
132
160
  }
133
161
  if (params.providerOutput && !params.providerMode) {
134
162
  errors.push("providerOutput is only valid when providerMode is enabled.");
@@ -136,15 +164,34 @@ ${sections.join("\n")}
136
164
  if (params.consumerOutput && !params.consumerMode) {
137
165
  errors.push("consumerOutput is only valid when consumerMode is enabled.");
138
166
  }
139
- if (params.consumerMode && (params.parentRequestData || params.parentStatusCode)) {
140
- errors.push("parentRequestData and parentStatusCode are not allowed when consumerMode is enabled.");
167
+ if (params.consumerMode && (params.parentRequestData || params.parentStatusCode || params.parentFormParams)) {
168
+ errors.push("parentRequestData, parentStatusCode, and parentFormParams are not allowed when consumerMode is enabled.");
169
+ }
170
+ const fw = (params.framework ?? "").toLowerCase();
171
+ if (fw === "playwright") {
172
+ const specPattern = /\.(spec|test)\.[tj]s$/;
173
+ for (const [field, value] of [
174
+ ["providerOutput", params.providerOutput],
175
+ ["consumerOutput", params.consumerOutput],
176
+ ]) {
177
+ if (value && value !== "") {
178
+ if (!specPattern.test(value)) {
179
+ const parsed = path.parse(value);
180
+ const suggested = /\.[tj]s$/.test(parsed.ext)
181
+ ? value.replace(/\.[tj]s$/, ".spec.ts")
182
+ : value + ".spec.ts";
183
+ errors.push(`Error: Playwright requires test files to match *.{spec}.{ts,js} (got "${value}" for ${field}). ` +
184
+ `Rename to e.g. ${suggested} so Playwright can discover it.`);
185
+ }
186
+ }
187
+ }
141
188
  }
142
189
  if (params.skipProvisionParents) {
143
190
  if (!params.providerMode) {
144
191
  errors.push("skipProvisionParents requires providerMode to be enabled.");
145
192
  }
146
- if (params.parentRequestData || params.parentStatusCode) {
147
- errors.push("parentRequestData and parentStatusCode are not allowed when skipProvisionParents is enabled.");
193
+ if (params.parentRequestData || params.parentStatusCode || params.parentFormParams) {
194
+ errors.push("parentRequestData, parentStatusCode, and parentFormParams are not allowed when skipProvisionParents is enabled.");
148
195
  }
149
196
  }
150
197
  if (errors.length > 0) {
@@ -166,6 +213,7 @@ ${sections.join("\n")}
166
213
  consumerOutput: params.consumerOutput,
167
214
  parentRequestData: params.parentRequestData,
168
215
  parentStatusCode: params.parentStatusCode,
216
+ parentFormParams: params.parentFormParams,
169
217
  skipProvisionParents: params.skipProvisionParents,
170
218
  };
171
219
  }
@@ -128,7 +128,10 @@ This file must:
128
128
  method: params.method,
129
129
  apiSchema: params.apiSchema ? [params.apiSchema] : [],
130
130
  language: params.language ?? "python",
131
- framework: params.framework ?? "",
131
+ framework: params.framework ??
132
+ (params.language === "typescript" || params.language === "javascript"
133
+ ? "playwright"
134
+ : ""),
132
135
  output: params.output,
133
136
  outputDir: params.outputDir,
134
137
  force: params.force ?? true,
@@ -88,7 +88,7 @@ export function registerSubmitReportTool(server) {
88
88
  .optional()
89
89
  .default([])
90
90
  .describe("Actionable next steps for the user. Populate when test failures suggest misconfiguration " +
91
- "(e.g. 404s on endpoints that exist in the diff → check target_setup_command)."),
91
+ "(e.g. 404s on endpoints that exist in the diff → check targetSetupCommand)."),
92
92
  commitMessage: z
93
93
  .string()
94
94
  .optional()
@@ -170,12 +170,12 @@ describe("registerSubmitReportTool", () => {
170
170
  const outputFile = path.join(tmpDir, "report.json");
171
171
  const result = await handler({
172
172
  ...sampleReportParams(outputFile),
173
- nextSteps: ["Check your target_setup_command — endpoints returned 404"],
173
+ nextSteps: ["Check your targetSetupCommand — endpoints returned 404"],
174
174
  });
175
175
  expect(result.isError).toBeUndefined();
176
176
  const written = JSON.parse(await fs.readFile(outputFile, "utf-8"));
177
177
  expect(written.nextSteps).toEqual([
178
- "Check your target_setup_command — endpoints returned 404",
178
+ "Check your targetSetupCommand — endpoints returned 404",
179
179
  ]);
180
180
  });
181
181
  it("defaults nextSteps to empty array when omitted", async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skyramp/mcp",
3
- "version": "0.0.63-rc.7",
3
+ "version": "0.0.63",
4
4
  "main": "build/index.js",
5
5
  "type": "module",
6
6
  "bin": {
@@ -46,7 +46,7 @@
46
46
  "dependencies": {
47
47
  "@modelcontextprotocol/sdk": "^1.24.3",
48
48
  "@playwright/test": "^1.55.0",
49
- "@skyramp/skyramp": "1.3.14",
49
+ "@skyramp/skyramp": "1.3.15",
50
50
  "dockerode": "^4.0.6",
51
51
  "fast-glob": "^3.3.3",
52
52
  "simple-git": "^3.30.0",