@zenera/cli 1.1.24 → 1.1.26

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.
Files changed (199) hide show
  1. package/README.md +65 -0
  2. package/dist/ask.js +28 -5
  3. package/dist/banner.js +2 -2
  4. package/dist/batch.d.ts +6 -0
  5. package/dist/batch.js +76 -1
  6. package/dist/catalog.d.ts +31 -1
  7. package/dist/catalog.js +140 -7
  8. package/dist/commands/index.js +2 -0
  9. package/dist/commands/inspect.d.ts +52 -2
  10. package/dist/commands/inspect.js +220 -31
  11. package/dist/commands/memory.js +156 -32
  12. package/dist/commands/meta.js +333 -24
  13. package/dist/commands/models.js +97 -12
  14. package/dist/commands/open.js +4 -4
  15. package/dist/commands/run.js +38 -4
  16. package/dist/commands/sandbox.js +148 -16
  17. package/dist/commands/view.d.ts +8 -0
  18. package/dist/commands/view.js +114 -0
  19. package/dist/engine.d.ts +8 -1
  20. package/dist/engine.js +7 -0
  21. package/dist/eventlog.d.ts +64 -0
  22. package/dist/eventlog.js +170 -0
  23. package/dist/liveness.d.ts +7 -0
  24. package/dist/liveness.js +35 -3
  25. package/dist/main.js +0 -0
  26. package/dist/meta/editor.d.ts +9 -0
  27. package/dist/meta/editor.js +43 -0
  28. package/dist/meta/finetune/analyze-brief.d.ts +26 -0
  29. package/dist/meta/finetune/analyze-brief.js +131 -0
  30. package/dist/meta/finetune/apply-brief.d.ts +23 -0
  31. package/dist/meta/finetune/apply-brief.js +247 -0
  32. package/dist/meta/finetune/brief.d.ts +45 -0
  33. package/dist/meta/finetune/brief.js +158 -0
  34. package/dist/meta/finetune/children.d.ts +8 -0
  35. package/dist/meta/finetune/children.js +76 -0
  36. package/dist/meta/finetune/command.d.ts +30 -0
  37. package/dist/meta/finetune/command.js +516 -0
  38. package/dist/meta/finetune/cost.d.ts +46 -0
  39. package/dist/meta/finetune/cost.js +105 -0
  40. package/dist/meta/finetune/dataset/anchors.d.ts +41 -0
  41. package/dist/meta/finetune/dataset/anchors.js +239 -0
  42. package/dist/meta/finetune/dataset/changes.d.ts +36 -0
  43. package/dist/meta/finetune/dataset/changes.js +319 -0
  44. package/dist/meta/finetune/dataset/command.d.ts +17 -0
  45. package/dist/meta/finetune/dataset/command.js +1011 -0
  46. package/dist/meta/finetune/dataset/drift.d.ts +33 -0
  47. package/dist/meta/finetune/dataset/drift.js +71 -0
  48. package/dist/meta/finetune/dataset/export.d.ts +26 -0
  49. package/dist/meta/finetune/dataset/export.js +51 -0
  50. package/dist/meta/finetune/dataset/index.d.ts +2 -0
  51. package/dist/meta/finetune/dataset/index.js +2 -0
  52. package/dist/meta/finetune/dataset/sample.d.ts +50 -0
  53. package/dist/meta/finetune/dataset/sample.js +197 -0
  54. package/dist/meta/finetune/dataset/schema.d.ts +33 -0
  55. package/dist/meta/finetune/dataset/schema.js +216 -0
  56. package/dist/meta/finetune/dataset/store.d.ts +35 -0
  57. package/dist/meta/finetune/dataset/store.js +177 -0
  58. package/dist/meta/finetune/dataset/types.d.ts +127 -0
  59. package/dist/meta/finetune/dataset/types.js +39 -0
  60. package/dist/meta/finetune/failure.d.ts +15 -0
  61. package/dist/meta/finetune/failure.js +26 -0
  62. package/dist/meta/finetune/feedback.d.ts +57 -0
  63. package/dist/meta/finetune/feedback.js +104 -0
  64. package/dist/meta/finetune/guard.d.ts +29 -0
  65. package/dist/meta/finetune/guard.js +104 -0
  66. package/dist/meta/finetune/improvements.d.ts +98 -0
  67. package/dist/meta/finetune/improvements.js +501 -0
  68. package/dist/meta/finetune/index.d.ts +2 -0
  69. package/dist/meta/finetune/index.js +2 -0
  70. package/dist/meta/finetune/journal.d.ts +35 -0
  71. package/dist/meta/finetune/journal.js +135 -0
  72. package/dist/meta/finetune/live.d.ts +84 -0
  73. package/dist/meta/finetune/live.js +272 -0
  74. package/dist/meta/finetune/loop.d.ts +3 -0
  75. package/dist/meta/finetune/loop.js +163 -0
  76. package/dist/meta/finetune/memories.d.ts +47 -0
  77. package/dist/meta/finetune/memories.js +154 -0
  78. package/dist/meta/finetune/recheck.d.ts +58 -0
  79. package/dist/meta/finetune/recheck.js +311 -0
  80. package/dist/meta/finetune/report.d.ts +40 -0
  81. package/dist/meta/finetune/report.js +1397 -0
  82. package/dist/meta/finetune/retry.d.ts +24 -0
  83. package/dist/meta/finetune/retry.js +96 -0
  84. package/dist/meta/finetune/sampler.d.ts +18 -0
  85. package/dist/meta/finetune/sampler.js +47 -0
  86. package/dist/meta/finetune/system.d.ts +27 -0
  87. package/dist/meta/finetune/system.js +132 -0
  88. package/dist/meta/finetune/train.d.ts +43 -0
  89. package/dist/meta/finetune/train.js +425 -0
  90. package/dist/meta/finetune/tui.d.ts +16 -0
  91. package/dist/meta/finetune/tui.js +316 -0
  92. package/dist/meta/finetune/tuning.d.ts +193 -0
  93. package/dist/meta/finetune/tuning.js +308 -0
  94. package/dist/meta/finetune/usage.d.ts +66 -0
  95. package/dist/meta/finetune/usage.js +260 -0
  96. package/dist/meta/finetune/view.d.ts +9 -0
  97. package/dist/meta/finetune/view.js +27 -0
  98. package/dist/meta/host.d.ts +15 -0
  99. package/dist/meta/host.js +21 -0
  100. package/dist/meta/index.d.ts +11 -0
  101. package/dist/meta/index.js +11 -0
  102. package/dist/meta/launch.d.ts +81 -0
  103. package/dist/meta/launch.js +286 -0
  104. package/dist/meta/model.d.ts +44 -0
  105. package/dist/meta/model.js +119 -0
  106. package/dist/meta/prompts.d.ts +18 -0
  107. package/dist/meta/prompts.js +61 -0
  108. package/dist/meta/relay.d.ts +20 -0
  109. package/dist/meta/relay.js +123 -0
  110. package/dist/meta/tokens.d.ts +52 -0
  111. package/dist/meta/tokens.js +226 -0
  112. package/dist/meta/window.d.ts +61 -0
  113. package/dist/meta/window.js +198 -0
  114. package/dist/meta/wire.d.ts +42 -0
  115. package/dist/meta/wire.js +129 -0
  116. package/dist/meta.d.ts +71 -1
  117. package/dist/meta.js +303 -6
  118. package/dist/modelref.d.ts +16 -0
  119. package/dist/modelref.js +41 -0
  120. package/dist/narrate.js +5 -2
  121. package/dist/podman.d.ts +26 -0
  122. package/dist/podman.js +83 -3
  123. package/dist/projects.d.ts +0 -5
  124. package/dist/projects.js +2 -15
  125. package/dist/resources.d.ts +215 -0
  126. package/dist/resources.js +856 -0
  127. package/dist/sandbox.d.ts +2 -0
  128. package/dist/sandbox.js +10 -3
  129. package/dist/scaffold.d.ts +15 -7
  130. package/dist/scaffold.js +24 -67
  131. package/dist/session.js +4 -29
  132. package/dist/term.d.ts +2 -0
  133. package/dist/term.js +11 -2
  134. package/dist/trace.d.ts +5 -0
  135. package/dist/trace.js +107 -7
  136. package/dist/tui/app.js +19 -5
  137. package/dist/tui/links.d.ts +27 -0
  138. package/dist/tui/links.js +142 -0
  139. package/dist/tui/models.d.ts +35 -0
  140. package/dist/tui/models.js +447 -0
  141. package/dist/tui/sandbox.d.ts +10 -0
  142. package/dist/tui/sandbox.js +131 -0
  143. package/dist/tui/wrap.d.ts +5 -0
  144. package/dist/tui/wrap.js +12 -0
  145. package/dist/usage.d.ts +78 -0
  146. package/dist/usage.js +51 -0
  147. package/package.json +4 -2
  148. package/templates/editor/.github/copilot-instructions.md +60 -145
  149. package/templates/editor/.github/prompts/analyze.prompt.md +33 -0
  150. package/templates/editor/.github/prompts/dataset.prompt.md +108 -0
  151. package/templates/editor/.github/prompts/finetune-apply.prompt.md +270 -0
  152. package/templates/editor/.github/prompts/finetune.prompt.md +691 -198
  153. package/templates/editor/.github/prompts/new-agent.prompt.md +3 -1
  154. package/templates/editor/.github/prompts/new-skill.prompt.md +2 -0
  155. package/templates/editor/.github/prompts/project-review.prompt.md +5 -4
  156. package/templates/editor/.github/skills/zen-analyze-run/SKILL.md +588 -0
  157. package/templates/editor/.github/skills/zen-cli/SKILL.md +9 -1
  158. package/templates/editor/.github/skills/zen-cli/references/dataset.md +34 -0
  159. package/templates/editor/.github/skills/zen-cli/references/finetune.md +137 -0
  160. package/templates/editor/.github/skills/zen-cli/references/inspect.md +63 -11
  161. package/templates/editor/.github/skills/zen-cli/references/memory.md +33 -10
  162. package/templates/editor/.github/skills/zen-cli/references/meta.md +61 -0
  163. package/templates/editor/.github/skills/zen-cli/references/models.md +5 -1
  164. package/templates/editor/.github/skills/zen-cli/references/projects.md +4 -6
  165. package/templates/editor/.github/skills/zen-cli/references/rag.md +24 -6
  166. package/templates/editor/.github/skills/zen-cli/references/sandbox.md +35 -14
  167. package/templates/editor/.github/skills/zen-code-python/SKILL.md +123 -0
  168. package/templates/editor/.github/skills/zen-code-python/references/code_python.md +48 -0
  169. package/templates/editor/.github/skills/zen-dataset/SKILL.md +253 -0
  170. package/templates/editor/.github/skills/zen-finetune/SKILL.md +1492 -660
  171. package/templates/editor/.github/skills/zen-finetune/references/readme-template.md +268 -0
  172. package/templates/editor/.github/skills/zen-finetune/scripts/batch.mjs +390 -0
  173. package/templates/editor/.github/skills/zen-finetune/scripts/difficult.mjs +243 -0
  174. package/templates/editor/.github/skills/zen-finetune/scripts/memory.mjs +280 -0
  175. package/templates/editor/.github/skills/zen-finetune/scripts/next.mjs +398 -0
  176. package/templates/editor/.github/skills/zen-finetune/scripts/report.mjs +797 -0
  177. package/templates/editor/.github/skills/zen-finetune/scripts/select.mjs +354 -0
  178. package/templates/editor/.github/skills/zen-finetune/scripts/usage.mjs +722 -0
  179. package/templates/editor/.github/skills/zen-inspect/SKILL.md +74 -26
  180. package/templates/editor/.github/skills/zen-inspect-ask/SKILL.md +271 -0
  181. package/templates/editor/.github/skills/zen-instructions/SKILL.md +4 -12
  182. package/templates/editor/.github/skills/zen-memory/SKILL.md +82 -53
  183. package/templates/editor/.github/skills/zen-rag-docs/SKILL.md +20 -8
  184. package/templates/editor/.github/skills/zen-review/SKILL.md +8 -31
  185. package/templates/editor/.github/skills/zen-review/scripts/check-paths.sh +5 -5
  186. package/templates/editor/.github/skills/zen-review/scripts/review.sh +3 -12
  187. package/templates/editor/.github/skills/zen-sandbox/SKILL.md +9 -4
  188. package/templates/editor/.github/skills/zen-sandbox-capacity/SKILL.md +2 -2
  189. package/templates/editor/.github/skills/zen-spec-sync/SKILL.md +2 -4
  190. package/templates/editor/.github/skills/zen-topology/SKILL.md +283 -0
  191. package/templates/editor/.vscode/settings.json +1 -0
  192. package/templates/project/agents/files-instructions.md +29 -20
  193. package/templates/project/agents/fork-instructions.md +78 -28
  194. package/templates/project/agents/memory-instructions.md +222 -494
  195. package/templates/project/agents/tools-instructions.md +14 -4
  196. package/templates/project/gitignore +2 -0
  197. package/templates/editor/.github/skills/zen-finetune/scripts/collect.sh +0 -432
  198. package/templates/editor/.github/skills/zen-finetune/scripts/sample.sh +0 -199
  199. package/templates/editor/.github/skills/zen-memory/scripts/check-instructions.sh +0 -116
@@ -0,0 +1,131 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // ---------------------------------------------------------------------------
3
+ // zen sandbox top
4
+ //
5
+ // The resource report, redrawn on a timer. Nothing here measures anything or
6
+ // decides what a figure means: resources.ts samples and lays out, and this
7
+ // file only colours the lines it is handed and owns the keys.
8
+ //
9
+ // The frame is cut to the terminal's height before Ink sees it — a frame
10
+ // taller than the screen scrolls its own top away and every repaint leaves a
11
+ // copy of it behind (see tui/app.tsx).
12
+ // ---------------------------------------------------------------------------
13
+ import { Box, render, Text, useApp, useInput, useStdout } from 'ink';
14
+ import React, { useEffect, useState } from 'react';
15
+ import { layout, SORTS, } from "../resources.js";
16
+ import { resolveTheme } from "./theme.js";
17
+ const message = (err) => (err instanceof Error ? err.message : String(err));
18
+ function styleOf(tone, theme) {
19
+ switch (tone) {
20
+ case 'strong':
21
+ return { bold: true };
22
+ case 'heading':
23
+ return { bold: true, color: theme.accent };
24
+ case 'dim':
25
+ return { color: theme.chrome.color };
26
+ case 'good':
27
+ return { color: theme.code.color };
28
+ case 'warn':
29
+ return { color: theme.warn };
30
+ case 'bad':
31
+ return { color: theme.line.error.color };
32
+ case 'accent':
33
+ return { color: theme.accent };
34
+ default:
35
+ return {};
36
+ }
37
+ }
38
+ function Painted({ line, theme }) {
39
+ if (line.length === 0) {
40
+ return _jsx(Text, { children: " " });
41
+ }
42
+ return (_jsx(Text, { wrap: "truncate-end", children: line.map((span, i) => (_jsx(Text, { ...styleOf(span.tone, theme), children: span.text }, i))) }));
43
+ }
44
+ function Top({ sampler, intervalMs, explain: start, palette }) {
45
+ const { exit } = useApp();
46
+ const { stdout } = useStdout();
47
+ const [size, setSize] = useState({ columns: stdout.columns || 80, rows: stdout.rows || 24 });
48
+ useEffect(() => {
49
+ const resized = () => setSize({ columns: stdout.columns || 80, rows: stdout.rows || 24 });
50
+ stdout.on('resize', resized);
51
+ return () => {
52
+ stdout.off('resize', resized);
53
+ };
54
+ }, [stdout]);
55
+ const [view, setView] = useState();
56
+ const [failure, setFailure] = useState();
57
+ const [explain, setExplain] = useState(start);
58
+ const [sort, setSort] = useState('memory');
59
+ const [paused, setPaused] = useState(false);
60
+ useEffect(() => {
61
+ if (paused) {
62
+ return;
63
+ }
64
+ let stopped = false;
65
+ let timer;
66
+ const tick = async () => {
67
+ try {
68
+ const next = await sampler.next();
69
+ if (!stopped) {
70
+ setView(next);
71
+ setFailure(undefined);
72
+ }
73
+ }
74
+ catch (err) {
75
+ if (!stopped) {
76
+ setFailure(message(err));
77
+ }
78
+ }
79
+ if (!stopped) {
80
+ timer = setTimeout(() => void tick(), intervalMs);
81
+ }
82
+ };
83
+ void tick();
84
+ return () => {
85
+ stopped = true;
86
+ clearTimeout(timer);
87
+ };
88
+ }, [sampler, intervalMs, paused]);
89
+ useInput((input, key) => {
90
+ // A pasted or piped key can arrive with a newline behind it.
91
+ const k = input.trim()[0];
92
+ if (k === 'q' || key.escape) {
93
+ exit();
94
+ }
95
+ else if (k === 'e' || k === '?') {
96
+ setExplain((on) => !on);
97
+ }
98
+ else if (k === 's') {
99
+ setSort((now) => SORTS[(SORTS.indexOf(now) + 1) % SORTS.length]);
100
+ }
101
+ else if (k === 'p' || input === ' ') {
102
+ setPaused((on) => !on);
103
+ }
104
+ });
105
+ // One row for the keys, one spare so the frame never reaches the bottom.
106
+ const rows = Math.max(4, size.rows - 2);
107
+ const lines = view
108
+ ? layout(view, {
109
+ width: size.columns - 1,
110
+ rows: failure ? rows - 1 : rows,
111
+ explain,
112
+ sort,
113
+ live: intervalMs / 1000,
114
+ })
115
+ : [[{ text: 'asking podman…', tone: 'dim' }]];
116
+ const keys = [
117
+ `e notes ${explain ? 'off' : 'on'}`,
118
+ `s sort: ${sort}`,
119
+ paused ? 'p resume' : 'p pause',
120
+ 'q quit',
121
+ ].join(' · ');
122
+ return (_jsxs(Box, { flexDirection: "column", children: [lines.map((line, i) => (_jsx(Painted, { line: line, theme: palette }, i))), failure ? (_jsx(Text, { wrap: "truncate-end", color: palette.line.error.color, children: ` ✗ ${failure}` })) : null, _jsx(Text, { wrap: "truncate-end", color: palette.chrome.color, children: paused ? `paused · ${keys}` : keys })] }));
123
+ }
124
+ /** Runs the live screen until the person leaves it. */
125
+ export async function watch(options) {
126
+ // Asked before Ink takes the terminal, as tui/app.tsx does.
127
+ const palette = await resolveTheme(options.theme);
128
+ const instance = render(_jsx(Top, { ...options, palette: palette }));
129
+ await instance.waitUntilExit();
130
+ }
131
+ //# sourceMappingURL=sandbox.js.map
@@ -15,6 +15,11 @@ export declare function windowOf(text: string, width: number, rows: number): str
15
15
  export declare function clip(text: string, width: number): string;
16
16
  /** Word wrap. Every returned row is at most `width` columns wide. */
17
17
  export declare function wrap(text: string, width: number): string[];
18
+ /**
19
+ * The first row of a scrolled list, moved as little as possible so that row
20
+ * `selected` is inside a window of `height` rows over `count` of them.
21
+ */
22
+ export declare function scrollTop(selected: number, top: number, height: number, count: number): number;
18
23
  /** The three footer rows, its margin, the prompt, and a row in hand. */
19
24
  export declare const CHROME_ROWS = 7;
20
25
  /**
package/dist/tui/wrap.js CHANGED
@@ -74,6 +74,18 @@ export function wrap(text, width) {
74
74
  }
75
75
  return out;
76
76
  }
77
+ /**
78
+ * The first row of a scrolled list, moved as little as possible so that row
79
+ * `selected` is inside a window of `height` rows over `count` of them.
80
+ */
81
+ export function scrollTop(selected, top, height, count) {
82
+ const h = Math.max(1, height);
83
+ let first = Math.min(top, selected);
84
+ if (selected >= first + h) {
85
+ first = selected - h + 1;
86
+ }
87
+ return Math.max(0, Math.min(first, count - h));
88
+ }
77
89
  // ---------------------------------------------------------------------------
78
90
  // Dividing the frame
79
91
  //
@@ -0,0 +1,78 @@
1
+ import type { ModelUsage, TokenUsage } from '@zenera/neo';
2
+ /** Set by `zen meta` for everything its agent runs, so all of it lands in one ledger. */
3
+ export declare const LEDGER_ENV = "ZENERA_USAGE_LEDGER";
4
+ /** The meta session whose agent started this process, if one did. */
5
+ export declare const META_SESSION_ENV = "ZENERA_META_SESSION";
6
+ /** The stored prompt that meta session was started with, if any. */
7
+ export declare const META_PROMPT_ENV = "ZENERA_META_PROMPT";
8
+ /**
9
+ * Where this project's usage goes: the variable when set, else the fine-tuning's
10
+ * own ledger when the project is being tuned. Elsewhere nothing is recorded.
11
+ */
12
+ export declare function ledgerPath(projectDir: string): string | undefined;
13
+ interface RowBase {
14
+ /** when the thing ended */
15
+ ts: string;
16
+ }
17
+ export interface MetaCallRow extends RowBase {
18
+ kind: 'meta.call';
19
+ session?: string;
20
+ model: string;
21
+ usage: TokenUsage;
22
+ cacheWriteTokens?: number;
23
+ startedAt: string;
24
+ durationMs: number;
25
+ traceId?: string;
26
+ spanId?: string;
27
+ }
28
+ export interface MetaSessionRow extends RowBase {
29
+ kind: 'meta.session';
30
+ session: string;
31
+ /** copilot's own totals for the whole session so far - cumulative across resumes */
32
+ models: ModelUsage[];
33
+ exitCode: number;
34
+ resumes: number;
35
+ startedAt: string;
36
+ durationMs: number;
37
+ }
38
+ export interface RunRow extends RowBase {
39
+ kind: 'run';
40
+ runDir?: string;
41
+ session?: string;
42
+ batchDir?: string;
43
+ item?: string;
44
+ ok: boolean;
45
+ error?: string;
46
+ stopReason?: string;
47
+ durationMs?: number;
48
+ models: ModelUsage[];
49
+ }
50
+ export interface BatchRow extends RowBase {
51
+ kind: 'batch';
52
+ batchDir: string;
53
+ input: string;
54
+ items: number;
55
+ ok: number;
56
+ failed: number;
57
+ concurrency: number;
58
+ memory: string;
59
+ startedAt: string;
60
+ durationMs: number;
61
+ models: ModelUsage[];
62
+ }
63
+ export interface AskRow extends RowBase {
64
+ kind: 'ask';
65
+ runDir: string;
66
+ node: string;
67
+ nodeAgent: string;
68
+ nodeModel: string;
69
+ model: string;
70
+ usage?: TokenUsage;
71
+ startedAt: string;
72
+ durationMs: number;
73
+ }
74
+ export type UsageRow = MetaCallRow | MetaSessionRow | RunRow | BatchRow | AskRow;
75
+ /** Appends one row. Never throws: losing a line of accounting must not fail a run. */
76
+ export declare function appendUsage(projectDir: string, row: UsageRow): void;
77
+ export {};
78
+ //# sourceMappingURL=usage.d.ts.map
package/dist/usage.js ADDED
@@ -0,0 +1,51 @@
1
+ import { appendFileSync, existsSync, mkdirSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { warn } from "./term.js";
4
+ // ---------------------------------------------------------------------------
5
+ // The usage ledger
6
+ //
7
+ // One JSON line per thing that spent tokens: a meta agent call, a run, a batch,
8
+ // an `inspect ask`. Append-only, so several processes - the meta agent, the
9
+ // batch it started, the ask it is grading with - can write to one file at once.
10
+ // Reports are folded out of it later; nothing here aggregates.
11
+ // ---------------------------------------------------------------------------
12
+ /** Set by `zen meta` for everything its agent runs, so all of it lands in one ledger. */
13
+ export const LEDGER_ENV = 'ZENERA_USAGE_LEDGER';
14
+ /** The meta session whose agent started this process, if one did. */
15
+ export const META_SESSION_ENV = 'ZENERA_META_SESSION';
16
+ /** The stored prompt that meta session was started with, if any. */
17
+ export const META_PROMPT_ENV = 'ZENERA_META_PROMPT';
18
+ /**
19
+ * Where this project's usage goes: the variable when set, else the fine-tuning's
20
+ * own ledger when the project is being tuned. Elsewhere nothing is recorded.
21
+ */
22
+ export function ledgerPath(projectDir) {
23
+ const set = process.env[LEDGER_ENV]?.trim();
24
+ if (set) {
25
+ return set;
26
+ }
27
+ return existsSync(join(projectDir, 'finetune'))
28
+ ? join(projectDir, 'finetune', 'usage', 'ledger.jsonl')
29
+ : undefined;
30
+ }
31
+ let warned = false;
32
+ /** Appends one row. Never throws: losing a line of accounting must not fail a run. */
33
+ export function appendUsage(projectDir, row) {
34
+ const path = ledgerPath(projectDir);
35
+ if (!path) {
36
+ return;
37
+ }
38
+ const meta = process.env[META_SESSION_ENV]?.trim();
39
+ const line = { v: 1, ...row, project: projectDir, pid: process.pid, ...(meta ? { meta } : {}) };
40
+ try {
41
+ mkdirSync(dirname(path), { recursive: true });
42
+ appendFileSync(path, `${JSON.stringify(line)}\n`);
43
+ }
44
+ catch (err) {
45
+ if (!warned) {
46
+ warned = true;
47
+ warn(`could not record usage in ${path} - ${err.message}`);
48
+ }
49
+ }
50
+ }
51
+ //# sourceMappingURL=usage.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenera/cli",
3
- "version": "1.1.24",
3
+ "version": "1.1.26",
4
4
  "description": "Command-line front end for @zenera/neo: agentic projects you can run, share and commit.",
5
5
  "keywords": [
6
6
  "agents",
@@ -52,11 +52,13 @@
52
52
  "@google/genai": "^2.18.0",
53
53
  "@inkjs/ui": "^2.0.0",
54
54
  "@openrouter/sdk": "^1.2.80",
55
- "@zenera/neo": "^1.1.24",
55
+ "@zenera/neo": "^1.1.26",
56
+ "@zenera/view": "^1.1.26",
56
57
  "google-auth-library": "^10.0.0",
57
58
  "ink": "^7.1.1",
58
59
  "openai": "^6.0.0",
59
60
  "react": "^19.2.8",
61
+ "yaml": "^2.9.0",
60
62
  "yauzl": "^3.4.0",
61
63
  "yazl": "^3.3.1"
62
64
  },
@@ -47,7 +47,10 @@ visible in `agents.yaml` and that `zen check` does not report.** Before
47
47
  reviewing or changing a project, list the capabilities it has turned on and load
48
48
  the editor skill for each one - `zen-memory` for a `memory:` block,
49
49
  `zen-sandbox` for sandbox configuration or shell tools, `zen-rag-schema` or
50
- `zen-rag-docs` for an index, `zen-sandbox-capacity` before any `zen run batch`,
50
+ `zen-rag-docs` for an index, `zen-code-python` for an agent that writes or runs
51
+ code, `zen-topology` for `handoffs:` or `fork:` on any agent,
52
+ `zen-sandbox-capacity` before any `zen run batch`
53
+ (except under `zen-finetune`, which sets its own concurrency),
51
54
  `zen-cli` always. A capability that is already
52
55
  configured and already passing `zen check` is exactly the case that looks
53
56
  finished and is not: the obligation lives in the skill, so a review that never
@@ -63,6 +66,14 @@ three those are, where a project's own rules on the same subjects go instead,
63
66
  how `requires:` conditions a document, and what filename order decides. None of
64
67
  that is visible in the file being edited.
65
68
 
69
+ **Load `zen-code-python` before writing, editing or reviewing any prompt, skill
70
+ or house rule for an agent that writes or runs code** - any agent holding
71
+ `sandbox:*` or `run_command` - and before shipping a script inside a skill.
72
+ Code an agent writes must be a reusable tool, so that memory can keep it and the
73
+ next similar question runs it instead of writing it again. The skill holds the
74
+ coding rules and decides where they go: a section of a dedicated code agent's
75
+ system prompt, or a coding skill for generic agents that sometimes run code.
76
+
66
77
  First determine whether the target project uses RAG: a `zen rag` command in an
67
78
  agent prompt or skill, RAG tools supplied by its host, or a documentation or
68
79
  schema index it is expected to consult all count. When it does, also load the
@@ -102,29 +113,20 @@ tool access; give tool-based RAG users the configured RAG tools instead. Run
102
113
  `zen check` after adding or changing the skill.
103
114
 
104
115
  Memory has one such obligation and it is absolute: **a project with a `memory:`
105
- block carries the `zen-memory` skill's `references/memory-instructions.md` in its
106
- own `agents/memory-instructions.md`.** `zen init` writes both, since it scaffolds
107
- memory on; what needs watching is a project that deleted the file, or one whose
108
- copy has fallen behind the reference. Do not read the two files against each
109
- other - they drift by trailing whitespace inside tables, which is invisible.
110
- The skill ships the check:
111
-
112
- ```sh
113
- .github/skills/zen-memory/scripts/check-instructions.sh # the verdict
114
- .github/skills/zen-memory/scripts/check-instructions.sh fix # copy the reference over
115
- ```
116
-
117
- It is a copy, never a transcription - the reference ships inside the project,
118
- because `zen init` and `zen open` write this whole `.github/` tree, so `fix` is
119
- just `cp` from one to the other.
116
+ block carries `agents/memory-instructions.md` exactly as `zen` ships it.**
117
+ `zen init` writes it, since it scaffolds memory on; what needs watching is a
118
+ project that deleted the file, or one whose copy has fallen behind. `zen check`
119
+ reports the first as `memory.uninstructed` and the second as `rules.stale` -
120
+ by bytes, so trailing whitespace inside a table, invisible on screen, is caught
121
+ too - and `zen check --fix` repairs both.
120
122
 
121
123
  Nothing else tells a running agent how the store works, so without it nothing
122
124
  forbids an agent from pointing `grep` or `cat` at `/memory` - a read that
123
- bypasses the audience mask and serves superseded nodes as current. Keep the copy
124
- byte-identical and put this project's own memory policy in a second topic file,
125
- `agents/memory-policy-instructions.md`, which is read straight after it: then the
126
- copy can be re-run after any `zen init` or `zen open` refreshes the reference,
127
- without losing anything. Never paraphrase the reference into prose of your own.
125
+ bypasses the audience mask and serves superseded nodes as current. Leave the
126
+ file untouched and put this project's own memory policy in a second topic file,
127
+ `agents/memory-policy-instructions.md`, which is read straight after it: then
128
+ `zen check --fix` can replace the first after any upgrade without losing
129
+ anything. Never paraphrase it into prose of your own.
128
130
  See §5.3.
129
131
 
130
132
  A project with a `SPECIFICATION.md` carries one more: **`.spec-sync/` records
@@ -1323,13 +1325,11 @@ derived from `access` and are never listed in `tools:`.
1323
1325
 
1324
1326
  **Memory comes on.** `zen init` writes the block above, `memory: true` on the
1325
1327
  default agent, and the half nobody would guess was part of it:
1326
- `agents/memory-instructions.md`, a copy of the `zen-memory` skill's
1327
- `references/memory-instructions.md`, which the project already holds. Adding
1328
- memory to a project that has none is both of those edits, and a copy that was
1329
- lost or went stale is one command:
1328
+ `agents/memory-instructions.md`. Adding memory to a project that has none is
1329
+ both of those edits, and a file that was lost or went stale is one command:
1330
1330
 
1331
1331
  ```sh
1332
- .github/skills/zen-memory/scripts/check-instructions.sh fix
1332
+ zen check --fix
1333
1333
  ```
1334
1334
 
1335
1335
  It is what tells the agent that the store is reached only through the tools, that
@@ -1341,19 +1341,17 @@ what a node must carry to be worth having, and that a correction is a
1341
1341
  with it - and it carries `requires: [memory]`, so an agent without the store
1342
1342
  never reads a word of it.
1343
1343
 
1344
- **Leave that file as a pure copy.** Anything this project decides for itself -
1344
+ **Leave that file untouched.** Anything this project decides for itself -
1345
1345
  which audience holds what, what must never be written down, what an agent is
1346
1346
  expected to commit at the end of a job - goes in
1347
1347
  `agents/memory-policy-instructions.md`. Topic files are read in filename order,
1348
- so the policy lands directly after the rules it qualifies, and the copy stays
1349
- re-runnable: the reference is rewritten by every `zen init` and `zen open`, and
1350
- keeping up with it is then the same one-line command rather than a hand-patch.
1348
+ so the policy lands directly after the rules it qualifies, and the file stays
1349
+ replaceable: keeping up with a newer `zen` is then `zen check --fix` rather
1350
+ than a hand-patch.
1351
1351
 
1352
- `zen check` validates the `memory:` block and says nothing about the rules'
1353
- absence, so this is checked every time, by
1354
- `.github/skills/zen-memory/scripts/check-instructions.sh` and never by reading
1355
- the two files against each other: they drift by trailing whitespace inside a
1356
- table, and the script is what can see that.
1352
+ `zen check` reports a missing file as `memory.uninstructed` and any differing
1353
+ byte as `rules.stale`. Never compare the file by eye: it drifts by trailing
1354
+ whitespace inside a table, and only a byte comparison sees that.
1357
1355
 
1358
1356
  Do not treat memory as a database. It is for things learned that should
1359
1357
  persist. Anything authoritative - a rate, a policy clause, a procedure - belongs
@@ -1430,108 +1428,23 @@ multi-agent instinct suggests.
1430
1428
 
1431
1429
  ### 6.3 Handoffs
1432
1430
 
1433
- - `description:` on the target agent is what the model reads when deciding.
1434
- Write it as a routing condition: _"Applies the written peril policies to a
1435
- claim and explains the outcome."_ - not _"The adjuster agent."_
1436
- - Handoffs are bare name strings; there is no per-edge configuration.
1437
- - Self-handoff is a load error.
1438
- - **Every handoff must be returnable.** For every `A → B` there must be a path
1439
- from `B` back to `A`. Indirect counts - `B → C → A` is a way home - so the
1440
- rule is that every handoff edge lies on a cycle. `zen check` warns
1441
- (`handoff.one-way`) on any edge that does not.
1442
- - Handoff collapses history by policy: the receiving agent sees a selection, not
1443
- the full transcript. Do not assume it saw a detail three turns back; if it
1444
- matters, put it in the handoff.
1445
-
1446
- **Why the return edge is not optional.** A handoff is a one-way door: control
1447
- moves and stays moved. Nothing hands it back, so an agent reached by a dead-end
1448
- edge owns the conversation for the rest of the session - the next question,
1449
- whatever it is about, is answered by the specialist the router sent the user to.
1450
- The drawn architecture holds for one turn and then quietly stops being the
1451
- architecture.
1452
-
1453
- **Forks are the exception, and the alternative.** A branch runs, answers, and
1454
- control returns to the agent that forked it; the return is the mechanism, not an
1455
- edge anyone has to declare. So there are two shapes and they are not
1456
- interchangeable:
1457
-
1458
- - The other agent should **own the conversation from here** → `handoffs:`, and
1459
- something on the far side has to lead back.
1460
- - This agent needs **an answer and then carries on** → `fork:`. Never a handoff:
1461
- a handoff spends the conversation to get the answer. One branch is enough -
1462
- a fork of one is exactly "ask the specialist and continue".
1463
-
1464
- But the return is **condensed**: `A → fork → B` rejoins as one tool result
1465
- holding B's answer, so A never sees the steps B took - no tool calls, no files
1466
- read, no intermediate reasoning. That is what makes fanning out cheap, and it is
1467
- what to design around: whatever A will need must be _in_ the answer, so say so in
1468
- B's prompt. Work whose value is the trace rather than the conclusion does not
1469
- survive a fork.
1431
+ `handoffs: [name, ...]` on an agent gives it one `transfer_to_<name>` tool per
1432
+ entry, described by the target's `description:`. Control moves to the target
1433
+ and **stays moved** - the target sees the whole transcript and answers every
1434
+ later turn until it hands off itself - so every edge needs a path back, and
1435
+ `zen check` warns `handoff.one-way` on one that has none.
1470
1436
 
1471
1437
  ### 6.4 Forking (fan-out / join)
1472
1438
 
1473
- Forking is **opt-in per agent**. Without the key the agent is never offered the
1474
- `fork` tool and cannot split, however obviously parallel the work looks:
1475
-
1476
- ```yaml
1477
- agents:
1478
- - name: trunk
1479
- fork: true # unrestricted: any agent, any number of branches
1480
-
1481
- - name: sweep
1482
- fork:
1483
- agents: [prober] # every branch runs the specialist
1484
- maxBranches: 6
1485
- ```
1439
+ `fork:` on an agent - `true`, or `{ agents, maxBranches }` - gives it the `fork`
1440
+ tool: N branches, run at once, rejoin as one tool result holding each branch's
1441
+ answer. One branch is delegation; several are a fan-out. Without the key the
1442
+ agent cannot split, however obviously parallel the work looks.
1486
1443
 
1487
- | Field | Default | Meaning |
1488
- | ------------- | -------------------- | ------------------------------------- |
1489
- | `agents` | every declared agent | Which agents a branch may run |
1490
- | `maxBranches` | unlimited | Cap on branches per call; minimum `1` |
1491
-
1492
- The **model** decides the split: it names N branches, each with self-contained
1493
- instructions. They run truly concurrently and rejoin as **one tool call and one
1494
- tool result** in the parent's history - so N branches cost the parent
1495
- O(N × summary), not O(N × full history).
1496
-
1497
- Rules worth knowing before you write the key:
1498
-
1499
- - `agents:` **may include the forking agent itself** - unlike `handoffs:`, that
1500
- is not an error, and one role fanned out over ten items is the common shape.
1501
- The list reaches the model as an `enum`, so a name outside it cannot even be
1502
- decoded.
1503
- - A fork of **one** branch is delegation, and it is valid: one assignment run
1504
- elsewhere, its conclusion returned, its transcript left out of this
1505
- conversation. Use it when another agent suits the job better, or when the job
1506
- would fill the caller's context with material it has no use for afterwards.
1507
- - **Branches cannot talk to each other.** If branch B needs branch A's answer,
1508
- it is a sequence, not a fork - keep it in one conversation.
1509
- - Nesting is capped by the run's `maxForkDepth` (2 by default), so a branch may
1510
- fork again but not without bound.
1511
- - Fork vs handoff: a handoff is _one_ conversation changing owner; a fork is the
1512
- _same_ question asked N times at once and merged. **A fork returns; a handoff
1513
- does not** - which is why a handoff needs a return path (§6.3) and a fork
1514
- needs nothing.
1515
-
1516
- Choose `context:` deliberately - the model sets it per call, so say in the
1517
- agent's prompt which one this work wants:
1518
-
1519
- - `inherit` - branch gets the full prefix. For work that depends on the case.
1520
- - `compact` - prefix minus tool calls, tool results and recalls: _what was
1521
- decided_, not the raw noise. **The default for wide fan-outs.**
1522
- - `none` - system prompt plus instructions only. Cheapest; for independent
1523
- lookups.
1524
-
1525
- Declaring `fork:` only makes the tool available. What a fork costs and what
1526
- survives the join is in `agents/fork-instructions.md`, which carries
1527
- `requires: [fork]` and so reaches exactly the agents holding the key. That file
1528
- is `zen`'s, not yours - `zen check --fix` replaces it, editing it or carrying an
1529
- older copy is reported as `rules.stale`, and deleting it leaves your forking
1530
- agents with the tool schema alone (`fork.uninstructed`). What is
1531
- left to you is _when_, in the terms of this domain - _"When the request covers
1532
- more than one region, fork one branch per region and merge their findings"_ - or
1533
- a weaker model will work through the list serially and never call it. Project
1534
- policy on forking goes in a topic file of your own beside it.
1444
+ **Load `zen-topology` before adding or changing either key, and before writing
1445
+ a prompt line that says when to delegate.** It holds the key reference, hand-off
1446
+ versus fork, which `context` a branch should start from, what each choice costs
1447
+ in tokens, prompt cache and time, and how a recorded run shows each mistake.
1535
1448
 
1536
1449
  ### 6.5 Termination
1537
1450
 
@@ -1939,8 +1852,8 @@ ok, `1` failed, `2` usage, `3` invalid project, `4` no usable credential.
1939
1852
 
1940
1853
  ## 9. Review checklist
1941
1854
 
1942
- Four of these are decidable, and are one command - `zen check`, the path sweep,
1943
- the memory copy, the spec-sync record, in that order:
1855
+ Three of these are decidable, and are one command - `zen check`, the path sweep,
1856
+ the spec-sync record, in that order:
1944
1857
 
1945
1858
  ```sh
1946
1859
  .github/skills/zen-review/scripts/review.sh
@@ -1969,7 +1882,7 @@ Before finishing any change here:
1969
1882
  - [ ] Each `agents/<topic>-instructions.md` is about one capability, and is true
1970
1883
  of every agent it reaches - `requires:` if it is about one of them
1971
1884
  - [ ] If any agent has file tools, `agents/files-instructions.md` is present - §3.6
1972
- - [ ] If any agent has `fork:`, `agents/fork-instructions.md` is present - §6.4
1885
+ - [ ] If any agent has `fork:`, `agents/fork-instructions.md` is present - zen-topology §8
1973
1886
  - [ ] No `rules.stale`: the four files that are `zen`'s rather than yours say
1974
1887
  what this version of the runtime does, and `zen check --fix` replaces them
1975
1888
  - [ ] Any change to an `agents/*instructions.md` was made with the
@@ -1979,10 +1892,9 @@ Before finishing any change here:
1979
1892
  - [ ] Failure paths stated for every instruction that can fail
1980
1893
  - [ ] No facts, rates or figures embedded in a prompt
1981
1894
  - [ ] No hedging, no meta-talk about the runtime
1982
- - [ ] If any agent has `memory:`,
1983
- `.github/skills/zen-memory/scripts/check-instructions.sh` exits zero -
1984
- `agents/memory-instructions.md` is the reference byte for byte - and
1985
- anything project-specific is in `agents/memory-policy-instructions.md` - §5.3
1895
+ - [ ] If any agent has `memory:`, `zen check` reports neither
1896
+ `memory.uninstructed` nor `rules.stale` - and anything project-specific
1897
+ is in `agents/memory-policy-instructions.md` - §5.3
1986
1898
 
1987
1899
  **Paths (§2.5 - `.github/skills/zen-review/scripts/check-paths.sh` finds the
1988
1900
  candidates; these are the judgements to make about each one)**
@@ -2004,6 +1916,9 @@ candidates; these are the judgements to make about each one)**
2004
1916
  - [ ] Catalog >~30 entries → `discovery: search`
2005
1917
  - [ ] A skill that ships a script writes its `/skills/<name>/...` path, the agent
2006
1918
  holds `sandbox:*`, and the sandbox image already has the interpreter
1919
+ - [ ] Every agent that writes or runs code has the `zen-code-python` rules -
1920
+ in its prompt if it is the dedicated code agent, as a skill otherwise -
1921
+ and nothing else restates or softens them - §0.1
2007
1922
  - [ ] A skill whose procedure needs particular tools, an index or a mounted file
2008
1923
  opens by naming them and says what to do without them - rather than naming
2009
1924
  the agents allowed to load it, which `agents.yaml` already decides - §0.1
@@ -2085,10 +2000,10 @@ candidates; these are the judgements to make about each one)**
2085
2000
  | Answers instead of routing | Router prompt prohibition; check `handoffs:` |
2086
2001
  | Routes to the wrong specialist | The target agents' `description:` fields |
2087
2002
  | Gets stuck in the agent it routed to | The target needs a handoff back - §6.3 |
2088
- | Loses a detail after a handoff | Say it in the handoff; check the collapse policy |
2003
+ | Loses a detail after a handoff | The target sees the whole transcript; its prompt must say to use it |
2089
2004
  | Works through N independent items serially | `fork:` on that agent, and a prompt line - §6.4 |
2090
2005
  | Forks when the steps actually depend | Prompt line: branches cannot see each other |
2091
- | Forks a sequence, or loses a branch's working | `agents/fork-instructions.md` is missing or empty - §6.4 |
2006
+ | Forks a sequence, or loses a branch's working | `agents/fork-instructions.md` is missing or empty - zen-topology §8 |
2092
2007
  | Edits files blindly or breaks patches | `agents/files-instructions.md` is missing or empty - §3.6 |
2093
2008
  | Slow and expensive on trivial cases | Demote that agent's model tier / reasoning effort |
2094
2009
  | Fails only on genuinely hard cases | Promote that agent's tier, or split the hard path out |
@@ -2115,10 +2030,10 @@ candidates; these are the judgements to make about each one)**
2115
2030
  the turn that follows it - §2.5.
2116
2031
  - **Arithmetic in prose.** A skill that walks the model through a calculation it
2117
2032
  will get wrong, in a folder that could have held the script - §3.4.1.
2118
- - **The unguarded store.** `memory:` turned on and the skill's
2119
- `references/memory-instructions.md` never copied to
2033
+ - **The unguarded store.** `memory:` turned on and no
2120
2034
  `agents/memory-instructions.md`, so nothing tells the agent the store is
2121
- reached only through the tools - and `zen check` passes throughout - §5.3.
2035
+ reached only through the tools - `zen check` fails with
2036
+ `memory.uninstructed`, and `zen check --fix` writes it - §5.3.
2122
2037
  - **Reviewing a capability without its skill.** A project whose memory, index or
2123
2038
  sandbox was configured by an earlier pass looks finished because it loads. The
2124
2039
  obligations are in the editor skill, not in `agents.yaml` - §0.1.
@@ -0,0 +1,33 @@
1
+ ---
2
+ 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.
3
+ ---
4
+
5
+ Load the **zen-analyze-run** skill and follow it to analyze one run of this
6
+ project. Everything about how to analyze it is in the skill. If `agents.yaml`
7
+ has a `memory:` key anywhere (`grep -n 'memory:' agents.yaml`), load the
8
+ **zen-memory** skill with it, before you read the run: the memory areas of the
9
+ audit cannot be graded without it.
10
+
11
+ ## Which run
12
+
13
+ The line after this prompt may name the run - a run directory or a run id.
14
+ If it does, use it. Words after it like `case=<id> ... feedback=<file>` mean
15
+ the tuning loop sent you: follow section 7 of the skill and write that file.
16
+ A `## The brief` section below that line is what the loop already ran for
17
+ you: section 1 of the skill says how to use it.
18
+
19
+ If it does not, list this project's most recent runs, newest first:
20
+
21
+ ```sh
22
+ zen list --runs --json --limit 500 \
23
+ | jq -r --arg p "$PWD/" '[.[] | select(.dir | startswith($p))][:5][]
24
+ | "\(.id) \(.agent // "-") \(.error // .stopReason // "-") \(.dir)"'
25
+ ```
26
+
27
+ - If there are none, stop and say this project has no runs yet.
28
+ - If you can ask the user a question, show that list and ask which run to
29
+ analyze, with the newest as the default.
30
+ - If you cannot ask, take the newest. Say which run you picked, and that it was
31
+ picked as the most recent, at the top of the report.
32
+
33
+ Then give the run to the skill.