@kirrosh/zond 0.7.0
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/CHANGELOG.md +130 -0
- package/LICENSE +21 -0
- package/README.md +130 -0
- package/package.json +53 -0
- package/src/bun-types.d.ts +5 -0
- package/src/cli/commands/add-api.ts +51 -0
- package/src/cli/commands/ai-generate.ts +106 -0
- package/src/cli/commands/chat.ts +43 -0
- package/src/cli/commands/ci-init.ts +163 -0
- package/src/cli/commands/collections.ts +41 -0
- package/src/cli/commands/compare.ts +129 -0
- package/src/cli/commands/coverage.ts +156 -0
- package/src/cli/commands/doctor.ts +127 -0
- package/src/cli/commands/init.ts +84 -0
- package/src/cli/commands/mcp.ts +16 -0
- package/src/cli/commands/run.ts +156 -0
- package/src/cli/commands/runs.ts +108 -0
- package/src/cli/commands/serve.ts +22 -0
- package/src/cli/commands/update.ts +142 -0
- package/src/cli/commands/validate.ts +18 -0
- package/src/cli/index.ts +529 -0
- package/src/cli/output.ts +24 -0
- package/src/cli/runtime.ts +7 -0
- package/src/core/agent/agent-loop.ts +116 -0
- package/src/core/agent/context-manager.ts +41 -0
- package/src/core/agent/system-prompt.ts +28 -0
- package/src/core/agent/tools/diagnose-failure.ts +51 -0
- package/src/core/agent/tools/explore-api.ts +40 -0
- package/src/core/agent/tools/index.ts +46 -0
- package/src/core/agent/tools/query-results.ts +40 -0
- package/src/core/agent/tools/run-tests.ts +38 -0
- package/src/core/agent/tools/send-request.ts +44 -0
- package/src/core/agent/tools/validate-tests.ts +23 -0
- package/src/core/agent/types.ts +22 -0
- package/src/core/diagnostics/failure-hints.ts +63 -0
- package/src/core/generator/ai/ai-generator.ts +61 -0
- package/src/core/generator/ai/llm-client.ts +159 -0
- package/src/core/generator/ai/output-parser.ts +307 -0
- package/src/core/generator/ai/prompt-builder.ts +153 -0
- package/src/core/generator/ai/types.ts +56 -0
- package/src/core/generator/chunker.ts +47 -0
- package/src/core/generator/coverage-scanner.ts +87 -0
- package/src/core/generator/data-factory.ts +115 -0
- package/src/core/generator/endpoint-warnings.ts +43 -0
- package/src/core/generator/index.ts +12 -0
- package/src/core/generator/openapi-reader.ts +143 -0
- package/src/core/generator/schema-utils.ts +52 -0
- package/src/core/generator/serializer.ts +189 -0
- package/src/core/generator/types.ts +48 -0
- package/src/core/parser/filter.ts +14 -0
- package/src/core/parser/index.ts +21 -0
- package/src/core/parser/schema.ts +175 -0
- package/src/core/parser/types.ts +52 -0
- package/src/core/parser/variables.ts +154 -0
- package/src/core/parser/yaml-parser.ts +85 -0
- package/src/core/reporter/console.ts +175 -0
- package/src/core/reporter/index.ts +23 -0
- package/src/core/reporter/json.ts +9 -0
- package/src/core/reporter/junit.ts +78 -0
- package/src/core/reporter/types.ts +12 -0
- package/src/core/runner/assertions.ts +173 -0
- package/src/core/runner/execute-run.ts +97 -0
- package/src/core/runner/executor.ts +183 -0
- package/src/core/runner/http-client.ts +69 -0
- package/src/core/runner/index.ts +12 -0
- package/src/core/runner/types.ts +48 -0
- package/src/core/setup-api.ts +113 -0
- package/src/core/utils.ts +9 -0
- package/src/db/queries.ts +774 -0
- package/src/db/schema.ts +159 -0
- package/src/mcp/descriptions.ts +88 -0
- package/src/mcp/server.ts +52 -0
- package/src/mcp/tools/ci-init.ts +54 -0
- package/src/mcp/tools/coverage-analysis.ts +141 -0
- package/src/mcp/tools/describe-endpoint.ts +241 -0
- package/src/mcp/tools/explore-api.ts +84 -0
- package/src/mcp/tools/generate-and-save.ts +129 -0
- package/src/mcp/tools/generate-missing-tests.ts +91 -0
- package/src/mcp/tools/generate-tests-guide.ts +391 -0
- package/src/mcp/tools/manage-server.ts +86 -0
- package/src/mcp/tools/query-db.ts +255 -0
- package/src/mcp/tools/run-tests.ts +71 -0
- package/src/mcp/tools/save-test-suite.ts +218 -0
- package/src/mcp/tools/send-request.ts +63 -0
- package/src/mcp/tools/set-work-dir.ts +35 -0
- package/src/mcp/tools/setup-api.ts +84 -0
- package/src/mcp/tools/validate-tests.ts +43 -0
- package/src/tui/chat-ui.ts +150 -0
- package/src/web/data/collection-state.ts +360 -0
- package/src/web/routes/api.ts +234 -0
- package/src/web/routes/dashboard.ts +313 -0
- package/src/web/routes/runs.ts +64 -0
- package/src/web/schemas.ts +121 -0
- package/src/web/server.ts +134 -0
- package/src/web/static/htmx.min.js +1 -0
- package/src/web/static/style.css +827 -0
- package/src/web/views/endpoints-tab.ts +170 -0
- package/src/web/views/health-strip.ts +92 -0
- package/src/web/views/layout.ts +48 -0
- package/src/web/views/results.ts +209 -0
- package/src/web/views/runs-tab.ts +126 -0
- package/src/web/views/suites-tab.ts +153 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { resolve, join } from "path";
|
|
2
|
+
import { mkdirSync, writeFileSync, existsSync, readFileSync } from "fs";
|
|
3
|
+
import { getDb } from "../db/schema.ts";
|
|
4
|
+
import { createCollection, deleteCollection, findCollectionByNameOrId, normalizePath } from "../db/queries.ts";
|
|
5
|
+
import { readOpenApiSpec, extractEndpoints } from "./generator/index.ts";
|
|
6
|
+
|
|
7
|
+
function toYaml(vars: Record<string, string>): string {
|
|
8
|
+
const lines: string[] = [];
|
|
9
|
+
for (const [k, v] of Object.entries(vars)) {
|
|
10
|
+
const needsQuote = /[:#\[\]{}&*!|>'"@`,%]/.test(v) || v.includes(" ") || v === "";
|
|
11
|
+
lines.push(`${k}: ${needsQuote ? `"${v.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"` : v}`);
|
|
12
|
+
}
|
|
13
|
+
return lines.join("\n");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface SetupApiOptions {
|
|
17
|
+
name: string;
|
|
18
|
+
spec?: string;
|
|
19
|
+
dir?: string;
|
|
20
|
+
envVars?: Record<string, string>;
|
|
21
|
+
dbPath?: string;
|
|
22
|
+
force?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface SetupApiResult {
|
|
26
|
+
created: true;
|
|
27
|
+
collectionId: number;
|
|
28
|
+
baseDir: string;
|
|
29
|
+
testPath: string;
|
|
30
|
+
baseUrl: string;
|
|
31
|
+
specEndpoints: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function setupApi(options: SetupApiOptions): Promise<SetupApiResult> {
|
|
35
|
+
const { name, spec, dbPath } = options;
|
|
36
|
+
|
|
37
|
+
getDb(dbPath);
|
|
38
|
+
|
|
39
|
+
// Validate name uniqueness (or force-replace)
|
|
40
|
+
const existing = findCollectionByNameOrId(name);
|
|
41
|
+
if (existing) {
|
|
42
|
+
if (options.force) {
|
|
43
|
+
deleteCollection(existing.id, true);
|
|
44
|
+
} else {
|
|
45
|
+
throw new Error(`API '${name}' already exists (id=${existing.id})`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Sanitize name for directory use
|
|
50
|
+
const dirName = name.replace(/[^a-zA-Z0-9_\-\.]/g, "-").toLowerCase();
|
|
51
|
+
const baseDir = resolve(options.dir ?? `./apis/${dirName}/`);
|
|
52
|
+
const testPath = join(baseDir, "tests");
|
|
53
|
+
|
|
54
|
+
// Create directories
|
|
55
|
+
mkdirSync(testPath, { recursive: true });
|
|
56
|
+
|
|
57
|
+
// Try to load and validate spec, extract base_url
|
|
58
|
+
let openapiSpec: string | null = null;
|
|
59
|
+
let baseUrl = "";
|
|
60
|
+
let endpointCount = 0;
|
|
61
|
+
if (spec) {
|
|
62
|
+
const doc = await readOpenApiSpec(spec);
|
|
63
|
+
openapiSpec = spec;
|
|
64
|
+
if ((doc as any).servers?.[0]?.url) {
|
|
65
|
+
baseUrl = (doc as any).servers[0].url;
|
|
66
|
+
}
|
|
67
|
+
endpointCount = extractEndpoints(doc).length;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Build environment variables
|
|
71
|
+
const envVars: Record<string, string> = {};
|
|
72
|
+
if (baseUrl) envVars.base_url = baseUrl;
|
|
73
|
+
if (options.envVars) {
|
|
74
|
+
Object.assign(envVars, options.envVars);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Write .env.yaml in base_dir
|
|
78
|
+
if (Object.keys(envVars).length > 0) {
|
|
79
|
+
const envFilePath = join(baseDir, ".env.yaml");
|
|
80
|
+
writeFileSync(envFilePath, toYaml(envVars) + "\n", "utf-8");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Create/update .gitignore to exclude env files
|
|
84
|
+
const gitignorePath = join(baseDir, ".gitignore");
|
|
85
|
+
const gitignoreContent = existsSync(gitignorePath) ? readFileSync(gitignorePath, "utf-8") : "";
|
|
86
|
+
if (!gitignoreContent.includes(".env*.yaml")) {
|
|
87
|
+
writeFileSync(
|
|
88
|
+
gitignorePath,
|
|
89
|
+
gitignoreContent + (gitignoreContent.endsWith("\n") || !gitignoreContent ? "" : "\n") + ".env*.yaml\n",
|
|
90
|
+
"utf-8",
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const normalizedTestPath = normalizePath(testPath);
|
|
95
|
+
const normalizedBaseDir = normalizePath(baseDir);
|
|
96
|
+
|
|
97
|
+
// Create collection in DB
|
|
98
|
+
const collectionId = createCollection({
|
|
99
|
+
name,
|
|
100
|
+
base_dir: normalizedBaseDir,
|
|
101
|
+
test_path: normalizedTestPath,
|
|
102
|
+
openapi_spec: openapiSpec ?? undefined,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
created: true,
|
|
107
|
+
collectionId,
|
|
108
|
+
baseDir: normalizedBaseDir,
|
|
109
|
+
testPath: normalizedTestPath,
|
|
110
|
+
baseUrl,
|
|
111
|
+
specEndpoints: endpointCount,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function getByPath(obj: unknown, path: string, defaultVal?: unknown): unknown {
|
|
2
|
+
const keys = path.split(".");
|
|
3
|
+
let result: unknown = obj;
|
|
4
|
+
for (const key of keys) {
|
|
5
|
+
result = (result as Record<string, unknown>)?.[key];
|
|
6
|
+
if (result === undefined) return defaultVal;
|
|
7
|
+
}
|
|
8
|
+
return result;
|
|
9
|
+
}
|