@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.
- package/README.md +65 -0
- package/dist/ask.js +28 -5
- package/dist/banner.js +2 -2
- package/dist/batch.d.ts +6 -0
- package/dist/batch.js +76 -1
- package/dist/catalog.d.ts +31 -1
- package/dist/catalog.js +140 -7
- package/dist/commands/index.js +2 -0
- package/dist/commands/inspect.d.ts +52 -2
- package/dist/commands/inspect.js +220 -31
- package/dist/commands/memory.js +156 -32
- package/dist/commands/meta.js +333 -24
- package/dist/commands/models.js +97 -12
- package/dist/commands/open.js +4 -4
- package/dist/commands/run.js +38 -4
- package/dist/commands/sandbox.js +148 -16
- package/dist/commands/view.d.ts +8 -0
- package/dist/commands/view.js +114 -0
- package/dist/engine.d.ts +8 -1
- package/dist/engine.js +7 -0
- package/dist/eventlog.d.ts +64 -0
- package/dist/eventlog.js +170 -0
- package/dist/liveness.d.ts +7 -0
- package/dist/liveness.js +35 -3
- package/dist/main.js +0 -0
- package/dist/meta/editor.d.ts +9 -0
- package/dist/meta/editor.js +43 -0
- package/dist/meta/finetune/analyze-brief.d.ts +26 -0
- package/dist/meta/finetune/analyze-brief.js +131 -0
- package/dist/meta/finetune/apply-brief.d.ts +23 -0
- package/dist/meta/finetune/apply-brief.js +247 -0
- package/dist/meta/finetune/brief.d.ts +45 -0
- package/dist/meta/finetune/brief.js +158 -0
- package/dist/meta/finetune/children.d.ts +8 -0
- package/dist/meta/finetune/children.js +76 -0
- package/dist/meta/finetune/command.d.ts +30 -0
- package/dist/meta/finetune/command.js +516 -0
- package/dist/meta/finetune/cost.d.ts +46 -0
- package/dist/meta/finetune/cost.js +105 -0
- package/dist/meta/finetune/dataset/anchors.d.ts +41 -0
- package/dist/meta/finetune/dataset/anchors.js +239 -0
- package/dist/meta/finetune/dataset/changes.d.ts +36 -0
- package/dist/meta/finetune/dataset/changes.js +319 -0
- package/dist/meta/finetune/dataset/command.d.ts +17 -0
- package/dist/meta/finetune/dataset/command.js +1011 -0
- package/dist/meta/finetune/dataset/drift.d.ts +33 -0
- package/dist/meta/finetune/dataset/drift.js +71 -0
- package/dist/meta/finetune/dataset/export.d.ts +26 -0
- package/dist/meta/finetune/dataset/export.js +51 -0
- package/dist/meta/finetune/dataset/index.d.ts +2 -0
- package/dist/meta/finetune/dataset/index.js +2 -0
- package/dist/meta/finetune/dataset/sample.d.ts +50 -0
- package/dist/meta/finetune/dataset/sample.js +197 -0
- package/dist/meta/finetune/dataset/schema.d.ts +33 -0
- package/dist/meta/finetune/dataset/schema.js +216 -0
- package/dist/meta/finetune/dataset/store.d.ts +35 -0
- package/dist/meta/finetune/dataset/store.js +177 -0
- package/dist/meta/finetune/dataset/types.d.ts +127 -0
- package/dist/meta/finetune/dataset/types.js +39 -0
- package/dist/meta/finetune/failure.d.ts +15 -0
- package/dist/meta/finetune/failure.js +26 -0
- package/dist/meta/finetune/feedback.d.ts +57 -0
- package/dist/meta/finetune/feedback.js +104 -0
- package/dist/meta/finetune/guard.d.ts +29 -0
- package/dist/meta/finetune/guard.js +104 -0
- package/dist/meta/finetune/improvements.d.ts +98 -0
- package/dist/meta/finetune/improvements.js +501 -0
- package/dist/meta/finetune/index.d.ts +2 -0
- package/dist/meta/finetune/index.js +2 -0
- package/dist/meta/finetune/journal.d.ts +35 -0
- package/dist/meta/finetune/journal.js +135 -0
- package/dist/meta/finetune/live.d.ts +84 -0
- package/dist/meta/finetune/live.js +272 -0
- package/dist/meta/finetune/loop.d.ts +3 -0
- package/dist/meta/finetune/loop.js +163 -0
- package/dist/meta/finetune/memories.d.ts +47 -0
- package/dist/meta/finetune/memories.js +154 -0
- package/dist/meta/finetune/recheck.d.ts +58 -0
- package/dist/meta/finetune/recheck.js +311 -0
- package/dist/meta/finetune/report.d.ts +40 -0
- package/dist/meta/finetune/report.js +1397 -0
- package/dist/meta/finetune/retry.d.ts +24 -0
- package/dist/meta/finetune/retry.js +96 -0
- package/dist/meta/finetune/sampler.d.ts +18 -0
- package/dist/meta/finetune/sampler.js +47 -0
- package/dist/meta/finetune/system.d.ts +27 -0
- package/dist/meta/finetune/system.js +132 -0
- package/dist/meta/finetune/train.d.ts +43 -0
- package/dist/meta/finetune/train.js +425 -0
- package/dist/meta/finetune/tui.d.ts +16 -0
- package/dist/meta/finetune/tui.js +316 -0
- package/dist/meta/finetune/tuning.d.ts +193 -0
- package/dist/meta/finetune/tuning.js +308 -0
- package/dist/meta/finetune/usage.d.ts +66 -0
- package/dist/meta/finetune/usage.js +260 -0
- package/dist/meta/finetune/view.d.ts +9 -0
- package/dist/meta/finetune/view.js +27 -0
- package/dist/meta/host.d.ts +15 -0
- package/dist/meta/host.js +21 -0
- package/dist/meta/index.d.ts +11 -0
- package/dist/meta/index.js +11 -0
- package/dist/meta/launch.d.ts +81 -0
- package/dist/meta/launch.js +286 -0
- package/dist/meta/model.d.ts +44 -0
- package/dist/meta/model.js +119 -0
- package/dist/meta/prompts.d.ts +18 -0
- package/dist/meta/prompts.js +61 -0
- package/dist/meta/relay.d.ts +20 -0
- package/dist/meta/relay.js +123 -0
- package/dist/meta/tokens.d.ts +52 -0
- package/dist/meta/tokens.js +226 -0
- package/dist/meta/window.d.ts +61 -0
- package/dist/meta/window.js +198 -0
- package/dist/meta/wire.d.ts +42 -0
- package/dist/meta/wire.js +129 -0
- package/dist/meta.d.ts +71 -1
- package/dist/meta.js +303 -6
- package/dist/modelref.d.ts +16 -0
- package/dist/modelref.js +41 -0
- package/dist/narrate.js +5 -2
- package/dist/podman.d.ts +26 -0
- package/dist/podman.js +83 -3
- package/dist/projects.d.ts +0 -5
- package/dist/projects.js +2 -15
- package/dist/resources.d.ts +215 -0
- package/dist/resources.js +856 -0
- package/dist/sandbox.d.ts +2 -0
- package/dist/sandbox.js +10 -3
- package/dist/scaffold.d.ts +15 -7
- package/dist/scaffold.js +24 -67
- package/dist/session.js +4 -29
- package/dist/term.d.ts +2 -0
- package/dist/term.js +11 -2
- package/dist/trace.d.ts +5 -0
- package/dist/trace.js +107 -7
- package/dist/tui/app.js +19 -5
- package/dist/tui/links.d.ts +27 -0
- package/dist/tui/links.js +142 -0
- package/dist/tui/models.d.ts +35 -0
- package/dist/tui/models.js +447 -0
- package/dist/tui/sandbox.d.ts +10 -0
- package/dist/tui/sandbox.js +131 -0
- package/dist/tui/wrap.d.ts +5 -0
- package/dist/tui/wrap.js +12 -0
- package/dist/usage.d.ts +78 -0
- package/dist/usage.js +51 -0
- package/package.json +4 -2
- package/templates/editor/.github/copilot-instructions.md +60 -145
- package/templates/editor/.github/prompts/analyze.prompt.md +33 -0
- package/templates/editor/.github/prompts/dataset.prompt.md +108 -0
- package/templates/editor/.github/prompts/finetune-apply.prompt.md +270 -0
- package/templates/editor/.github/prompts/finetune.prompt.md +691 -198
- package/templates/editor/.github/prompts/new-agent.prompt.md +3 -1
- package/templates/editor/.github/prompts/new-skill.prompt.md +2 -0
- package/templates/editor/.github/prompts/project-review.prompt.md +5 -4
- package/templates/editor/.github/skills/zen-analyze-run/SKILL.md +588 -0
- package/templates/editor/.github/skills/zen-cli/SKILL.md +9 -1
- package/templates/editor/.github/skills/zen-cli/references/dataset.md +34 -0
- package/templates/editor/.github/skills/zen-cli/references/finetune.md +137 -0
- package/templates/editor/.github/skills/zen-cli/references/inspect.md +63 -11
- package/templates/editor/.github/skills/zen-cli/references/memory.md +33 -10
- package/templates/editor/.github/skills/zen-cli/references/meta.md +61 -0
- package/templates/editor/.github/skills/zen-cli/references/models.md +5 -1
- package/templates/editor/.github/skills/zen-cli/references/projects.md +4 -6
- package/templates/editor/.github/skills/zen-cli/references/rag.md +24 -6
- package/templates/editor/.github/skills/zen-cli/references/sandbox.md +35 -14
- package/templates/editor/.github/skills/zen-code-python/SKILL.md +123 -0
- package/templates/editor/.github/skills/zen-code-python/references/code_python.md +48 -0
- package/templates/editor/.github/skills/zen-dataset/SKILL.md +253 -0
- package/templates/editor/.github/skills/zen-finetune/SKILL.md +1492 -660
- package/templates/editor/.github/skills/zen-finetune/references/readme-template.md +268 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/batch.mjs +390 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/difficult.mjs +243 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/memory.mjs +280 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/next.mjs +398 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/report.mjs +797 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/select.mjs +354 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/usage.mjs +722 -0
- package/templates/editor/.github/skills/zen-inspect/SKILL.md +74 -26
- package/templates/editor/.github/skills/zen-inspect-ask/SKILL.md +271 -0
- package/templates/editor/.github/skills/zen-instructions/SKILL.md +4 -12
- package/templates/editor/.github/skills/zen-memory/SKILL.md +82 -53
- package/templates/editor/.github/skills/zen-rag-docs/SKILL.md +20 -8
- package/templates/editor/.github/skills/zen-review/SKILL.md +8 -31
- package/templates/editor/.github/skills/zen-review/scripts/check-paths.sh +5 -5
- package/templates/editor/.github/skills/zen-review/scripts/review.sh +3 -12
- package/templates/editor/.github/skills/zen-sandbox/SKILL.md +9 -4
- package/templates/editor/.github/skills/zen-sandbox-capacity/SKILL.md +2 -2
- package/templates/editor/.github/skills/zen-spec-sync/SKILL.md +2 -4
- package/templates/editor/.github/skills/zen-topology/SKILL.md +283 -0
- package/templates/editor/.vscode/settings.json +1 -0
- package/templates/project/agents/files-instructions.md +29 -20
- package/templates/project/agents/fork-instructions.md +78 -28
- package/templates/project/agents/memory-instructions.md +222 -494
- package/templates/project/agents/tools-instructions.md +14 -4
- package/templates/project/gitignore +2 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/collect.sh +0 -432
- package/templates/editor/.github/skills/zen-finetune/scripts/sample.sh +0 -199
- package/templates/editor/.github/skills/zen-memory/scripts/check-instructions.sh +0 -116
package/dist/commands/memory.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { ALL_AGENTS, buildMemoryReport, createEmbedder, GREP_FIELDS, grepMemory, hostPath, memoryDir, MemoryError, MemoryIndex, MemoryStore, MergeConflicts, mergeMemories, readProjectConfig, renderMemoryHtml, renderRecollection, } from '@zenera/neo';
|
|
1
|
+
import { ALL_AGENTS, buildMemoryReport, createEmbedder, diffMemories, GREP_FIELDS, grepMemory, hostPath, memoryDir, MemoryError, MemoryIndex, MemoryStore, MergeConflicts, mergeMemories, readProjectConfig, renderMemoryHtml, renderRecollection, } from '@zenera/neo';
|
|
2
2
|
import { spawn } from 'node:child_process';
|
|
3
|
-
import { existsSync } from 'node:fs';
|
|
3
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
4
4
|
import { writeFile } from 'node:fs/promises';
|
|
5
|
-
import { basename, isAbsolute, join,
|
|
5
|
+
import { basename, isAbsolute, join, resolve } from 'node:path';
|
|
6
6
|
import { parse } from "../args.js";
|
|
7
7
|
import { loadProjectEnv } from "../env.js";
|
|
8
8
|
import { KeyStore } from "../keys.js";
|
|
9
9
|
import { project as resolveProject } from "../resolve.js";
|
|
10
|
-
import { ago, bold, bytes, CliError, confirm, count, cyan, dim, EXIT, green, isInteractive, json, note, table, usageError, write, writeAll, yellow, } from "../term.js";
|
|
11
|
-
const USAGE = 'zen memory [stats|ls|search|grep|show|export|merge|forget] [args] [options]';
|
|
12
|
-
const SUBCOMMANDS = ['stats', 'ls', 'search', 'grep', 'show', 'export', 'merge', 'forget'];
|
|
10
|
+
import { ago, bold, bytes, CliError, confirm, count, cyan, dim, EXIT, green, isInteractive, json, note, plain, table, usageError, write, writeAll, yellow, } from "../term.js";
|
|
11
|
+
const USAGE = 'zen memory [stats|ls|search|grep|show|diff|export|merge|forget] [args] [options]';
|
|
12
|
+
const SUBCOMMANDS = ['stats', 'ls', 'search', 'grep', 'show', 'diff', 'export', 'merge', 'forget'];
|
|
13
13
|
/** Enough to see the shape of it; the rest is a number. */
|
|
14
14
|
const LISTED = 30;
|
|
15
15
|
// ---------------------------------------------------------------------------
|
|
@@ -42,12 +42,14 @@ export const memory = {
|
|
|
42
42
|
' search <text> Recall it, the way an agent does. Ranked.',
|
|
43
43
|
' grep <pattern> Every node containing it, with the matching lines.',
|
|
44
44
|
' show <id> One node in full, with what it links to.',
|
|
45
|
+
' diff <base> What this memory holds that <base> did not.',
|
|
45
46
|
' export [file] The whole graph as one HTML page.',
|
|
46
47
|
' merge <dir...> Fold other memories into this one.',
|
|
47
48
|
' forget <id...> Remove nodes, their vectors and their files.',
|
|
48
49
|
'',
|
|
49
50
|
' --project <name|dir> Which project. Defaults to the one you are in.',
|
|
50
51
|
' --dir <dir> Read this memory directory instead of the project’s.',
|
|
52
|
+
' Run from inside a memory directory, that one is the default.',
|
|
51
53
|
' --kind <name> Only this kind of node.',
|
|
52
54
|
' --audience <name> Only nodes committed under this label.',
|
|
53
55
|
' --files Only nodes that remember a file.',
|
|
@@ -104,6 +106,12 @@ export const memory = {
|
|
|
104
106
|
' zen memory merge <batch-dir>/*/memory',
|
|
105
107
|
'',
|
|
106
108
|
'which is where `zen run batch` leaves them.',
|
|
109
|
+
'',
|
|
110
|
+
'`diff` is the question after a run that started from a copy: what it',
|
|
111
|
+
'added, which of those `merge` would fold onto a node <base> already held',
|
|
112
|
+
'(a re-commit), what it revised, and which nodes `memory_load` read:',
|
|
113
|
+
'',
|
|
114
|
+
' zen memory diff <candidate> --dir <batch-dir>/<id>/memory',
|
|
107
115
|
],
|
|
108
116
|
run: async (ctx) => {
|
|
109
117
|
const { values, positionals } = parse(ctx.args, {
|
|
@@ -156,6 +164,8 @@ export const memory = {
|
|
|
156
164
|
return await grep(opened, rest, values, ctx.json);
|
|
157
165
|
case 'show':
|
|
158
166
|
return show(opened, rest, ctx.json);
|
|
167
|
+
case 'diff':
|
|
168
|
+
return await diff(opened, rest, ctx.cwd, ctx.json);
|
|
159
169
|
case 'export':
|
|
160
170
|
return await write_(opened, rest, values, ctx.cwd, ctx.json);
|
|
161
171
|
case 'merge':
|
|
@@ -189,6 +199,11 @@ export const memory = {
|
|
|
189
199
|
*/
|
|
190
200
|
async function open(cwd, want, at, opts = {}) {
|
|
191
201
|
const { create = false, lock = true } = opts;
|
|
202
|
+
// Standing inside a memory (a merged or batch copy) means that memory, not
|
|
203
|
+
// the project's own one a few directories up.
|
|
204
|
+
if (!at && !want && isMemoryDir(cwd)) {
|
|
205
|
+
at = cwd;
|
|
206
|
+
}
|
|
192
207
|
if (at) {
|
|
193
208
|
const dir = resolve(cwd, at);
|
|
194
209
|
if (!create && !existsSync(join(dir, 'manifest.json'))) {
|
|
@@ -212,6 +227,19 @@ async function open(cwd, want, at, opts = {}) {
|
|
|
212
227
|
at: { root: project.dir, config },
|
|
213
228
|
};
|
|
214
229
|
}
|
|
230
|
+
/** A rag index also has a manifest and a graph.json; only a memory's manifest counts nodes and edges. */
|
|
231
|
+
function isMemoryDir(dir) {
|
|
232
|
+
if (!existsSync(join(dir, 'graph.json'))) {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
const m = JSON.parse(readFileSync(join(dir, 'manifest.json'), 'utf8'));
|
|
237
|
+
return typeof m?.nodes === 'number' && typeof m?.edges === 'number';
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
215
243
|
// ---------------------------------------------------------------------------
|
|
216
244
|
// stats
|
|
217
245
|
// ---------------------------------------------------------------------------
|
|
@@ -309,23 +337,22 @@ function list(o, flags, asJson) {
|
|
|
309
337
|
.filter((n) => !flags.stale || stale.has(n.id))
|
|
310
338
|
.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
311
339
|
if (asJson) {
|
|
312
|
-
json({ total: all.length, nodes: all.slice(0, limit) });
|
|
340
|
+
json({ total: all.length, nodes: all.slice(0, limit).map((n) => onHost(o, n)) });
|
|
313
341
|
return;
|
|
314
342
|
}
|
|
315
343
|
if (!all.length) {
|
|
316
344
|
note('nothing matches');
|
|
317
345
|
return;
|
|
318
346
|
}
|
|
319
|
-
writeAll(
|
|
347
|
+
writeAll(textLast(all
|
|
320
348
|
.slice(0, limit)
|
|
321
349
|
.map((n) => [
|
|
322
350
|
cyan(n.id),
|
|
323
|
-
n.kind,
|
|
324
|
-
n.
|
|
325
|
-
|
|
326
|
-
dim(ago(n.createdAt)),
|
|
327
|
-
|
|
328
|
-
])));
|
|
351
|
+
n.kind + (n.file ? dim(' ⎘ ' + n.file.format) : ''),
|
|
352
|
+
n.audience.join(','),
|
|
353
|
+
dim(`r${n.revision}`),
|
|
354
|
+
dim(ago(n.createdAt)) + (stale.has(n.id) ? ' ' + yellow('superseded') : ''),
|
|
355
|
+
]), all.slice(0, limit).map((n) => n.text)));
|
|
329
356
|
if (all.length > limit) {
|
|
330
357
|
write();
|
|
331
358
|
note(dim(`${all.length - limit} more — raise --limit, or use \`zen memory export\``));
|
|
@@ -552,7 +579,7 @@ async function grep(o, rest, flags, asJson) {
|
|
|
552
579
|
hits: m.hits,
|
|
553
580
|
more: m.more,
|
|
554
581
|
})),
|
|
555
|
-
unsearched: res.skipped,
|
|
582
|
+
unsearched: res.skipped.map((s) => ({ ...s, path: hostPath(o.dir, s) })),
|
|
556
583
|
});
|
|
557
584
|
return;
|
|
558
585
|
}
|
|
@@ -562,7 +589,7 @@ async function grep(o, rest, flags, asJson) {
|
|
|
562
589
|
}
|
|
563
590
|
if (!res.found) {
|
|
564
591
|
note(`nothing matches ${pattern}`);
|
|
565
|
-
unsearched(res.skipped);
|
|
592
|
+
unsearched(o, res.skipped);
|
|
566
593
|
return;
|
|
567
594
|
}
|
|
568
595
|
for (const m of res.matches) {
|
|
@@ -570,7 +597,7 @@ async function grep(o, rest, flags, asJson) {
|
|
|
570
597
|
' ' +
|
|
571
598
|
m.node.kind +
|
|
572
599
|
(m.stale ? ' ' + yellow('superseded') : '') +
|
|
573
|
-
(m.node.file ? ' ' + dim(m.node.file
|
|
600
|
+
(m.node.file ? ' ' + dim(hostPath(o.dir, m.node.file)) : ''));
|
|
574
601
|
writeAll(table(m.hits.map((h) => [` ${dim(h.where + ':' + h.line)}`, clip(h.text, 120)])));
|
|
575
602
|
if (m.more) {
|
|
576
603
|
write(dim(` … ${count(m.more, 'more line')} in this node`));
|
|
@@ -580,19 +607,19 @@ async function grep(o, rest, flags, asJson) {
|
|
|
580
607
|
if (res.truncated) {
|
|
581
608
|
note(dim(`${res.found - res.matches.length} more nodes — raise --limit`));
|
|
582
609
|
}
|
|
583
|
-
unsearched(res.skipped);
|
|
610
|
+
unsearched(o, res.skipped);
|
|
584
611
|
}
|
|
585
612
|
/**
|
|
586
613
|
* Named rather than counted. A file that was not read is a hole in an answer
|
|
587
614
|
* whose whole value is that it has none, so the ids have to be printable.
|
|
588
615
|
*/
|
|
589
|
-
function unsearched(skipped) {
|
|
616
|
+
function unsearched(o, skipped) {
|
|
590
617
|
if (!skipped.length) {
|
|
591
618
|
return;
|
|
592
619
|
}
|
|
593
620
|
write();
|
|
594
621
|
note(yellow(`${count(skipped.length, 'file')} not searched`));
|
|
595
|
-
writeAll(table(skipped.map((s) => [` ${cyan(s.id)}`, dim(s.reason), s
|
|
622
|
+
writeAll(table(skipped.map((s) => [` ${cyan(s.id)}`, dim(s.reason), hostPath(o.dir, s)])));
|
|
596
623
|
}
|
|
597
624
|
// ---------------------------------------------------------------------------
|
|
598
625
|
// show
|
|
@@ -608,7 +635,11 @@ function show(o, ids, asJson) {
|
|
|
608
635
|
}
|
|
609
636
|
const links = o.store.graph.neighbors(id);
|
|
610
637
|
if (asJson) {
|
|
611
|
-
json({
|
|
638
|
+
json({
|
|
639
|
+
node: onHost(o, node),
|
|
640
|
+
links,
|
|
641
|
+
file: node.file ? hostPath(o.dir, node.file) : undefined,
|
|
642
|
+
});
|
|
612
643
|
return;
|
|
613
644
|
}
|
|
614
645
|
write(bold(node.id) + ' ' + cyan(node.kind));
|
|
@@ -653,6 +684,82 @@ function show(o, ids, asJson) {
|
|
|
653
684
|
})));
|
|
654
685
|
}
|
|
655
686
|
// ---------------------------------------------------------------------------
|
|
687
|
+
// diff
|
|
688
|
+
// ---------------------------------------------------------------------------
|
|
689
|
+
async function diff(o, rest, cwd, asJson) {
|
|
690
|
+
if (rest.length !== 1) {
|
|
691
|
+
throw usageError('diff takes exactly one base memory', 'zen memory diff <base> [--dir <dir>]');
|
|
692
|
+
}
|
|
693
|
+
const at = resolve(cwd, rest[0]);
|
|
694
|
+
if (!existsSync(join(at, 'manifest.json'))) {
|
|
695
|
+
throw usageError(`${at} is not a memory`, 'no manifest.json in it');
|
|
696
|
+
}
|
|
697
|
+
const base = await MemoryStore.open(at, { lock: false });
|
|
698
|
+
try {
|
|
699
|
+
const d = diffMemories(base, o.store);
|
|
700
|
+
const mine = (n) => onHost(o, n);
|
|
701
|
+
const theirs = (n) => n.file ? { ...n, file: { ...n.file, path: hostPath(at, n.file) } } : n;
|
|
702
|
+
if (asJson) {
|
|
703
|
+
json({
|
|
704
|
+
...d,
|
|
705
|
+
added: d.added.map((a) => ({ ...a, node: mine(a.node) })),
|
|
706
|
+
revised: d.revised.map((r) => ({ before: theirs(r.before), after: mine(r.after) })),
|
|
707
|
+
used: d.used.map((u) => ({ ...u, node: mine(u.node) })),
|
|
708
|
+
removed: d.removed.map(theirs),
|
|
709
|
+
});
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
712
|
+
const twins = d.added.filter((a) => a.twin).length;
|
|
713
|
+
write(bold(o.dir) + dim(` against ${at} · nearest by ${d.by}`));
|
|
714
|
+
write();
|
|
715
|
+
write(`${bold('added')} ${d.added.length}` +
|
|
716
|
+
(twins ? ` · ${yellow(`${twins} already held`)}` : '') +
|
|
717
|
+
` · ${bold('revised')} ${d.revised.length}` +
|
|
718
|
+
` · ${bold('used')} ${d.used.length}` +
|
|
719
|
+
` · ${bold('removed')} ${d.removed.length}` +
|
|
720
|
+
` · ${bold('edges')} +${d.edges}`);
|
|
721
|
+
if (d.added.length) {
|
|
722
|
+
write();
|
|
723
|
+
write(dim('added'));
|
|
724
|
+
writeAll(textLast(d.added.map((a) => [
|
|
725
|
+
` ${cyan(a.node.id)}`,
|
|
726
|
+
a.node.kind,
|
|
727
|
+
a.node.audience.join(','),
|
|
728
|
+
a.nearest
|
|
729
|
+
? `${a.twin ? yellow('twin of') : dim('near')} ${a.nearest.id} ${dim(a.nearest.score.toFixed(2))}`
|
|
730
|
+
: dim('nothing near'),
|
|
731
|
+
]), d.added.map((a) => a.node.text)));
|
|
732
|
+
}
|
|
733
|
+
if (d.revised.length) {
|
|
734
|
+
write();
|
|
735
|
+
write(dim('revised'));
|
|
736
|
+
writeAll(textLast(d.revised.map((r) => [
|
|
737
|
+
` ${cyan(r.after.id)}`,
|
|
738
|
+
r.after.kind,
|
|
739
|
+
dim(`r${r.before.revision} → r${r.after.revision}`),
|
|
740
|
+
]), d.revised.map((r) => r.after.text)));
|
|
741
|
+
}
|
|
742
|
+
if (d.used.length) {
|
|
743
|
+
write();
|
|
744
|
+
write(dim('used — returned by memory_load'));
|
|
745
|
+
writeAll(textLast(d.used.map((u) => [` ${cyan(u.node.id)}`, u.node.kind, `${u.loads}×`]), d.used.map((u) => u.node.text)));
|
|
746
|
+
}
|
|
747
|
+
if (d.removed.length) {
|
|
748
|
+
write();
|
|
749
|
+
write(dim('removed'));
|
|
750
|
+
writeAll(textLast(d.removed.map((n) => [` ${cyan(n.id)}`, n.kind]), d.removed.map((n) => n.text)));
|
|
751
|
+
}
|
|
752
|
+
if (d.supersedes.length) {
|
|
753
|
+
write();
|
|
754
|
+
write(dim('supersedes'));
|
|
755
|
+
writeAll(table(d.supersedes.map((s) => [` ${cyan(s.source)}`, '→', cyan(s.target)])));
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
finally {
|
|
759
|
+
base.release();
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
// ---------------------------------------------------------------------------
|
|
656
763
|
// export
|
|
657
764
|
// ---------------------------------------------------------------------------
|
|
658
765
|
async function write_(o, rest, flags, cwd, asJson) {
|
|
@@ -661,13 +768,20 @@ async function write_(o, rest, flags, cwd, asJson) {
|
|
|
661
768
|
}
|
|
662
769
|
const named = rest[0] ?? flags.out ?? 'memory.html';
|
|
663
770
|
const target = isAbsolute(named) ? named : resolve(cwd, named);
|
|
664
|
-
const
|
|
771
|
+
const built = await buildMemoryReport(o.store, { title: `${o.project} · memory` });
|
|
772
|
+
const report = { ...built, nodes: built.nodes.map((n) => onHost(o, n)) };
|
|
665
773
|
await writeFile(target, renderMemoryHtml(report), 'utf8');
|
|
666
774
|
if (asJson) {
|
|
667
|
-
json({
|
|
775
|
+
json({
|
|
776
|
+
path: target,
|
|
777
|
+
from: o.dir,
|
|
778
|
+
nodes: report.nodes.length,
|
|
779
|
+
edges: report.edges.length,
|
|
780
|
+
});
|
|
668
781
|
}
|
|
669
782
|
else {
|
|
670
|
-
note(`${green('wrote')} ${target} ${dim(`· ${count(report.nodes.length, 'node')}, ${count(report.edges.length, 'edge')}`
|
|
783
|
+
note(`${green('wrote')} ${target} ${dim(`· ${count(report.nodes.length, 'node')}, ${count(report.edges.length, 'edge')}` +
|
|
784
|
+
` · from ${o.dir}`)}`);
|
|
671
785
|
}
|
|
672
786
|
if (flags.open) {
|
|
673
787
|
reveal(target);
|
|
@@ -720,7 +834,7 @@ async function merge(o, dirs, flags, cwd, asJson) {
|
|
|
720
834
|
}
|
|
721
835
|
catch (err) {
|
|
722
836
|
if (err instanceof MergeConflicts) {
|
|
723
|
-
throw diverged(err,
|
|
837
|
+
throw diverged(err, asJson);
|
|
724
838
|
}
|
|
725
839
|
throw err;
|
|
726
840
|
}
|
|
@@ -731,7 +845,7 @@ async function merge(o, dirs, flags, cwd, asJson) {
|
|
|
731
845
|
writeAll(table([
|
|
732
846
|
[dim('memory'), dim('nodes'), dim('new'), dim('shared'), dim('folded'), dim('files')],
|
|
733
847
|
...report.sources.map((s) => [
|
|
734
|
-
|
|
848
|
+
s.dir,
|
|
735
849
|
String(s.nodes),
|
|
736
850
|
s.added ? green(String(s.added)) : '0',
|
|
737
851
|
String(s.shared),
|
|
@@ -752,7 +866,7 @@ async function merge(o, dirs, flags, cwd, asJson) {
|
|
|
752
866
|
* point of stopping is that a person decides, and they cannot decide from a
|
|
753
867
|
* count.
|
|
754
868
|
*/
|
|
755
|
-
function diverged(err,
|
|
869
|
+
function diverged(err, asJson) {
|
|
756
870
|
if (asJson) {
|
|
757
871
|
json({ error: err.message, conflicts: err.conflicts });
|
|
758
872
|
}
|
|
@@ -761,7 +875,7 @@ function diverged(err, cwd, asJson) {
|
|
|
761
875
|
cyan(c.id),
|
|
762
876
|
dim(`r${c.mine} ↔ r${c.theirs}`),
|
|
763
877
|
clip(c.text, 48),
|
|
764
|
-
dim(
|
|
878
|
+
dim(c.dir),
|
|
765
879
|
])));
|
|
766
880
|
write();
|
|
767
881
|
}
|
|
@@ -818,9 +932,19 @@ function clip(text, n) {
|
|
|
818
932
|
const one = text.replace(/\s+/g, ' ').trim();
|
|
819
933
|
return one.length > n ? one.slice(0, n - 1) + '…' : one;
|
|
820
934
|
}
|
|
821
|
-
/**
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
935
|
+
/**
|
|
936
|
+
* A table whose last column is the text: cut to what the terminal has left,
|
|
937
|
+
* and whole when nobody is looking at a terminal — a pipe or an agent wants all of it.
|
|
938
|
+
*/
|
|
939
|
+
function textLast(rows, texts) {
|
|
940
|
+
const widths = rows[0]?.map((_, c) => Math.max(...rows.map((r) => plain(r[c] ?? '').length)));
|
|
941
|
+
const room = process.stdout.isTTY
|
|
942
|
+
? Math.max(24, (process.stdout.columns || 120) - (widths ?? []).reduce((t, w) => t + w + 2, 0))
|
|
943
|
+
: Infinity;
|
|
944
|
+
return table(rows.map((r, i) => [...r, clip(texts[i] ?? '', room)]));
|
|
945
|
+
}
|
|
946
|
+
/** The stored `/memory/<id>.<ext>` is the agent's mount path; a terminal needs the host one. */
|
|
947
|
+
function onHost(o, n) {
|
|
948
|
+
return n.file ? { ...n, file: { ...n.file, path: hostPath(o.dir, n.file) } } : n;
|
|
825
949
|
}
|
|
826
950
|
//# sourceMappingURL=memory.js.map
|