@skyramp/mcp 0.0.64 → 0.0.65

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.
@@ -1,6 +1,7 @@
1
1
  import * as crypto from "crypto";
2
2
  import { WorkspaceAuthType } from "../../utils/workspaceAuth.js";
3
3
  import { buildToolWorkflows, buildTestPatternGuidelines, buildTestQualityCriteria, buildTestExamples, buildGenerationRules, getAuthSnippets, MAX_TESTS_TO_GENERATE, MAX_RECOMMENDATIONS, MAX_CRITICAL_TESTS, } from "./recommendationSections.js";
4
+ import { CATEGORY_PRIORITY, TEST_CATEGORIES } from "../../types/TestRecommendation.js";
4
5
  function formatTestLocations(locs) {
5
6
  const entries = Object.entries(locs || {});
6
7
  if (entries.length === 0)
@@ -9,18 +10,11 @@ function formatTestLocations(locs) {
9
10
  " If a GENERATE item's resource path matches a path listed here, UPDATE that file instead of creating a new one.\n" +
10
11
  entries.map(([type, files]) => " - [" + type + "] " + files).join("\n");
11
12
  }
12
- const CATEGORY_PRIORITY = {
13
- new_endpoint: "CRITICAL", // diff-direct scenarios always fill GENERATE slots first
14
- security_boundary: "HIGH",
15
- business_rule: "HIGH",
16
- data_integrity: "HIGH",
17
- breaking_change: "HIGH",
18
- auth: "HIGH",
19
- workflow: "MEDIUM",
20
- "error-handling": "MEDIUM",
21
- "data-validation": "MEDIUM",
22
- crud: "LOW",
23
- };
13
+ // ── Priority-tier ordering (replaces numeric CATEGORY_WEIGHTS) ──
14
+ // Categories map to HIGH / MEDIUM / LOW tiers.
15
+ // Within a tier, novelty (new > modified > existing) breaks ties,
16
+ // then cross-resource, step count, and finally the deterministic SHA-256 seed.
17
+ // CATEGORY_PRIORITY and PriorityTier imported from ../../types/TestRecommendation.js
24
18
  const PRIORITY_ORDER = { CRITICAL: 4, HIGH: 3, MEDIUM: 2, LOW: 1 };
25
19
  const NOVELTY_ORDER = { new: 3, modified: 2, existing: 1 };
26
20
  function classifyNovelty(scenario, diffContext) {
@@ -227,7 +221,7 @@ Quality gate — ask all three questions:
227
221
  2. "Does this test exercise a real workflow or catch a real bug?" → YES = at least MEDIUM
228
222
  3. "Does this test cover a mutation that modifies child items and triggers total/amount recalculation?" → YES = HIGH priority, and prefer it for GENERATE over simple single-field update tests for the same endpoint
229
223
 
230
- Assign category: security_boundary | business_rule | data_integrity | breaking_change | auth | workflow | error-handling | data-validation | crud
224
+ Assign category: ${TEST_CATEGORIES.join(" | ")}
231
225
 
232
226
  ${buildTestPatternGuidelines()}
233
227
 
@@ -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.17";
11
+ export const EXECUTOR_DOCKER_IMAGE = "skyramp/executor:v1.3.18";
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
@@ -362,6 +362,7 @@ ${result}`;
362
362
  entrypoint: getEntryPoint(),
363
363
  chainingKey: params.chainingKey,
364
364
  mockPort: params.mockPort ?? 0,
365
+ optionalFields: params.optionalFields ?? false,
365
366
  };
366
367
  }
367
368
  }
@@ -150,6 +150,7 @@ This file must:
150
150
  traceFilePath: params.trace,
151
151
  entrypoint: getEntryPoint(),
152
152
  mockPort: params.mockPort ?? 0,
153
+ optionalFields: params.optionalFields ?? false,
153
154
  };
154
155
  }
155
156
  async executeGeneration(generateOptions) {
@@ -3,6 +3,7 @@ import { logger } from "../utils/logger.js";
3
3
  import * as fs from "fs/promises";
4
4
  import * as path from "path";
5
5
  import { AnalyticsService } from "../services/AnalyticsService.js";
6
+ import { TEST_CATEGORIES, externalCategory } from "../types/TestRecommendation.js";
6
7
  const TOOL_NAME = "skyramp_submit_report";
7
8
  const DEFAULT_COMMIT_MESSAGE = "Added recommendations by Skyramp Testbot.";
8
9
  const testResultSchema = z.object({
@@ -14,7 +15,7 @@ const testResultSchema = z.object({
14
15
  const newTestSchema = z.object({
15
16
  testId: z.string().describe("Human-readable kebab-case identifier, e.g. 'contract-get-products' or 'integration-users-orders-workflow'. Format: '<testType>-<method>-<resource>' for single-endpoint tests or '<testType>-<scenario-slug>' for multi-step tests. Must be unique within the report."),
16
17
  testType: z.string().describe("Type of test created: Smoke, Contract, Integration, etc. Do not include priority or other metadata in this field."),
17
- category: z.enum(["security_boundary", "business_rule", "breaking_change", "data_integrity", "workflow"]).describe("Test category — critical categories (security_boundary, business_rule, data_integrity, breaking_change) get generation priority over workflow"),
18
+ category: z.preprocess((val) => externalCategory(val), z.enum(TEST_CATEGORIES)).describe("Test category — critical categories (security_boundary, business_rule, data_integrity, breaking_change) get generation priority over workflow"),
18
19
  endpoint: z.string().describe("HTTP verb and path, e.g. 'GET /api/v1/products'"),
19
20
  fileName: z.string().describe("Name of the generated test file"),
20
21
  description: z.string().optional().describe("What the test does — the steps and assertions, not the bugs it finds. e.g. 'Creates a collection, adds a link, then verifies the link exists'. Do NOT describe expected failures or bugs here — those belong in issuesFound."),
@@ -43,7 +44,7 @@ const scenarioStepSchema = z.object({
43
44
  const additionalRecommendationSchema = z.object({
44
45
  testId: z.string().describe("Human-readable kebab-case identifier, e.g. 'integration-products-orders-workflow' or 'e2e-checkout-flow'. Format: '<testType>-<scenario-slug>'. Must be unique within the report."),
45
46
  testType: z.string().describe("Type of test: Integration, E2E, Contract, UI, etc. Do not include priority or other metadata in this field."),
46
- category: z.enum(["security_boundary", "business_rule", "breaking_change", "data_integrity", "workflow"]).describe("Test category — critical categories get generation priority over workflow"),
47
+ category: z.preprocess((val) => externalCategory(val), z.enum(TEST_CATEGORIES)).describe("Test category — critical categories get generation priority over workflow"),
47
48
  scenarioName: z.string().describe("Name of the scenario, e.g. 'products_orders_workflow'"),
48
49
  steps: z.array(scenarioStepSchema).describe("Ordered sequence of API/UI steps in this test scenario"),
49
50
  description: z.string().describe("Why this test is valuable and what it would cover"),
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import { SCENARIO_CATEGORIES } from "./TestRecommendation.js";
2
3
  // ── Zod schemas ──
3
4
  export const analysisScopeSchema = z.enum(["full_repo", "current_branch_diff"]);
4
5
  export const paramInfoSchema = z.object({
@@ -76,18 +77,7 @@ export const scenarioStepSchema = z.object({
76
77
  export const draftedScenarioSchema = z.object({
77
78
  scenarioName: z.string(),
78
79
  description: z.string(),
79
- category: z.enum([
80
- "crud",
81
- "workflow",
82
- "auth",
83
- "error-handling",
84
- "data-validation",
85
- "security_boundary",
86
- "business_rule",
87
- "data_integrity",
88
- "breaking_change",
89
- "new_endpoint",
90
- ]),
80
+ category: z.enum(SCENARIO_CATEGORIES),
91
81
  priority: z.enum(["high", "medium", "low"]),
92
82
  steps: z.array(scenarioStepSchema),
93
83
  chainingKeys: z.array(z.string()),
@@ -1,5 +1,47 @@
1
1
  import { z } from "zod";
2
2
  import { TestType } from "./TestTypes.js";
3
+ /** Internal-only categories (not submitted to tools). */
4
+ const INTERNAL_CATEGORIES = [
5
+ "new_endpoint", // CRITICAL - diff-direct scenarios always fill GENERATE slots first
6
+ ];
7
+ /** External categories valid for tool submissions, ordered by priority. */
8
+ const CATEGORIES = [
9
+ // HIGH priority
10
+ "security_boundary", // auth, permission, cross-user isolation, idempotency
11
+ "business_rule", // unique constraints, range validation, state machines
12
+ "data_integrity", // cascade deletes, orphan prevention, referential integrity
13
+ "breaking_change", // route renames, auth migration, response shape changes
14
+ "auth", // authentication and authorization flows
15
+ // MEDIUM priority
16
+ "workflow", // cross-resource integration, user journeys
17
+ "error_handling", // error responses and edge cases
18
+ "data_validation", // input validation and schema enforcement
19
+ // LOW priority
20
+ "crud", // basic create/read/update/delete operations
21
+ ];
22
+ /** All categories including internal ones. */
23
+ export const SCENARIO_CATEGORIES = [...INTERNAL_CATEGORIES, ...CATEGORIES];
24
+ /** Categories valid for tool submissions (excludes internal-only categories). */
25
+ export const TEST_CATEGORIES = CATEGORIES;
26
+ /** Priority assignment for each category. */
27
+ export const CATEGORY_PRIORITY = {
28
+ new_endpoint: "CRITICAL",
29
+ security_boundary: "HIGH",
30
+ business_rule: "HIGH",
31
+ data_integrity: "HIGH",
32
+ breaking_change: "HIGH",
33
+ auth: "HIGH",
34
+ workflow: "MEDIUM",
35
+ error_handling: "MEDIUM",
36
+ data_validation: "MEDIUM",
37
+ crud: "LOW",
38
+ };
39
+ /** Map internal-only categories to their external equivalent for tool submission. */
40
+ export function externalCategory(cat) {
41
+ if (cat === "new_endpoint")
42
+ return "crud";
43
+ return cat;
44
+ }
3
45
  // Test type to documentation URL mapping
4
46
  export const TEST_TYPE_DOCS = {
5
47
  [TestType.SMOKE]: "https://www.skyramp.dev/docs/smoke-tests",
@@ -33,7 +75,7 @@ export const specificTestSchema = z.object({
33
75
  export const testTypeRecommendationSchema = z.object({
34
76
  priority: z.enum(["high", "medium", "low"]),
35
77
  testType: z.nativeEnum(TestType),
36
- category: z.enum(["security_boundary", "business_rule", "breaking_change", "data_integrity", "workflow"]),
78
+ category: z.enum(TEST_CATEGORIES),
37
79
  rationale: z.string(),
38
80
  reasoning: z.string(),
39
81
  specificTests: z.array(specificTestSchema),
@@ -101,6 +101,10 @@ export const baseSchema = z.object({
101
101
  .number()
102
102
  .default(0)
103
103
  .describe("Port number for the mock server"),
104
+ optionalFields: z
105
+ .boolean()
106
+ .default(false)
107
+ .describe("Whether to include optional fields in the generated test/mock"),
104
108
  prompt: z.string().describe("The prompt user provided to generate the test"),
105
109
  });
106
110
  export const basePlaywrightSchema = z.object({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skyramp/mcp",
3
- "version": "0.0.64",
3
+ "version": "0.0.65",
4
4
  "main": "build/index.js",
5
5
  "exports": {
6
6
  ".": "./build/index.js",
@@ -54,7 +54,7 @@
54
54
  "dependencies": {
55
55
  "@modelcontextprotocol/sdk": "^1.24.3",
56
56
  "@playwright/test": "^1.55.0",
57
- "@skyramp/skyramp": "1.3.17",
57
+ "@skyramp/skyramp": "1.3.18",
58
58
  "dockerode": "^4.0.6",
59
59
  "fast-glob": "^3.3.3",
60
60
  "playwright": "file:vendor/skyramp-playwright-1.58.2-skyramp.8.9.0.tgz",