@zenera/cli 1.1.4 → 1.1.6
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/dist/commands/index.js +1 -1
- package/dist/scaffold.js +9 -0
- package/package.json +2 -2
- package/templates/editor/.github/skills/api-schema-index/SKILL.md +246 -28
- package/templates/editor/.github/skills/zen-cli/SKILL.md +1 -1
- package/templates/editor/.github/skills/zen-cli/references/rag.md +112 -21
- package/templates/project/sandbox/{Dockerfile → Dockerfile.tmpl} +3 -1
package/dist/commands/index.js
CHANGED
|
@@ -49,7 +49,7 @@ export const EXTERNAL = {
|
|
|
49
49
|
rag: {
|
|
50
50
|
package: '@zenera/rag',
|
|
51
51
|
summary: 'Search an openapi/swagger document as a graph.',
|
|
52
|
-
usage: 'zen rag schema <index|search|show|stats> [spec...]',
|
|
52
|
+
usage: 'zen rag schema <index|search|list|grep|show|stats> [spec...]',
|
|
53
53
|
install: 'npm i -g @zenera/rag',
|
|
54
54
|
banner: { head: 'Zenera', accent: 'Rag', subtitle: 'Api Retrieval' },
|
|
55
55
|
},
|
package/dist/scaffold.js
CHANGED
|
@@ -26,6 +26,14 @@ import { fileURLToPath } from 'node:url';
|
|
|
26
26
|
const TEMPLATES = fileURLToPath(new URL('../templates', import.meta.url));
|
|
27
27
|
/** The suffix on a file with `{{...}}` in it, dropped when the file lands. */
|
|
28
28
|
const TEMPLATE = '.tmpl';
|
|
29
|
+
/**
|
|
30
|
+
* This `zen`'s own version, which the scaffold pins the sandbox's tools to.
|
|
31
|
+
* The publishable packages move in lockstep, so one number covers them all.
|
|
32
|
+
*/
|
|
33
|
+
function ownVersion() {
|
|
34
|
+
const manifest = fileURLToPath(new URL('../package.json', import.meta.url));
|
|
35
|
+
return JSON.parse(readFileSync(manifest, 'utf8')).version;
|
|
36
|
+
}
|
|
29
37
|
/**
|
|
30
38
|
* Fills the `{{name}}` in a template, in the two shapes templates use.
|
|
31
39
|
*
|
|
@@ -169,6 +177,7 @@ export function scaffold(opts) {
|
|
|
169
177
|
vars: {
|
|
170
178
|
model: modelSection(opts.model, opts.modelOptions),
|
|
171
179
|
exa: opts.web ? part('exa.yaml') : '',
|
|
180
|
+
version: ownVersion(),
|
|
172
181
|
},
|
|
173
182
|
});
|
|
174
183
|
// The directories with no file to put in them: a skill is a folder someone
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenera/cli",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.6",
|
|
4
4
|
"description": "Command-line front end for @zenera/neo: agentic projects you can run, share and commit.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agents",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"@inkjs/ui": "^2.0.0",
|
|
52
52
|
"ink": "^7.1.1",
|
|
53
53
|
"react": "^19.2.8",
|
|
54
|
-
"@zenera/neo": "^1.1.
|
|
54
|
+
"@zenera/neo": "^1.1.6",
|
|
55
55
|
"@anthropic-ai/sdk": "^0.120.0",
|
|
56
56
|
"@google/genai": "^2.18.0",
|
|
57
57
|
"@openrouter/sdk": "^1.2.80",
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: api-schema-index
|
|
3
|
-
description: What a schema index is, how it finds the right call inside a large OpenAPI/Swagger document, and how to build and query one with `zen rag schema` (or `npx @zenera/cli`) —
|
|
3
|
+
description: What a schema index is, how it finds the right call inside a large OpenAPI/Swagger document, and how to build and query one with `zen rag schema` (or `npx @zenera/cli`) — searching it by meaning, listing and grepping it exactly instead of reaching for shell `grep`/`rg`, and giving it to an agent as tools.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# The schema index
|
|
7
7
|
|
|
8
8
|
A schema index is an OpenAPI/Swagger description turned into something that can
|
|
9
9
|
be **asked a question**. It is built once, on disk, and answered from without a
|
|
10
|
-
model: `zen rag schema index` writes it,
|
|
10
|
+
model: `zen rag schema index` writes it, and five commands read it.
|
|
11
11
|
|
|
12
12
|
It exists because a real specification does not fit in a context window, and
|
|
13
13
|
grepping it does not help. The parts that answer "how do I reset a password?"
|
|
@@ -15,6 +15,45 @@ are scattered on purpose: the field is on a schema, the schema is a request
|
|
|
15
15
|
body, the request body belongs to one operation out of three hundred, and the
|
|
16
16
|
word "password" appears in forty places that are not the one you want.
|
|
17
17
|
|
|
18
|
+
## The commands
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
zen rag schema <index|search|list|grep|show|stats> [spec...]
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
| Command | Answers | Embedder? | Typical |
|
|
25
|
+
| -------- | -------------------------------------- | --------- | ------- |
|
|
26
|
+
| `index` | builds the thing | yes | minutes |
|
|
27
|
+
| `search` | _what is this API's way to do X?_ | **yes** | seconds |
|
|
28
|
+
| `list` | _what methods/types/fields are there?_ | no | instant |
|
|
29
|
+
| `grep` | _does the string X appear anywhere?_ | no | instant |
|
|
30
|
+
| `show` | _print exactly these things_ | no | instant |
|
|
31
|
+
| `stats` | _what is in this index?_ | no | instant |
|
|
32
|
+
|
|
33
|
+
Only `search` ranks, and only `search` costs a network round trip — it embeds
|
|
34
|
+
the query before it can compare anything. The other four read `graph.json` off
|
|
35
|
+
the disk and answer in milliseconds, so reach for `search` when the question is
|
|
36
|
+
vague and for `list`/`grep` when it is precise. If a search feels slow, it is
|
|
37
|
+
that one embedding call, not the index: near-zero CPU for several seconds is
|
|
38
|
+
the tell.
|
|
39
|
+
|
|
40
|
+
> **`search` takes bare words as the query, not as a subcommand.**
|
|
41
|
+
> `zen rag schema search list methods` does not list anything — it runs a
|
|
42
|
+
> semantic search for the phrase _"list methods"_ and returns ten ranked
|
|
43
|
+
> guesses. The listing command is `zen rag schema list methods`.
|
|
44
|
+
|
|
45
|
+
> **Never reach for shell `grep`, `rg`, `find`, `cat` or `jq` here.**
|
|
46
|
+
> Not on the specification, not on `graph.json`, not on anything under the
|
|
47
|
+
> index directory. `zen rag schema grep` and `zen rag schema list` are the
|
|
48
|
+
> exact-matching commands, they are local, they need no credential, and they
|
|
49
|
+
> answer in milliseconds. Shell tools on the same files are strictly worse:
|
|
50
|
+
> they match raw YAML/JSON lines rather than nodes, so they cannot tell a
|
|
51
|
+
> field from a `$ref` from a description, cannot say which operation a hit
|
|
52
|
+
> belongs to, cannot filter by kind or direction, and they miss every name
|
|
53
|
+
> the index normalised. A `grep -r password openapi.yaml` returns forty lines
|
|
54
|
+
> of text; `zen rag schema grep password` returns the nodes, with their ids,
|
|
55
|
+
> ready to hand back to `show`.
|
|
56
|
+
|
|
18
57
|
## Why it is a graph and not a search box
|
|
19
58
|
|
|
20
59
|
Two structures, kept together, because neither answers alone:
|
|
@@ -97,7 +136,7 @@ zen rag schema index <spec...> [--embedding <ref>] [-o <dir>] [--batch <n>]
|
|
|
97
136
|
| Flag | Default | Meaning |
|
|
98
137
|
| ------------------- | ------------- | ------------------------------------------------------------ |
|
|
99
138
|
| `--embedding <ref>` | — | Which embedder makes the vectors. Omit it to see the choices |
|
|
100
|
-
| `-o`, `--out <dir>` | `./schema-db` | Where the index goes
|
|
139
|
+
| `-o`, `--out <dir>` | `./schema-db` | Where the index goes; `$ZEN_SCHEMA_DB` if that is set |
|
|
101
140
|
| `--batch <n>` | `96` | Texts per embedding request, and how often progress prints |
|
|
102
141
|
| `--quiet` | — | No narration |
|
|
103
142
|
|
|
@@ -122,6 +161,27 @@ a real environment variable always wins.
|
|
|
122
161
|
Rebuild the index when the specification changes. Nothing watches it, and a
|
|
123
162
|
stale index is a confident wrong answer.
|
|
124
163
|
|
|
164
|
+
## Which index gets read
|
|
165
|
+
|
|
166
|
+
Every reading command takes `-d`, `--dir`. Without one:
|
|
167
|
+
|
|
168
|
+
1. `$ZEN_SCHEMA_DB`, if it is set. **Set this once** instead of typing `-d` on
|
|
169
|
+
every command — `export ZEN_SCHEMA_DB=/assets/schema-db`.
|
|
170
|
+
2. Otherwise the **nearest index** to the working directory: here, then a short
|
|
171
|
+
way down into it, then up a level and again, stopping at your home
|
|
172
|
+
directory. The one chosen is named on stderr as it is used, so an answer is
|
|
173
|
+
never anonymous.
|
|
174
|
+
3. Otherwise `./schema-db`, which is only so the error names the directory you
|
|
175
|
+
were expecting.
|
|
176
|
+
|
|
177
|
+
What is looked for is a `manifest.json` — an index is self-describing, so
|
|
178
|
+
nothing searches for a directory _called_ `schema-db` and one called anything
|
|
179
|
+
else is found the same way. `schema-db` is just the name a new one is given.
|
|
180
|
+
|
|
181
|
+
Two indexes the same distance away is refused rather than guessed at: the wrong
|
|
182
|
+
index does not fail, it answers confidently about a different API. Name one
|
|
183
|
+
with `-d`, or set `ZEN_SCHEMA_DB`.
|
|
184
|
+
|
|
125
185
|
## Searching it
|
|
126
186
|
|
|
127
187
|
```
|
|
@@ -154,23 +214,24 @@ response field in `--output-property`, an action in `--method`.
|
|
|
154
214
|
|
|
155
215
|
### Shaping the answer
|
|
156
216
|
|
|
157
|
-
| Flag | Default
|
|
158
|
-
| --------------------------- |
|
|
159
|
-
| `-d`, `--dir <dir>` |
|
|
160
|
-
| `--embedding <ref>` | the index's
|
|
161
|
-
| `--direction <d>` | `any`
|
|
162
|
-
| `--method-type <t>` | `any`
|
|
163
|
-
| `--exclude-id <id>` | —
|
|
164
|
-
| `--exclude-method <name>` | —
|
|
165
|
-
| `--exclude-type <name>` | —
|
|
166
|
-
| `--exclude-property <name>` | —
|
|
167
|
-
| `--limit <n>` | `5`
|
|
168
|
-
| `--max-hops <n>` | `3`
|
|
169
|
-
| `--max-nodes <n>` | `200`
|
|
170
|
-
| `--format <f>` | `text`
|
|
171
|
-
| `--
|
|
172
|
-
| `--
|
|
173
|
-
| `--
|
|
217
|
+
| Flag | Default | Meaning |
|
|
218
|
+
| --------------------------- | ----------- | ------------------------------------------------------- |
|
|
219
|
+
| `-d`, `--dir <dir>` | found | Which index — see "Which index gets read" |
|
|
220
|
+
| `--embedding <ref>` | the index's | Must be the one the index was built with |
|
|
221
|
+
| `--direction <d>` | `any` | `input`, `output` or `any` |
|
|
222
|
+
| `--method-type <t>` | `any` | `read_only` (GET/HEAD/OPTIONS) or `read_write` |
|
|
223
|
+
| `--exclude-id <id>` | — | Drop a node. Repeatable |
|
|
224
|
+
| `--exclude-method <name>` | — | Drop an operation by name. Repeatable |
|
|
225
|
+
| `--exclude-type <name>` | — | Drop a schema by name. Repeatable |
|
|
226
|
+
| `--exclude-property <name>` | — | Drop a field by name. Repeatable |
|
|
227
|
+
| `--limit <n>` | `5` | Seeds kept per term |
|
|
228
|
+
| `--max-hops <n>` | `3` | How far apart two hits may be and still join |
|
|
229
|
+
| `--max-nodes <n>` | `200` | Nodes per result |
|
|
230
|
+
| `--format <f>` | `text` | `text`, `mermaid`, `mermaid-flowchart`, `ts`, `openapi` |
|
|
231
|
+
| `--show-source` | — | Tag each operation and schema with its document |
|
|
232
|
+
| `--no-docs` | — | Leave the descriptions out |
|
|
233
|
+
| `--interactive` | — | Prompt, search, refine. Needs a terminal |
|
|
234
|
+
| `--quiet` | — | No narration |
|
|
174
235
|
|
|
175
236
|
```sh
|
|
176
237
|
zen rag schema search --method "reset a user password" --format ts
|
|
@@ -236,7 +297,8 @@ quit
|
|
|
236
297
|
|
|
237
298
|
## Reading it without searching
|
|
238
299
|
|
|
239
|
-
|
|
300
|
+
None of these need an embedder or a credential — they are plain reads of the
|
|
301
|
+
graph on disk.
|
|
240
302
|
|
|
241
303
|
```sh
|
|
242
304
|
zen rag schema show Type:Invoice Method:listInvoices --format ts
|
|
@@ -248,9 +310,153 @@ an index and what built it — counts by kind, the embedding model, the document
|
|
|
248
310
|
it came from. `stats` is the fastest way to answer "is this index the one I
|
|
249
311
|
think it is?".
|
|
250
312
|
|
|
313
|
+
### Which one to reach for
|
|
314
|
+
|
|
315
|
+
| The question | The command |
|
|
316
|
+
| ------------------------------------------------ | ---------------------------------------- |
|
|
317
|
+
| "how do I reset a password with this API?" | `search --method "reset a password"` |
|
|
318
|
+
| _anything you would have run `grep` for_ | `grep` / `list` — never the shell |
|
|
319
|
+
| "what does the create-user request look like?" | `search --input-type "create user"` |
|
|
320
|
+
| "what operations exist under /users?" | `list methods --path "*/users*"` |
|
|
321
|
+
| "how many operations are there at all?" | `list methods` (or `--json` for `found`) |
|
|
322
|
+
| "is there a field called `mfa_secret` anywhere?" | `grep mfa_secret` |
|
|
323
|
+
| "which schemas mention tenancy?" | `grep tenancy --kind type` |
|
|
324
|
+
| "give me `GetUser` as OpenAPI" | `show --method GetUser --format openapi` |
|
|
325
|
+
| "is this index the right one?" | `stats` |
|
|
326
|
+
|
|
327
|
+
The rule: **a question about meaning is a `search`; a question about presence,
|
|
328
|
+
count or spelling is a `list` or a `grep`.** Search cannot answer the second
|
|
329
|
+
kind, because a ranking always returns its best guesses whether or not any of
|
|
330
|
+
them are right.
|
|
331
|
+
|
|
332
|
+
### Exact matching, when the question is whether something exists
|
|
333
|
+
|
|
334
|
+
Search **ranks**. A ranking returns the top of a list, which means it can never
|
|
335
|
+
tell you that something is absent — "no results" and "not there" look the same.
|
|
336
|
+
When that is the actual question, do not search:
|
|
337
|
+
|
|
338
|
+
```
|
|
339
|
+
zen rag schema list <methods|types|properties> [-d <dir>] [filters…]
|
|
340
|
+
zen rag schema grep <pattern> [-d <dir>] [filters…]
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
| Flag | For | Meaning |
|
|
344
|
+
| ------------------- | ------ | ---------------------------------------------- |
|
|
345
|
+
| `--name <p>` | both | Match the name. Repeatable |
|
|
346
|
+
| `--path <p>` | both | Match the route it sits on. Repeatable |
|
|
347
|
+
| `--regex` | both | Read every pattern as a regular expression |
|
|
348
|
+
| `--case-sensitive` | both | Stop ignoring case |
|
|
349
|
+
| `--source <name>` | both | Only one document, as `stats` names it |
|
|
350
|
+
| `--show-source` | both | Print which document each row came from |
|
|
351
|
+
| `--method-type <t>` | `list` | `read_only`, `read_write` or `any` |
|
|
352
|
+
| `--direction <d>` | `list` | `input`, `output` or `any` |
|
|
353
|
+
| `--kind <k>` | `grep` | `method`, `type` or `property`. Repeatable |
|
|
354
|
+
| `--ids-only` | `grep` | Bare ids, one per line, for piping |
|
|
355
|
+
| `--limit <n>` | both | Print at most n; `found` still counts them all |
|
|
356
|
+
| `--json` | both | `{found, truncated, rows}` / `…, matches}` |
|
|
357
|
+
| `--quiet` | both | No narration |
|
|
358
|
+
|
|
359
|
+
```sh
|
|
360
|
+
zen rag schema list methods # all of them, sorted by route
|
|
361
|
+
zen rag schema list methods --path "*/users*" # every route under /users
|
|
362
|
+
zen rag schema list methods --method-type read_only
|
|
363
|
+
zen rag schema list types --name "*Password*" # every schema so named
|
|
364
|
+
zen rag schema list types --direction output # everything a call can return
|
|
365
|
+
zen rag schema list properties --name password # every field so named
|
|
366
|
+
zen rag schema grep password # every literal occurrence
|
|
367
|
+
zen rag schema grep "pass(word|phrase)" --regex
|
|
368
|
+
zen rag schema grep password --kind type --ids-only
|
|
369
|
+
zen rag schema grep status --path "/invoices/*" # the word, in one corner
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
`list` walks one kind of node and matches its structured fields; `grep` matches
|
|
373
|
+
the text of every node in the index — the same text the search was built from,
|
|
374
|
+
so the two agree on what the API says. A pattern with `*` or `?` is a glob
|
|
375
|
+
matched against the whole string; a plain word is a substring, so `--name
|
|
376
|
+
password` finds `ResetPasswordPayload` and `--name "Password*"` finds nothing.
|
|
377
|
+
|
|
378
|
+
**`--regex` applies to both commands and to every pattern**, which is the only
|
|
379
|
+
way to say "one of these" — a glob has no alternation:
|
|
380
|
+
|
|
381
|
+
```sh
|
|
382
|
+
zen rag schema list methods --regex --path "^/(users|teams)/"
|
|
383
|
+
zen rag schema list types --regex --name "(Request|Response)$"
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
`--name` and `--path` are constraints on `grep` as well, which is what makes a
|
|
387
|
+
common word usable: `grep status` across a whole API is unreadable,
|
|
388
|
+
`grep status --path "/invoices/*" --kind property` is an answer. On `list
|
|
389
|
+
properties` and on `grep`, `--path` matches the route a parameter's operation
|
|
390
|
+
sits on; a schema belongs to no one route, so `--path` never selects one.
|
|
391
|
+
|
|
392
|
+
When an index holds several documents, `--show-source` puts
|
|
393
|
+
`[source: billing_api_v2]` on every row, so which document answered does not
|
|
394
|
+
have to be recovered from `--json`.
|
|
395
|
+
|
|
396
|
+
Both report `found` as the true total even when `--limit` shortens what is
|
|
397
|
+
printed, so a cut answer never misreports how much there is. Nothing matching
|
|
398
|
+
exits 0 with empty stdout — and that emptiness is trustworthy, which is the
|
|
399
|
+
whole point of them.
|
|
400
|
+
|
|
401
|
+
`grep --ids-only` composes:
|
|
402
|
+
|
|
403
|
+
```sh
|
|
404
|
+
zen rag schema grep token --ids-only | xargs zen rag schema show --format ts
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Instead of the shell
|
|
408
|
+
|
|
409
|
+
Every reflex that reaches for a shell tool has a command here that answers the
|
|
410
|
+
same question better. Add `-d <dir>` when the index is not the nearest one, or
|
|
411
|
+
name it once with `ZEN_SCHEMA_DB`.
|
|
412
|
+
|
|
413
|
+
| The reflex | The command |
|
|
414
|
+
| --------------------------------------- | ----------------------------------------------------- |
|
|
415
|
+
| `grep -ri password spec.yaml` | `zen rag schema grep password` |
|
|
416
|
+
| `grep -r password` \| _only in schemas_ | `zen rag schema grep password --kind type` |
|
|
417
|
+
| `grep -E "pass(word\|phrase)"` | `zen rag schema grep "pass(word\|phrase)" --regex` |
|
|
418
|
+
| `grep password` (case matters) | `zen rag schema grep password --case-sensitive` |
|
|
419
|
+
| `grep -c` / `wc -l` | `--json`, and read `found` — it counts past `--limit` |
|
|
420
|
+
| `grep -l` / `grep -o` for piping | `zen rag schema grep password --ids-only` |
|
|
421
|
+
| `grep "/users" spec.yaml` | `zen rag schema list methods --path "*/users*"` |
|
|
422
|
+
| `grep -i "updateuser"` | `zen rag schema list methods --name "*Update*"` |
|
|
423
|
+
| `grep "UserSettings"` | `zen rag schema list types --name "*UserSettings*"` |
|
|
424
|
+
| `grep -A5 password` for the field | `zen rag schema list properties --name "*password*"` |
|
|
425
|
+
| `grep -rl password specs/` (which one?) | `zen rag schema grep password --show-source` |
|
|
426
|
+
| `cat`/`yq` a schema out of the document | `zen rag schema show --type UserSettings --format ts` |
|
|
427
|
+
| `ls` the index directory | `zen rag schema stats` |
|
|
428
|
+
|
|
429
|
+
```sh
|
|
430
|
+
export ZEN_SCHEMA_DB=/assets/schema-db # once, then never again
|
|
431
|
+
zen rag schema grep "password" --limit 10
|
|
432
|
+
zen rag schema list methods --path "*user*"
|
|
433
|
+
zen rag schema list types --name "*UserSettings*"
|
|
434
|
+
zen rag schema list properties --name "*password*" --show-source
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
If none of these fits the question, the question is about meaning, and the
|
|
438
|
+
answer is `search` — still not the shell.
|
|
439
|
+
|
|
440
|
+
### Naming what you want in `show`
|
|
441
|
+
|
|
442
|
+
```sh
|
|
443
|
+
zen rag schema show --method GetCurrentUserInfo --format openapi --exact
|
|
444
|
+
zen rag schema show --type "*Invoice*" --format ts
|
|
445
|
+
zen rag schema show --source billing-api --format openapi
|
|
446
|
+
zen rag schema show --type "*Invoice*" --show-source
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
Ids are one way in, but `--method` and `--type` take the names you already
|
|
450
|
+
have. A bare name means exactly that name; add `*` to take more than one.
|
|
451
|
+
`--show-source` names the document each node came from, which is the quick way
|
|
452
|
+
to tell two versions of the same API apart. `--exact` prints only what was
|
|
453
|
+
named instead of the neighbourhood around it, which with `--format openapi`
|
|
454
|
+
gives a valid self-contained slice of the specification — enough to generate a
|
|
455
|
+
client or a mock payload from.
|
|
456
|
+
|
|
251
457
|
## Giving it to an agent
|
|
252
458
|
|
|
253
|
-
The same engine, as
|
|
459
|
+
The same engine, as five tools in the group `schema`. An agent takes them all
|
|
254
460
|
with `schema:*` in its `tools:`.
|
|
255
461
|
|
|
256
462
|
```ts
|
|
@@ -269,12 +475,22 @@ const project = await loadProject('./my-project', { tools: schemaTools(index) })
|
|
|
269
475
|
| `search_api` | the search above, with the same fields |
|
|
270
476
|
| `describe_types` | named schemas as TypeScript, closed over what they refer to |
|
|
271
477
|
| `find_types_with_property` | every schema with a field of this name — exact lookup, no searching |
|
|
272
|
-
| `
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
`
|
|
276
|
-
the
|
|
277
|
-
|
|
478
|
+
| `list_api` | methods, types or fields by name — complete, and counted in full |
|
|
479
|
+
| `grep_api` | every literal occurrence of a string — the way to prove absence |
|
|
480
|
+
|
|
481
|
+
Only `search_api` ranks; the other four are exact. `find_types_with_property`
|
|
482
|
+
is the one for the repair loop. When `tsc` says `'password' does not exist in
|
|
483
|
+
type 'PublicUserProfile'`, the model does not need the word explained again —
|
|
484
|
+
it needs the list of types that _do_ have one, and embedding the word will only
|
|
485
|
+
rank the guess it already made near the top. `grep_api` is the same instinct
|
|
486
|
+
widened: it is how a model checks that a search returning nothing really means
|
|
487
|
+
there is nothing.
|
|
488
|
+
|
|
489
|
+
`list_api` and `grep_api` take `name`, `path`, `regex` and `source`, so a
|
|
490
|
+
common word can be narrowed to one route or one document rather than read out
|
|
491
|
+
in full. When an index holds more than one document, both tools name the source
|
|
492
|
+
of every row without being asked — with two versions of the same API indexed
|
|
493
|
+
together, which one answered is part of the answer.
|
|
278
494
|
|
|
279
495
|
Tell the agent in its prompt to search before it writes a call, and to put the
|
|
280
496
|
intent in the narrow field. A model left to itself puts everything in `all`.
|
|
@@ -290,3 +506,5 @@ intent in the narrow field. A model left to itself puts everything in `all`.
|
|
|
290
506
|
| A usage error before any credential is asked for | Deliberate: everything about the invocation is checked first, so a typo is a typo |
|
|
291
507
|
| Nothing matched | Exit 0 with an empty answer. Try fewer words, or `--all` instead of a narrow field |
|
|
292
508
|
| Answers about the wrong version of the API | Nothing watches the document. Re-index after it changes |
|
|
509
|
+
| A search took ten seconds, using no CPU | One embedding round trip, not the index. `list`/`grep` make none |
|
|
510
|
+
| `search <word> <word>` gave ranked nonsense | Bare words after `search` are the QUERY, not a subcommand. You meant `list`/`grep` |
|
|
@@ -28,7 +28,7 @@ zen sandbox [status|up|pull|clean|disk] [options]
|
|
|
28
28
|
zen version
|
|
29
29
|
|
|
30
30
|
zen faker <serve|build|cache> [spec...]
|
|
31
|
-
zen rag schema <index|search|show|stats> [spec...]
|
|
31
|
+
zen rag schema <index|search|list|grep|show|stats> [spec...]
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
## Read the reference before answering
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# API search — `zen rag`
|
|
2
2
|
|
|
3
3
|
```
|
|
4
|
-
zen rag schema <index|search|show|stats> [spec...]
|
|
4
|
+
zen rag schema <index|search|list|grep|show|stats> [spec...]
|
|
5
5
|
```
|
|
6
6
|
|
|
7
7
|
Provided by `@zenera/rag` — `npm i -g @zenera/rag` if `zen rag` says it is not
|
|
@@ -25,7 +25,7 @@ zen rag schema index <spec...> [--embedding <ref>] [-o <dir>] [--batch <n>]
|
|
|
25
25
|
| Flag | Default | Meaning |
|
|
26
26
|
| ------------------- | ------------- | ------------------------------------------------------------ |
|
|
27
27
|
| `--embedding <ref>` | — | Which embedder makes the vectors. Omit it to see the choices |
|
|
28
|
-
| `-o`, `--out <dir>` | `./schema-db` | Where the index goes
|
|
28
|
+
| `-o`, `--out <dir>` | `./schema-db` | Where the index goes; `$ZEN_SCHEMA_DB` if set |
|
|
29
29
|
| `--batch <n>` | `96` | Texts per embedding request, and how often progress prints |
|
|
30
30
|
|
|
31
31
|
```
|
|
@@ -49,6 +49,21 @@ lance/ the vector and full-text indexes
|
|
|
49
49
|
The manifest records the embedding ref **and** the embedder's own id, so a
|
|
50
50
|
search with a different model is refused rather than quietly returning nonsense.
|
|
51
51
|
|
|
52
|
+
## Which index gets read
|
|
53
|
+
|
|
54
|
+
Every reading command takes `-d`, `--dir`. Without one:
|
|
55
|
+
|
|
56
|
+
1. `$ZEN_SCHEMA_DB`, if it is set.
|
|
57
|
+
2. Otherwise the **nearest index** to the working directory — here, then a
|
|
58
|
+
short way down, then up a level and again, stopping at your home directory.
|
|
59
|
+
The one used is named on stderr.
|
|
60
|
+
3. Otherwise `./schema-db`, so the error names the directory you expected.
|
|
61
|
+
|
|
62
|
+
What is looked for is a `manifest.json`, not a directory called `schema-db`, so
|
|
63
|
+
an index called anything else is found the same way. Two the same distance away
|
|
64
|
+
is refused rather than guessed at — name one with `-d`, or set `ZEN_SCHEMA_DB`
|
|
65
|
+
once and stop typing it.
|
|
66
|
+
|
|
52
67
|
## `search`
|
|
53
68
|
|
|
54
69
|
```
|
|
@@ -58,6 +73,11 @@ zen rag schema search [terms…] [filters…]
|
|
|
58
73
|
Every argument is validated before an embedder is constructed, so a typo is a
|
|
59
74
|
usage error rather than a credential error.
|
|
60
75
|
|
|
76
|
+
**Bare words are the query, not a subcommand.** `zen rag schema search list
|
|
77
|
+
methods` searches for the phrase _"list methods"_ and returns ranked guesses;
|
|
78
|
+
`zen rag schema list methods` is the listing. `search` is also the only read
|
|
79
|
+
command that embeds, so it is the only slow one.
|
|
80
|
+
|
|
61
81
|
### Terms — repeatable, and the field is the point
|
|
62
82
|
|
|
63
83
|
| Term | Searches |
|
|
@@ -79,23 +99,24 @@ search good. A request field belongs in `--input-property`, a response field in
|
|
|
79
99
|
|
|
80
100
|
### Filters and shape
|
|
81
101
|
|
|
82
|
-
| Flag | Default
|
|
83
|
-
| --------------------------- |
|
|
84
|
-
| `-d`, `--dir <dir>` |
|
|
85
|
-
| `--embedding <ref>` | the index's
|
|
86
|
-
| `--direction <d>` | `any`
|
|
87
|
-
| `--method-type <t>` | `any`
|
|
88
|
-
| `--exclude-id <id>` | —
|
|
89
|
-
| `--exclude-method <name>` | —
|
|
90
|
-
| `--exclude-type <name>` | —
|
|
91
|
-
| `--exclude-property <name>` | —
|
|
92
|
-
| `--limit <n>` | `5`
|
|
93
|
-
| `--max-hops <n>` | `3`
|
|
94
|
-
| `--max-nodes <n>` | `200`
|
|
95
|
-
| `--format <f>` | `text`
|
|
96
|
-
| `--
|
|
97
|
-
| `--
|
|
98
|
-
| `--
|
|
102
|
+
| Flag | Default | Meaning |
|
|
103
|
+
| --------------------------- | ----------- | ------------------------------------------------------- |
|
|
104
|
+
| `-d`, `--dir <dir>` | found | Which index — see "Which index gets read" |
|
|
105
|
+
| `--embedding <ref>` | the index's | Must be the one the index was built with |
|
|
106
|
+
| `--direction <d>` | `any` | `input`, `output` or `any` |
|
|
107
|
+
| `--method-type <t>` | `any` | `read_only`, `read_write` or `any` |
|
|
108
|
+
| `--exclude-id <id>` | — | Drop a node. Repeatable |
|
|
109
|
+
| `--exclude-method <name>` | — | Drop an operation by name. Repeatable |
|
|
110
|
+
| `--exclude-type <name>` | — | Drop a schema by name. Repeatable |
|
|
111
|
+
| `--exclude-property <name>` | — | Drop a field by name. Repeatable |
|
|
112
|
+
| `--limit <n>` | `5` | Seeds kept per term |
|
|
113
|
+
| `--max-hops <n>` | `3` | How far apart two hits may be |
|
|
114
|
+
| `--max-nodes <n>` | `200` | Nodes per result |
|
|
115
|
+
| `--format <f>` | `text` | `text`, `mermaid`, `mermaid-flowchart`, `ts`, `openapi` |
|
|
116
|
+
| `--show-source` | — | Tag each operation and schema with its document |
|
|
117
|
+
| `--no-docs` | — | Leave the descriptions out |
|
|
118
|
+
| `--interactive` | — | Prompt, search, refine. Needs a terminal |
|
|
119
|
+
| `--quiet` | — | No narration |
|
|
99
120
|
|
|
100
121
|
```
|
|
101
122
|
zen rag schema search --method "reset a user password" --format ts
|
|
@@ -126,15 +147,80 @@ reset forget it, exclusions included
|
|
|
126
147
|
quit
|
|
127
148
|
```
|
|
128
149
|
|
|
150
|
+
## `list` and `grep`
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
zen rag schema list <methods|types|properties> [-d <dir>] [--name <p>] [--path <p>]
|
|
154
|
+
zen rag schema grep <pattern> [-d <dir>] [--name <p>] [--path <p>] [--kind <k>]
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Exact, and therefore complete. `search` ranks, so it can only hand back the top
|
|
158
|
+
of a list — it cannot tell you that something is _not_ there. These can: they
|
|
159
|
+
read `graph.json` directly, with no embedder, no credential and no network.
|
|
160
|
+
|
|
161
|
+
| Flag | For | Meaning |
|
|
162
|
+
| ------------------- | ------ | -------------------------------------------- |
|
|
163
|
+
| `--name <p>` | both | Match the name. Repeatable |
|
|
164
|
+
| `--path <p>` | both | Match the route it sits on. Repeatable |
|
|
165
|
+
| `--regex` | both | Read every pattern as a regular expression |
|
|
166
|
+
| `--case-sensitive` | both | Stop ignoring case |
|
|
167
|
+
| `--source <name>` | both | Only nodes from one document |
|
|
168
|
+
| `--show-source` | both | Print which document each row came from |
|
|
169
|
+
| `--method-type <t>` | `list` | `read_only`, `read_write` or `any` |
|
|
170
|
+
| `--direction <d>` | `list` | `input`, `output` or `any` |
|
|
171
|
+
| `--kind <k>` | `grep` | `method`, `type` or `property`. Repeatable |
|
|
172
|
+
| `--ids-only` | `grep` | Just the ids, one per line, for piping |
|
|
173
|
+
| `--limit <n>` | both | Rows to print. `found` still counts them all |
|
|
174
|
+
|
|
175
|
+
A pattern with `*` or `?` is a glob matched against the whole string; a plain
|
|
176
|
+
word is a substring. So `--name password` finds `ResetPasswordPayload`, and
|
|
177
|
+
`--name "Password*"` finds nothing, because nothing starts with it. `--regex`
|
|
178
|
+
makes it a regular expression instead — the only way to say "one of these":
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
zen rag schema list methods --regex --path "^/(users|teams)/"
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
`--path` selects on the route an operation sits on, and on the route a
|
|
185
|
+
parameter's operation sits on. A schema belongs to no one route, so `--path`
|
|
186
|
+
never selects one.
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
zen rag schema list methods --path "*/users*"
|
|
190
|
+
zen rag schema list types --name "*Password*"
|
|
191
|
+
zen rag schema grep password
|
|
192
|
+
zen rag schema grep "pass(word|phrase)" --regex
|
|
193
|
+
zen rag schema grep status --path "/invoices/*" --kind property
|
|
194
|
+
zen rag schema grep token --ids-only | xargs zen rag schema show --format ts
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
No match exits 0 with nothing on stdout — that is the answer, and unlike an
|
|
198
|
+
empty search it is a reliable one. Under `--limit`, `found` is still the true
|
|
199
|
+
total, so a shortened answer never misreports how much there is.
|
|
200
|
+
|
|
129
201
|
## `show`
|
|
130
202
|
|
|
131
203
|
```
|
|
132
|
-
zen rag schema show
|
|
204
|
+
zen rag schema show [id...] [-d <dir>] [--format <f>]
|
|
205
|
+
[--method <name>] [--type <name>] [--source <name>]
|
|
206
|
+
[--show-source] [--exact]
|
|
133
207
|
```
|
|
134
208
|
|
|
135
209
|
Prints named nodes with no search in between. Needs no embedder and no
|
|
136
210
|
credential — it is a read of the graph.
|
|
137
211
|
|
|
212
|
+
Ids are one way in; `--method` and `--type` name things directly, which is
|
|
213
|
+
usually what you have. A bare name means exactly that name; add `*` to select
|
|
214
|
+
more than one. `--source <name>` takes a whole document, and `--show-source`
|
|
215
|
+
tags each node with the document it came from. `--exact` prints only what was
|
|
216
|
+
named instead of the neighbourhood around it — with `--format openapi` that is
|
|
217
|
+
a valid, self-contained slice of the specification.
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
zen rag schema show --method GetCurrentUserInfo --format openapi --exact
|
|
221
|
+
zen rag schema show --type "*Invoice*" --format ts
|
|
222
|
+
```
|
|
223
|
+
|
|
138
224
|
## `stats`
|
|
139
225
|
|
|
140
226
|
```
|
|
@@ -153,7 +239,12 @@ documents it came from. Also needs no embedder.
|
|
|
153
239
|
| `search_api` | The search above, with the same fields |
|
|
154
240
|
| `describe_types` | Named schemas as TypeScript, closed over what they refer to |
|
|
155
241
|
| `find_types_with_property` | Every schema with a field of this name — exact lookup, no searching |
|
|
156
|
-
| `
|
|
242
|
+
| `list_api` | Methods, types or fields by name — complete, and counted in full |
|
|
243
|
+
| `grep_api` | Every literal occurrence of a string — the way to prove absence |
|
|
244
|
+
|
|
245
|
+
Only `search_api` ranks. Reach for the others whenever the question is whether
|
|
246
|
+
something exists, because a search that returns nothing and a thing that is not
|
|
247
|
+
there look exactly the same.
|
|
157
248
|
|
|
158
249
|
They share the group `schema`, so an agent takes them with `schema:*` in its
|
|
159
250
|
`tools:`.
|
|
@@ -18,4 +18,6 @@ COPY --from=node /usr/local/lib/node_modules /usr/local/lib/node_modules
|
|
|
18
18
|
RUN ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
|
|
19
19
|
&& ln -s /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
# Pinned to the `zen` that wrote this file, so the tools in the container are
|
|
22
|
+
# the ones the session outside it was built by. Bump both together.
|
|
23
|
+
RUN npm install -g @zenera/cli@{{version}} @zenera/rag@{{version}}
|