@kirrosh/zond 0.9.1 → 0.9.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kirrosh/zond",
3
- "version": "0.9.1",
3
+ "version": "0.9.3",
4
4
  "description": "API testing platform — define tests in YAML, run from CLI or WebUI, generate from OpenAPI specs",
5
5
  "license": "MIT",
6
6
  "module": "index.ts",
@@ -59,6 +59,66 @@ export function compressEndpointsWithSchemas(
59
59
  return lines.join("\n");
60
60
  }
61
61
 
62
+ const YAML_FORMAT_CHEATSHEET = `
63
+ ## YAML Test Format Reference
64
+
65
+ ### Suite structure
66
+ \`\`\`yaml
67
+ name: Suite Name # required
68
+ base_url: "{{base_url}}" # or hardcoded URL
69
+ tags: [smoke] # optional: smoke | crud | destructive | auth
70
+ tests:
71
+ - GET /endpoint: # method + path as YAML key
72
+ query: { limit: 10 }
73
+ expect:
74
+ status: 200
75
+ _body: { type: array }
76
+ \`\`\`
77
+
78
+ ### Assertion operators
79
+ | Operator | Example |
80
+ |----------|---------|
81
+ | equals (default) | \`status: 200\` |
82
+ | not_equals | \`status: { not_equals: 500 }\` |
83
+ | contains | \`name: { contains: "john" }\` |
84
+ | not_contains | \`body: { not_contains: "error" }\` |
85
+ | exists / not_exists | \`id: { exists: true }\` |
86
+ | gt / gte / lt / lte | \`count: { gte: 1 }\` |
87
+ | matches (regex) | \`email: { matches: "^.+@.+$" }\` |
88
+ | type | \`items: { type: array }\` |
89
+ | length | \`items: { length: 5 }\` |
90
+ | length_gt/gte/lt/lte | \`items: { length_gt: 0 }\` |
91
+
92
+ ### Body assertions
93
+ - \`_body\` — assert on entire response body: \`_body: { type: array }\`
94
+ - Dot-notation for nested: \`data.user.id: { exists: true }\`
95
+ - Array item access: \`items.0.name: { exists: true }\`
96
+
97
+ ### Request body (JSON)
98
+ \`\`\`yaml
99
+ - POST /resource:
100
+ json: { name: "test", email: "a@b.com" }
101
+ expect:
102
+ status: 201
103
+ \`\`\`
104
+
105
+ ### Built-in generators
106
+ \`{{$uuid}}\`, \`{{$randomInt}}\`, \`{{$timestamp}}\`, \`{{$isoTimestamp}}\`, \`{{$randomEmail}}\`, \`{{$randomString}}\`
107
+
108
+ ### Variable capture & interpolation
109
+ \`\`\`yaml
110
+ - POST /items:
111
+ json: { name: "test-{{$uuid}}" }
112
+ capture:
113
+ created_id: id # saves response.id
114
+ expect:
115
+ status: 201
116
+ - GET /items/{{created_id}}:
117
+ expect:
118
+ status: 200
119
+ \`\`\`
120
+ `;
121
+
62
122
  export interface GuideOptions {
63
123
  title: string;
64
124
  baseUrl?: string;
@@ -67,6 +127,7 @@ export interface GuideOptions {
67
127
  securitySchemes: SecuritySchemeInfo[];
68
128
  endpointCount: number;
69
129
  coverageHeader?: string;
130
+ includeFormat?: boolean;
70
131
  }
71
132
 
72
133
  export function buildGenerationGuide(opts: GuideOptions): string {
@@ -76,11 +137,13 @@ export function buildGenerationGuide(opts: GuideOptions): string {
76
137
  ? `Security: ${opts.securitySchemes.map(s => `${s.name} (${s.type}${s.scheme ? `/${s.scheme}` : ""})`).join(", ")}`
77
138
  : "Security: none";
78
139
 
140
+ const formatSection = opts.includeFormat !== false ? YAML_FORMAT_CHEATSHEET : "";
141
+
79
142
  return `# Test Generation Guide for ${opts.title}
80
143
  ${opts.coverageHeader ? `\n${opts.coverageHeader}\n` : ""}
81
144
  ## API Specification (${opts.endpointCount} endpoints)
82
145
  ${opts.baseUrl ? `Base URL: ${opts.baseUrl}` : "Base URL: use {{base_url}} environment variable"}
83
146
  ${securitySummary}
84
147
 
85
- ${opts.apiContext}`;
148
+ ${opts.apiContext}${formatSection}`;
86
149
  }
@@ -56,7 +56,8 @@ export const TOOL_DESCRIPTIONS = {
56
56
  "Read an OpenAPI spec, auto-chunk by tags if large (>30 endpoints), " +
57
57
  "and return a focused test generation guide. For large APIs returns a chunking plan — " +
58
58
  "call again with tag parameter for each chunk. Use testsDir param to only generate for uncovered endpoints. " +
59
- "After generating YAML, use save_test_suites to save files, then run_tests to verify.",
59
+ "After generating YAML, use save_test_suites to save files, then run_tests to verify. " +
60
+ "Includes YAML format cheatsheet by default; pass includeFormat: false for subsequent tag chunks to save tokens.",
60
61
 
61
62
  ci_init:
62
63
  "Generate a CI/CD workflow file for running API tests automatically on push, PR, and schedule. " +
package/src/mcp/server.ts CHANGED
@@ -11,6 +11,7 @@ import { registerCiInitTool } from "./tools/ci-init.ts";
11
11
  import { registerSetWorkDirTool } from "./tools/set-work-dir.ts";
12
12
  import { registerDescribeEndpointTool } from "./tools/describe-endpoint.ts";
13
13
  import { registerGenerateAndSaveTool } from "./tools/generate-and-save.ts";
14
+ import { version } from "../../package.json";
14
15
 
15
16
  export interface McpServerOptions {
16
17
  dbPath?: string;
@@ -21,7 +22,7 @@ export async function startMcpServer(options: McpServerOptions = {}): Promise<vo
21
22
 
22
23
  const server = new McpServer({
23
24
  name: "zond",
24
- version: "0.8.0",
25
+ version,
25
26
  });
26
27
 
27
28
  // Register all tools
@@ -21,8 +21,9 @@ export function registerGenerateAndSaveTool(server: McpServer) {
21
21
  methodFilter: z.optional(z.array(z.string())).describe("Only include endpoints with these HTTP methods (e.g. [\"GET\"] for smoke tests)"),
22
22
  testsDir: z.optional(z.string()).describe("Path to existing tests directory — filters to uncovered endpoints only"),
23
23
  overwrite: z.optional(z.boolean()).describe("Hint for save_test_suites overwrite behavior (default: false)"),
24
+ includeFormat: z.optional(z.boolean()).describe("Include YAML format reference (default: true, set false for subsequent tag chunks)"),
24
25
  },
25
- }, async ({ specPath, outputDir, tag, methodFilter, testsDir, overwrite }) => {
26
+ }, async ({ specPath, outputDir, tag, methodFilter, testsDir, overwrite, includeFormat }) => {
26
27
  try {
27
28
  const doc = await readOpenApiSpec(specPath);
28
29
  let endpoints = extractEndpoints(doc);
@@ -82,6 +83,7 @@ export function registerGenerateAndSaveTool(server: McpServer) {
82
83
  instruction:
83
84
  `This API has ${plan.totalEndpoints} endpoints across ${plan.chunks.length} tags. ` +
84
85
  `Call generate_and_save with tag parameter for each chunk sequentially. ` +
86
+ `Pass includeFormat: false for subsequent chunks to save tokens. ` +
85
87
  `Example: generate_and_save(specPath: '${specPath}', tag: '${plan.chunks[0].tag}')`,
86
88
  };
87
89
  if (coverageInfo) {
@@ -106,6 +108,7 @@ export function registerGenerateAndSaveTool(server: McpServer) {
106
108
  securitySchemes,
107
109
  endpointCount: endpoints.length,
108
110
  coverageHeader,
111
+ includeFormat: includeFormat ?? true,
109
112
  });
110
113
 
111
114
  const saveInstructions = `