@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
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
|
+
[](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,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
|
+
}
|