@zenera/cli 1.1.11 → 1.1.14
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/README.md +20 -0
- package/dist/banner.js +69 -47
- package/dist/commands/index.js +3 -0
- package/dist/commands/init.js +8 -4
- package/dist/commands/inspect.js +23 -5
- package/dist/commands/memory.d.ts +3 -0
- package/dist/commands/memory.js +375 -0
- package/dist/engine.js +15 -9
- package/dist/main.js +9 -0
- package/dist/podman.js +43 -9
- package/dist/projects.js +10 -2
- package/dist/scaffold.js +22 -1
- package/dist/tui/app.js +19 -11
- package/dist/tui/theme.d.ts +7 -0
- package/dist/tui/theme.js +18 -11
- package/package.json +2 -2
- package/templates/editor/.github/copilot-instructions.md +151 -43
- package/templates/editor/.github/prompts/review-project.prompt.md +5 -0
- package/templates/editor/.github/prompts/sync-with-spec.prompt.md +7 -4
- package/templates/editor/.github/skills/zen-cli/SKILL.md +3 -0
- package/templates/editor/.github/skills/zen-cli/references/memory.md +113 -0
- package/templates/editor/.github/skills/zen-cli/references/rag.md +2 -2
- package/templates/editor/.github/skills/zen-cli/references/run.md +3 -1
- package/templates/editor/.github/skills/zen-memory/SKILL.md +555 -0
- package/templates/editor/.github/skills/zen-rag-docs/SKILL.md +16 -16
- package/templates/editor/.github/skills/zen-rag-schema/SKILL.md +2 -2
- package/templates/editor/.vscode/settings.json +4 -2
- package/templates/parts/exa.prompt.md.tmpl +4 -0
- package/templates/parts/exa.spec.md.tmpl +2 -0
- package/templates/project/INSTRUCTIONS.md +8 -0
- package/templates/project/SPECIFICATION.md.tmpl +47 -0
- package/templates/project/agents/prompts/{default.md → default.md.tmpl} +4 -0
- package/templates/project/agents.yaml.tmpl +4 -0
- package/templates/project/gitignore +7 -1
- package/templates/project/scripts/_setup.sh +101 -0
- package/templates/project/SPECIFICATION.md +0 -6
|
@@ -147,7 +147,7 @@ documentation tree is what makes "which release says this?" answerable at all.
|
|
|
147
147
|
|
|
148
148
|
```sh
|
|
149
149
|
zen rag docs index ./docs ./README.md ./packages/*/README.md --embedding openai:text-embedding-3-small
|
|
150
|
-
zen rag docs index "releases/
|
|
150
|
+
zen rag docs index "releases/acme_4.*/**/*.md" --embedding google:gemini-embedding-001 -o .index/acme
|
|
151
151
|
```
|
|
152
152
|
|
|
153
153
|
### The name is the identity
|
|
@@ -157,8 +157,8 @@ everything you named. Nothing anywhere records where the file was on the machine
|
|
|
157
157
|
that built the index.
|
|
158
158
|
|
|
159
159
|
That name is what `--file` patterns match, so it is worth arranging on purpose.
|
|
160
|
-
Indexing two release trees at once keeps `
|
|
161
|
-
`
|
|
160
|
+
Indexing two release trees at once keeps `acme_4.1.0/api/routing.md` and
|
|
161
|
+
`acme_4.2.0/api/routing.md` apart, and a search can be pinned to one of them.
|
|
162
162
|
Indexing one tree from inside it gives you `api/routing.md`. Two files that
|
|
163
163
|
would land on the same name are deduped rather than merged.
|
|
164
164
|
|
|
@@ -229,7 +229,7 @@ zen rag docs search "how are rate limits counted"
|
|
|
229
229
|
The answer is the corpus quoting itself:
|
|
230
230
|
|
|
231
231
|
```
|
|
232
|
-
##
|
|
232
|
+
## acme_4.2.0/api/routing.md — 9 of 148 lines
|
|
233
233
|
|
|
234
234
|
5 | ## Rate limits
|
|
235
235
|
7 | Requests are counted per tenant and rejected past the limit.
|
|
@@ -259,14 +259,14 @@ question with a narrowing on it — not a different command.
|
|
|
259
259
|
| `--exclude-id <id>` | a passage already seen. Repeatable |
|
|
260
260
|
|
|
261
261
|
```sh
|
|
262
|
-
zen rag docs search --file "
|
|
262
|
+
zen rag docs search --file "acme_4.2.*/api/**" "rate limit for the users route"
|
|
263
263
|
zen rag docs search --section "Rate limits" --kind table "requests per minute"
|
|
264
264
|
zen rag docs search --mode text "X-RateLimit-Remaining"
|
|
265
265
|
```
|
|
266
266
|
|
|
267
267
|
A `--file` pattern with `*` or `?` is a glob matched against the whole document
|
|
268
268
|
name; a plain word is a substring. So `--file routing` finds
|
|
269
|
-
`
|
|
269
|
+
`acme_4.2.0/api/routing.md` and `--file "routing*"` finds nothing.
|
|
270
270
|
|
|
271
271
|
`--section` takes a heading title, a structure id, or the structure path an
|
|
272
272
|
earlier answer printed. A title that appears in four documents becomes four
|
|
@@ -397,7 +397,7 @@ think it is?".
|
|
|
397
397
|
| "what is the shape of this manual?" | `list sections --depth 2` |
|
|
398
398
|
| "where is the table of per-route limits?" | `list tables --file "api/**"` |
|
|
399
399
|
| "the exact error string, not something like it" | `search --mode text "connection reset by peer"` |
|
|
400
|
-
| "same question, but only the 4.2 docs" | `search --file "
|
|
400
|
+
| "same question, but only the 4.2 docs" | `search --file "acme_4.2*/**" "…"` |
|
|
401
401
|
| "is this index the right one?" | `stats` |
|
|
402
402
|
|
|
403
403
|
The rule: **a question about meaning is a `search`; a question about presence,
|
|
@@ -461,7 +461,7 @@ list, so an empty answer and an absent thing look identical. `grep_docs` is how
|
|
|
461
461
|
|
|
462
462
|
`search_docs` is shaped for the **second** call rather than the first. The first
|
|
463
463
|
is always a sentence and always returns some of the wrong tree; the second is
|
|
464
|
-
the same sentence with `files: ["
|
|
464
|
+
the same sentence with `files: ["acme_4.2*/api/**"]`, or `section: "Rate limits"`,
|
|
465
465
|
or `kind: ["table"]`. Those are parameters and not separate tools, so narrowing
|
|
466
466
|
costs one call instead of three. `exclude_ids` takes the ids from an earlier
|
|
467
467
|
answer, so asking again moves on instead of repeating itself.
|
|
@@ -482,7 +482,7 @@ project.** Not optional, and not the same thing as passing the tools in.
|
|
|
482
482
|
|
|
483
483
|
Wiring alone leaves the model to infer everything that matters. A tool
|
|
484
484
|
description says what `grep_docs` does; it cannot say that this index holds the
|
|
485
|
-
|
|
485
|
+
ACME 4.1 and 4.2 manuals side by side, that every answer must be pinned to a
|
|
486
486
|
release with `files`, that the API reference lives under `*/api/**` and the
|
|
487
487
|
task guides under `*/guides/**`, or that the numbers anybody actually wants are
|
|
488
488
|
in tables and so `kind: ["table_row"]` is the right first move. That is project
|
|
@@ -530,19 +530,19 @@ Best practice, in order of how often it is got wrong:
|
|
|
530
530
|
|
|
531
531
|
```md
|
|
532
532
|
---
|
|
533
|
-
name:
|
|
534
|
-
description: How to find an answer in the
|
|
533
|
+
name: acme-docs
|
|
534
|
+
description: How to find an answer in the ACME 4.1 and 4.2 manuals — which document says it,
|
|
535
535
|
what it says verbatim, and which release it is true of. Use before answering anything
|
|
536
|
-
about
|
|
536
|
+
about ACME behaviour, limits or API routes.
|
|
537
537
|
---
|
|
538
538
|
|
|
539
|
-
# The
|
|
539
|
+
# The ACME manuals
|
|
540
540
|
|
|
541
541
|
Indexed at `/assets/docs-db` (already in `$ZEN_DOCS_DB`). Two releases side by
|
|
542
|
-
side; document names begin `
|
|
542
|
+
side; document names begin `acme_4.1.0/` or `acme_4.2.0/`, then `api/` for the
|
|
543
543
|
reference and `guides/` for the task documentation.
|
|
544
544
|
|
|
545
|
-
- Always pin the release: `files: ["
|
|
545
|
+
- Always pin the release: `files: ["acme_4.2.0/**"]`. An unpinned search mixes them.
|
|
546
546
|
- Vague question ("how does edge failover work?") → `search_docs`, then ask again
|
|
547
547
|
with `section` or `files` once you can see which half of the tree it is in.
|
|
548
548
|
- Does X exist, how is it spelled, how many are there → `grep_docs`. It is
|
|
@@ -553,7 +553,7 @@ reference and `guides/` for the task documentation.
|
|
|
553
553
|
- Never `grep`/`rg`/`cat` the tree — the tools above are local and exact.
|
|
554
554
|
|
|
555
555
|
Worked: per-route rate limits are the table under "Rate limits" in
|
|
556
|
-
`
|
|
556
|
+
`acme_4.2.0/api/routing.md` (lines 24-31); the retry envelope is described two
|
|
557
557
|
sections down. Cite the document name and the line numbers.
|
|
558
558
|
```
|
|
559
559
|
|
|
@@ -577,8 +577,8 @@ project.** Not optional, and not the same thing as passing the tools in.
|
|
|
577
577
|
|
|
578
578
|
Wiring alone leaves the model to infer everything that matters. A tool
|
|
579
579
|
description says what `grep_api` does; it cannot say that this index holds the
|
|
580
|
-
|
|
581
|
-
`/
|
|
580
|
+
ACME policy API, that names are `snake_case`, that every route is under
|
|
581
|
+
`/api/v1/policy`, or that `list_api` is the right first move here because the
|
|
582
582
|
API has three hundred operations and search will hand back five. That is
|
|
583
583
|
project knowledge, and project knowledge belongs in a skill — where it is
|
|
584
584
|
loaded only when the model is actually working on this API, instead of sitting
|
|
@@ -5,3 +5,11 @@ place for the things that are true regardless of who is answering: tone,
|
|
|
5
5
|
constraints, what to do when the answer is not knowable.
|
|
6
6
|
|
|
7
7
|
Replace this with yours.
|
|
8
|
+
|
|
9
|
+
## Reporting
|
|
10
|
+
|
|
11
|
+
Say what you did, file by file, and say what you deliberately did not do.
|
|
12
|
+
|
|
13
|
+
Every claim about what a command did has to be one you can make because you ran
|
|
14
|
+
it and read the output. When something cannot be established, say so and say
|
|
15
|
+
what would settle it — a guess offered as an answer is worse than no answer.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Specification
|
|
2
|
+
|
|
3
|
+
What this project is for. The files around it are the implementation; where the
|
|
4
|
+
two disagree, this one wins.
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
Carry out work inside a workspace on request — read it, change it, run
|
|
9
|
+
something in it — and report what was done in enough detail to be checked.
|
|
10
|
+
|
|
11
|
+
## Scope
|
|
12
|
+
|
|
13
|
+
- One request at a time, in one workspace, with the person who asked it present.
|
|
14
|
+
- No schedule, no queue, nothing that outlives the session it was asked in.
|
|
15
|
+
|
|
16
|
+
## Agents
|
|
17
|
+
|
|
18
|
+
- `default` — the entry point and the only agent; nobody to hand work to.
|
|
19
|
+
- Establishes what it is looking at before it acts: reads a file before
|
|
20
|
+
changing it, runs a command rather than predicting its output.
|
|
21
|
+
|
|
22
|
+
## Tools and boundaries
|
|
23
|
+
|
|
24
|
+
- Files — read, search, create, edit, move, delete. The workspace is the only
|
|
25
|
+
writable thing, symlinks included.
|
|
26
|
+
- Shell — commands run in the container, on that same workspace.
|
|
27
|
+
- `assets/` is reference material, and read-only.
|
|
28
|
+
{{web}}
|
|
29
|
+
|
|
30
|
+
## Environment
|
|
31
|
+
|
|
32
|
+
- Model: `{{modelRef}}`, one for the whole project.
|
|
33
|
+
- Sandbox: built from `sandbox/Dockerfile`, persists between runs, and can
|
|
34
|
+
reach the network. What the work always needs belongs in the image, not in an
|
|
35
|
+
instruction that reinstalls it on every run.
|
|
36
|
+
- Setup: none. `scripts/_setup.sh` is where a step would go, and it has none.
|
|
37
|
+
|
|
38
|
+
## Done means
|
|
39
|
+
|
|
40
|
+
- The change asked for is in the workspace, or the question is answered from
|
|
41
|
+
what is actually in it.
|
|
42
|
+
- Every claim about a command is one that was run and whose output was read.
|
|
43
|
+
- The reply names what changed, file by file, and says what it deliberately did
|
|
44
|
+
not do.
|
|
45
|
+
- An answer that cannot be produced honestly is a refusal with the reason.
|
|
46
|
+
|
|
47
|
+
|
|
@@ -7,9 +7,13 @@ You can also run shell commands. They run in a container over the same
|
|
|
7
7
|
workspace, not on the user's machine, so a command that fails there has cost
|
|
8
8
|
them nothing — but it is still their work in the directory, so read before you
|
|
9
9
|
overwrite and say what you ran.
|
|
10
|
+
{{webPrompt}}
|
|
10
11
|
|
|
11
12
|
Read a file before you change it: `apply_patch` matches the surrounding text
|
|
12
13
|
exactly, so a patch written from memory will not apply. Use `apply_patch` to
|
|
13
14
|
change part of a file and `write_file` only for a new one.
|
|
14
15
|
|
|
16
|
+
Anything under `/assets` is reference material: read it, search it, and do not
|
|
17
|
+
try to change it.
|
|
18
|
+
|
|
15
19
|
Say what you changed.
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Who exists, and what they may reach for.
|
|
2
2
|
#
|
|
3
|
+
# This implements the Agents, Tools and boundaries, and Environment sections of
|
|
4
|
+
# SPECIFICATION.md. Change what the system does there first, then bring this
|
|
5
|
+
# file to match it — `/sync-with-spec` in your editor does exactly that.
|
|
6
|
+
#
|
|
3
7
|
version: 1
|
|
4
8
|
|
|
5
9
|
{{model}}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
# Sessions hold run state,
|
|
1
|
+
# Sessions hold run state, blobs and whatever the agent wrote.
|
|
2
2
|
# None of it is source.
|
|
3
3
|
sessions/
|
|
4
4
|
|
|
5
|
+
# Memory is worth keeping: `graph.json` and `files/` are what the agents
|
|
6
|
+
# learned, and they diff. The vectors are not — they are derived from the
|
|
7
|
+
# graph and can be rebuilt with `zen memory reembed`.
|
|
8
|
+
memory/vectors.*
|
|
9
|
+
memory/.lock
|
|
10
|
+
|
|
5
11
|
# Scratch, inside the workspace so the sandbox can reach it.
|
|
6
12
|
.tmp/
|
|
7
13
|
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# The one command that initialises this project.
|
|
4
|
+
#
|
|
5
|
+
# scripts/_setup.sh do whatever is not done yet
|
|
6
|
+
# scripts/_setup.sh --force do all of it again
|
|
7
|
+
#
|
|
8
|
+
# Anything that has to be in place before a run — an index built, a document
|
|
9
|
+
# fetched, a file generated — is a script in this directory rather than a
|
|
10
|
+
# paragraph somebody is meant to follow. The leading underscore is what
|
|
11
|
+
# separates the runner from the steps it runs.
|
|
12
|
+
#
|
|
13
|
+
# Each step is `scripts/<name>.sh`, named below in the order they depend on
|
|
14
|
+
# each other. A step:
|
|
15
|
+
#
|
|
16
|
+
# - starts `set -eu` and `cd "$(dirname "$0")/.."`, so it works from anywhere
|
|
17
|
+
# - takes no arguments, and reads $FORCE to know whether to redo finished work
|
|
18
|
+
# - exits 0 when it did the work, 3 when there was nothing to do, non-zero
|
|
19
|
+
# when it failed
|
|
20
|
+
# - writes under .tmp/ and moves the result into place, so an interrupted run
|
|
21
|
+
# never leaves half an artefact behind
|
|
22
|
+
#
|
|
23
|
+
# Running this twice has to be safe, and the second run is what proves it: every
|
|
24
|
+
# step should report `skipped`.
|
|
25
|
+
|
|
26
|
+
set -eu
|
|
27
|
+
cd "$(dirname "$0")/.."
|
|
28
|
+
|
|
29
|
+
FORCE=0
|
|
30
|
+
if [ "${1:-}" = "--force" ]; then
|
|
31
|
+
FORCE=1
|
|
32
|
+
fi
|
|
33
|
+
export FORCE
|
|
34
|
+
|
|
35
|
+
LOGS=.tmp/logs
|
|
36
|
+
|
|
37
|
+
# The steps, in order. Nothing here yet — a project with nothing to build
|
|
38
|
+
# before it runs is a project with no steps, and that is a real answer.
|
|
39
|
+
#
|
|
40
|
+
# An example of what one looks like, for when there is something to build:
|
|
41
|
+
#
|
|
42
|
+
# STEPS="docs_index"
|
|
43
|
+
#
|
|
44
|
+
# with scripts/docs_index.sh holding
|
|
45
|
+
#
|
|
46
|
+
# set -eu
|
|
47
|
+
# cd "$(dirname "$0")/.."
|
|
48
|
+
# if [ "${FORCE:-0}" = 0 ] && [ -f assets/docs-db/manifest.json ]; then
|
|
49
|
+
# echo "assets/docs-db is already built"
|
|
50
|
+
# exit 3
|
|
51
|
+
# fi
|
|
52
|
+
# rm -rf .tmp/docs-db
|
|
53
|
+
# zen rag docs index assets/docs \
|
|
54
|
+
# --embedding openai:text-embedding-3-small --out .tmp/docs-db
|
|
55
|
+
# rm -rf assets/docs-db
|
|
56
|
+
# mv .tmp/docs-db assets/docs-db
|
|
57
|
+
#
|
|
58
|
+
STEPS=""
|
|
59
|
+
|
|
60
|
+
if [ -z "$STEPS" ]; then
|
|
61
|
+
echo "nothing to set up — this project builds nothing before it runs"
|
|
62
|
+
exit 0
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
mkdir -p "$LOGS"
|
|
66
|
+
summary=""
|
|
67
|
+
failed=0
|
|
68
|
+
|
|
69
|
+
for name in $STEPS; do
|
|
70
|
+
log="$LOGS/setup-$name.log"
|
|
71
|
+
echo
|
|
72
|
+
echo "-- $name $(date '+%H:%M:%S') ($log)"
|
|
73
|
+
|
|
74
|
+
# Watched rather than waited on: the output goes to the screen and to its
|
|
75
|
+
# own log at once, so a long step can be followed from either.
|
|
76
|
+
set +e
|
|
77
|
+
"scripts/$name.sh" 2>&1 | tee "$log"
|
|
78
|
+
code=${PIPESTATUS[0]}
|
|
79
|
+
set -e
|
|
80
|
+
|
|
81
|
+
case "$code" in
|
|
82
|
+
0) word=ok ;;
|
|
83
|
+
3) word=skipped ;;
|
|
84
|
+
*)
|
|
85
|
+
word="failed ($code)"
|
|
86
|
+
failed=1
|
|
87
|
+
;;
|
|
88
|
+
esac
|
|
89
|
+
summary="${summary} ${name}: ${word}
|
|
90
|
+
"
|
|
91
|
+
# Later steps depend on earlier ones, so a failure stops rather than
|
|
92
|
+
# producing a second failure that is only a consequence of the first.
|
|
93
|
+
if [ "$failed" = 1 ]; then
|
|
94
|
+
break
|
|
95
|
+
fi
|
|
96
|
+
done
|
|
97
|
+
|
|
98
|
+
echo
|
|
99
|
+
echo "setup:"
|
|
100
|
+
printf '%s' "$summary"
|
|
101
|
+
exit "$failed"
|