@hiveai/cli 0.2.4 → 0.2.6
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/Dashboard-SRPCHP7Z.js +194 -0
- package/dist/Dashboard-SRPCHP7Z.js.map +1 -0
- package/dist/index.js +249 -107
- package/dist/index.js.map +1 -1
- package/package.json +8 -3
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command26 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/briefing.ts
|
|
7
7
|
import { existsSync } from "fs";
|
|
@@ -54,7 +54,7 @@ function registerBriefing(program2) {
|
|
|
54
54
|
"--scope <scope>",
|
|
55
55
|
"personal | team | module | all (default: team)",
|
|
56
56
|
"team"
|
|
57
|
-
).option("--include-draft", "include draft memories (excluded by default)").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
57
|
+
).option("--include-draft", "include draft memories (excluded by default)").option("--include-stale", "include stale memories (excluded by default \u2014 may be outdated)").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
58
58
|
const root = findProjectRoot(opts.dir);
|
|
59
59
|
const paths = resolveHaivePaths(root);
|
|
60
60
|
if (existsSync(paths.projectContext)) {
|
|
@@ -78,6 +78,7 @@ function registerBriefing(program2) {
|
|
|
78
78
|
const fm = mem.frontmatter;
|
|
79
79
|
if (fm.status === "rejected" || fm.status === "deprecated") return false;
|
|
80
80
|
if (!opts.includeDraft && fm.status === "draft") return false;
|
|
81
|
+
if (!opts.includeStale && fm.status === "stale") return false;
|
|
81
82
|
if (scopeFilter !== "all" && fm.scope !== scopeFilter) return false;
|
|
82
83
|
return true;
|
|
83
84
|
});
|
|
@@ -108,8 +109,9 @@ function registerBriefing(program2) {
|
|
|
108
109
|
const fm = mem.frontmatter;
|
|
109
110
|
const badge = ui.statusBadge(fm.status);
|
|
110
111
|
const draftMarker = fm.status === "draft" ? ui.yellow(" [DRAFT]") : "";
|
|
112
|
+
const unverifiedMarker = fm.status === "proposed" ? ui.yellow(" [UNVERIFIED]") : "";
|
|
111
113
|
console.log(
|
|
112
|
-
`${ui.bold(fm.id)} ${ui.dim(fm.scope + "/" + fm.type)} ${badge}${draftMarker}`
|
|
114
|
+
`${ui.bold(fm.id)} ${ui.dim(fm.scope + "/" + fm.type)} ${badge}${draftMarker}${unverifiedMarker}`
|
|
113
115
|
);
|
|
114
116
|
console.log(mem.body.trim());
|
|
115
117
|
console.log();
|
|
@@ -122,15 +124,34 @@ function parseCsv(value) {
|
|
|
122
124
|
return value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
123
125
|
}
|
|
124
126
|
|
|
127
|
+
// src/commands/tui.ts
|
|
128
|
+
import "commander";
|
|
129
|
+
import { findProjectRoot as findProjectRoot2 } from "@hiveai/core";
|
|
130
|
+
function registerTui(program2) {
|
|
131
|
+
program2.command("tui").description("Interactive TUI dashboard \u2014 browse, filter, and manage memories in the terminal").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
132
|
+
if (!process.stdout.isTTY) {
|
|
133
|
+
console.error("haive tui requires an interactive terminal (TTY).");
|
|
134
|
+
process.exitCode = 1;
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const root = findProjectRoot2(opts.dir);
|
|
138
|
+
const { render } = await import("ink");
|
|
139
|
+
const { createElement } = await import("react");
|
|
140
|
+
const { Dashboard } = await import("./Dashboard-SRPCHP7Z.js");
|
|
141
|
+
const { waitUntilExit } = render(createElement(Dashboard, { root }));
|
|
142
|
+
await waitUntilExit();
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
125
146
|
// src/commands/embeddings.ts
|
|
126
147
|
import { existsSync as existsSync2 } from "fs";
|
|
127
148
|
import path from "path";
|
|
128
149
|
import "commander";
|
|
129
|
-
import { findProjectRoot as
|
|
150
|
+
import { findProjectRoot as findProjectRoot3, resolveHaivePaths as resolveHaivePaths2 } from "@hiveai/core";
|
|
130
151
|
function registerEmbeddings(program2) {
|
|
131
152
|
const embeddings = program2.command("embeddings").description("Manage local embeddings index for semantic search");
|
|
132
153
|
embeddings.command("index").description("Generate or refresh the embeddings index for all memories").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
133
|
-
const root =
|
|
154
|
+
const root = findProjectRoot3(opts.dir);
|
|
134
155
|
const paths = resolveHaivePaths2(root);
|
|
135
156
|
if (!existsSync2(paths.memoriesDir)) {
|
|
136
157
|
ui.error(`No .ai/memories at ${root}. Run \`haive init\` first.`);
|
|
@@ -147,7 +168,7 @@ function registerEmbeddings(program2) {
|
|
|
147
168
|
);
|
|
148
169
|
});
|
|
149
170
|
embeddings.command("query <text>").description("Run a semantic search against the local embeddings index").option("-d, --dir <dir>", "project root").option("--limit <n>", "max results", "10").option("--min-score <n>", "minimum cosine similarity (0-1)", "0").action(async (text, opts) => {
|
|
150
|
-
const root =
|
|
171
|
+
const root = findProjectRoot3(opts.dir);
|
|
151
172
|
const paths = resolveHaivePaths2(root);
|
|
152
173
|
const { semanticSearch } = await loadEmbeddings();
|
|
153
174
|
const result = await semanticSearch(paths, text, {
|
|
@@ -170,7 +191,7 @@ function registerEmbeddings(program2) {
|
|
|
170
191
|
}
|
|
171
192
|
});
|
|
172
193
|
embeddings.command("status").description("Show the embeddings index status").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
173
|
-
const root =
|
|
194
|
+
const root = findProjectRoot3(opts.dir);
|
|
174
195
|
const paths = resolveHaivePaths2(root);
|
|
175
196
|
const { indexStat } = await loadEmbeddings();
|
|
176
197
|
const stat = await indexStat(paths);
|
|
@@ -201,7 +222,7 @@ import "commander";
|
|
|
201
222
|
import {
|
|
202
223
|
buildCodeMap,
|
|
203
224
|
codeMapPath,
|
|
204
|
-
findProjectRoot as
|
|
225
|
+
findProjectRoot as findProjectRoot4,
|
|
205
226
|
resolveHaivePaths as resolveHaivePaths3,
|
|
206
227
|
saveCodeMap
|
|
207
228
|
} from "@hiveai/core";
|
|
@@ -213,7 +234,7 @@ function registerIndexCode(program2) {
|
|
|
213
234
|
"extra directory names to skip (comma-separated)",
|
|
214
235
|
""
|
|
215
236
|
).action(async (opts) => {
|
|
216
|
-
const root =
|
|
237
|
+
const root = findProjectRoot4(opts.dir);
|
|
217
238
|
const paths = resolveHaivePaths3(root);
|
|
218
239
|
const extraExcludes = (opts.exclude ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
219
240
|
ui.info(`Indexing source files in ${root}\u2026`);
|
|
@@ -311,7 +332,7 @@ import { mkdir as mkdir2, writeFile as writeFile2, chmod, readFile as readFile2
|
|
|
311
332
|
import { existsSync as existsSync4 } from "fs";
|
|
312
333
|
import path4 from "path";
|
|
313
334
|
import "commander";
|
|
314
|
-
import { findProjectRoot as
|
|
335
|
+
import { findProjectRoot as findProjectRoot6 } from "@hiveai/core";
|
|
315
336
|
var HOOK_MARKER = "# hAIve auto-generated";
|
|
316
337
|
var HOOK_BODY = `#!/bin/sh
|
|
317
338
|
${HOOK_MARKER} \u2014 keep this block to allow upgrades. Hand-edit anything outside it.
|
|
@@ -327,7 +348,7 @@ fi
|
|
|
327
348
|
var HOOKS = ["post-merge", "post-rewrite"];
|
|
328
349
|
function registerInstallHooks(program2) {
|
|
329
350
|
program2.command("install-hooks").description("Install git hooks that run `haive sync` after pull/merge").option("-d, --dir <dir>", "project root").option("--force", "overwrite existing hooks").action(async (opts) => {
|
|
330
|
-
const root =
|
|
351
|
+
const root = findProjectRoot6(opts.dir);
|
|
331
352
|
const gitDir = path4.join(root, ".git");
|
|
332
353
|
if (!existsSync4(gitDir)) {
|
|
333
354
|
ui.error(`No .git directory at ${root}.`);
|
|
@@ -364,11 +385,11 @@ import { createRequire } from "module";
|
|
|
364
385
|
import path5 from "path";
|
|
365
386
|
import { fileURLToPath } from "url";
|
|
366
387
|
import "commander";
|
|
367
|
-
import { findProjectRoot as
|
|
388
|
+
import { findProjectRoot as findProjectRoot7 } from "@hiveai/core";
|
|
368
389
|
var require2 = createRequire(import.meta.url);
|
|
369
390
|
function registerMcp(program2) {
|
|
370
391
|
program2.command("mcp").description("Start the hAIve MCP server (stdio transport)").option("-d, --dir <dir>", "project root (defaults to nearest .ai/ or .git/)").action((opts) => {
|
|
371
|
-
const root =
|
|
392
|
+
const root = findProjectRoot7(opts.dir);
|
|
372
393
|
const bin = locateMcpBin();
|
|
373
394
|
if (!bin) {
|
|
374
395
|
ui.error(
|
|
@@ -399,13 +420,13 @@ function locateMcpBin() {
|
|
|
399
420
|
|
|
400
421
|
// src/commands/sync.ts
|
|
401
422
|
import { spawnSync } from "child_process";
|
|
402
|
-
import { writeFile as writeFile3 } from "fs/promises";
|
|
423
|
+
import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
403
424
|
import { existsSync as existsSync6 } from "fs";
|
|
404
|
-
import "path";
|
|
425
|
+
import path6 from "path";
|
|
405
426
|
import "commander";
|
|
406
427
|
import {
|
|
407
428
|
DEFAULT_AUTO_PROMOTE_RULE,
|
|
408
|
-
findProjectRoot as
|
|
429
|
+
findProjectRoot as findProjectRoot8,
|
|
409
430
|
getUsage,
|
|
410
431
|
isAutoPromoteEligible,
|
|
411
432
|
loadMemoriesFromDir as loadMemoriesFromDir2,
|
|
@@ -414,12 +435,17 @@ import {
|
|
|
414
435
|
serializeMemory,
|
|
415
436
|
verifyAnchor
|
|
416
437
|
} from "@hiveai/core";
|
|
438
|
+
var BRIDGE_START = "<!-- haive:memories-start -->";
|
|
439
|
+
var BRIDGE_END = "<!-- haive:memories-end -->";
|
|
417
440
|
function registerSync(program2) {
|
|
418
441
|
program2.command("sync").description("Refresh memory state after a pull/merge: verify anchors, auto-promote, report changes").option("-d, --dir <dir>", "project root").option("--quiet", "minimal output (suitable for git hooks)").option(
|
|
419
442
|
"--since <ref>",
|
|
420
443
|
"git ref/commit to compare against; report memories added/modified/removed since"
|
|
421
|
-
).option("--no-verify", "skip the anchor verification step").option("--no-promote", "skip the auto-promotion step").
|
|
422
|
-
|
|
444
|
+
).option("--no-verify", "skip the anchor verification step").option("--no-promote", "skip the auto-promotion step").option(
|
|
445
|
+
"--inject-bridge",
|
|
446
|
+
"inject top validated memories into CLAUDE.md (or --bridge-file) between <!-- haive:memories-start/end --> markers"
|
|
447
|
+
).option("--bridge-file <path>", "bridge file to inject into (default: CLAUDE.md)").option("--bridge-max-memories <n>", "max memories to inject into bridge file", "5").action(async (opts) => {
|
|
448
|
+
const root = findProjectRoot8(opts.dir);
|
|
423
449
|
const paths = resolveHaivePaths5(root);
|
|
424
450
|
if (!existsSync6(paths.memoriesDir)) {
|
|
425
451
|
if (!opts.quiet) ui.warn(`No .ai/memories at ${root}. Run \`haive init\` first.`);
|
|
@@ -510,6 +536,11 @@ function registerSync(program2) {
|
|
|
510
536
|
)
|
|
511
537
|
);
|
|
512
538
|
}
|
|
539
|
+
if (opts.injectBridge) {
|
|
540
|
+
const bridgeFile = opts.bridgeFile ? path6.resolve(opts.bridgeFile) : path6.join(root, "CLAUDE.md");
|
|
541
|
+
const maxInject = Math.max(1, Number(opts.bridgeMaxMemories ?? 5));
|
|
542
|
+
await injectBridge(bridgeFile, paths.memoriesDir, maxInject, root, opts.quiet);
|
|
543
|
+
}
|
|
513
544
|
if (sinceReport && !opts.quiet) {
|
|
514
545
|
if (sinceReport.added.length > 0) {
|
|
515
546
|
log(ui.bold("\nNew memories:"));
|
|
@@ -526,6 +557,47 @@ function registerSync(program2) {
|
|
|
526
557
|
}
|
|
527
558
|
});
|
|
528
559
|
}
|
|
560
|
+
async function injectBridge(bridgeFile, memoriesDir, maxMemories, root, quiet) {
|
|
561
|
+
if (!existsSync6(memoriesDir)) return;
|
|
562
|
+
const all = await loadMemoriesFromDir2(memoriesDir);
|
|
563
|
+
const top = all.filter(({ memory: memory2 }) => {
|
|
564
|
+
const s = memory2.frontmatter.status;
|
|
565
|
+
return s === "validated" || s === "proposed";
|
|
566
|
+
}).sort((a, b) => {
|
|
567
|
+
const score = (m) => {
|
|
568
|
+
const s = m.memory.frontmatter.status;
|
|
569
|
+
return s === "validated" ? 2 : 1;
|
|
570
|
+
};
|
|
571
|
+
return score(b) - score(a);
|
|
572
|
+
}).slice(0, maxMemories);
|
|
573
|
+
const block = top.map((m) => {
|
|
574
|
+
const fm = m.memory.frontmatter;
|
|
575
|
+
const unverified = fm.status === "proposed" ? " [UNVERIFIED]" : "";
|
|
576
|
+
return `### ${fm.id} (${fm.scope}/${fm.type})${unverified}
|
|
577
|
+
${m.memory.body.trim()}`;
|
|
578
|
+
}).join("\n\n---\n\n");
|
|
579
|
+
const injected = `${BRIDGE_START}
|
|
580
|
+
<!-- AUTO-GENERATED by haive sync --inject-bridge \u2014 do not edit between these markers -->
|
|
581
|
+
|
|
582
|
+
` + block + `
|
|
583
|
+
|
|
584
|
+
${BRIDGE_END}`;
|
|
585
|
+
let existing = existsSync6(bridgeFile) ? await readFile3(bridgeFile, "utf8") : "";
|
|
586
|
+
const startIdx = existing.indexOf(BRIDGE_START);
|
|
587
|
+
const endIdx = existing.indexOf(BRIDGE_END);
|
|
588
|
+
let updated;
|
|
589
|
+
if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
|
|
590
|
+
updated = existing.slice(0, startIdx) + injected + existing.slice(endIdx + BRIDGE_END.length);
|
|
591
|
+
} else {
|
|
592
|
+
updated = existing + (existing.endsWith("\n") ? "" : "\n") + "\n" + injected + "\n";
|
|
593
|
+
}
|
|
594
|
+
await writeFile3(bridgeFile, updated, "utf8");
|
|
595
|
+
if (!quiet) {
|
|
596
|
+
console.log(
|
|
597
|
+
ui.dim(`bridge: injected ${top.length} memor${top.length === 1 ? "y" : "ies"} into ${path6.relative(root, bridgeFile)}`)
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
529
601
|
function collectSinceChanges(root, ref) {
|
|
530
602
|
const result = spawnSync(
|
|
531
603
|
"git",
|
|
@@ -552,15 +624,15 @@ import path7 from "path";
|
|
|
552
624
|
import "commander";
|
|
553
625
|
import {
|
|
554
626
|
buildFrontmatter,
|
|
555
|
-
findProjectRoot as
|
|
627
|
+
findProjectRoot as findProjectRoot9,
|
|
556
628
|
inferModulesFromPaths,
|
|
557
629
|
memoryFilePath,
|
|
558
630
|
resolveHaivePaths as resolveHaivePaths6,
|
|
559
631
|
serializeMemory as serializeMemory2
|
|
560
632
|
} from "@hiveai/core";
|
|
561
633
|
function registerMemoryAdd(memory2) {
|
|
562
|
-
memory2.command("add").description("Add a new memory (defaults to personal scope)").requiredOption("--type <type>", "convention | decision | gotcha | architecture | glossary").requiredOption("--slug <slug>", "short identifier used in the file name").option("--title <text>", "memory title \u2014 becomes the first heading of the body").option("--scope <scope>", "personal | team | module", "personal").option("--module <name>", "module name (required when scope=module)").option("--tags <csv>", "comma-separated tags").option("--domain <domain>", "domain (e.g. transactions)").option("--author <author>", "author email or handle").option("--paths <csv>", "anchor paths, comma-separated").option("--symbols <csv>", "anchor symbols, comma-separated").option("--commit <sha>", "anchor commit SHA").option("--body <text>", "memory body content (Markdown) \u2014 overrides --title default body").option("--no-auto-tag", "disable automatic tag suggestions inferred from anchor paths").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
563
|
-
const root =
|
|
634
|
+
memory2.command("add").description("Add a new memory (defaults to personal scope)").requiredOption("--type <type>", "convention | decision | gotcha | architecture | glossary | attempt").requiredOption("--slug <slug>", "short identifier used in the file name").option("--title <text>", "memory title \u2014 becomes the first heading of the body").option("--scope <scope>", "personal | team | module", "personal").option("--module <name>", "module name (required when scope=module)").option("--tags <csv>", "comma-separated tags").option("--domain <domain>", "domain (e.g. transactions)").option("--author <author>", "author email or handle").option("--paths <csv>", "anchor paths, comma-separated").option("--symbols <csv>", "anchor symbols, comma-separated").option("--commit <sha>", "anchor commit SHA").option("--body <text>", "memory body content (Markdown) \u2014 overrides --title default body").option("--no-auto-tag", "disable automatic tag suggestions inferred from anchor paths").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
635
|
+
const root = findProjectRoot9(opts.dir);
|
|
564
636
|
const paths = resolveHaivePaths6(root);
|
|
565
637
|
if (!existsSync7(paths.haiveDir)) {
|
|
566
638
|
ui.error(`No .ai/ found at ${root}. Run \`haive init\` first.`);
|
|
@@ -631,7 +703,7 @@ function parseCsv2(value) {
|
|
|
631
703
|
import { existsSync as existsSync8 } from "fs";
|
|
632
704
|
import path8 from "path";
|
|
633
705
|
import "commander";
|
|
634
|
-
import { findProjectRoot as
|
|
706
|
+
import { findProjectRoot as findProjectRoot10, resolveHaivePaths as resolveHaivePaths7 } from "@hiveai/core";
|
|
635
707
|
|
|
636
708
|
// src/utils/fs.ts
|
|
637
709
|
import {
|
|
@@ -643,7 +715,7 @@ import {
|
|
|
643
715
|
// src/commands/memory-list.ts
|
|
644
716
|
function registerMemoryList(memory2) {
|
|
645
717
|
memory2.command("list").description("List memories with optional filters").option("--scope <scope>", "personal | team | module").option("--type <type>", "filter by type").option("--tag <tag>", "filter by tag").option("--module <name>", "filter by module name").option("--status <csv>", "filter by status (draft,proposed,validated,stale,rejected,deprecated)").option("--show-rejected", "include rejected memories (hidden by default)").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
646
|
-
const root =
|
|
718
|
+
const root = findProjectRoot10(opts.dir);
|
|
647
719
|
const paths = resolveHaivePaths7(root);
|
|
648
720
|
if (!existsSync8(paths.memoriesDir)) {
|
|
649
721
|
ui.error(`No memories directory at ${paths.memoriesDir}. Run \`haive init\` first.`);
|
|
@@ -717,14 +789,14 @@ import { existsSync as existsSync9 } from "fs";
|
|
|
717
789
|
import path9 from "path";
|
|
718
790
|
import "commander";
|
|
719
791
|
import {
|
|
720
|
-
findProjectRoot as
|
|
792
|
+
findProjectRoot as findProjectRoot11,
|
|
721
793
|
memoryFilePath as memoryFilePath2,
|
|
722
794
|
resolveHaivePaths as resolveHaivePaths8,
|
|
723
795
|
serializeMemory as serializeMemory3
|
|
724
796
|
} from "@hiveai/core";
|
|
725
797
|
function registerMemoryPromote(memory2) {
|
|
726
798
|
memory2.command("promote <id>").description("Promote a personal memory to team scope (status -> proposed)").option("-d, --dir <dir>", "project root").action(async (id, opts) => {
|
|
727
|
-
const root =
|
|
799
|
+
const root = findProjectRoot11(opts.dir);
|
|
728
800
|
const paths = resolveHaivePaths8(root);
|
|
729
801
|
if (!existsSync9(paths.memoriesDir)) {
|
|
730
802
|
ui.error(`No memories directory at ${paths.memoriesDir}. Run \`haive init\` first.`);
|
|
@@ -776,13 +848,13 @@ import { writeFile as writeFile6 } from "fs/promises";
|
|
|
776
848
|
import path10 from "path";
|
|
777
849
|
import "commander";
|
|
778
850
|
import {
|
|
779
|
-
findProjectRoot as
|
|
851
|
+
findProjectRoot as findProjectRoot12,
|
|
780
852
|
resolveHaivePaths as resolveHaivePaths9,
|
|
781
853
|
serializeMemory as serializeMemory4
|
|
782
854
|
} from "@hiveai/core";
|
|
783
855
|
function registerMemoryApprove(memory2) {
|
|
784
856
|
memory2.command("approve [id]").description("Mark a memory as 'validated'. Use --all to bulk-approve all proposed/draft memories.").option("--all", "approve all proposed and draft memories at once").option("--pending", "approve all memories with status 'proposed'").option("-d, --dir <dir>", "project root").action(async (id, opts) => {
|
|
785
|
-
const root =
|
|
857
|
+
const root = findProjectRoot12(opts.dir);
|
|
786
858
|
const paths = resolveHaivePaths9(root);
|
|
787
859
|
if (!existsSync10(paths.memoriesDir)) {
|
|
788
860
|
ui.error(`No .ai/memories at ${root}.`);
|
|
@@ -847,13 +919,13 @@ import { existsSync as existsSync11 } from "fs";
|
|
|
847
919
|
import path11 from "path";
|
|
848
920
|
import "commander";
|
|
849
921
|
import {
|
|
850
|
-
findProjectRoot as
|
|
922
|
+
findProjectRoot as findProjectRoot13,
|
|
851
923
|
resolveHaivePaths as resolveHaivePaths10,
|
|
852
924
|
serializeMemory as serializeMemory5
|
|
853
925
|
} from "@hiveai/core";
|
|
854
926
|
function registerMemoryUpdate(memory2) {
|
|
855
927
|
memory2.command("update <id>").description("Update body, tags, or anchor of an existing memory (preserves id and usage history)").option("--title <text>", "new title \u2014 replaces the first heading of the body").option("--body <text>", "new Markdown body \u2014 replaces the existing body").option("--tags <csv>", "new tags, comma-separated \u2014 fully replaces existing tags").option("--paths <csv>", "new anchor paths, comma-separated").option("--symbols <csv>", "new anchor symbols, comma-separated").option("--commit <sha>", "new anchor commit SHA").option("--domain <domain>", "new domain label").option("--author <author>", "new author handle or email").option("-d, --dir <dir>", "project root").action(async (id, opts) => {
|
|
856
|
-
const root =
|
|
928
|
+
const root = findProjectRoot13(opts.dir);
|
|
857
929
|
const paths = resolveHaivePaths10(root);
|
|
858
930
|
if (!existsSync11(paths.memoriesDir)) {
|
|
859
931
|
ui.error(`No .ai/memories at ${root}. Run \`haive init\` first.`);
|
|
@@ -932,7 +1004,7 @@ import path12 from "path";
|
|
|
932
1004
|
import "commander";
|
|
933
1005
|
import {
|
|
934
1006
|
DEFAULT_AUTO_PROMOTE_RULE as DEFAULT_AUTO_PROMOTE_RULE2,
|
|
935
|
-
findProjectRoot as
|
|
1007
|
+
findProjectRoot as findProjectRoot14,
|
|
936
1008
|
getUsage as getUsage2,
|
|
937
1009
|
isAutoPromoteEligible as isAutoPromoteEligible2,
|
|
938
1010
|
loadUsageIndex as loadUsageIndex2,
|
|
@@ -945,7 +1017,7 @@ function registerMemoryAutoPromote(memory2) {
|
|
|
945
1017
|
"memories with more rejections than this are skipped",
|
|
946
1018
|
String(DEFAULT_AUTO_PROMOTE_RULE2.maxRejections)
|
|
947
1019
|
).option("--apply", "actually write status=validated to disk (default: dry-run)").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
948
|
-
const root =
|
|
1020
|
+
const root = findProjectRoot14(opts.dir);
|
|
949
1021
|
const paths = resolveHaivePaths11(root);
|
|
950
1022
|
if (!existsSync12(paths.memoriesDir)) {
|
|
951
1023
|
ui.error(`No .ai/memories at ${root}.`);
|
|
@@ -991,17 +1063,17 @@ function registerMemoryAutoPromote(memory2) {
|
|
|
991
1063
|
// src/commands/memory-edit.ts
|
|
992
1064
|
import { spawn as spawn2 } from "child_process";
|
|
993
1065
|
import { existsSync as existsSync13 } from "fs";
|
|
994
|
-
import { readFile as
|
|
1066
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
995
1067
|
import path13 from "path";
|
|
996
1068
|
import "commander";
|
|
997
1069
|
import {
|
|
998
|
-
findProjectRoot as
|
|
1070
|
+
findProjectRoot as findProjectRoot15,
|
|
999
1071
|
parseMemory,
|
|
1000
1072
|
resolveHaivePaths as resolveHaivePaths12
|
|
1001
1073
|
} from "@hiveai/core";
|
|
1002
1074
|
function registerMemoryEdit(memory2) {
|
|
1003
1075
|
memory2.command("edit <id>").description("Open a memory in $EDITOR and re-validate when you save").option("-e, --editor <cmd>", "editor command (defaults to $EDITOR or 'vi')").option("-d, --dir <dir>", "project root").action(async (id, opts) => {
|
|
1004
|
-
const root =
|
|
1076
|
+
const root = findProjectRoot15(opts.dir);
|
|
1005
1077
|
const paths = resolveHaivePaths12(root);
|
|
1006
1078
|
if (!existsSync13(paths.memoriesDir)) {
|
|
1007
1079
|
ui.error(`No .ai/memories at ${root}.`);
|
|
@@ -1022,7 +1094,7 @@ function registerMemoryEdit(memory2) {
|
|
|
1022
1094
|
ui.warn(`Editor exited with status ${code}.`);
|
|
1023
1095
|
}
|
|
1024
1096
|
try {
|
|
1025
|
-
const fresh = await
|
|
1097
|
+
const fresh = await readFile4(found.filePath, "utf8");
|
|
1026
1098
|
parseMemory(fresh);
|
|
1027
1099
|
ui.success("Memory still parses cleanly.");
|
|
1028
1100
|
} catch (err) {
|
|
@@ -1048,7 +1120,7 @@ import path14 from "path";
|
|
|
1048
1120
|
import "commander";
|
|
1049
1121
|
import {
|
|
1050
1122
|
deriveConfidence,
|
|
1051
|
-
findProjectRoot as
|
|
1123
|
+
findProjectRoot as findProjectRoot16,
|
|
1052
1124
|
getUsage as getUsage3,
|
|
1053
1125
|
inferModulesFromPaths as inferModulesFromPaths2,
|
|
1054
1126
|
loadUsageIndex as loadUsageIndex3,
|
|
@@ -1057,7 +1129,7 @@ import {
|
|
|
1057
1129
|
} from "@hiveai/core";
|
|
1058
1130
|
function registerMemoryForFiles(memory2) {
|
|
1059
1131
|
memory2.command("for-files <files...>").description("Show memories relevant to the given files (anchor overlap, module, domain)").option("-d, --dir <dir>", "project root").action(async (files, opts) => {
|
|
1060
|
-
const root =
|
|
1132
|
+
const root = findProjectRoot16(opts.dir);
|
|
1061
1133
|
const paths = resolveHaivePaths13(root);
|
|
1062
1134
|
if (!existsSync14(paths.memoriesDir)) {
|
|
1063
1135
|
ui.error(`No .ai/memories at ${root}.`);
|
|
@@ -1121,14 +1193,14 @@ import { existsSync as existsSync15 } from "fs";
|
|
|
1121
1193
|
import path15 from "path";
|
|
1122
1194
|
import "commander";
|
|
1123
1195
|
import {
|
|
1124
|
-
findProjectRoot as
|
|
1196
|
+
findProjectRoot as findProjectRoot17,
|
|
1125
1197
|
getUsage as getUsage4,
|
|
1126
1198
|
loadUsageIndex as loadUsageIndex4,
|
|
1127
1199
|
resolveHaivePaths as resolveHaivePaths14
|
|
1128
1200
|
} from "@hiveai/core";
|
|
1129
1201
|
function registerMemoryHot(memory2) {
|
|
1130
1202
|
memory2.command("hot").description("List memories actively used but not yet validated (good promotion candidates)").option("--threshold <n>", "minimum read_count to qualify", "3").option("--status <status>", "limit to one status (default: draft + proposed)").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
1131
|
-
const root =
|
|
1203
|
+
const root = findProjectRoot17(opts.dir);
|
|
1132
1204
|
const paths = resolveHaivePaths14(root);
|
|
1133
1205
|
if (!existsSync15(paths.memoriesDir)) {
|
|
1134
1206
|
ui.error(`No .ai/memories at ${root}.`);
|
|
@@ -1166,21 +1238,78 @@ function registerMemoryHot(memory2) {
|
|
|
1166
1238
|
});
|
|
1167
1239
|
}
|
|
1168
1240
|
|
|
1169
|
-
// src/commands/memory-
|
|
1241
|
+
// src/commands/memory-tried.ts
|
|
1242
|
+
import { mkdir as mkdir5, writeFile as writeFile9 } from "fs/promises";
|
|
1170
1243
|
import { existsSync as existsSync16 } from "fs";
|
|
1171
1244
|
import path16 from "path";
|
|
1172
1245
|
import "commander";
|
|
1173
1246
|
import {
|
|
1174
|
-
|
|
1247
|
+
buildFrontmatter as buildFrontmatter2,
|
|
1248
|
+
findProjectRoot as findProjectRoot18,
|
|
1249
|
+
memoryFilePath as memoryFilePath3,
|
|
1250
|
+
resolveHaivePaths as resolveHaivePaths15,
|
|
1251
|
+
serializeMemory as serializeMemory7
|
|
1252
|
+
} from "@hiveai/core";
|
|
1253
|
+
function registerMemoryTried(memory2) {
|
|
1254
|
+
memory2.command("tried").description(
|
|
1255
|
+
"Record a failed approach \u2014 negative knowledge to prevent repeated AI mistakes"
|
|
1256
|
+
).requiredOption("--what <text>", "what approach was tried").requiredOption("--why-failed <text>", "why it failed or should NOT be used").option("--instead <text>", "recommended alternative").option("--scope <scope>", "personal | team | module", "personal").option("--module <name>", "module name (required when scope=module)").option("--tags <csv>", "comma-separated tags").option("--paths <csv>", "anchor paths, comma-separated").option("--author <author>", "author email or handle").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
1257
|
+
const root = findProjectRoot18(opts.dir);
|
|
1258
|
+
const paths = resolveHaivePaths15(root);
|
|
1259
|
+
if (!existsSync16(paths.haiveDir)) {
|
|
1260
|
+
ui.error(`No .ai/ found at ${root}. Run \`haive init\` first.`);
|
|
1261
|
+
process.exitCode = 1;
|
|
1262
|
+
return;
|
|
1263
|
+
}
|
|
1264
|
+
const slug = opts.what.toLowerCase().replace(/[^a-z0-9\s]/g, "").trim().split(/\s+/).slice(0, 5).join("-");
|
|
1265
|
+
const baseFm = buildFrontmatter2({
|
|
1266
|
+
type: "attempt",
|
|
1267
|
+
slug,
|
|
1268
|
+
scope: opts.scope,
|
|
1269
|
+
module: opts.module,
|
|
1270
|
+
tags: parseCsv4(opts.tags),
|
|
1271
|
+
paths: parseCsv4(opts.paths),
|
|
1272
|
+
author: opts.author
|
|
1273
|
+
});
|
|
1274
|
+
const frontmatter = { ...baseFm, status: "validated" };
|
|
1275
|
+
const lines = [`# ${opts.what}`, ""];
|
|
1276
|
+
lines.push(`**Why it failed / do NOT use:** ${opts.whyFailed}`);
|
|
1277
|
+
if (opts.instead) {
|
|
1278
|
+
lines.push("", `**Instead, use:** ${opts.instead}`);
|
|
1279
|
+
}
|
|
1280
|
+
const body = lines.join("\n") + "\n";
|
|
1281
|
+
const file = memoryFilePath3(paths, frontmatter.scope, frontmatter.id, frontmatter.module);
|
|
1282
|
+
await mkdir5(path16.dirname(file), { recursive: true });
|
|
1283
|
+
if (existsSync16(file)) {
|
|
1284
|
+
ui.error(`Memory already exists at ${file}`);
|
|
1285
|
+
process.exitCode = 1;
|
|
1286
|
+
return;
|
|
1287
|
+
}
|
|
1288
|
+
await writeFile9(file, serializeMemory7({ frontmatter, body }), "utf8");
|
|
1289
|
+
ui.success(`Recorded: ${path16.relative(root, file)}`);
|
|
1290
|
+
ui.info(`id=${frontmatter.id} type=attempt status=validated (auto-approved)`);
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1293
|
+
function parseCsv4(value) {
|
|
1294
|
+
if (!value) return [];
|
|
1295
|
+
return value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
// src/commands/memory-pending.ts
|
|
1299
|
+
import { existsSync as existsSync17 } from "fs";
|
|
1300
|
+
import path17 from "path";
|
|
1301
|
+
import "commander";
|
|
1302
|
+
import {
|
|
1303
|
+
findProjectRoot as findProjectRoot19,
|
|
1175
1304
|
getUsage as getUsage5,
|
|
1176
1305
|
loadUsageIndex as loadUsageIndex5,
|
|
1177
|
-
resolveHaivePaths as
|
|
1306
|
+
resolveHaivePaths as resolveHaivePaths16
|
|
1178
1307
|
} from "@hiveai/core";
|
|
1179
1308
|
function registerMemoryPending(memory2) {
|
|
1180
1309
|
memory2.command("pending").description("List 'proposed' memories awaiting review (sorted by reads desc)").option("--scope <scope>", "filter by scope (personal | team | module)").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
1181
|
-
const root =
|
|
1182
|
-
const paths =
|
|
1183
|
-
if (!
|
|
1310
|
+
const root = findProjectRoot19(opts.dir);
|
|
1311
|
+
const paths = resolveHaivePaths16(root);
|
|
1312
|
+
if (!existsSync17(paths.memoriesDir)) {
|
|
1184
1313
|
ui.error(`No .ai/memories at ${root}.`);
|
|
1185
1314
|
process.exitCode = 1;
|
|
1186
1315
|
return;
|
|
@@ -1208,29 +1337,30 @@ function registerMemoryPending(memory2) {
|
|
|
1208
1337
|
console.log(
|
|
1209
1338
|
`${ui.bold(fm.id)} ${ui.dim(`${fm.scope}/${fm.type}`)} ${ui.dim(`age=${ageStr} reads=${u.read_count} rejections=${u.rejected_count}`)}`
|
|
1210
1339
|
);
|
|
1211
|
-
console.log(` ${ui.dim(
|
|
1340
|
+
console.log(` ${ui.dim(path17.relative(root, filePath))}`);
|
|
1212
1341
|
}
|
|
1213
1342
|
ui.info(`${proposed.length} pending`);
|
|
1214
1343
|
});
|
|
1215
1344
|
}
|
|
1216
1345
|
|
|
1217
1346
|
// src/commands/memory-query.ts
|
|
1218
|
-
import { existsSync as
|
|
1219
|
-
import
|
|
1347
|
+
import { existsSync as existsSync18 } from "fs";
|
|
1348
|
+
import path18 from "path";
|
|
1220
1349
|
import "commander";
|
|
1221
1350
|
import {
|
|
1222
1351
|
extractSnippet,
|
|
1223
|
-
findProjectRoot as
|
|
1352
|
+
findProjectRoot as findProjectRoot20,
|
|
1224
1353
|
literalMatchesAllTokens as literalMatchesAllTokens2,
|
|
1354
|
+
literalMatchesAnyToken,
|
|
1225
1355
|
pickSnippetNeedle,
|
|
1226
|
-
resolveHaivePaths as
|
|
1356
|
+
resolveHaivePaths as resolveHaivePaths17,
|
|
1227
1357
|
tokenizeQuery as tokenizeQuery2
|
|
1228
1358
|
} from "@hiveai/core";
|
|
1229
1359
|
function registerMemoryQuery(memory2) {
|
|
1230
|
-
memory2.command("query <text>").description("Search memories by id, tag, or substring (
|
|
1231
|
-
const root =
|
|
1232
|
-
const paths =
|
|
1233
|
-
if (!
|
|
1360
|
+
memory2.command("query <text>").description("Search memories by id, tag, or substring (AND, OR fallback)").option("-d, --dir <dir>", "project root").option("--limit <n>", "max results", "20").option("--scope <scope>", "personal | team | module").option("--status <csv>", "filter by status (draft,proposed,validated,stale,rejected)").option("--show-rejected", "include rejected memories (hidden by default)").action(async (text, opts) => {
|
|
1361
|
+
const root = findProjectRoot20(opts.dir);
|
|
1362
|
+
const paths = resolveHaivePaths17(root);
|
|
1363
|
+
if (!existsSync18(paths.memoriesDir)) {
|
|
1234
1364
|
ui.error(`No memories directory at ${paths.memoriesDir}. Run \`haive init\` first.`);
|
|
1235
1365
|
process.exitCode = 1;
|
|
1236
1366
|
return;
|
|
@@ -1238,25 +1368,35 @@ function registerMemoryQuery(memory2) {
|
|
|
1238
1368
|
const tokens = tokenizeQuery2(text);
|
|
1239
1369
|
const statusFilter = opts.status ? opts.status.split(",").map((s) => s.trim()) : null;
|
|
1240
1370
|
const all = await loadMemoriesFromDir3(paths.memoriesDir);
|
|
1241
|
-
const
|
|
1371
|
+
const passesFilters = (mem) => {
|
|
1242
1372
|
const fm = mem.frontmatter;
|
|
1243
1373
|
if (opts.scope && fm.scope !== opts.scope) return false;
|
|
1244
1374
|
if (!opts.showRejected && !statusFilter && fm.status === "rejected") return false;
|
|
1245
1375
|
if (statusFilter && !statusFilter.includes(fm.status)) return false;
|
|
1246
|
-
return
|
|
1247
|
-
}
|
|
1376
|
+
return true;
|
|
1377
|
+
};
|
|
1378
|
+
const eligible = all.filter(({ memory: mem }) => passesFilters(mem));
|
|
1379
|
+
let matches = eligible.filter(({ memory: mem }) => literalMatchesAllTokens2(mem, tokens));
|
|
1380
|
+
let fallback = false;
|
|
1381
|
+
if (matches.length === 0 && tokens.length > 1) {
|
|
1382
|
+
matches = eligible.filter(({ memory: mem }) => literalMatchesAnyToken(mem, tokens));
|
|
1383
|
+
fallback = true;
|
|
1384
|
+
}
|
|
1248
1385
|
const limit = Math.max(1, Number(opts.limit ?? 20));
|
|
1249
1386
|
const top = matches.slice(0, limit);
|
|
1250
1387
|
if (top.length === 0) {
|
|
1251
1388
|
ui.info(`No matches for "${text}".`);
|
|
1252
1389
|
return;
|
|
1253
1390
|
}
|
|
1391
|
+
if (fallback) {
|
|
1392
|
+
ui.info(`No exact match \u2014 showing partial results (OR fallback):`);
|
|
1393
|
+
}
|
|
1254
1394
|
const snippetNeedle = pickSnippetNeedle(text);
|
|
1255
1395
|
for (const { memory: mem, filePath } of top) {
|
|
1256
1396
|
const fm = mem.frontmatter;
|
|
1257
1397
|
const statusBadge = ui.statusBadge(fm.status);
|
|
1258
1398
|
console.log(`${ui.bold(fm.id)} ${ui.dim(fm.scope)} ${statusBadge}`);
|
|
1259
|
-
console.log(` ${ui.dim(
|
|
1399
|
+
console.log(` ${ui.dim(path18.relative(root, filePath))}`);
|
|
1260
1400
|
const snippet = extractSnippet(mem.body, snippetNeedle);
|
|
1261
1401
|
if (snippet) console.log(` ${snippet}`);
|
|
1262
1402
|
}
|
|
@@ -1268,22 +1408,22 @@ ${top.length} of ${matches.length} match${matches.length === 1 ? "" : "es"}`)
|
|
|
1268
1408
|
}
|
|
1269
1409
|
|
|
1270
1410
|
// src/commands/memory-reject.ts
|
|
1271
|
-
import { writeFile as
|
|
1272
|
-
import { existsSync as
|
|
1411
|
+
import { writeFile as writeFile10 } from "fs/promises";
|
|
1412
|
+
import { existsSync as existsSync19 } from "fs";
|
|
1273
1413
|
import "commander";
|
|
1274
1414
|
import {
|
|
1275
|
-
findProjectRoot as
|
|
1415
|
+
findProjectRoot as findProjectRoot21,
|
|
1276
1416
|
loadUsageIndex as loadUsageIndex6,
|
|
1277
1417
|
recordRejection,
|
|
1278
|
-
resolveHaivePaths as
|
|
1418
|
+
resolveHaivePaths as resolveHaivePaths18,
|
|
1279
1419
|
saveUsageIndex,
|
|
1280
|
-
serializeMemory as
|
|
1420
|
+
serializeMemory as serializeMemory8
|
|
1281
1421
|
} from "@hiveai/core";
|
|
1282
1422
|
function registerMemoryReject(memory2) {
|
|
1283
1423
|
memory2.command("reject <id>").description("Record a rejection (blocks auto-promotion and lowers confidence)").option("-r, --reason <reason>", "why this memory is being rejected").option("-d, --dir <dir>", "project root").action(async (id, opts) => {
|
|
1284
|
-
const root =
|
|
1285
|
-
const paths =
|
|
1286
|
-
if (!
|
|
1424
|
+
const root = findProjectRoot21(opts.dir);
|
|
1425
|
+
const paths = resolveHaivePaths18(root);
|
|
1426
|
+
if (!existsSync19(paths.memoriesDir)) {
|
|
1287
1427
|
ui.error(`No .ai/memories at ${root}.`);
|
|
1288
1428
|
process.exitCode = 1;
|
|
1289
1429
|
return;
|
|
@@ -1295,9 +1435,9 @@ function registerMemoryReject(memory2) {
|
|
|
1295
1435
|
process.exitCode = 1;
|
|
1296
1436
|
return;
|
|
1297
1437
|
}
|
|
1298
|
-
await
|
|
1438
|
+
await writeFile10(
|
|
1299
1439
|
loaded.filePath,
|
|
1300
|
-
|
|
1440
|
+
serializeMemory8({
|
|
1301
1441
|
frontmatter: {
|
|
1302
1442
|
...loaded.memory.frontmatter,
|
|
1303
1443
|
status: "rejected",
|
|
@@ -1319,22 +1459,22 @@ function registerMemoryReject(memory2) {
|
|
|
1319
1459
|
}
|
|
1320
1460
|
|
|
1321
1461
|
// src/commands/memory-rm.ts
|
|
1322
|
-
import { existsSync as
|
|
1462
|
+
import { existsSync as existsSync20 } from "fs";
|
|
1323
1463
|
import { unlink as unlink2 } from "fs/promises";
|
|
1324
|
-
import
|
|
1464
|
+
import path19 from "path";
|
|
1325
1465
|
import { createInterface } from "readline/promises";
|
|
1326
1466
|
import "commander";
|
|
1327
1467
|
import {
|
|
1328
|
-
findProjectRoot as
|
|
1468
|
+
findProjectRoot as findProjectRoot22,
|
|
1329
1469
|
loadUsageIndex as loadUsageIndex7,
|
|
1330
|
-
resolveHaivePaths as
|
|
1470
|
+
resolveHaivePaths as resolveHaivePaths19,
|
|
1331
1471
|
saveUsageIndex as saveUsageIndex2
|
|
1332
1472
|
} from "@hiveai/core";
|
|
1333
1473
|
function registerMemoryRm(memory2) {
|
|
1334
1474
|
memory2.command("rm <id>").description("Delete a memory file (and its usage entry by default)").option("-y, --yes", "skip the confirmation prompt").option("--keep-usage", "do not remove the usage.json entry").option("-d, --dir <dir>", "project root").action(async (id, opts) => {
|
|
1335
|
-
const root =
|
|
1336
|
-
const paths =
|
|
1337
|
-
if (!
|
|
1475
|
+
const root = findProjectRoot22(opts.dir);
|
|
1476
|
+
const paths = resolveHaivePaths19(root);
|
|
1477
|
+
if (!existsSync20(paths.memoriesDir)) {
|
|
1338
1478
|
ui.error(`No .ai/memories at ${root}.`);
|
|
1339
1479
|
process.exitCode = 1;
|
|
1340
1480
|
return;
|
|
@@ -1346,7 +1486,7 @@ function registerMemoryRm(memory2) {
|
|
|
1346
1486
|
process.exitCode = 1;
|
|
1347
1487
|
return;
|
|
1348
1488
|
}
|
|
1349
|
-
const rel =
|
|
1489
|
+
const rel = path19.relative(root, found.filePath);
|
|
1350
1490
|
if (!opts.yes) {
|
|
1351
1491
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1352
1492
|
const answer = (await rl.question(`Delete ${rel}? [y/N] `)).trim().toLowerCase();
|
|
@@ -1370,22 +1510,22 @@ function registerMemoryRm(memory2) {
|
|
|
1370
1510
|
}
|
|
1371
1511
|
|
|
1372
1512
|
// src/commands/memory-show.ts
|
|
1373
|
-
import { existsSync as
|
|
1374
|
-
import { readFile as
|
|
1375
|
-
import
|
|
1513
|
+
import { existsSync as existsSync21 } from "fs";
|
|
1514
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
1515
|
+
import path20 from "path";
|
|
1376
1516
|
import "commander";
|
|
1377
1517
|
import {
|
|
1378
1518
|
deriveConfidence as deriveConfidence2,
|
|
1379
|
-
findProjectRoot as
|
|
1519
|
+
findProjectRoot as findProjectRoot23,
|
|
1380
1520
|
getUsage as getUsage6,
|
|
1381
1521
|
loadUsageIndex as loadUsageIndex8,
|
|
1382
|
-
resolveHaivePaths as
|
|
1522
|
+
resolveHaivePaths as resolveHaivePaths20
|
|
1383
1523
|
} from "@hiveai/core";
|
|
1384
1524
|
function registerMemoryShow(memory2) {
|
|
1385
1525
|
memory2.command("show <id>").description("Print a memory's frontmatter, body, and confidence/usage").option("--raw", "print the raw file contents instead of a summary").option("-d, --dir <dir>", "project root").action(async (id, opts) => {
|
|
1386
|
-
const root =
|
|
1387
|
-
const paths =
|
|
1388
|
-
if (!
|
|
1526
|
+
const root = findProjectRoot23(opts.dir);
|
|
1527
|
+
const paths = resolveHaivePaths20(root);
|
|
1528
|
+
if (!existsSync21(paths.memoriesDir)) {
|
|
1389
1529
|
ui.error(`No .ai/memories at ${root}.`);
|
|
1390
1530
|
process.exitCode = 1;
|
|
1391
1531
|
return;
|
|
@@ -1398,7 +1538,7 @@ function registerMemoryShow(memory2) {
|
|
|
1398
1538
|
return;
|
|
1399
1539
|
}
|
|
1400
1540
|
if (opts.raw) {
|
|
1401
|
-
console.log(await
|
|
1541
|
+
console.log(await readFile5(found.filePath, "utf8"));
|
|
1402
1542
|
return;
|
|
1403
1543
|
}
|
|
1404
1544
|
const fm = found.memory.frontmatter;
|
|
@@ -1414,7 +1554,7 @@ function registerMemoryShow(memory2) {
|
|
|
1414
1554
|
if (fm.verified_at) console.log(`${ui.dim("verified:")} ${fm.verified_at}`);
|
|
1415
1555
|
if (fm.stale_reason) console.log(`${ui.dim("stale:")} ${fm.stale_reason}`);
|
|
1416
1556
|
console.log(`${ui.dim("reads:")} ${u.read_count} ${ui.dim("rejections:")} ${u.rejected_count}`);
|
|
1417
|
-
console.log(`${ui.dim("file:")} ${
|
|
1557
|
+
console.log(`${ui.dim("file:")} ${path20.relative(root, found.filePath)}`);
|
|
1418
1558
|
if (fm.anchor.paths.length || fm.anchor.symbols.length) {
|
|
1419
1559
|
console.log(ui.dim("anchor:"));
|
|
1420
1560
|
if (fm.anchor.commit) console.log(` ${ui.dim("commit:")} ${fm.anchor.commit}`);
|
|
@@ -1429,21 +1569,21 @@ function registerMemoryShow(memory2) {
|
|
|
1429
1569
|
}
|
|
1430
1570
|
|
|
1431
1571
|
// src/commands/memory-stats.ts
|
|
1432
|
-
import { existsSync as
|
|
1433
|
-
import
|
|
1572
|
+
import { existsSync as existsSync22 } from "fs";
|
|
1573
|
+
import path21 from "path";
|
|
1434
1574
|
import "commander";
|
|
1435
1575
|
import {
|
|
1436
1576
|
deriveConfidence as deriveConfidence3,
|
|
1437
|
-
findProjectRoot as
|
|
1577
|
+
findProjectRoot as findProjectRoot24,
|
|
1438
1578
|
getUsage as getUsage7,
|
|
1439
1579
|
loadUsageIndex as loadUsageIndex9,
|
|
1440
|
-
resolveHaivePaths as
|
|
1580
|
+
resolveHaivePaths as resolveHaivePaths21
|
|
1441
1581
|
} from "@hiveai/core";
|
|
1442
1582
|
function registerMemoryStats(memory2) {
|
|
1443
1583
|
memory2.command("stats").description("Show usage stats and confidence levels per memory").option("--id <id>", "show stats for a single memory id").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
1444
|
-
const root =
|
|
1445
|
-
const paths =
|
|
1446
|
-
if (!
|
|
1584
|
+
const root = findProjectRoot24(opts.dir);
|
|
1585
|
+
const paths = resolveHaivePaths21(root);
|
|
1586
|
+
if (!existsSync22(paths.memoriesDir)) {
|
|
1447
1587
|
ui.error(`No .ai/memories at ${root}. Run \`haive init\` first.`);
|
|
1448
1588
|
process.exitCode = 1;
|
|
1449
1589
|
return;
|
|
@@ -1468,27 +1608,27 @@ function registerMemoryStats(memory2) {
|
|
|
1468
1608
|
console.log(
|
|
1469
1609
|
` ${ui.dim("status:")} ${fm.status} ${ui.dim("reads:")} ${u.read_count} ${ui.dim("rejections:")} ${u.rejected_count}`
|
|
1470
1610
|
);
|
|
1471
|
-
console.log(` ${ui.dim(
|
|
1611
|
+
console.log(` ${ui.dim(path21.relative(root, filePath))}`);
|
|
1472
1612
|
}
|
|
1473
1613
|
});
|
|
1474
1614
|
}
|
|
1475
1615
|
|
|
1476
1616
|
// src/commands/memory-verify.ts
|
|
1477
|
-
import { writeFile as
|
|
1478
|
-
import { existsSync as
|
|
1479
|
-
import
|
|
1617
|
+
import { writeFile as writeFile11 } from "fs/promises";
|
|
1618
|
+
import { existsSync as existsSync23 } from "fs";
|
|
1619
|
+
import path22 from "path";
|
|
1480
1620
|
import "commander";
|
|
1481
1621
|
import {
|
|
1482
|
-
findProjectRoot as
|
|
1483
|
-
resolveHaivePaths as
|
|
1484
|
-
serializeMemory as
|
|
1622
|
+
findProjectRoot as findProjectRoot25,
|
|
1623
|
+
resolveHaivePaths as resolveHaivePaths22,
|
|
1624
|
+
serializeMemory as serializeMemory9,
|
|
1485
1625
|
verifyAnchor as verifyAnchor2
|
|
1486
1626
|
} from "@hiveai/core";
|
|
1487
1627
|
function registerMemoryVerify(memory2) {
|
|
1488
1628
|
memory2.command("verify").description("Check memory anchors against current code, optionally marking stale ones").option("--id <id>", "verify a single memory by id").option("--all", "verify every memory (default if --id is omitted)").option("--update", "write status=stale (or status=validated for re-freshed) back to disk").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
1489
|
-
const root =
|
|
1490
|
-
const paths =
|
|
1491
|
-
if (!
|
|
1629
|
+
const root = findProjectRoot25(opts.dir);
|
|
1630
|
+
const paths = resolveHaivePaths22(root);
|
|
1631
|
+
if (!existsSync23(paths.memoriesDir)) {
|
|
1492
1632
|
ui.error(`No .ai/memories at ${root}. Run \`haive init\` first.`);
|
|
1493
1633
|
process.exitCode = 1;
|
|
1494
1634
|
return;
|
|
@@ -1511,7 +1651,7 @@ function registerMemoryVerify(memory2) {
|
|
|
1511
1651
|
anchorless++;
|
|
1512
1652
|
continue;
|
|
1513
1653
|
}
|
|
1514
|
-
const rel =
|
|
1654
|
+
const rel = path22.relative(root, filePath);
|
|
1515
1655
|
if (result.stale) {
|
|
1516
1656
|
staleCount++;
|
|
1517
1657
|
console.log(`${ui.bold("STALE")} ${mem.frontmatter.id}`);
|
|
@@ -1523,7 +1663,7 @@ function registerMemoryVerify(memory2) {
|
|
|
1523
1663
|
}
|
|
1524
1664
|
if (opts.update) {
|
|
1525
1665
|
const next = applyVerification(mem, result);
|
|
1526
|
-
await
|
|
1666
|
+
await writeFile11(filePath, serializeMemory9(next), "utf8");
|
|
1527
1667
|
updated++;
|
|
1528
1668
|
}
|
|
1529
1669
|
}
|
|
@@ -1562,11 +1702,12 @@ function applyVerification(mem, result) {
|
|
|
1562
1702
|
}
|
|
1563
1703
|
|
|
1564
1704
|
// src/index.ts
|
|
1565
|
-
var program = new
|
|
1566
|
-
program.name("haive").description("hAIve \u2014 team-first persistent memory layer for AI coding agents").version("0.2.
|
|
1705
|
+
var program = new Command26();
|
|
1706
|
+
program.name("haive").description("hAIve \u2014 team-first persistent memory layer for AI coding agents").version("0.2.6");
|
|
1567
1707
|
registerInit(program);
|
|
1568
1708
|
registerMcp(program);
|
|
1569
1709
|
registerBriefing(program);
|
|
1710
|
+
registerTui(program);
|
|
1570
1711
|
registerEmbeddings(program);
|
|
1571
1712
|
registerSync(program);
|
|
1572
1713
|
registerInstallHooks(program);
|
|
@@ -1588,6 +1729,7 @@ registerMemoryPending(memory);
|
|
|
1588
1729
|
registerMemoryApprove(memory);
|
|
1589
1730
|
registerMemoryUpdate(memory);
|
|
1590
1731
|
registerMemoryHot(memory);
|
|
1732
|
+
registerMemoryTried(memory);
|
|
1591
1733
|
program.parseAsync(process.argv).catch((err) => {
|
|
1592
1734
|
if (isZodError(err)) {
|
|
1593
1735
|
for (const issue of err.issues) {
|