@zenera/cli 1.1.43 → 1.1.45
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/completion.d.ts +1 -1
- package/dist/commands/completion.js +4 -4
- package/dist/commands/meta.js +10 -10
- package/dist/completion.js +1 -1
- package/dist/meta/editor.js +43 -3
- package/dist/meta/finetune/command.js +2 -2
- package/dist/meta/finetune/improvements.js +1 -1
- package/dist/meta/prompts.d.ts +8 -3
- package/dist/meta/prompts.js +42 -19
- package/dist/usage.d.ts +1 -1
- package/dist/usage.js +1 -1
- package/package.json +4 -4
- package/templates/editor/.github/copilot-instructions.md +35 -22
- package/templates/editor/.github/{prompts/analyze.prompt.md → skills/analyze/SKILL.md} +6 -3
- package/templates/editor/.github/{prompts/dataset.prompt.md → skills/dataset/SKILL.md} +6 -3
- package/templates/editor/.github/{prompts/finetune.prompt.md → skills/finetune/SKILL.md} +7 -4
- package/templates/editor/.github/{prompts/new-agent.prompt.md → skills/new-agent/SKILL.md} +3 -1
- package/templates/editor/.github/{prompts/new-skill.prompt.md → skills/new-skill/SKILL.md} +3 -1
- package/templates/editor/.github/{prompts/project-review.prompt.md → skills/project-review/SKILL.md} +6 -0
- package/templates/editor/.github/{prompts/spec-apply-feedback.prompt.md → skills/spec-apply-feedback/SKILL.md} +2 -0
- package/templates/editor/.github/skills/spec-edit/SKILL.md +324 -0
- package/templates/editor/.github/{prompts/spec-sync-project.prompt.md → skills/spec-sync-project/SKILL.md} +41 -15
- package/templates/editor/.github/skills/zen-analyze-run/SKILL.md +1 -0
- package/templates/editor/.github/skills/zen-cli/SKILL.md +21 -20
- package/templates/editor/.github/skills/zen-cli/references/finetune.md +1 -1
- package/templates/editor/.github/skills/zen-cli/references/meta.md +2 -2
- package/templates/editor/.github/skills/zen-code-python/SKILL.md +1 -0
- package/templates/editor/.github/skills/zen-dataset/SKILL.md +1 -0
- package/templates/editor/.github/skills/zen-finetune/SKILL.md +2 -1
- package/templates/editor/.github/{prompts/finetune-apply.prompt.md → skills/zen-finetune-apply/SKILL.md} +7 -4
- package/templates/editor/.github/skills/zen-inspect/SKILL.md +1 -0
- package/templates/editor/.github/skills/zen-inspect-ask/SKILL.md +1 -0
- package/templates/editor/.github/skills/zen-instructions/SKILL.md +1 -0
- package/templates/editor/.github/skills/zen-memory/SKILL.md +1 -0
- package/templates/editor/.github/skills/zen-memory-warmup/SKILL.md +1 -0
- package/templates/editor/.github/skills/zen-rag-docs/SKILL.md +1 -0
- package/templates/editor/.github/skills/zen-rag-schema/SKILL.md +1 -0
- package/templates/editor/.github/skills/zen-review/SKILL.md +34 -0
- package/templates/editor/.github/skills/zen-review/scripts/check-paths.sh +1 -1
- package/templates/editor/.github/skills/zen-review/scripts/check-receipt.mjs +95 -0
- package/templates/editor/.github/skills/zen-review/scripts/review.sh +27 -2
- package/templates/editor/.github/skills/zen-sandbox/SKILL.md +2 -1
- package/templates/editor/.github/skills/zen-sandbox-capacity/SKILL.md +2 -1
- package/templates/editor/.github/skills/zen-spec-sync/SKILL.md +115 -20
- package/templates/editor/.github/skills/zen-spec-sync/scripts/snapshot.sh +83 -2
- package/templates/editor/.github/skills/zen-topology/SKILL.md +1 -0
- package/templates/project/agents/prompts/default.md.tmpl +3 -3
- package/templates/editor/.github/prompts/spec-edit.prompt.md +0 -250
|
@@ -2,7 +2,7 @@ import type { Command } from '../command.ts';
|
|
|
2
2
|
export { install, installed, loader, rcFile } from '../completion-install.ts';
|
|
3
3
|
/**
|
|
4
4
|
* Prints the shell's side of tab completion. The script is a few lines that
|
|
5
|
-
* call back into `zen __complete`, so the project names and
|
|
5
|
+
* call back into `zen __complete`, so the project names and commands it
|
|
6
6
|
* offers are always read from the machine it runs on, never baked in.
|
|
7
7
|
*/
|
|
8
8
|
export declare const completion: Command;
|
|
@@ -8,7 +8,7 @@ export { install, installed, loader, rcFile } from "../completion-install.js";
|
|
|
8
8
|
const USAGE = 'zen completion [<zsh|bash|fish>] [--install [--yes]]';
|
|
9
9
|
/**
|
|
10
10
|
* Prints the shell's side of tab completion. The script is a few lines that
|
|
11
|
-
* call back into `zen __complete`, so the project names and
|
|
11
|
+
* call back into `zen __complete`, so the project names and commands it
|
|
12
12
|
* offers are always read from the machine it runs on, never baked in.
|
|
13
13
|
*/
|
|
14
14
|
export const completion = {
|
|
@@ -29,12 +29,12 @@ export const completion = {
|
|
|
29
29
|
' zen completion zsh --install --yes without asking',
|
|
30
30
|
'',
|
|
31
31
|
'Then, in a new shell:',
|
|
32
|
-
' zen meta run my-project /<Tab> the project’s
|
|
32
|
+
' zen meta run my-project /<Tab> the project’s commands',
|
|
33
33
|
' zen meta <Tab> run, prompts, resume, model …',
|
|
34
34
|
' zen run <Tab> your projects',
|
|
35
35
|
'',
|
|
36
|
-
'The
|
|
37
|
-
'
|
|
36
|
+
'The commands are the skills in .github/skills/ an editor offers as slash',
|
|
37
|
+
'commands - not the zen-* ones, which are the model’s. Where there is nothing to offer, file names are.',
|
|
38
38
|
],
|
|
39
39
|
run: async (ctx) => {
|
|
40
40
|
const { values, positionals } = parse(ctx.args, { install: { type: 'boolean' }, yes: { type: 'boolean' } }, USAGE);
|
package/dist/commands/meta.js
CHANGED
|
@@ -10,7 +10,7 @@ import { parse } from "../args.js";
|
|
|
10
10
|
import { matching, projectNames } from "../candidates.js";
|
|
11
11
|
import { copilotEventLog } from "../eventlog.js";
|
|
12
12
|
import { probeChat, probeModel } from "../liveness.js";
|
|
13
|
-
import { answerBox, chooseModel, DATASET_DETAILS, DATASET_SUMMARY, DATASET_USAGE, datasetProjectFlag, DEFAULT_RESUMES, editorFiles, fallbackRef, FINETUNE_DETAILS, FINETUNE_SUMMARY, FINETUNE_USAGE, finetuneProjectFlag, lastSession, launch, listPrompts, loadPrompt, locate, masked, metaCompatible, misspelledProvider, MODEL_ENV, openLog, ORDER,
|
|
13
|
+
import { answerBox, chooseModel, DATASET_DETAILS, DATASET_SUMMARY, DATASET_USAGE, datasetProjectFlag, DEFAULT_RESUMES, editorFiles, fallbackRef, FINETUNE_DETAILS, FINETUNE_SUMMARY, FINETUNE_USAGE, finetuneProjectFlag, lastSession, launch, listPrompts, loadPrompt, locate, masked, metaCompatible, misspelledProvider, MODEL_ENV, openLog, ORDER, SKILL_DIR, providersWarning, readMeta, recordSession, RESUME_PROMPT, resumeDelayMs, runDataset, runFinetune, sameModel, sessionModel, sessionTotals, SOURCE_LABELS, startVertexRelay, tailSpans, Tally, terminalSink, transient, wire, wireGateway, writeMeta, } from "../meta/index.js";
|
|
14
14
|
import { splitRef } from "../modelref.js";
|
|
15
15
|
import { duration } from "../narrate.js";
|
|
16
16
|
import { project as resolveProject } from "../resolve.js";
|
|
@@ -84,16 +84,16 @@ const OPTIONS = {
|
|
|
84
84
|
};
|
|
85
85
|
const RUN_FORMS = [
|
|
86
86
|
' zen meta run [project] "<question>" ask it something',
|
|
87
|
-
' zen meta run [project] /<name> [words] run
|
|
88
|
-
' zen meta run [project] pick one of its
|
|
87
|
+
' zen meta run [project] /<name> [words] run one of its commands',
|
|
88
|
+
' zen meta run [project] pick one of its commands',
|
|
89
89
|
];
|
|
90
90
|
const RUN_ARGUMENTS = [
|
|
91
91
|
'Arguments:',
|
|
92
92
|
' [project] Name of a project. Default: the one you are in.',
|
|
93
93
|
' [prompt] Your question, in quotes. Or --prompt, or piped in when neither',
|
|
94
94
|
' it nor --prompt-file is given.',
|
|
95
|
-
' /<name> A
|
|
96
|
-
' [words]
|
|
95
|
+
' /<name> A command: the skill in .github/skills/<name>/SKILL.md.',
|
|
96
|
+
' [words] Given to that command, after its text.',
|
|
97
97
|
];
|
|
98
98
|
const RUN_OPTIONS = [
|
|
99
99
|
'Options:',
|
|
@@ -126,7 +126,7 @@ export const meta = {
|
|
|
126
126
|
details: [
|
|
127
127
|
'Forms:',
|
|
128
128
|
...RUN_FORMS,
|
|
129
|
-
' zen meta prompts [project] list
|
|
129
|
+
' zen meta prompts [project] list its commands',
|
|
130
130
|
' zen meta resume [project] [session] carry on a run that stopped',
|
|
131
131
|
' zen meta model [ref] show or set the model it uses',
|
|
132
132
|
' zen meta dataset <verb> the cases it tunes against',
|
|
@@ -134,7 +134,7 @@ export const meta = {
|
|
|
134
134
|
'',
|
|
135
135
|
'The project may come before the verb instead: `zen meta acme run`.',
|
|
136
136
|
'`zen meta dataset --help`, `zen meta finetune --help` and `zen meta run --help`',
|
|
137
|
-
'have their own pages; the last lists the
|
|
137
|
+
'have their own pages; the last lists the commands.',
|
|
138
138
|
'',
|
|
139
139
|
...RUN_ARGUMENTS,
|
|
140
140
|
'',
|
|
@@ -281,7 +281,7 @@ async function runHelp(ctx, words) {
|
|
|
281
281
|
lines.push('', ...RUN_ARGUMENTS, '', ...RUN_OPTIONS, '', 'Examples:', ' zen meta run "what does this project do?"', ' zen meta run acme /project-review', ' zen meta run acme /spec-sync-project agents/triage.md', ' zen meta run acme /analyze --json');
|
|
282
282
|
page({
|
|
283
283
|
usage: 'zen meta run [project] [/<name> [words] | "<question>"] [options]',
|
|
284
|
-
summary: 'Ask the meta agent a question, or run one of the
|
|
284
|
+
summary: 'Ask the meta agent a question, or run one of the commands.',
|
|
285
285
|
details: lines,
|
|
286
286
|
});
|
|
287
287
|
}
|
|
@@ -359,7 +359,7 @@ async function stored(ctx, values, args) {
|
|
|
359
359
|
if (question) {
|
|
360
360
|
return await go(ctx, values, project, question);
|
|
361
361
|
}
|
|
362
|
-
// Nothing said and nothing piped: the
|
|
362
|
+
// Nothing said and nothing piped: the commands are what is left to offer.
|
|
363
363
|
return await runPrompt(ctx, values, project, await pickPrompt(ctx, project), []);
|
|
364
364
|
}
|
|
365
365
|
async function runPrompt(ctx, values, project, name, extra) {
|
|
@@ -508,7 +508,7 @@ async function prompts(ctx, values, args) {
|
|
|
508
508
|
return json(found.map(({ name, description, path }) => ({ name, description, path })));
|
|
509
509
|
}
|
|
510
510
|
if (found.length === 0) {
|
|
511
|
-
note(dim(`no
|
|
511
|
+
note(dim(`no commands in ${project.name}/${SKILL_DIR}`));
|
|
512
512
|
return;
|
|
513
513
|
}
|
|
514
514
|
writeAll(table(found.map((p) => [`/${p.name}`, p.description ? dim(p.description) : ''])));
|
package/dist/completion.js
CHANGED
|
@@ -14,7 +14,7 @@ import { completeMeta } from "./commands/meta.js";
|
|
|
14
14
|
// One candidate per line, `value<TAB>description`. Nothing at all means "no
|
|
15
15
|
// opinion", and the shell falls back to completing file names — which is the
|
|
16
16
|
// right answer for `-C <dir>`, for `--events <file>`, and for the files that
|
|
17
|
-
// follow a stored
|
|
17
|
+
// follow a stored command.
|
|
18
18
|
// ---------------------------------------------------------------------------
|
|
19
19
|
/** Flags the frame owns, offered where a command name would be. */
|
|
20
20
|
const GLOBAL_FLAGS = [
|
package/dist/meta/editor.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { existsSync, readdirSync, rmdirSync, rmSync } from 'node:fs';
|
|
1
2
|
import { join } from 'node:path';
|
|
2
3
|
import { copyTree, TEMPLATES } from "./host.js";
|
|
3
4
|
// ---------------------------------------------------------------------------
|
|
@@ -27,8 +28,8 @@ import { copyTree, TEMPLATES } from "./host.js";
|
|
|
27
28
|
// assistant still needs a brief of its own, and what it needs to know is how
|
|
28
29
|
// this kind of project is put together — the file formats, how a prompt is
|
|
29
30
|
// written, when to add a skill rather than an agent. That is what the
|
|
30
|
-
// `.github/` tree is: the standing brief, plus the
|
|
31
|
-
//
|
|
31
|
+
// `.github/` tree is: the standing brief, plus the skills the editor picks up
|
|
32
|
+
// from the same place - `zen-*` for the model to load, the rest as `/commands`.
|
|
32
33
|
// ---------------------------------------------------------------------------
|
|
33
34
|
/**
|
|
34
35
|
* Writes the editor's files under `dir`, replacing what is there. They are
|
|
@@ -38,6 +39,45 @@ import { copyTree, TEMPLATES } from "./host.js";
|
|
|
38
39
|
* none. Returns the relative paths that actually changed.
|
|
39
40
|
*/
|
|
40
41
|
export function editorFiles(dir) {
|
|
41
|
-
return copyTree(join(TEMPLATES, 'editor'), dir, '', {});
|
|
42
|
+
return [...copyTree(join(TEMPLATES, 'editor'), dir, '', {}), ...retirePrompts(dir)];
|
|
43
|
+
}
|
|
44
|
+
// Every `.github/prompts/*.prompt.md` `zen` has ever shipped. Copilot dropped
|
|
45
|
+
// prompt files for skills, and these are now `.github/skills/<name>/` - so the
|
|
46
|
+
// old copy would only offer a second, stale `/name`. A prompt file the project
|
|
47
|
+
// wrote itself is not on this list, and stays.
|
|
48
|
+
const RETIRED_PROMPTS = [
|
|
49
|
+
'analyze',
|
|
50
|
+
'dataset',
|
|
51
|
+
'finetune',
|
|
52
|
+
'finetune-apply',
|
|
53
|
+
'finetune-consolidate',
|
|
54
|
+
'inspect',
|
|
55
|
+
'new-agent',
|
|
56
|
+
'new-skill',
|
|
57
|
+
'project-review',
|
|
58
|
+
'review-project',
|
|
59
|
+
'spec-apply-feedback',
|
|
60
|
+
'spec-edit',
|
|
61
|
+
'spec-sync-project',
|
|
62
|
+
'sync-with-spec',
|
|
63
|
+
'update-spec-from-feedback',
|
|
64
|
+
];
|
|
65
|
+
function retirePrompts(dir) {
|
|
66
|
+
const folder = join(dir, '.github', 'prompts');
|
|
67
|
+
if (!existsSync(folder)) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
const removed = [];
|
|
71
|
+
for (const name of RETIRED_PROMPTS) {
|
|
72
|
+
const file = join(folder, `${name}.prompt.md`);
|
|
73
|
+
if (existsSync(file)) {
|
|
74
|
+
rmSync(file);
|
|
75
|
+
removed.push(join('.github', 'prompts', `${name}.prompt.md`));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (readdirSync(folder).length === 0) {
|
|
79
|
+
rmdirSync(folder);
|
|
80
|
+
}
|
|
81
|
+
return removed;
|
|
42
82
|
}
|
|
43
83
|
//# sourceMappingURL=editor.js.map
|
|
@@ -89,7 +89,7 @@ export const FINETUNE_DETAILS = [
|
|
|
89
89
|
'has its own private memory; passing memories are merged into finetune/memories/.',
|
|
90
90
|
'',
|
|
91
91
|
'A parked case gives its worker back; woken cases take a worker before new ones.',
|
|
92
|
-
'/finetune-apply fixes the parked cases together: when -M wait, or once nothing',
|
|
92
|
+
'/zen-finetune-apply fixes the parked cases together: when -M wait, or once nothing',
|
|
93
93
|
'else can run. No run starts during an apply. What it may do:',
|
|
94
94
|
' - Every call reads the house rules, the prompt, preloaded skills and one line per',
|
|
95
95
|
' skill, so that is what --budget counts. A skill body is paid only once loaded:',
|
|
@@ -461,7 +461,7 @@ async function gate(ctx, project, rest, options) {
|
|
|
461
461
|
const dir = resolve(ctx.cwd, at);
|
|
462
462
|
const g = readJson(join(dir, 'gate.json'));
|
|
463
463
|
if (!g || existsSync(join(dir, 'applied.json'))) {
|
|
464
|
-
throw invalidError(`${at} is not an apply in progress`, 'pass the apply directory named
|
|
464
|
+
throw invalidError(`${at} is not an apply in progress`, 'pass the apply directory named after /zen-finetune-apply');
|
|
465
465
|
}
|
|
466
466
|
const after = await measure(project.dir);
|
|
467
467
|
const over = overLimits(g.before, after, g.limits);
|
|
@@ -401,7 +401,7 @@ export class Improvements {
|
|
|
401
401
|
join(dir, 'apply.events.jsonl'),
|
|
402
402
|
'--prompt-file',
|
|
403
403
|
brief,
|
|
404
|
-
'/finetune-apply',
|
|
404
|
+
'/zen-finetune-apply',
|
|
405
405
|
dir,
|
|
406
406
|
], applyLog);
|
|
407
407
|
writeFileSync(join(dir, attempt === 1 ? 'apply.json' : `apply-${attempt}.json`), res.stdout);
|
package/dist/meta/prompts.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export declare const SKILL_DIR = ".github/skills";
|
|
1
2
|
export declare const PROMPT_DIR = ".github/prompts";
|
|
2
3
|
/** `/project-review`, `project-review`, `project-review.prompt.md` or a path. */
|
|
3
4
|
export declare function promptPath(dir: string, name: string): string;
|
|
@@ -5,14 +6,18 @@ export interface StoredPrompt {
|
|
|
5
6
|
name: string;
|
|
6
7
|
path: string;
|
|
7
8
|
description?: string;
|
|
9
|
+
/** False for a skill marked `user-invocable: false` - the model's, not a command. */
|
|
10
|
+
invocable: boolean;
|
|
8
11
|
body: string;
|
|
9
12
|
}
|
|
10
13
|
/**
|
|
11
|
-
* Frontmatter is the editor's business — `
|
|
12
|
-
* none of it means anything
|
|
13
|
-
*
|
|
14
|
+
* Frontmatter is the editor's business — `name`, `argument-hint`, the
|
|
15
|
+
* invocation switches — and none of it means anything once the body is the
|
|
16
|
+
* prompt, so only the body is sent. `description` is kept for the one line of
|
|
17
|
+
* narration that says which command is running.
|
|
14
18
|
*/
|
|
15
19
|
export declare function readPrompt(path: string, name: string, text: string): StoredPrompt;
|
|
16
20
|
export declare function loadPrompt(dir: string, name: string): Promise<StoredPrompt>;
|
|
21
|
+
/** The commands a person may type: every skill not marked for the model only, and any legacy prompt file. */
|
|
17
22
|
export declare function listPrompts(dir: string): Promise<string[]>;
|
|
18
23
|
//# sourceMappingURL=prompts.d.ts.map
|
package/dist/meta/prompts.js
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
3
|
import { usageError } from "./host.js";
|
|
4
4
|
// ---------------------------------------------------------------------------
|
|
5
|
-
// Stored
|
|
5
|
+
// Stored commands
|
|
6
6
|
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
// `zen meta run
|
|
7
|
+
// The editor offers `.github/skills/<name>/SKILL.md` as `/name`. The `zen-*`
|
|
8
|
+
// skills are reference the model loads on its own (`user-invocable: false`);
|
|
9
|
+
// the rest are commands somebody types (`disable-model-invocation: true`), and
|
|
10
|
+
// those are what `zen meta run /<name>` runs. Copilot would expand `/name`
|
|
11
|
+
// itself, but reading the file and handing over its body works the same with
|
|
12
|
+
// every model and leaves room for `--prompt-file` after it.
|
|
13
|
+
//
|
|
14
|
+
// `.github/prompts/*.prompt.md` is the format these used to be in. Copilot has
|
|
15
|
+
// dropped it, but a project may still have prompt files of its own, so one
|
|
16
|
+
// whose name no skill takes is still run.
|
|
11
17
|
// ---------------------------------------------------------------------------
|
|
18
|
+
export const SKILL_DIR = '.github/skills';
|
|
12
19
|
export const PROMPT_DIR = '.github/prompts';
|
|
13
20
|
const PROMPT_SUFFIX = '.prompt.md';
|
|
14
21
|
/** `/project-review`, `project-review`, `project-review.prompt.md` or a path. */
|
|
@@ -17,42 +24,58 @@ export function promptPath(dir, name) {
|
|
|
17
24
|
if (bare.includes('/') || bare.endsWith('.md')) {
|
|
18
25
|
return `${dir}/${bare}`;
|
|
19
26
|
}
|
|
20
|
-
|
|
27
|
+
const skill = `${dir}/${SKILL_DIR}/${bare}/SKILL.md`;
|
|
28
|
+
const legacy = `${dir}/${PROMPT_DIR}/${bare}${PROMPT_SUFFIX}`;
|
|
29
|
+
return !existsSync(skill) && existsSync(legacy) ? legacy : skill;
|
|
21
30
|
}
|
|
22
31
|
/**
|
|
23
|
-
* Frontmatter is the editor's business — `
|
|
24
|
-
* none of it means anything
|
|
25
|
-
*
|
|
32
|
+
* Frontmatter is the editor's business — `name`, `argument-hint`, the
|
|
33
|
+
* invocation switches — and none of it means anything once the body is the
|
|
34
|
+
* prompt, so only the body is sent. `description` is kept for the one line of
|
|
35
|
+
* narration that says which command is running.
|
|
26
36
|
*/
|
|
27
37
|
export function readPrompt(path, name, text) {
|
|
28
38
|
let body = text;
|
|
29
39
|
let description;
|
|
40
|
+
let invocable = true;
|
|
30
41
|
const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(text);
|
|
31
42
|
if (match) {
|
|
32
43
|
body = text.slice(match[0].length);
|
|
33
44
|
const found = /^description:\s*(.+)$/m.exec(match[1]);
|
|
34
45
|
description = found?.[1].trim().replace(/^['"]|['"]$/g, '');
|
|
46
|
+
invocable = !/^user-invocable:\s*['"]?false['"]?\s*$/m.test(match[1]);
|
|
35
47
|
}
|
|
36
|
-
return { name, path, description, body: body.trim() };
|
|
48
|
+
return { name, path, description, invocable, body: body.trim() };
|
|
37
49
|
}
|
|
38
50
|
export async function loadPrompt(dir, name) {
|
|
39
51
|
const path = promptPath(dir, name);
|
|
40
52
|
if (!existsSync(path)) {
|
|
41
53
|
const known = await listPrompts(dir);
|
|
42
|
-
throw usageError(`no
|
|
54
|
+
throw usageError(`no command named ${name.replace(/^\//, '')}`, known.length > 0
|
|
43
55
|
? `try: ${known.map((p) => `/${p}`).join(', ')}`
|
|
44
|
-
: `put one in ${
|
|
56
|
+
: `put one in ${SKILL_DIR}/<name>/SKILL.md`);
|
|
45
57
|
}
|
|
46
58
|
return readPrompt(path, name.replace(/^\//, ''), await readFile(path, 'utf8'));
|
|
47
59
|
}
|
|
60
|
+
/** The commands a person may type: every skill not marked for the model only, and any legacy prompt file. */
|
|
48
61
|
export async function listPrompts(dir) {
|
|
49
|
-
const
|
|
62
|
+
const names = new Set();
|
|
63
|
+
for (const entry of entries(`${dir}/${SKILL_DIR}`)) {
|
|
64
|
+
const path = `${dir}/${SKILL_DIR}/${entry}/SKILL.md`;
|
|
65
|
+
if (existsSync(path) && readPrompt(path, entry, readFileSync(path, 'utf8')).invocable) {
|
|
66
|
+
names.add(entry);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
for (const entry of entries(`${dir}/${PROMPT_DIR}`)) {
|
|
70
|
+
if (entry.endsWith(PROMPT_SUFFIX)) {
|
|
71
|
+
names.add(entry.slice(0, -PROMPT_SUFFIX.length));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return [...names].sort();
|
|
75
|
+
}
|
|
76
|
+
function entries(path) {
|
|
50
77
|
try {
|
|
51
|
-
|
|
52
|
-
return names
|
|
53
|
-
.filter((n) => n.endsWith(PROMPT_SUFFIX))
|
|
54
|
-
.map((n) => n.slice(0, -PROMPT_SUFFIX.length))
|
|
55
|
-
.sort();
|
|
78
|
+
return readdirSync(path);
|
|
56
79
|
}
|
|
57
80
|
catch {
|
|
58
81
|
return [];
|
package/dist/usage.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { ModelUsage, TokenUsage } from '@zenera/neo';
|
|
|
3
3
|
export declare const LEDGER_ENV = "ZENERA_USAGE_LEDGER";
|
|
4
4
|
/** The meta session whose agent started this process, if one did. */
|
|
5
5
|
export declare const META_SESSION_ENV = "ZENERA_META_SESSION";
|
|
6
|
-
/** The stored
|
|
6
|
+
/** The stored command that meta session was started with, if any. */
|
|
7
7
|
export declare const META_PROMPT_ENV = "ZENERA_META_PROMPT";
|
|
8
8
|
/**
|
|
9
9
|
* Where this project's usage goes: the variable when set, else the fine-tuning's
|
package/dist/usage.js
CHANGED
|
@@ -13,7 +13,7 @@ import { warn } from "./term.js";
|
|
|
13
13
|
export const LEDGER_ENV = 'ZENERA_USAGE_LEDGER';
|
|
14
14
|
/** The meta session whose agent started this process, if one did. */
|
|
15
15
|
export const META_SESSION_ENV = 'ZENERA_META_SESSION';
|
|
16
|
-
/** The stored
|
|
16
|
+
/** The stored command that meta session was started with, if any. */
|
|
17
17
|
export const META_PROMPT_ENV = 'ZENERA_META_PROMPT';
|
|
18
18
|
/**
|
|
19
19
|
* Where this project's usage goes: the variable when set, else the fine-tuning's
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenera/cli",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.45",
|
|
4
4
|
"description": "Command-line front end for @zenera/neo: agentic projects you can run, share and commit.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agents",
|
|
@@ -54,9 +54,9 @@
|
|
|
54
54
|
"@google/genai": "^2.30.0",
|
|
55
55
|
"@inkjs/ui": "^2.0.0",
|
|
56
56
|
"@openrouter/sdk": "^1.4.25",
|
|
57
|
-
"@zenera/engine": "^1.1.
|
|
58
|
-
"@zenera/neo": "^1.1.
|
|
59
|
-
"@zenera/view": "^1.1.
|
|
57
|
+
"@zenera/engine": "^1.1.45",
|
|
58
|
+
"@zenera/neo": "^1.1.45",
|
|
59
|
+
"@zenera/view": "^1.1.45",
|
|
60
60
|
"google-auth-library": "^10.0.0",
|
|
61
61
|
"ink": "^7.1.1",
|
|
62
62
|
"openai": "^6.0.0",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Copilot instructions - agent projects
|
|
2
2
|
|
|
3
3
|
> Written by `zen init` into `.github/copilot-instructions.md`, alongside the
|
|
4
|
-
>
|
|
4
|
+
> skills and commands in the same tree (§2.4). VS Code loads it
|
|
5
5
|
> automatically for every request in this folder, so it is the standing brief
|
|
6
6
|
> for anyone - human or agent - editing this project.
|
|
7
7
|
>
|
|
@@ -35,12 +35,15 @@ programmed: what an agent knows, which model answers, and which of the tools
|
|
|
35
35
|
6. Every change must still load: `agents.yaml` is validated strictly at load,
|
|
36
36
|
and `zen check` says so before a model is ever called.
|
|
37
37
|
|
|
38
|
-
### 0.1 Copilot is the meta-agent: load
|
|
38
|
+
### 0.1 Copilot is the meta-agent: load skills for the capabilities in scope
|
|
39
39
|
|
|
40
40
|
Copilot is always the meta-agent that creates and changes target projects. Load
|
|
41
41
|
the editor's `zen-cli` skill before deciding how a target project should run,
|
|
42
42
|
be validated, or use command-line capabilities. It is the command contract; do
|
|
43
43
|
not reconstruct `zen` arguments from memory or call `--help` to discover them.
|
|
44
|
+
When the task is to bring a project into compliance with `SPECIFICATION.md`,
|
|
45
|
+
load `zen-spec-sync` first; its narrow tiers contain the exact validation
|
|
46
|
+
commands and do not require loading `zen-cli` as well.
|
|
44
47
|
|
|
45
48
|
**Every runtime capability a project turns on carries obligations that are not
|
|
46
49
|
visible in `agents.yaml` and that `zen check` does not report.** Before
|
|
@@ -54,20 +57,23 @@ code, `zen-topology` for `handoffs:` or `fork:` on any agent,
|
|
|
54
57
|
`zen-cli` always. A capability that is already
|
|
55
58
|
configured and already passing `zen check` is exactly the case that looks
|
|
56
59
|
finished and is not: the obligation lives in the skill, so a review that never
|
|
57
|
-
opens the skill cannot find what is missing.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
opens the skill cannot find what is missing. Outside a specification-sync pass,
|
|
61
|
+
this applies whatever prompted the change. During an incremental sync, load only
|
|
62
|
+
skills for capabilities its changed requirements, files, keys or unresolved
|
|
63
|
+
work touch. A full pass still loads every enabled capability's skill. The
|
|
64
|
+
**spec-only** and **model-reference-only** tiers load no capability skill unless
|
|
65
|
+
the work expands beyond their eligibility rules.
|
|
62
66
|
|
|
63
67
|
**Load `zen-instructions` before writing, editing, reviewing or deleting any
|
|
64
68
|
`agents/*instructions.md`.** They are the house rules, prepended to every
|
|
65
|
-
agent's prompt, and
|
|
69
|
+
agent's prompt, and four of them are `zen`'s own copies rather than the
|
|
66
70
|
project's: an edit made inside one is lost at the next `zen check --fix`, `zen
|
|
67
71
|
init` or `zen open`, with no diff to show for it. The skill is what says which
|
|
68
|
-
|
|
72
|
+
four those are, where a project's own rules on the same subjects go instead,
|
|
69
73
|
how `requires:` conditions a document, and what filename order decides. None of
|
|
70
74
|
that is visible in the file being edited.
|
|
75
|
+
Replacing generated copies with `zen check --fix` is maintenance, not manual
|
|
76
|
+
house-rule editing, and does not by itself require loading `zen-instructions`.
|
|
71
77
|
|
|
72
78
|
**Load `zen-code-python` before writing, editing or reviewing any prompt, skill
|
|
73
79
|
or house rule for an agent that writes or runs code** - any agent holding
|
|
@@ -251,8 +257,7 @@ Two consequences that drive nearly every design rule in this document:
|
|
|
251
257
|
my-project/
|
|
252
258
|
├── .github/ the editor's brief - §2.4
|
|
253
259
|
│ ├── copilot-instructions.md this file
|
|
254
|
-
│
|
|
255
|
-
│ └── skills/*/SKILL.md reference the editor loads on demand
|
|
260
|
+
│ └── skills/*/SKILL.md zen-* reference loaded on demand; the rest /commands
|
|
256
261
|
├── .env this project's environment - NEVER committed
|
|
257
262
|
├── .spec-sync/ what the last /spec-sync-project applied - §0.1
|
|
258
263
|
├── agents.yaml who exists, what they may reach for
|
|
@@ -349,15 +354,18 @@ agents do, for the same reason - it is a prefix somebody pays for:
|
|
|
349
354
|
|
|
350
355
|
- **`copilot-instructions.md`** is always on. Everything in it is loaded for
|
|
351
356
|
every request in this folder, so it holds only what is true of every task.
|
|
352
|
-
- **`.github/skills
|
|
353
|
-
`description` matches what you asked. Put long, occasional material here
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
- **`.github/
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
357
|
+
- **`.github/skills/zen-<name>/SKILL.md`** is reference the editor loads when
|
|
358
|
+
its `description` matches what you asked. Put long, occasional material here
|
|
359
|
+
- a command surface, a vendor's quirks, a format spec - not in the file above.
|
|
360
|
+
The `description` is the routing key; §3.4 applies to these as much as to the
|
|
361
|
+
project's own skills. `user-invocable: false` keeps them out of the `/` menu.
|
|
362
|
+
- **`.github/skills/<name>/SKILL.md`** without the `zen-` prefix is a command
|
|
363
|
+
you invoke by name (`/name`, or `zen meta run /name`), with
|
|
364
|
+
`disable-model-invocation: true` so the model never starts one on a hunch,
|
|
365
|
+
and an `argument-hint` when it takes words. Write one when a job is done
|
|
366
|
+
repeatedly and has a right order - adding an agent, adding a skill, reviewing
|
|
367
|
+
before a commit. It holds the order of the work and loads the `zen-*` skills
|
|
368
|
+
that hold the rules.
|
|
361
369
|
|
|
362
370
|
`zen init` and `zen open` rewrite this whole tree from the version of `zen` in
|
|
363
371
|
hand, so **edits inside `.github/` do not survive**. Project-specific conventions
|
|
@@ -1885,6 +1893,11 @@ the spec-sync record, in that order:
|
|
|
1885
1893
|
|
|
1886
1894
|
Run it first and read what it says. Everything else below is judgement, which is
|
|
1887
1895
|
why it is still a list. The `zen-review` skill has the detail.
|
|
1896
|
+
Within a specification-sync pass, reuse its final check with
|
|
1897
|
+
`review.sh --skip-check` instead of probing again, and apply the sync skill's
|
|
1898
|
+
explicit tier scope to this checklist. Use `--skip-check no-sandbox` only for an
|
|
1899
|
+
eligible model-reference-only pass. Independent reviews still cover the whole
|
|
1900
|
+
checklist.
|
|
1888
1901
|
|
|
1889
1902
|
Before finishing any change here:
|
|
1890
1903
|
|
|
@@ -2086,8 +2099,8 @@ install` is an `image:` that was never set - §3.7.
|
|
|
2086
2099
|
|
|
2087
2100
|
This file is loaded on every request in this repository, so it is subject to its
|
|
2088
2101
|
own rules: stable, factual, no hedging. Before adding a section, ask whether it
|
|
2089
|
-
is true of every task - if it is not, it is a skill under
|
|
2090
|
-
a
|
|
2102
|
+
is true of every task - if it is not, it is a `zen-*` skill under
|
|
2103
|
+
`.github/skills/`, or a command skill there if it is a procedure (§2.4).
|
|
2091
2104
|
|
|
2092
2105
|
Update it when:
|
|
2093
2106
|
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
---
|
|
2
|
+
name: analyze
|
|
2
3
|
description: Analyze one recorded run of this project - its health, what it wasted, and what to change in the instructions. Name the run (directory or id) after the command, or get the most recent one.
|
|
4
|
+
argument-hint: '[run directory or run id]'
|
|
5
|
+
disable-model-invocation: true
|
|
3
6
|
---
|
|
4
7
|
|
|
5
8
|
Load the **zen-analyze-run** skill and follow it to analyze one run of this
|
|
@@ -10,10 +13,10 @@ audit cannot be graded without it.
|
|
|
10
13
|
|
|
11
14
|
## Which run
|
|
12
15
|
|
|
13
|
-
The
|
|
14
|
-
If
|
|
16
|
+
The words given with the command may name the run - a run directory or a run
|
|
17
|
+
id. If they do, use it. Words after it like `case=<id> ... feedback=<file>` mean
|
|
15
18
|
the tuning loop sent you: follow section 7 of the skill and write that file.
|
|
16
|
-
A `## The brief` section below
|
|
19
|
+
A `## The brief` section below them is what the loop already ran for
|
|
17
20
|
you: section 1 of the skill says how to use it.
|
|
18
21
|
|
|
19
22
|
If it does not, list this project's most recent runs, newest first:
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
---
|
|
2
|
+
name: dataset
|
|
2
3
|
description: Build or refresh this project's dataset - every case read from its sources with a class, complexity, tags, a verbatim rubric and an anchor - re-reading only the sections that changed since the last revision. Name a source after the command to add it, `rebuild` to read everything again, or a case and what to fix.
|
|
4
|
+
argument-hint: '[source file | rebuild | <case id> <what to fix>]'
|
|
5
|
+
disable-model-invocation: true
|
|
3
6
|
---
|
|
4
7
|
|
|
5
8
|
Keep `dataset/` in step with its sources. **Load the `zen-dataset` skill before
|
|
6
9
|
anything else**, and `zen-cli` for the command reference. The skill holds the
|
|
7
|
-
extraction rules and every verb; this
|
|
10
|
+
extraction rules and every verb; this command is the order of the work. If
|
|
8
11
|
loading a skill fails, read `.github/skills/<name>/SKILL.md` with your file tool
|
|
9
12
|
before going on.
|
|
10
13
|
|
|
11
14
|
You never run cases, never edit `agents/`, and never edit a source. Only
|
|
12
15
|
`zen meta dataset` writes `dataset/` - never a file tool, never a script.
|
|
13
16
|
|
|
14
|
-
This
|
|
17
|
+
This command is **reentrant**: the state on disk says what to do, so running it
|
|
15
18
|
twice in a row does nothing the second time.
|
|
16
19
|
|
|
17
20
|
## 1. Where things stand
|
|
@@ -27,7 +30,7 @@ sections are `changed`, `gone` or `uncovered`.
|
|
|
27
30
|
|
|
28
31
|
## 2. What to do
|
|
29
32
|
|
|
30
|
-
|
|
33
|
+
Words may be given with the command. Then read the table top down and
|
|
31
34
|
take the first row that fits:
|
|
32
35
|
|
|
33
36
|
| State | Do |
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
---
|
|
2
|
+
name: finetune
|
|
2
3
|
description: Fine-tune this project against a training set, a batch at a time - every batch first with no memory, fixing the instructions, then with the memory it just built, making the same work cheaper - starting from a 3-case smoke test and doubling each smooth batch, until every case is used and no difficult case is open.
|
|
4
|
+
argument-hint: '[training set] [limit]'
|
|
5
|
+
disable-model-invocation: true
|
|
3
6
|
---
|
|
4
7
|
|
|
5
8
|
Tune this project against real queries. Nothing here touches model weights: what
|
|
@@ -9,7 +12,7 @@ queries produce.
|
|
|
9
12
|
|
|
10
13
|
**Load the `zen-finetune` skill before anything else**, and load `zen-inspect`,
|
|
11
14
|
`zen-analyze-run`, `zen-topology` and `zen-inspect-ask` before you grade, and
|
|
12
|
-
`zen-instructions` before you write a policy file. This
|
|
15
|
+
`zen-instructions` before you write a policy file. This command is the order of the work; the skill
|
|
13
16
|
is how each step is done, and it holds the rules that are easy to get wrong. If
|
|
14
17
|
loading a skill fails, read `.github/skills/<name>/SKILL.md` with your file tool
|
|
15
18
|
before going on - never carry on without it.
|
|
@@ -28,7 +31,7 @@ command:
|
|
|
28
31
|
| one memory node in full | `zen memory show <node-id> --dir "$RUN/batch/<id>/memory"` |
|
|
29
32
|
| a whole memory, or what one added to another | `zen memory ls --dir <dir>`, `zen memory diff <base> --dir <dir>` |
|
|
30
33
|
|
|
31
|
-
This
|
|
34
|
+
This command is **reentrant**. Tuning is long and gets interrupted - a run dies, a
|
|
32
35
|
session ends, I stop you mid-batch. Every step leaves its result on disk under
|
|
33
36
|
`finetune/`, so a second invocation does not start over: it reads that state,
|
|
34
37
|
works out where the work stopped, says so, and carries on from there unless I
|
|
@@ -199,7 +202,7 @@ in your reports instead of re-typing it.
|
|
|
199
202
|
|
|
200
203
|
## Where you are - work this out before anything else
|
|
201
204
|
|
|
202
|
-
Do this every time this
|
|
205
|
+
Do this every time this command runs, including the first:
|
|
203
206
|
|
|
204
207
|
```sh
|
|
205
208
|
.github/skills/zen-finetune/scripts/next.mjs
|
|
@@ -208,7 +211,7 @@ Do this every time this prompt runs, including the first:
|
|
|
208
211
|
```
|
|
209
212
|
|
|
210
213
|
`next.mjs` reads the whole `finetune/` tree and prints the next step. Do not
|
|
211
|
-
re-derive the state from an `ls`. Map what it says onto this
|
|
214
|
+
re-derive the state from an `ls`. Map what it says onto this command:
|
|
212
215
|
|
|
213
216
|
| What `next.mjs` says | Go to |
|
|
214
217
|
| ---------------------------------------------------------------- | --------------------------------------------------------------------------------- |
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
2
|
+
name: new-agent
|
|
3
3
|
description: Add an agent to agents.yaml, with its prompt, tools and handoffs.
|
|
4
|
+
argument-hint: "[the agent's job in one sentence]"
|
|
5
|
+
disable-model-invocation: true
|
|
4
6
|
---
|
|
5
7
|
|
|
6
8
|
Add an agent to this project. Ask for the one sentence that states its job
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
2
|
+
name: new-skill
|
|
3
3
|
description: Add a skill under agents/skills, with a description that routes.
|
|
4
|
+
argument-hint: '[what the skill says and when it applies]'
|
|
5
|
+
disable-model-invocation: true
|
|
4
6
|
---
|
|
5
7
|
|
|
6
8
|
Add a skill to this project. A skill is curated instruction content - and
|