@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.
Files changed (102) hide show
  1. package/CHANGELOG.md +130 -0
  2. package/LICENSE +21 -0
  3. package/README.md +130 -0
  4. package/package.json +53 -0
  5. package/src/bun-types.d.ts +5 -0
  6. package/src/cli/commands/add-api.ts +51 -0
  7. package/src/cli/commands/ai-generate.ts +106 -0
  8. package/src/cli/commands/chat.ts +43 -0
  9. package/src/cli/commands/ci-init.ts +163 -0
  10. package/src/cli/commands/collections.ts +41 -0
  11. package/src/cli/commands/compare.ts +129 -0
  12. package/src/cli/commands/coverage.ts +156 -0
  13. package/src/cli/commands/doctor.ts +127 -0
  14. package/src/cli/commands/init.ts +84 -0
  15. package/src/cli/commands/mcp.ts +16 -0
  16. package/src/cli/commands/run.ts +156 -0
  17. package/src/cli/commands/runs.ts +108 -0
  18. package/src/cli/commands/serve.ts +22 -0
  19. package/src/cli/commands/update.ts +142 -0
  20. package/src/cli/commands/validate.ts +18 -0
  21. package/src/cli/index.ts +529 -0
  22. package/src/cli/output.ts +24 -0
  23. package/src/cli/runtime.ts +7 -0
  24. package/src/core/agent/agent-loop.ts +116 -0
  25. package/src/core/agent/context-manager.ts +41 -0
  26. package/src/core/agent/system-prompt.ts +28 -0
  27. package/src/core/agent/tools/diagnose-failure.ts +51 -0
  28. package/src/core/agent/tools/explore-api.ts +40 -0
  29. package/src/core/agent/tools/index.ts +46 -0
  30. package/src/core/agent/tools/query-results.ts +40 -0
  31. package/src/core/agent/tools/run-tests.ts +38 -0
  32. package/src/core/agent/tools/send-request.ts +44 -0
  33. package/src/core/agent/tools/validate-tests.ts +23 -0
  34. package/src/core/agent/types.ts +22 -0
  35. package/src/core/diagnostics/failure-hints.ts +63 -0
  36. package/src/core/generator/ai/ai-generator.ts +61 -0
  37. package/src/core/generator/ai/llm-client.ts +159 -0
  38. package/src/core/generator/ai/output-parser.ts +307 -0
  39. package/src/core/generator/ai/prompt-builder.ts +153 -0
  40. package/src/core/generator/ai/types.ts +56 -0
  41. package/src/core/generator/chunker.ts +47 -0
  42. package/src/core/generator/coverage-scanner.ts +87 -0
  43. package/src/core/generator/data-factory.ts +115 -0
  44. package/src/core/generator/endpoint-warnings.ts +43 -0
  45. package/src/core/generator/index.ts +12 -0
  46. package/src/core/generator/openapi-reader.ts +143 -0
  47. package/src/core/generator/schema-utils.ts +52 -0
  48. package/src/core/generator/serializer.ts +189 -0
  49. package/src/core/generator/types.ts +48 -0
  50. package/src/core/parser/filter.ts +14 -0
  51. package/src/core/parser/index.ts +21 -0
  52. package/src/core/parser/schema.ts +175 -0
  53. package/src/core/parser/types.ts +52 -0
  54. package/src/core/parser/variables.ts +154 -0
  55. package/src/core/parser/yaml-parser.ts +85 -0
  56. package/src/core/reporter/console.ts +175 -0
  57. package/src/core/reporter/index.ts +23 -0
  58. package/src/core/reporter/json.ts +9 -0
  59. package/src/core/reporter/junit.ts +78 -0
  60. package/src/core/reporter/types.ts +12 -0
  61. package/src/core/runner/assertions.ts +173 -0
  62. package/src/core/runner/execute-run.ts +97 -0
  63. package/src/core/runner/executor.ts +183 -0
  64. package/src/core/runner/http-client.ts +69 -0
  65. package/src/core/runner/index.ts +12 -0
  66. package/src/core/runner/types.ts +48 -0
  67. package/src/core/setup-api.ts +113 -0
  68. package/src/core/utils.ts +9 -0
  69. package/src/db/queries.ts +774 -0
  70. package/src/db/schema.ts +159 -0
  71. package/src/mcp/descriptions.ts +88 -0
  72. package/src/mcp/server.ts +52 -0
  73. package/src/mcp/tools/ci-init.ts +54 -0
  74. package/src/mcp/tools/coverage-analysis.ts +141 -0
  75. package/src/mcp/tools/describe-endpoint.ts +241 -0
  76. package/src/mcp/tools/explore-api.ts +84 -0
  77. package/src/mcp/tools/generate-and-save.ts +129 -0
  78. package/src/mcp/tools/generate-missing-tests.ts +91 -0
  79. package/src/mcp/tools/generate-tests-guide.ts +391 -0
  80. package/src/mcp/tools/manage-server.ts +86 -0
  81. package/src/mcp/tools/query-db.ts +255 -0
  82. package/src/mcp/tools/run-tests.ts +71 -0
  83. package/src/mcp/tools/save-test-suite.ts +218 -0
  84. package/src/mcp/tools/send-request.ts +63 -0
  85. package/src/mcp/tools/set-work-dir.ts +35 -0
  86. package/src/mcp/tools/setup-api.ts +84 -0
  87. package/src/mcp/tools/validate-tests.ts +43 -0
  88. package/src/tui/chat-ui.ts +150 -0
  89. package/src/web/data/collection-state.ts +360 -0
  90. package/src/web/routes/api.ts +234 -0
  91. package/src/web/routes/dashboard.ts +313 -0
  92. package/src/web/routes/runs.ts +64 -0
  93. package/src/web/schemas.ts +121 -0
  94. package/src/web/server.ts +134 -0
  95. package/src/web/static/htmx.min.js +1 -0
  96. package/src/web/static/style.css +827 -0
  97. package/src/web/views/endpoints-tab.ts +170 -0
  98. package/src/web/views/health-strip.ts +92 -0
  99. package/src/web/views/layout.ts +48 -0
  100. package/src/web/views/results.ts +209 -0
  101. package/src/web/views/runs-tab.ts +126 -0
  102. package/src/web/views/suites-tab.ts +153 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,130 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [0.7.0] — Renamed to zond
6
+
7
+ - Renamed package from `@kirrosh/apitool` to `zond`
8
+ - CLI binary: `apitool` → `zond`
9
+ - Database: `apitool.db` → `zond.db`
10
+ - Environment variable: `APITOOL_AI_KEY` → `ZOND_AI_KEY`
11
+ - MCP server name: `apitool` → `zond`
12
+ - Fresh DB schema (no migrations)
13
+
14
+ ## [0.6.1] - 2026-03-04
15
+
16
+ ### Changed
17
+
18
+ - **Web UI redesign** — single-page dashboard with three tabs:
19
+ - **Endpoints** — all OpenAPI spec endpoints with coverage status (passing/failing/no tests/not run), filters by status and method, expandable details with covering test steps, assertions, and response status
20
+ - **Suites** — all YAML test files on disk with run results, expandable step details showing assertions, captures, error messages, and response body for failed steps
21
+ - **Runs** — paginated run history with progress bars, drill-down into run details with JUnit/JSON export
22
+ - **Health strip** — top-of-page overview: coverage donut chart, pass/fail/skip stats, progress bar, environment alert banner
23
+ - **Broken endpoint marking** — `deprecated`, `no_response_schema`, `no_responses_defined`, `required_params_no_examples` warnings shown as badges on endpoints
24
+ - **diagnose_failure** enriched with `failure_type` (api_error / assertion_failed / network_error) and summary counts
25
+
26
+ ### Fixed
27
+
28
+ - Slim npm package — non-essential files excluded via `files` field in package.json
29
+
30
+ ## [0.5.4] - 2026-03-03
31
+
32
+ ### Fixed
33
+
34
+ - **`execute-run.ts`**: removed stale `"default"` fallback for `effectiveEnvName` — when no `envName` was passed but a collection existed, the runner looked for `.env.default.yaml` instead of `.env.yaml`, causing all variables (including `base_url`) to be empty and every request to fail with `"URL is invalid"`
35
+
36
+ ### Added
37
+
38
+ - **`executor.ts`**: early URL validation before `fetch()` — if `base_url` is missing or empty the step now fails immediately with a descriptive error `"base_url is not configured — URL resolved to a relative path: …"` instead of the cryptic `TypeError: URL is invalid`; subsequent steps that depend on captures from the failed step are automatically skipped
39
+ - **`diagnose_failure`**: `envHint()` detector — surfaces actionable `.env.yaml` hints per failure:
40
+ - relative URL → `"base_url is not set or empty — add base_url to <path>/.env.yaml"`
41
+ - URL contains `{{variable}}` → `"URL contains unresolved variable — check variable names in .env.yaml"`
42
+ - error message contains `"URL is invalid"` → `"URL is malformed — likely base_url is empty or invalid"`
43
+ - env hints take priority over generic `statusHint` (401/404/5xx)
44
+ - new top-level `env_issue` field when ALL failures share the same env problem category
45
+ - env file path resolved from `collection.base_dir` — agent sees the exact file to edit
46
+ - **`run_tests` MCP**: always suggests `manage_server(action: 'start')` in `hints` after a run
47
+ - **`generate_tests_guide` / `generate_missing_tests` descriptions**: mention `manage_server` as the next step after saving and running tests
48
+
49
+ ## [Unreleased]
50
+
51
+ ### Added
52
+
53
+ - **MCP feedback improvements**
54
+ - `diagnose_failure` now includes `response_headers` in failure output (e.g. `X-Ably-ErrorMessage`)
55
+ - `generate_tests_guide`: annotates `any`-typed request bodies with a warning comment
56
+ - `generate_tests_guide`: added 204 No Content tips in Practical Tips and Common Mistakes sections
57
+ - `schema-utils.ts`: added `isAnySchema()` helper
58
+ - DB schema v6: `results.response_headers TEXT` column
59
+
60
+ - **M22: MCP-first smart test generation**
61
+ - `generate_tests_guide` MCP tool — returns full API spec with schemas + step-by-step generation algorithm
62
+ - `save_test_suite` MCP tool — validates YAML and saves test files with structured error reporting
63
+ - `explore_api` enhanced — new `includeSchemas` parameter for full request/response body schemas
64
+ - `schema-utils.ts` — extracted `compressSchema()` and `formatParam()` as shared utilities
65
+ - Improved MCP tool descriptions with "when to use" guidance
66
+
67
+ ### Removed
68
+
69
+ - `list_environments` MCP tool — duplicated by `manage_environment(action: "list")`
70
+
71
+ ---
72
+
73
+ ## [0.3.0] - Unreleased (post-M21)
74
+
75
+ ### Added
76
+
77
+ - **Environment management in WebUI** — full CRUD for environments (`/environments`)
78
+ - **Key-value editor** — add/remove variables with inline JavaScript
79
+ - **Environment selector** — `<select name="env">` dropdown in collection "Run Tests" form
80
+ - **DB queries** — `getEnvironmentById()`, `deleteEnvironment()`, `listEnvironmentRecords()`
81
+ - **Navigation** — "Environments" link in navbar
82
+ - **Improved runs filter** — environment dropdown merges defined environments + run history
83
+ - **Self-documented API** — routes use `@hono/zod-openapi`, `GET /api/openapi.json` serves spec
84
+ - **Incremental generation** — `apitool generate` skips already-covered endpoints
85
+ - **Dogfooding** — integration tests run against apitool's own API
86
+ - **Generator: `additionalProperties`** — Record types generate sample key-value pairs instead of `{}`
87
+ - **CI: typecheck** — `tsc --noEmit` step added to CI pipeline
88
+
89
+ ### Changed
90
+
91
+ - **Auth-flow test** — rewritten with inline OpenAPI server (no external `test-server/` dependency)
92
+
93
+ ### Removed
94
+
95
+ - **`test-server/`** — replaced by inline test servers in integration tests
96
+ - **Duplicate spec files** — `openapi-self.json`, `self-tests-spec.json` removed from project root
97
+
98
+ ### Fixed
99
+
100
+ - **Type errors** — `z.coerce.number()` in schemas, `c.body()` return type in export route
101
+ - **Environments CRUD skeleton** — `variables` field now generates test data correctly
102
+
103
+ ## [0.1.0] - 2025-02-27
104
+
105
+ Initial public release.
106
+
107
+ ### Features
108
+
109
+ - **YAML test definitions** — declarative API tests with steps, assertions, variables, and captures
110
+ - **Test runner** — sequential HTTP execution with variable substitution, chained captures, and configurable timeouts
111
+ - **Assertions** — status code, JSON body (exact, contains, path), headers, response time
112
+ - **Environment files** — `.env.<name>.yaml` for per-environment variables (base URLs, tokens, etc.)
113
+ - **OpenAPI test generator** — generate skeleton YAML tests from OpenAPI 3.x specs (CRUD operations, auth-aware)
114
+ - **AI-powered test generation** — generate tests using LLM providers (Ollama, OpenAI, Anthropic, custom)
115
+ - **Reporters** — console (colored), JSON, JUnit XML output formats
116
+ - **SQLite storage** — persist test runs, results, and collections in `apitool.db`
117
+ - **WebUI dashboard** — Hono + HTMX web interface with:
118
+ - Health strip: coverage donut, pass/fail/skip stats, progress bar
119
+ - Endpoints tab: spec endpoints with coverage status and warning badges
120
+ - Suites tab: test files with step-level results, assertions, captures
121
+ - Runs tab: paginated history with drill-down and JUnit/JSON export
122
+ - **CLI commands**:
123
+ - `apitool run <path>` — execute tests with env, reporter, timeout, bail options
124
+ - `apitool validate <path>` — validate YAML test files
125
+ - `apitool generate --from <spec>` — generate tests from OpenAPI
126
+ - `apitool ai-generate --from <spec> --prompt "..."` — AI test generation
127
+ - `apitool serve` — start web dashboard
128
+ - `apitool collections` — list test collections
129
+ - **Multi-auth support** — Basic, Bearer, API Key auth in CLI (`--auth-token`) and WebUI
130
+ - **Standalone binary** — single-file executable via `bun build --compile`
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 apitool contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,130 @@
1
+ # @kirrosh/zond
2
+
3
+ Point your AI agent at an OpenAPI spec. Get working tests in minutes. No config, no cloud, no Postman.
4
+
5
+ [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=zond&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBraXJyb3NoL3pvbmQiLCJtY3AiXX0K)
6
+
7
+ ## Claude Code Plugin
8
+
9
+ Install in Claude Code:
10
+
11
+ ```
12
+ /plugin marketplace add kirrosh/zond
13
+ /plugin install zond@zond-marketplace
14
+ ```
15
+
16
+ This gives you:
17
+ - **17 MCP tools** for API testing (test generation, execution, diagnostics, coverage)
18
+ - **Skills** for test generation, debugging failures, and CI setup
19
+ - **Slash commands**: `/zond:api-test`, `/zond:api-coverage`
20
+
21
+ After installation, just say: _"Safely cover the API from openapi.json with tests"_ — the agent handles everything.
22
+
23
+ ## Install
24
+
25
+ ```bash
26
+ # Option 1: via npx (recommended — works everywhere with Node.js)
27
+ npx -y @kirrosh/zond --version
28
+
29
+ # Option 2: Binary (no Node.js required)
30
+ # macOS / Linux
31
+ curl -fsSL https://raw.githubusercontent.com/kirrosh/zond/master/install.sh | sh
32
+
33
+ # Windows
34
+ iwr https://raw.githubusercontent.com/kirrosh/zond/master/install.ps1 | iex
35
+ ```
36
+
37
+ [All releases](https://github.com/kirrosh/zond/releases) (Linux x64, macOS ARM, Windows x64)
38
+
39
+ ## MCP Setup (Cursor / Claude Code / Windsurf)
40
+
41
+ Click the badge above, or add manually:
42
+
43
+ ```json
44
+ {
45
+ "mcpServers": {
46
+ "zond": {
47
+ "command": "npx",
48
+ "args": [
49
+ "-y",
50
+ "@kirrosh/zond@latest",
51
+ "mcp",
52
+ "--dir",
53
+ "${workspaceFolder}"
54
+ ]
55
+ }
56
+ }
57
+ }
58
+ ```
59
+
60
+ > `@latest` ensures npx always pulls the newest version on each restart — no manual update needed.
61
+
62
+ **Where to put this:**
63
+
64
+ | Editor | Config file |
65
+ | ----------- | ----------------------------------------------------- |
66
+ | Cursor | Settings > MCP, or `.cursor/mcp.json` in project root |
67
+ | Claude Code | `.mcp.json` in project root |
68
+ | Windsurf | `.windsurfrules/mcp.json` or settings |
69
+
70
+ ## Main Flow (5 steps)
71
+
72
+ Once MCP is connected, ask your AI agent to cover your API with tests:
73
+
74
+ **1. Register your API**
75
+
76
+ ```
77
+ setup_api(name: "myapi", specPath: "openapi.json")
78
+ ```
79
+
80
+ **2. Generate a test guide** (agent reads OpenAPI + gets instructions)
81
+
82
+ ```
83
+ generate_and_save(specPath: "openapi.json")
84
+ ```
85
+
86
+ For large APIs (>30 endpoints), auto-chunks by tags and returns a plan. Call with `tag` for each chunk.
87
+
88
+ **3. Save test suites** (agent writes YAML based on the guide)
89
+
90
+ ```
91
+ save_test_suite(filePath: "apis/myapi/tests/smoke.yaml", content: "...")
92
+ ```
93
+
94
+ **4. Run tests**
95
+
96
+ ```
97
+ run_tests(testPath: "apis/myapi/tests/", safe: true)
98
+ ```
99
+
100
+ **5. Diagnose failures**
101
+
102
+ ```
103
+ query_db(action: "diagnose_failure", runId: 42)
104
+ ```
105
+
106
+ Or just say: _"Safely cover the API from openapi.json with tests"_ — the agent will do all 5 steps.
107
+
108
+ ## CLI
109
+
110
+ ```
111
+ zond run <path> Run tests (--env, --safe, --tag, --dry-run, --env-var, --report)
112
+ zond add-api <name> Register API (--spec <openapi>)
113
+ zond coverage API test coverage (--spec, --tests, --fail-on-coverage)
114
+ zond compare <runA> <runB> Compare two test runs
115
+ zond serve Web dashboard with health strip + endpoints/suites/runs tabs (--port 8080)
116
+ zond mcp Start MCP server
117
+ zond chat AI chat agent (--provider ollama|openai|anthropic)
118
+ zond doctor Diagnostics
119
+ ```
120
+
121
+ ## Documentation
122
+
123
+ - [docs/quickstart.md](docs/quickstart.md) — step-by-step quickstart guide (RU)
124
+ - [ZOND.md](ZOND.md) — full CLI and MCP tools reference
125
+ - [docs/mcp-guide.md](docs/mcp-guide.md) — MCP agent workflow guide
126
+ - [docs/ci.md](docs/ci.md) — CI/CD integration
127
+
128
+ ## License
129
+
130
+ [MIT](LICENSE)
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@kirrosh/zond",
3
+ "version": "0.7.0",
4
+ "description": "API testing platform — define tests in YAML, run from CLI or WebUI, generate from OpenAPI specs",
5
+ "license": "MIT",
6
+ "module": "index.ts",
7
+ "type": "module",
8
+ "keywords": [
9
+ "api",
10
+ "testing",
11
+ "openapi",
12
+ "yaml",
13
+ "cli",
14
+ "rest",
15
+ "http"
16
+ ],
17
+ "files": [
18
+ "src/",
19
+ "README.md",
20
+ "LICENSE",
21
+ "CHANGELOG.md"
22
+ ],
23
+ "bin": {
24
+ "zond": "src/cli/index.ts"
25
+ },
26
+ "scripts": {
27
+ "zond": "bun run src/cli/index.ts",
28
+ "test": "bun run test:unit && bun run test:mocked",
29
+ "test:unit": "bun test tests/db/ tests/parser/ tests/runner/ tests/generator/ tests/core/ tests/cli/args.test.ts tests/cli/chat.test.ts tests/cli/ci-init.test.ts tests/cli/commands.test.ts tests/cli/doctor.test.ts tests/cli/init.test.ts tests/cli/runs.test.ts tests/cli/safe-run.test.ts tests/cli/update.test.ts tests/integration/ tests/web/ tests/mcp/tools.test.ts tests/mcp/save-test-suite.test.ts tests/agent/agent-loop.test.ts tests/agent/context-manager.test.ts tests/agent/system-prompt.test.ts tests/reporter/",
30
+ "test:mocked": "bun run scripts/run-mocked-tests.ts",
31
+ "test:ai": "bun test tests/ai/",
32
+ "check": "tsc --noEmit --project tsconfig.json",
33
+ "build": "bun build --compile src/cli/index.ts --outfile zond"
34
+ },
35
+ "devDependencies": {
36
+ "@types/bun": "latest"
37
+ },
38
+ "peerDependencies": {
39
+ "typescript": "^5"
40
+ },
41
+ "dependencies": {
42
+ "@humanwhocodes/momoa": "^2.0.3",
43
+ "@ai-sdk/anthropic": "^2",
44
+ "@ai-sdk/openai": "^2",
45
+ "@hono/zod-openapi": "^1.2.2",
46
+ "@modelcontextprotocol/sdk": "^1.27.1",
47
+ "@readme/openapi-parser": "^5.5.0",
48
+ "ai": "^6",
49
+ "hono": "^4.12.2",
50
+ "openapi-types": "^12.1.3",
51
+ "zod": "^4.3.6"
52
+ }
53
+ }
@@ -0,0 +1,5 @@
1
+ declare module "*.css" {
2
+ const path: string;
3
+ export default path;
4
+ }
5
+
@@ -0,0 +1,51 @@
1
+ import { setupApi } from "../../core/setup-api.ts";
2
+ import { printError, printSuccess } from "../output.ts";
3
+
4
+ export interface AddApiOptions {
5
+ name: string;
6
+ spec?: string;
7
+ dir?: string;
8
+ envPairs?: string[];
9
+ dbPath?: string;
10
+ }
11
+
12
+ export async function addApiCommand(options: AddApiOptions): Promise<number> {
13
+ const { name, spec, envPairs, dbPath, dir } = options;
14
+
15
+ // Parse --env key=value pairs into a record
16
+ const envVars: Record<string, string> = {};
17
+ if (envPairs) {
18
+ for (const pair of envPairs) {
19
+ const idx = pair.indexOf("=");
20
+ if (idx === -1) continue;
21
+ const key = pair.slice(0, idx).trim();
22
+ const value = pair.slice(idx + 1).trim();
23
+ if (key) envVars[key] = value;
24
+ }
25
+ }
26
+
27
+ try {
28
+ const result = await setupApi({
29
+ name,
30
+ spec,
31
+ dir,
32
+ envVars: Object.keys(envVars).length > 0 ? envVars : undefined,
33
+ dbPath,
34
+ });
35
+
36
+ printSuccess(`API '${name}' created (id=${result.collectionId})`);
37
+ console.log(` Directory: ${result.testPath.replace(/\/tests$/, "")}`);
38
+ console.log(` Tests: ${result.testPath}/`);
39
+ if (spec) console.log(` Spec: ${spec}`);
40
+ if (result.baseUrl) console.log(` Base URL: ${result.baseUrl}`);
41
+ console.log();
42
+ console.log("Next steps:");
43
+ console.log(` zond ai-generate --api ${name} --prompt "test the user endpoints"`);
44
+ console.log(` zond run --api ${name}`);
45
+
46
+ return 0;
47
+ } catch (err) {
48
+ printError((err as Error).message);
49
+ return 1;
50
+ }
51
+ }
@@ -0,0 +1,106 @@
1
+ import { resolve, dirname } from "path";
2
+ import { generateWithAI } from "../../core/generator/ai/ai-generator.ts";
3
+ import { resolveProviderConfig } from "../../core/generator/ai/types.ts";
4
+ import type { AIProviderConfig } from "../../core/generator/ai/types.ts";
5
+ import { printError, printSuccess } from "../output.ts";
6
+
7
+ export interface AIGenerateCommandOptions {
8
+ from: string;
9
+ prompt: string;
10
+ provider: string;
11
+ model?: string;
12
+ apiKey?: string;
13
+ baseUrl?: string;
14
+ output?: string;
15
+ }
16
+
17
+ export async function aiGenerateCommand(options: AIGenerateCommandOptions): Promise<number> {
18
+ try {
19
+ const providerName = options.provider as AIProviderConfig["provider"];
20
+ if (!["ollama", "openai", "anthropic", "custom"].includes(providerName)) {
21
+ printError(`Unknown provider: ${options.provider}. Use: ollama, openai, anthropic, custom`);
22
+ return 2;
23
+ }
24
+
25
+ const provider = resolveProviderConfig({
26
+ provider: providerName,
27
+ model: options.model,
28
+ baseUrl: options.baseUrl,
29
+ apiKey: options.apiKey ?? process.env.ZOND_AI_KEY,
30
+ });
31
+
32
+ console.log(`Provider: ${provider.provider} (${provider.model})`);
33
+ console.log(`Spec: ${options.from}`);
34
+ console.log(`Prompt: ${options.prompt}`);
35
+ console.log(`Generating...`);
36
+
37
+ const startTime = Date.now();
38
+ const result = await generateWithAI({
39
+ specPath: options.from,
40
+ prompt: options.prompt,
41
+ provider,
42
+ });
43
+ const durationMs = Date.now() - startTime;
44
+
45
+ console.log(`Done in ${(durationMs / 1000).toFixed(1)}s (model: ${result.model})`);
46
+ if (result.promptTokens) {
47
+ console.log(`Tokens: ${result.promptTokens} prompt + ${result.completionTokens} completion`);
48
+ }
49
+
50
+ // Write output
51
+ const outputDir = options.output ?? "./generated/ai/";
52
+ const { mkdir } = await import("node:fs/promises");
53
+ await mkdir(outputDir, { recursive: true });
54
+
55
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
56
+ const fileName = `ai-generated-${timestamp}.yaml`;
57
+ const filePath = resolve(outputDir, fileName);
58
+
59
+ await Bun.write(filePath, result.yaml);
60
+ printSuccess(`Written: ${filePath}`);
61
+
62
+ // Auto-create collection if DB is available
63
+ try {
64
+ const { getDb } = await import("../../db/schema.ts");
65
+ getDb();
66
+ const { findCollectionByTestPath, findCollectionBySpec, createCollection, normalizePath, saveAIGeneration } = await import("../../db/queries.ts");
67
+ const { resolveSpecPath } = await import("../../core/generator/serializer.ts");
68
+ const normalizedOutput = normalizePath(outputDir);
69
+ const resolvedSpec = resolveSpecPath(options.from);
70
+
71
+ let collectionId: number | undefined;
72
+ const existing = findCollectionByTestPath(normalizedOutput) ?? findCollectionBySpec(resolvedSpec);
73
+ if (existing) {
74
+ collectionId = existing.id;
75
+ } else {
76
+ const specName = `AI Tests (${new Date().toLocaleDateString()})`;
77
+ collectionId = createCollection({
78
+ name: specName,
79
+ test_path: normalizedOutput,
80
+ openapi_spec: resolvedSpec,
81
+ });
82
+ printSuccess(`Created collection "${specName}" (id: ${collectionId})`);
83
+ }
84
+
85
+ saveAIGeneration({
86
+ collection_id: collectionId,
87
+ prompt: options.prompt,
88
+ model: result.model,
89
+ provider: providerName,
90
+ generated_yaml: result.yaml,
91
+ output_path: filePath,
92
+ status: "success",
93
+ prompt_tokens: result.promptTokens,
94
+ completion_tokens: result.completionTokens,
95
+ duration_ms: durationMs,
96
+ });
97
+ } catch {
98
+ // DB not critical
99
+ }
100
+
101
+ return 0;
102
+ } catch (err) {
103
+ printError(err instanceof Error ? err.message : String(err));
104
+ return 2;
105
+ }
106
+ }
@@ -0,0 +1,43 @@
1
+ import { resolveProviderConfig, PROVIDER_DEFAULTS } from "../../core/generator/ai/types.ts";
2
+ import type { AIProviderConfig } from "../../core/generator/ai/types.ts";
3
+ import { printError } from "../output.ts";
4
+
5
+ export interface ChatCommandOptions {
6
+ provider?: string;
7
+ model?: string;
8
+ apiKey?: string;
9
+ baseUrl?: string;
10
+ safe?: boolean;
11
+ dbPath?: string;
12
+ }
13
+
14
+ const VALID_PROVIDERS = new Set(["ollama", "openai", "anthropic", "custom"]);
15
+
16
+ export async function chatCommand(options: ChatCommandOptions): Promise<number> {
17
+ const providerName = options.provider ?? "ollama";
18
+
19
+ if (!VALID_PROVIDERS.has(providerName)) {
20
+ printError(`Unknown provider: ${providerName}. Available: ollama, openai, anthropic, custom`);
21
+ return 2;
22
+ }
23
+
24
+ const providerConfig = resolveProviderConfig({
25
+ provider: providerName as AIProviderConfig["provider"],
26
+ model: options.model,
27
+ apiKey: options.apiKey ?? process.env["ZOND_AI_KEY"],
28
+ baseUrl: options.baseUrl,
29
+ });
30
+
31
+ try {
32
+ const { startChatUI } = await import("../../tui/chat-ui.ts");
33
+ await startChatUI({
34
+ provider: providerConfig,
35
+ safeMode: options.safe,
36
+ dbPath: options.dbPath,
37
+ });
38
+ return 0;
39
+ } catch (err) {
40
+ printError(`Chat error: ${(err as Error).message}`);
41
+ return 2;
42
+ }
43
+ }