@zenera/cli 1.1.19 → 1.1.20
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 +6 -0
- package/dist/banner.d.ts +8 -0
- package/dist/banner.js +2 -0
- package/dist/commands/cache.js +1 -0
- package/dist/commands/check.js +34 -2
- package/dist/commands/index.js +1 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/meta.js +1 -1
- package/dist/commands/open.js +1 -1
- package/dist/main.js +8 -1
- package/dist/meta.js +19 -7
- package/dist/scaffold.d.ts +37 -0
- package/dist/scaffold.js +67 -3
- package/dist/term.d.ts +2 -0
- package/dist/term.js +25 -0
- package/dist/tui/app.js +237 -65
- package/dist/tui/theme.d.ts +10 -0
- package/dist/tui/theme.js +4 -0
- package/dist/tui/wrap.d.ts +100 -18
- package/dist/tui/wrap.js +500 -27
- package/dist/validate.js +115 -9
- package/package.json +2 -2
- package/templates/editor/.github/copilot-instructions.md +33 -8
- package/templates/editor/.github/skills/zen-cli/references/projects.md +19 -8
- package/templates/editor/.github/skills/zen-memory/SKILL.md +77 -33
- package/templates/editor/.github/skills/zen-memory/scripts/check-instructions.sh +2 -1
- package/templates/editor/.vscode/agents.schema.json +611 -0
- package/templates/editor/.vscode/extensions.json +3 -0
- package/templates/editor/.vscode/settings.json +8 -0
- package/templates/project/agents/fork-instructions.md +151 -0
- package/templates/project/agents/memory-instructions.md +120 -8
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
---
|
|
2
|
+
requires: [fork]
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Forking
|
|
6
|
+
|
|
7
|
+
These rules are for agents that can fork. If `fork` is not among your tools,
|
|
8
|
+
work that looks parallel stays sequential here.
|
|
9
|
+
|
|
10
|
+
Forking runs work in separate conversations and brings back only the answers.
|
|
11
|
+
|
|
12
|
+
A branch is a run of its own: its own conversation, its own tool calls, its own
|
|
13
|
+
reasoning. None of that returns. What returns is each branch's final answer, as
|
|
14
|
+
the result of your `fork` call — so whatever you will need afterwards has to be
|
|
15
|
+
_in_ that answer, and the branch only knows it if your instructions say so. Work
|
|
16
|
+
whose value is the trace rather than the conclusion should not be forked at all.
|
|
17
|
+
|
|
18
|
+
The instructions you write are the entire assignment. A branch cannot ask you a
|
|
19
|
+
question, cannot see what its siblings are doing, and cannot be corrected once
|
|
20
|
+
it starts. Say what it must do, what it must leave alone, and the exact shape of
|
|
21
|
+
what it must hand back.
|
|
22
|
+
|
|
23
|
+
**One branch is delegation**: the work happens elsewhere and you get the
|
|
24
|
+
conclusion instead of the transcript. Use it when another agent is better suited
|
|
25
|
+
to the job, or when the job would otherwise fill this conversation with material
|
|
26
|
+
you have no use for afterwards — a long file survey, a noisy build loop, an
|
|
27
|
+
exploration down a path that may go nowhere. **Several branches are a fan-out**:
|
|
28
|
+
independent parts of one task, worked at the same time, merged by you. It is the
|
|
29
|
+
same call either way; the number of branches is the only difference.
|
|
30
|
+
|
|
31
|
+
Do not fork a sequence. Branches run at once and can exchange nothing, so a step
|
|
32
|
+
that needs the step before it has to stay in this conversation.
|
|
33
|
+
|
|
34
|
+
## When it is worth it
|
|
35
|
+
|
|
36
|
+
One question decides it: **could this be finished by someone who cannot ask you
|
|
37
|
+
anything, and would a written answer be all you want back?** If either half is
|
|
38
|
+
no, the work stays here.
|
|
39
|
+
|
|
40
|
+
| The work in front of you | What it is |
|
|
41
|
+
| -------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
|
|
42
|
+
| The same question asked of twenty things — files, endpoints, regions, candidate fixes | A fan-out: one branch each, merged by you |
|
|
43
|
+
| One task whose parts need different skills and none of them the others | A fan-out too: each branch on the agent that fits |
|
|
44
|
+
| A job another agent is plainly better at | Delegation: one branch, on that agent |
|
|
45
|
+
| Long and noisy with a short verdict — a build loop, a bisect, a survey that may find nothing | Delegation: you get the verdict, not the noise |
|
|
46
|
+
| Find the config, then change it, then test it | Not a fork. Each step needs the one before it |
|
|
47
|
+
| A change you would want to steer while it happens | Not a fork. A branch cannot be corrected once it starts |
|
|
48
|
+
| One read, one search, one command | Not a fork. A whole conversation to save yourself a line |
|
|
49
|
+
| Two jobs that would write the same file | Not a fork until they write different files — see below |
|
|
50
|
+
|
|
51
|
+
## Fanning out
|
|
52
|
+
|
|
53
|
+
Branches run at the same time, so a fan-out costs about as long as its slowest
|
|
54
|
+
branch instead of the sum of all of them. That alone is reason enough: work you
|
|
55
|
+
would otherwise grind through one item at a time, whose items do not need each
|
|
56
|
+
other, is a fan-out. It is the most ordinary use of this tool.
|
|
57
|
+
|
|
58
|
+
Which agent runs a branch is set per branch, and that is what tells the two
|
|
59
|
+
shapes apart.
|
|
60
|
+
|
|
61
|
+
**One job, many subjects.** The same work repeated over different material, so
|
|
62
|
+
every branch runs the agent that would have done it anyway — usually you. Write
|
|
63
|
+
the assignment once, then vary the subject and the destination:
|
|
64
|
+
|
|
65
|
+
> `auth` — Audit `/workspace/src/auth/**` for calls that bypass the rate
|
|
66
|
+
> limiter. Write the hits to `/workspace/reports/audit-auth.md`, one line each
|
|
67
|
+
> as `file:line — call — why`. Return how many and the worst one.
|
|
68
|
+
>
|
|
69
|
+
> `billing` — The same, over `/workspace/src/billing/**`, to
|
|
70
|
+
> `/workspace/reports/audit-billing.md`.
|
|
71
|
+
>
|
|
72
|
+
> `admin` — The same, over `/workspace/src/admin/**`, to
|
|
73
|
+
> `/workspace/reports/audit-admin.md`.
|
|
74
|
+
|
|
75
|
+
**One job, many trades.** The task divides by what each part demands rather than
|
|
76
|
+
by what it is about, so the branches differ from each other and each names the
|
|
77
|
+
agent that fits:
|
|
78
|
+
|
|
79
|
+
> `tests`, on the agent that runs the suite — Run it against the current tree.
|
|
80
|
+
> Return every failure with the first assertion of each, and nothing else.
|
|
81
|
+
>
|
|
82
|
+
> `security`, on the agent that reviews for security — Review the change in
|
|
83
|
+
> `/workspace/src/auth/**`. Return findings worst first, file and line for each.
|
|
84
|
+
> Change nothing.
|
|
85
|
+
>
|
|
86
|
+
> `docs`, on the writing agent — Bring `/workspace/docs/auth.md` in line with
|
|
87
|
+
> the code as it now stands. Return the path and a one-line note per section you
|
|
88
|
+
> touched.
|
|
89
|
+
|
|
90
|
+
Both shapes hold to the same two rules. Divide so that nothing is covered twice
|
|
91
|
+
and nothing is left out: overlap is paid for twice over, and a gap comes back as
|
|
92
|
+
silence rather than as a complaint. And repeat in each branch's instructions
|
|
93
|
+
whatever that branch needs, because a sibling's finding will never reach it.
|
|
94
|
+
|
|
95
|
+
## Choosing `context`
|
|
96
|
+
|
|
97
|
+
`context` decides what each branch starts from. It is one setting for the whole
|
|
98
|
+
call, chosen per call:
|
|
99
|
+
|
|
100
|
+
- `inherit` — everything said here so far. For work that only makes sense
|
|
101
|
+
against the case as it stands: reviewing what has just been written here,
|
|
102
|
+
continuing an investigation whose earlier findings are the thing being built
|
|
103
|
+
on.
|
|
104
|
+
- `compact` — the same, without the tool traffic: what was decided, not how it
|
|
105
|
+
was found out. The usual choice for a wide fan-out, where branches need the
|
|
106
|
+
case and the plan but not the fifty reads that produced them.
|
|
107
|
+
- `none` — nothing but its own instructions. The cheapest, and the honest one
|
|
108
|
+
when the assignment is self-contained: a lookup, one file summarised, a
|
|
109
|
+
command run elsewhere. Everything the branch needs must then be written out in
|
|
110
|
+
the instructions, paths included.
|
|
111
|
+
|
|
112
|
+
When two modes seem possible, write the missing facts into the instructions and
|
|
113
|
+
take the cheaper one. Instructions are exact; an inherited transcript is only
|
|
114
|
+
approximately about the branch's job.
|
|
115
|
+
|
|
116
|
+
## What comes back, and what stays
|
|
117
|
+
|
|
118
|
+
Only the answer comes back, and it is prose. Everything else a branch does is
|
|
119
|
+
real and outlasts it: branches share this workspace with you and with each
|
|
120
|
+
other, so a file one of them writes is a file you can read after the join, and
|
|
121
|
+
anything committed to memory is there for every later run.
|
|
122
|
+
|
|
123
|
+
So decide, for each branch, which of the two carries its result:
|
|
124
|
+
|
|
125
|
+
- **Prose, in the answer** — findings, a verdict, a short list, anything you are
|
|
126
|
+
about to reason with. If it is not in the answer it is gone.
|
|
127
|
+
- **A file, and its path in the answer** — anything bulky, or meant to be used
|
|
128
|
+
rather than read: a generated document, extracted data, a patch, a long log.
|
|
129
|
+
Pasting it into the answer puts it in this conversation whether you need it
|
|
130
|
+
there or not.
|
|
131
|
+
|
|
132
|
+
Say which you want in the branch's own instructions, and be exact:
|
|
133
|
+
|
|
134
|
+
> Read `/workspace/docs/api/*.md` and find every endpoint still documenting the
|
|
135
|
+
> v1 auth header. Write them to `/workspace/reports/v1-auth.md`, one line each
|
|
136
|
+
> as `path — section — the quoted line`. Change nothing else. Return the path,
|
|
137
|
+
> how many you found, and the two you are least sure about.
|
|
138
|
+
|
|
139
|
+
Give every branch a path of its own. Two branches writing one file is a lost
|
|
140
|
+
write that nothing reports — the join reads the same either way. The same holds
|
|
141
|
+
for anything else they could contend over: one branch installing while another
|
|
142
|
+
builds, two branches reformatting the same tree.
|
|
143
|
+
|
|
144
|
+
## When a branch comes back wrong
|
|
145
|
+
|
|
146
|
+
Each branch reports under its own name, with its status, and a failed one says
|
|
147
|
+
why. What the final answer is remains your decision, not the join's.
|
|
148
|
+
|
|
149
|
+
A branch rarely fails at random; the usual cause is an assignment missing
|
|
150
|
+
something it could not ask for. Re-running the same instructions gets the same
|
|
151
|
+
answer. Fix them and fork again, or do that piece here.
|
|
@@ -1,9 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
requires: [memory]
|
|
3
|
+
---
|
|
4
|
+
|
|
1
5
|
# Memory
|
|
2
6
|
|
|
3
7
|
This project has a memory: a graph of what earlier runs worked out, kept with
|
|
4
|
-
the project rather than with the session
|
|
5
|
-
`memory_*` tools - `memory_search`
|
|
6
|
-
`
|
|
8
|
+
the project rather than with the session, and shared with every other agent that
|
|
9
|
+
can see it. It is reached **only** through the `memory_*` tools - `memory_search`
|
|
10
|
+
to find, `memory_load` to read.
|
|
11
|
+
|
|
12
|
+
Not every agent may write to it. Read what follows against the tools you
|
|
13
|
+
actually have: if `memory_commit` is not among them, everything under
|
|
14
|
+
[Updating it](#updating-it) is not yours to do, and if `memory_forget` is not
|
|
15
|
+
among them, neither is [Forgetting](#forgetting).
|
|
7
16
|
|
|
8
17
|
It exists to make the next run cheaper. Work that cost something - a long
|
|
9
18
|
investigation, a fan-out of searches, a build, an invocation found by trial -
|
|
@@ -51,7 +60,7 @@ runs past a line or two, it is content, and content goes in the file.
|
|
|
51
60
|
| `snippet` | a few lines of code or configuration |
|
|
52
61
|
| `file` | an artifact kept whole - a script to re-run, an answer or passage too big for a text |
|
|
53
62
|
| `operation` | an external call that was made - endpoint, command, query. The call, not its answer |
|
|
54
|
-
| `preference` | a standing instruction from the user
|
|
63
|
+
| `preference` | a standing instruction from the user, or what they told you about themselves |
|
|
55
64
|
|
|
56
65
|
| Relation | Reads as |
|
|
57
66
|
| ------------ | --------------------------------------------------- |
|
|
@@ -93,6 +102,30 @@ its own source.
|
|
|
93
102
|
160 characters. `memory_load` is what reads a node whole, by id - load anything
|
|
94
103
|
you are going to rely on.
|
|
95
104
|
|
|
105
|
+
### The shape of a recollection
|
|
106
|
+
|
|
107
|
+
A recollection arrives in a `<memory-recollection>` block, and it is a subgraph
|
|
108
|
+
rather than a ranked list - the links are as much of the answer as the nodes. It
|
|
109
|
+
is an outline, and the indentation is the graph.
|
|
110
|
+
|
|
111
|
+
A line at the left margin reads `score kind id` and is something the search
|
|
112
|
+
matched; a root the walk reached rather than matched carries `--` where the
|
|
113
|
+
score would be. A line indented under it reads `<arrow>relation kind id` and is
|
|
114
|
+
a neighbour: `→produced` means the line above produced this one, `←informed`
|
|
115
|
+
means this one informed the line above. A neighbour the search matched in its
|
|
116
|
+
own right carries its score too, after the arrow.
|
|
117
|
+
|
|
118
|
+
Under each header, indented further, is that node's text. A `file` node carries
|
|
119
|
+
one line more, above the text: the path under `/memory` to open or run, its
|
|
120
|
+
size, and how often it has been read.
|
|
121
|
+
|
|
122
|
+
A line beginning `+` is a link to an id already shown above, for an edge the
|
|
123
|
+
outline could not nest. It never points forward, so resolving one only ever
|
|
124
|
+
means looking back up the block.
|
|
125
|
+
|
|
126
|
+
Text is clipped at 160 characters - copy an id into `memory_load` to read a node
|
|
127
|
+
whole. `memory_search` finds ids; it does not return contents.
|
|
128
|
+
|
|
96
129
|
A remembered file appears at `/memory/<id>.<ext>`. Open it or run it, but arrive
|
|
97
130
|
at that path through `memory_load`, never by looking around in the directory.
|
|
98
131
|
|
|
@@ -121,6 +154,19 @@ Search **before** paying for anything: an investigation, an index query, a
|
|
|
121
154
|
build, a long command. The point is not to find a pointer - it is to arrive at
|
|
122
155
|
the answer without buying it twice.
|
|
123
156
|
|
|
157
|
+
Four moments are each worth one search:
|
|
158
|
+
|
|
159
|
+
| At | Search for |
|
|
160
|
+
| ---------------------------------------- | ---------------------------------------------------------------------- |
|
|
161
|
+
| a request arriving | the request itself, before the first step is planned |
|
|
162
|
+
| arriving by handoff, or as a fork branch | the brief you were handed - it is new to you, not to the project |
|
|
163
|
+
| the point where real work would start | the question that work would answer, whenever it is more than one call |
|
|
164
|
+
| a dead end mid-run | what you now know you are missing, in the words you would ask it in |
|
|
165
|
+
|
|
166
|
+
Search the QUESTION, not the turn. Asking the same question again in different
|
|
167
|
+
words is a round trip for an answer you already have; search again when what
|
|
168
|
+
you need to know changes, not when the step does.
|
|
169
|
+
|
|
124
170
|
One `memory_load` is not cheaper than re-reading the single file a node names.
|
|
125
171
|
It is far cheaper than redoing what produced that node: several documents read
|
|
126
172
|
in sequence, a fan-out of searches, a delegated lookup, a long run. Price a
|
|
@@ -166,10 +212,46 @@ the documents and line ranges it was taken from. The pointer says where to look
|
|
|
166
212
|
and the conclusion says what it meant, but only the passage saves the next run
|
|
167
213
|
from opening the sources to find out what they actually said.
|
|
168
214
|
|
|
169
|
-
|
|
215
|
+
### When to commit
|
|
216
|
+
|
|
217
|
+
That test says what is worth keeping. It does not say when to write it down, and
|
|
218
|
+
work that is never written down cost what it cost for nothing.
|
|
219
|
+
|
|
220
|
+
Two things call for a commit while the run is still going:
|
|
221
|
+
|
|
222
|
+
- **A search came back empty, or came back beside the point, and you went on to
|
|
223
|
+
work the answer out anyway.** That gap is the next run's gap too, and you are
|
|
224
|
+
the only one in a position to close it. It is the usual reason a memory stays
|
|
225
|
+
useless: every run pays for the same answer, no run writes it down.
|
|
226
|
+
- **Something cost more than a `memory_load` will** - several reads, a fan-out,
|
|
227
|
+
a build, a long command, a delegated lookup - or produced an artifact that
|
|
228
|
+
works: a script, a query, a request body, the invocation that finally ran.
|
|
229
|
+
|
|
230
|
+
And three moments must not pass without one:
|
|
231
|
+
|
|
232
|
+
| Before | Because |
|
|
233
|
+
| -------------------------------------- | ----------------------------------------------------------------- |
|
|
234
|
+
| returning your final answer | the turn ends there, and nothing is written after it |
|
|
235
|
+
| handing off to another agent | control moves and does not come back - what you know goes with it |
|
|
236
|
+
| returning to the agent that forked you | only your answer returns; your transcript is dropped at the join |
|
|
237
|
+
|
|
238
|
+
Commit a piece of work when it is finished rather than saving all of it for one
|
|
239
|
+
call at the end: a run that is interrupted, or that runs out of room, loses
|
|
240
|
+
whatever was being held back. That is not licence to split one subgraph across
|
|
241
|
+
calls - refs resolve only within a single `memory_commit`, so whatever links
|
|
242
|
+
together is still committed together.
|
|
243
|
+
|
|
244
|
+
### How to write it down
|
|
170
245
|
|
|
171
246
|
**Commit the whole subgraph in one call.** A script with no record of what asked
|
|
172
|
-
for it, or a fact with nothing that acts on it, is a memory nobody can use.
|
|
247
|
+
for it, or a fact with nothing that acts on it, is a memory nobody can use. Refs
|
|
248
|
+
resolve only within a single `memory_commit`, so a subgraph split across calls
|
|
249
|
+
arrives without its links.
|
|
250
|
+
|
|
251
|
+
**Do not re-commit what a search already returned.** A node that says what one
|
|
252
|
+
already in memory says is folded into it, and its existing id comes back under
|
|
253
|
+
your ref - so the links you asked for still land, on the memory that was already
|
|
254
|
+
there.
|
|
173
255
|
|
|
174
256
|
**Say where the content came from.** This is what lets an incomplete
|
|
175
257
|
recollection be continued instead of believed:
|
|
@@ -266,8 +348,8 @@ of it again - which is the reading the memory was supposed to buy.
|
|
|
266
348
|
A body or a result set may still be worth keeping as a SPECIMEN - a shape to
|
|
267
349
|
write against, a case to reproduce. Commit it as a `file` node whose text says
|
|
268
350
|
what was asked, when, and that it is what came back then, never what the data
|
|
269
|
-
is. Keep credentials
|
|
270
|
-
session and every later run can read it.
|
|
351
|
+
is. Keep credentials out of the store, along with any personal data the specimen
|
|
352
|
+
did not need: it outlives the session and every later run can read it.
|
|
271
353
|
|
|
272
354
|
**Correct by superseding, never by editing.** Commit the new node and link it to
|
|
273
355
|
the old one with `SUPERSEDES`. Recall then stops serving the wrong answer
|
|
@@ -276,3 +358,33 @@ without destroying the record of why it changed.
|
|
|
276
358
|
**Ask whether it will still be true next month.** Memory has no expiry and no
|
|
277
359
|
reviewer. A durable fact about this project survives; a fact about this
|
|
278
360
|
afternoon's state is how a graph becomes confidently wrong.
|
|
361
|
+
|
|
362
|
+
### Preferences
|
|
363
|
+
|
|
364
|
+
A `preference` is a standing instruction from the user, and it is not recalled
|
|
365
|
+
like everything else: every preference you can see is rendered into a
|
|
366
|
+
`<memory-preferences>` block at the start of every later run, each with its id.
|
|
367
|
+
They apply unless that run's request contradicts them.
|
|
368
|
+
|
|
369
|
+
So commit one only when the user's own words generalise - "always", "from now
|
|
370
|
+
on", "I prefer", "never". A single request being fulfilled is not a standing
|
|
371
|
+
instruction, and one committed by mistake is in every future prompt until
|
|
372
|
+
something supersedes it.
|
|
373
|
+
|
|
374
|
+
What the user says about THEMSELVES belongs here too, and for the same reason: a
|
|
375
|
+
later run that has to ask again has already lost what the block is for. Their
|
|
376
|
+
name and how they want to be addressed, the role they work in, the timezone
|
|
377
|
+
their dates are in, which of several accounts, environments or repositories is
|
|
378
|
+
theirs, the language or the units they want answers in. Commit what they stated,
|
|
379
|
+
in their own terms - never what you inferred from how they happened to phrase a
|
|
380
|
+
request, and never a credential or a secret, which is not a preference however
|
|
381
|
+
it was offered.
|
|
382
|
+
|
|
383
|
+
To change one, commit the replacement and link it to the id shown in that block
|
|
384
|
+
with `SUPERSEDES`.
|
|
385
|
+
|
|
386
|
+
### Forgetting
|
|
387
|
+
|
|
388
|
+
Forget only what is wrong and has no successor. A superseded memory is already
|
|
389
|
+
hidden from recall and should stay for the history, so `memory_forget` is for
|
|
390
|
+
what should never have been written, not for what has been replaced.
|