@hiveai/cli 0.2.1 → 0.2.3

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/index.js CHANGED
@@ -1,13 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { Command as Command22 } from "commander";
4
+ import { Command as Command24 } from "commander";
5
5
 
6
- // src/commands/embeddings.ts
6
+ // src/commands/briefing.ts
7
7
  import { existsSync } from "fs";
8
- import path from "path";
8
+ import { readFile } from "fs/promises";
9
9
  import "commander";
10
- import { findProjectRoot, resolveHaivePaths } from "@hiveai/core";
10
+ import {
11
+ findProjectRoot,
12
+ literalMatchesAllTokens,
13
+ loadMemoriesFromDir,
14
+ memoryMatchesAnchorPaths,
15
+ resolveHaivePaths,
16
+ tokenizeQuery
17
+ } from "@hiveai/core";
11
18
 
12
19
  // src/utils/ui.ts
13
20
  import pc from "picocolors";
@@ -17,16 +24,107 @@ var ui = {
17
24
  warn: (msg) => console.log(pc.yellow("\u26A0"), msg),
18
25
  error: (msg) => console.error(pc.red("\u2717"), msg),
19
26
  dim: (msg) => pc.dim(msg),
20
- bold: (msg) => pc.bold(msg)
27
+ bold: (msg) => pc.bold(msg),
28
+ green: (msg) => pc.green(msg),
29
+ yellow: (msg) => pc.yellow(msg),
30
+ red: (msg) => pc.red(msg),
31
+ statusBadge: (status) => {
32
+ switch (status) {
33
+ case "validated":
34
+ return pc.green(status);
35
+ case "proposed":
36
+ return pc.yellow(status);
37
+ case "stale":
38
+ return pc.yellow(status);
39
+ case "rejected":
40
+ return pc.red(status);
41
+ case "deprecated":
42
+ return pc.dim(status);
43
+ default:
44
+ return pc.dim(status);
45
+ }
46
+ }
21
47
  };
22
48
 
49
+ // src/commands/briefing.ts
50
+ function registerBriefing(program2) {
51
+ program2.command("briefing").description(
52
+ "Print project context + relevant memories in one shot \u2014 ideal for agent onboarding"
53
+ ).option("--task <text>", "what you are about to do \u2014 filters memories by relevance").option("--files <csv>", "comma-separated file paths being worked on (anchors memories)").option("--max-memories <n>", "cap on memories surfaced", "10").option(
54
+ "--scope <scope>",
55
+ "personal | team | module (default: team + validated only)",
56
+ "team"
57
+ ).option("-d, --dir <dir>", "project root").action(async (opts) => {
58
+ const root = findProjectRoot(opts.dir);
59
+ const paths = resolveHaivePaths(root);
60
+ if (existsSync(paths.projectContext)) {
61
+ const ctx = await readFile(paths.projectContext, "utf8");
62
+ console.log(`${ui.bold("=== Project Context ===")}
63
+ `);
64
+ console.log(ctx.trim());
65
+ console.log();
66
+ } else {
67
+ ui.warn(
68
+ "No project-context.md found. Run `haive init` and the `bootstrap_project` MCP prompt to set it up."
69
+ );
70
+ }
71
+ if (!existsSync(paths.memoriesDir)) return;
72
+ const all = await loadMemoriesFromDir(paths.memoriesDir);
73
+ const filePaths = parseCsv(opts.files);
74
+ const tokens = opts.task ? tokenizeQuery(opts.task) : null;
75
+ const maxMemories = Math.max(1, Number(opts.maxMemories ?? 10));
76
+ const scopeFilter = opts.scope ?? "team";
77
+ const candidates = all.filter(({ memory: mem }) => {
78
+ const fm = mem.frontmatter;
79
+ if (fm.status === "rejected" || fm.status === "deprecated") return false;
80
+ if (scopeFilter !== "all" && fm.scope !== scopeFilter) return false;
81
+ return true;
82
+ });
83
+ const scored = candidates.map(({ memory: mem, filePath }) => {
84
+ const fm = mem.frontmatter;
85
+ let score = 0;
86
+ if (fm.status === "validated") score += 3;
87
+ else if (fm.status === "proposed") score += 1;
88
+ if (filePaths.length > 0 && memoryMatchesAnchorPaths(mem, filePaths)) score += 4;
89
+ if (tokens && literalMatchesAllTokens(mem, tokens)) score += 3;
90
+ return { memory: mem, filePath, score };
91
+ });
92
+ scored.sort((a, b) => b.score - a.score);
93
+ const top = scored.slice(0, maxMemories);
94
+ if (top.length === 0) {
95
+ ui.info("No relevant memories found.");
96
+ return;
97
+ }
98
+ console.log(`${ui.bold("=== Relevant Memories ===")}
99
+ `);
100
+ for (const { memory: mem } of top) {
101
+ const fm = mem.frontmatter;
102
+ const badge = ui.statusBadge(fm.status);
103
+ console.log(
104
+ `${ui.bold(fm.id)} ${ui.dim(fm.scope + "/" + fm.type)} ${badge}`
105
+ );
106
+ console.log(mem.body.trim());
107
+ console.log();
108
+ }
109
+ console.log(ui.dim(`${top.length} memor${top.length === 1 ? "y" : "ies"} surfaced`));
110
+ });
111
+ }
112
+ function parseCsv(value) {
113
+ if (!value) return [];
114
+ return value.split(",").map((s) => s.trim()).filter(Boolean);
115
+ }
116
+
23
117
  // src/commands/embeddings.ts
118
+ import { existsSync as existsSync2 } from "fs";
119
+ import path from "path";
120
+ import "commander";
121
+ import { findProjectRoot as findProjectRoot2, resolveHaivePaths as resolveHaivePaths2 } from "@hiveai/core";
24
122
  function registerEmbeddings(program2) {
25
123
  const embeddings = program2.command("embeddings").description("Manage local embeddings index for semantic search");
26
124
  embeddings.command("index").description("Generate or refresh the embeddings index for all memories").option("-d, --dir <dir>", "project root").action(async (opts) => {
27
- const root = findProjectRoot(opts.dir);
28
- const paths = resolveHaivePaths(root);
29
- if (!existsSync(paths.memoriesDir)) {
125
+ const root = findProjectRoot2(opts.dir);
126
+ const paths = resolveHaivePaths2(root);
127
+ if (!existsSync2(paths.memoriesDir)) {
30
128
  ui.error(`No .ai/memories at ${root}. Run \`haive init\` first.`);
31
129
  process.exitCode = 1;
32
130
  return;
@@ -41,8 +139,8 @@ function registerEmbeddings(program2) {
41
139
  );
42
140
  });
43
141
  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) => {
44
- const root = findProjectRoot(opts.dir);
45
- const paths = resolveHaivePaths(root);
142
+ const root = findProjectRoot2(opts.dir);
143
+ const paths = resolveHaivePaths2(root);
46
144
  const { semanticSearch } = await loadEmbeddings();
47
145
  const result = await semanticSearch(paths, text, {
48
146
  limit: Number(opts.limit ?? 10),
@@ -64,8 +162,8 @@ function registerEmbeddings(program2) {
64
162
  }
65
163
  });
66
164
  embeddings.command("status").description("Show the embeddings index status").option("-d, --dir <dir>", "project root").action(async (opts) => {
67
- const root = findProjectRoot(opts.dir);
68
- const paths = resolveHaivePaths(root);
165
+ const root = findProjectRoot2(opts.dir);
166
+ const paths = resolveHaivePaths2(root);
69
167
  const { indexStat } = await loadEmbeddings();
70
168
  const stat = await indexStat(paths);
71
169
  if (!stat.exists) {
@@ -81,11 +179,11 @@ function registerEmbeddings(program2) {
81
179
  async function loadEmbeddings() {
82
180
  try {
83
181
  return await import("@hiveai/embeddings");
84
- } catch (err) {
182
+ } catch {
85
183
  ui.error(
86
184
  "Could not load @hiveai/embeddings. Run: npm install -g @hiveai/embeddings (or `pnpm build` in the monorepo)"
87
185
  );
88
- throw err;
186
+ process.exit(1);
89
187
  }
90
188
  }
91
189
 
@@ -95,8 +193,8 @@ import "commander";
95
193
  import {
96
194
  buildCodeMap,
97
195
  codeMapPath,
98
- findProjectRoot as findProjectRoot2,
99
- resolveHaivePaths as resolveHaivePaths2,
196
+ findProjectRoot as findProjectRoot3,
197
+ resolveHaivePaths as resolveHaivePaths3,
100
198
  saveCodeMap
101
199
  } from "@hiveai/core";
102
200
  function registerIndexCode(program2) {
@@ -107,8 +205,8 @@ function registerIndexCode(program2) {
107
205
  "extra directory names to skip (comma-separated)",
108
206
  ""
109
207
  ).action(async (opts) => {
110
- const root = findProjectRoot2(opts.dir);
111
- const paths = resolveHaivePaths2(root);
208
+ const root = findProjectRoot3(opts.dir);
209
+ const paths = resolveHaivePaths3(root);
112
210
  const extraExcludes = (opts.exclude ?? "").split(",").map((s) => s.trim()).filter(Boolean);
113
211
  ui.info(`Indexing source files in ${root}\u2026`);
114
212
  const map = await buildCodeMap(root, {
@@ -136,10 +234,10 @@ function registerIndexCode(program2) {
136
234
 
137
235
  // src/commands/init.ts
138
236
  import { mkdir, writeFile } from "fs/promises";
139
- import { existsSync as existsSync2 } from "fs";
237
+ import { existsSync as existsSync3 } from "fs";
140
238
  import path3 from "path";
141
239
  import "commander";
142
- import { resolveHaivePaths as resolveHaivePaths3 } from "@hiveai/core";
240
+ import { resolveHaivePaths as resolveHaivePaths4 } from "@hiveai/core";
143
241
  var PROJECT_CONTEXT_TEMPLATE = `# Project context
144
242
 
145
243
  > Generated by \`haive init\`. Edit this file (or let your AI agent fill it via the upcoming MCP \`bootstrap_project\` tool).
@@ -168,15 +266,15 @@ Memories live under \`.ai/memories/\` (personal/team/module).
168
266
  function registerInit(program2) {
169
267
  program2.command("init").description("Initialize a hAIve project (.ai/ structure + bridge files)").option("-d, --dir <dir>", "project root", process.cwd()).option("--no-bridges", "do not generate CLAUDE.md / .cursorrules / copilot-instructions.md").action(async (opts) => {
170
268
  const root = path3.resolve(opts.dir);
171
- const paths = resolveHaivePaths3(root);
172
- if (existsSync2(paths.haiveDir)) {
269
+ const paths = resolveHaivePaths4(root);
270
+ if (existsSync3(paths.haiveDir)) {
173
271
  ui.warn(`.ai/ already exists at ${paths.haiveDir} \u2014 leaving existing files in place.`);
174
272
  }
175
273
  await mkdir(paths.personalDir, { recursive: true });
176
274
  await mkdir(paths.teamDir, { recursive: true });
177
275
  await mkdir(paths.moduleDir, { recursive: true });
178
276
  await mkdir(paths.modulesContextDir, { recursive: true });
179
- if (!existsSync2(paths.projectContext)) {
277
+ if (!existsSync3(paths.projectContext)) {
180
278
  await writeFile(paths.projectContext, PROJECT_CONTEXT_TEMPLATE, "utf8");
181
279
  ui.success(`Created ${path3.relative(root, paths.projectContext)}`);
182
280
  }
@@ -191,7 +289,7 @@ function registerInit(program2) {
191
289
  }
192
290
  async function writeBridge(root, relPath) {
193
291
  const target = path3.join(root, relPath);
194
- if (existsSync2(target)) {
292
+ if (existsSync3(target)) {
195
293
  ui.info(`Bridge ${relPath} already exists \u2014 skipped`);
196
294
  return;
197
295
  }
@@ -201,11 +299,11 @@ async function writeBridge(root, relPath) {
201
299
  }
202
300
 
203
301
  // src/commands/install-hooks.ts
204
- import { mkdir as mkdir2, writeFile as writeFile2, chmod, readFile } from "fs/promises";
205
- import { existsSync as existsSync3 } from "fs";
302
+ import { mkdir as mkdir2, writeFile as writeFile2, chmod, readFile as readFile2 } from "fs/promises";
303
+ import { existsSync as existsSync4 } from "fs";
206
304
  import path4 from "path";
207
305
  import "commander";
208
- import { findProjectRoot as findProjectRoot4 } from "@hiveai/core";
306
+ import { findProjectRoot as findProjectRoot5 } from "@hiveai/core";
209
307
  var HOOK_MARKER = "# hAIve auto-generated";
210
308
  var HOOK_BODY = `#!/bin/sh
211
309
  ${HOOK_MARKER} \u2014 keep this block to allow upgrades. Hand-edit anything outside it.
@@ -221,9 +319,9 @@ fi
221
319
  var HOOKS = ["post-merge", "post-rewrite"];
222
320
  function registerInstallHooks(program2) {
223
321
  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) => {
224
- const root = findProjectRoot4(opts.dir);
322
+ const root = findProjectRoot5(opts.dir);
225
323
  const gitDir = path4.join(root, ".git");
226
- if (!existsSync3(gitDir)) {
324
+ if (!existsSync4(gitDir)) {
227
325
  ui.error(`No .git directory at ${root}.`);
228
326
  process.exitCode = 1;
229
327
  return;
@@ -234,8 +332,8 @@ function registerInstallHooks(program2) {
234
332
  let skipped = 0;
235
333
  for (const name of HOOKS) {
236
334
  const file = path4.join(hooksDir, name);
237
- if (existsSync3(file) && !opts.force) {
238
- const existing = await readFile(file, "utf8");
335
+ if (existsSync4(file) && !opts.force) {
336
+ const existing = await readFile2(file, "utf8");
239
337
  if (!existing.includes(HOOK_MARKER)) {
240
338
  ui.warn(`${name} already exists and was not written by hAIve. Re-run with --force to overwrite.`);
241
339
  skipped++;
@@ -253,16 +351,16 @@ function registerInstallHooks(program2) {
253
351
 
254
352
  // src/commands/mcp.ts
255
353
  import { spawn } from "child_process";
256
- import { existsSync as existsSync4 } from "fs";
354
+ import { existsSync as existsSync5 } from "fs";
257
355
  import { createRequire } from "module";
258
356
  import path5 from "path";
259
357
  import { fileURLToPath } from "url";
260
358
  import "commander";
261
- import { findProjectRoot as findProjectRoot5 } from "@hiveai/core";
359
+ import { findProjectRoot as findProjectRoot6 } from "@hiveai/core";
262
360
  var require2 = createRequire(import.meta.url);
263
361
  function registerMcp(program2) {
264
362
  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) => {
265
- const root = findProjectRoot5(opts.dir);
363
+ const root = findProjectRoot6(opts.dir);
266
364
  const bin = locateMcpBin();
267
365
  if (!bin) {
268
366
  ui.error(
@@ -282,29 +380,29 @@ function locateMcpBin() {
282
380
  const pkgPath = require2.resolve("@hiveai/mcp/package.json");
283
381
  const pkgDir = path5.dirname(pkgPath);
284
382
  const candidate = path5.join(pkgDir, "dist", "index.js");
285
- if (existsSync4(candidate)) return candidate;
383
+ if (existsSync5(candidate)) return candidate;
286
384
  } catch {
287
385
  }
288
386
  const here = path5.dirname(fileURLToPath(import.meta.url));
289
387
  const sibling = path5.resolve(here, "..", "..", "..", "mcp", "dist", "index.js");
290
- if (existsSync4(sibling)) return sibling;
388
+ if (existsSync5(sibling)) return sibling;
291
389
  return null;
292
390
  }
293
391
 
294
392
  // src/commands/sync.ts
295
393
  import { spawnSync } from "child_process";
296
394
  import { writeFile as writeFile3 } from "fs/promises";
297
- import { existsSync as existsSync5 } from "fs";
395
+ import { existsSync as existsSync6 } from "fs";
298
396
  import "path";
299
397
  import "commander";
300
398
  import {
301
399
  DEFAULT_AUTO_PROMOTE_RULE,
302
- findProjectRoot as findProjectRoot6,
400
+ findProjectRoot as findProjectRoot7,
303
401
  getUsage,
304
402
  isAutoPromoteEligible,
305
- loadMemoriesFromDir,
403
+ loadMemoriesFromDir as loadMemoriesFromDir2,
306
404
  loadUsageIndex,
307
- resolveHaivePaths as resolveHaivePaths4,
405
+ resolveHaivePaths as resolveHaivePaths5,
308
406
  serializeMemory,
309
407
  verifyAnchor
310
408
  } from "@hiveai/core";
@@ -313,9 +411,9 @@ function registerSync(program2) {
313
411
  "--since <ref>",
314
412
  "git ref/commit to compare against; report memories added/modified/removed since"
315
413
  ).option("--no-verify", "skip the anchor verification step").option("--no-promote", "skip the auto-promotion step").action(async (opts) => {
316
- const root = findProjectRoot6(opts.dir);
317
- const paths = resolveHaivePaths4(root);
318
- if (!existsSync5(paths.memoriesDir)) {
414
+ const root = findProjectRoot7(opts.dir);
415
+ const paths = resolveHaivePaths5(root);
416
+ if (!existsSync6(paths.memoriesDir)) {
319
417
  if (!opts.quiet) ui.warn(`No .ai/memories at ${root}. Run \`haive init\` first.`);
320
418
  process.exitCode = 1;
321
419
  return;
@@ -327,7 +425,7 @@ function registerSync(program2) {
327
425
  let revalidated = 0;
328
426
  let promoted = 0;
329
427
  if (opts.verify !== false) {
330
- const memories = await loadMemoriesFromDir(paths.memoriesDir);
428
+ const memories = await loadMemoriesFromDir2(paths.memoriesDir);
331
429
  for (const { memory: memory2, filePath } of memories) {
332
430
  const isAnchored = memory2.frontmatter.anchor.paths.length > 0 || memory2.frontmatter.anchor.symbols.length > 0;
333
431
  if (!isAnchored) continue;
@@ -369,7 +467,7 @@ function registerSync(program2) {
369
467
  }
370
468
  }
371
469
  if (opts.promote !== false) {
372
- const memories = await loadMemoriesFromDir(paths.memoriesDir);
470
+ const memories = await loadMemoriesFromDir2(paths.memoriesDir);
373
471
  const usage = await loadUsageIndex(paths);
374
472
  for (const { memory: memory2, filePath } of memories) {
375
473
  if (isAutoPromoteEligible(
@@ -390,9 +488,20 @@ function registerSync(program2) {
390
488
  }
391
489
  }
392
490
  const sinceReport = opts.since ? collectSinceChanges(root, opts.since) : null;
491
+ const draftMemories = (await loadMemoriesFromDir2(paths.memoriesDir)).filter(
492
+ (m) => m.memory.frontmatter.status === "draft"
493
+ );
494
+ const draftCount = draftMemories.length;
393
495
  log(
394
496
  `${ui.dim("sync:")} ${staleMarked} stale \xB7 ${revalidated} revalidated \xB7 ${promoted} promoted${sinceReport ? ` \xB7 ${sinceReport.added.length}+/${sinceReport.modified.length}~/${sinceReport.removed.length}- since ${opts.since}` : ""}`
395
497
  );
498
+ if (!opts.quiet && draftCount > 0) {
499
+ log(
500
+ ui.dim(
501
+ `\u2139 ${draftCount} memor${draftCount === 1 ? "y" : "ies"} in draft \u2014 run \`haive memory approve <id>\` to activate or \`haive memory list --status draft\` to review`
502
+ )
503
+ );
504
+ }
396
505
  if (sinceReport && !opts.quiet) {
397
506
  if (sinceReport.added.length > 0) {
398
507
  log(ui.bold("\nNew memories:"));
@@ -430,28 +539,28 @@ function collectSinceChanges(root, ref) {
430
539
 
431
540
  // src/commands/memory-add.ts
432
541
  import { mkdir as mkdir3, writeFile as writeFile4 } from "fs/promises";
433
- import { existsSync as existsSync6 } from "fs";
542
+ import { existsSync as existsSync7 } from "fs";
434
543
  import path7 from "path";
435
544
  import "commander";
436
545
  import {
437
546
  buildFrontmatter,
438
- findProjectRoot as findProjectRoot7,
547
+ findProjectRoot as findProjectRoot8,
439
548
  inferModulesFromPaths,
440
549
  memoryFilePath,
441
- resolveHaivePaths as resolveHaivePaths5,
550
+ resolveHaivePaths as resolveHaivePaths6,
442
551
  serializeMemory as serializeMemory2
443
552
  } from "@hiveai/core";
444
553
  function registerMemoryAdd(memory2) {
445
- memory2.command("add").description("Add a new memory (defaults to personal scope \u2014 v0.1 approach B)").requiredOption("--type <type>", "convention | decision | gotcha | architecture | glossary").requiredOption("--slug <slug>", "short identifier used in the file name").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)").option("--no-auto-tag", "disable automatic tag suggestions inferred from anchor paths").option("-d, --dir <dir>", "project root").action(async (opts) => {
446
- const root = findProjectRoot7(opts.dir);
447
- const paths = resolveHaivePaths5(root);
448
- if (!existsSync6(paths.haiveDir)) {
554
+ 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) => {
555
+ const root = findProjectRoot8(opts.dir);
556
+ const paths = resolveHaivePaths6(root);
557
+ if (!existsSync7(paths.haiveDir)) {
449
558
  ui.error(`No .ai/ found at ${root}. Run \`haive init\` first.`);
450
559
  process.exitCode = 1;
451
560
  return;
452
561
  }
453
- const userTags = parseCsv(opts.tags);
454
- const anchorPaths = parseCsv(opts.paths);
562
+ const userTags = parseCsv2(opts.tags);
563
+ const anchorPaths = parseCsv2(opts.paths);
455
564
  const autoTagsEnabled = opts.autoTag !== false;
456
565
  const inferredTags = autoTagsEnabled ? inferModulesFromPaths(anchorPaths) : [];
457
566
  const mergedTags = Array.from(/* @__PURE__ */ new Set([...userTags, ...inferredTags]));
@@ -464,73 +573,112 @@ function registerMemoryAdd(memory2) {
464
573
  domain: opts.domain,
465
574
  author: opts.author,
466
575
  paths: anchorPaths,
467
- symbols: parseCsv(opts.symbols),
576
+ symbols: parseCsv2(opts.symbols),
468
577
  commit: opts.commit
469
578
  });
470
- const body = opts.body ?? `# ${opts.slug}
579
+ const title = opts.title ?? opts.slug;
580
+ let body;
581
+ if (opts.body !== void 0) {
582
+ body = opts.title ? `# ${opts.title}
583
+
584
+ ${opts.body}` : opts.body;
585
+ } else {
586
+ body = `# ${title}
471
587
 
472
588
  TODO \u2014 write the memory body.
473
589
  `;
590
+ }
474
591
  const file = memoryFilePath(paths, frontmatter.scope, frontmatter.id, frontmatter.module);
475
592
  await mkdir3(path7.dirname(file), { recursive: true });
476
- if (existsSync6(file)) {
593
+ if (existsSync7(file)) {
477
594
  ui.error(`Memory already exists at ${file}`);
478
595
  process.exitCode = 1;
479
596
  return;
480
597
  }
481
598
  await writeFile4(file, serializeMemory2({ frontmatter, body }), "utf8");
482
599
  ui.success(`Created ${path7.relative(root, file)}`);
483
- ui.info(`scope=${frontmatter.scope} status=${frontmatter.status} id=${frontmatter.id}`);
600
+ ui.info(`id=${frontmatter.id} scope=${frontmatter.scope} status=${frontmatter.status}`);
484
601
  if (inferredTags.length > 0) {
485
602
  ui.info(`auto-tagged: ${inferredTags.join(", ")} (use --no-auto-tag to disable)`);
486
603
  }
604
+ if (frontmatter.scope === "personal") {
605
+ console.log(
606
+ ui.dim(
607
+ `\u2192 next: haive memory approve ${frontmatter.id} (activate) | haive memory promote ${frontmatter.id} (share with team)`
608
+ )
609
+ );
610
+ } else {
611
+ console.log(
612
+ ui.dim(`\u2192 next: haive memory approve ${frontmatter.id} (mark as validated)`)
613
+ );
614
+ }
487
615
  });
488
616
  }
489
- function parseCsv(value) {
617
+ function parseCsv2(value) {
490
618
  if (!value) return [];
491
619
  return value.split(",").map((s) => s.trim()).filter(Boolean);
492
620
  }
493
621
 
494
622
  // src/commands/memory-list.ts
495
- import { existsSync as existsSync7 } from "fs";
623
+ import { existsSync as existsSync8 } from "fs";
496
624
  import path8 from "path";
497
625
  import "commander";
498
- import { findProjectRoot as findProjectRoot8, resolveHaivePaths as resolveHaivePaths6 } from "@hiveai/core";
626
+ import { findProjectRoot as findProjectRoot9, resolveHaivePaths as resolveHaivePaths7 } from "@hiveai/core";
499
627
 
500
628
  // src/utils/fs.ts
501
629
  import {
502
- loadMemoriesFromDir as loadMemoriesFromDir2,
630
+ loadMemoriesFromDir as loadMemoriesFromDir3,
503
631
  loadMemory,
504
632
  listMarkdownFilesRecursive
505
633
  } from "@hiveai/core";
506
634
 
507
635
  // src/commands/memory-list.ts
508
636
  function registerMemoryList(memory2) {
509
- 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("-d, --dir <dir>", "project root").action(async (opts) => {
510
- const root = findProjectRoot8(opts.dir);
511
- const paths = resolveHaivePaths6(root);
512
- if (!existsSync7(paths.memoriesDir)) {
637
+ 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) => {
638
+ const root = findProjectRoot9(opts.dir);
639
+ const paths = resolveHaivePaths7(root);
640
+ if (!existsSync8(paths.memoriesDir)) {
513
641
  ui.error(`No memories directory at ${paths.memoriesDir}. Run \`haive init\` first.`);
514
642
  process.exitCode = 1;
515
643
  return;
516
644
  }
517
- const all = await loadMemoriesFromDir2(paths.memoriesDir);
518
- const filtered = all.filter((m) => matchesFilters(m, opts));
645
+ const all = await loadMemoriesFromDir3(paths.memoriesDir);
646
+ const statusFilter = opts.status ? opts.status.split(",").map((s) => s.trim()) : null;
647
+ const filtered = all.filter((m) => {
648
+ if (!matchesFilters(m, opts)) return false;
649
+ const status = m.memory.frontmatter.status;
650
+ if (!opts.showRejected && status === "rejected") return false;
651
+ if (statusFilter && !statusFilter.includes(status)) return false;
652
+ return true;
653
+ });
519
654
  if (filtered.length === 0) {
520
655
  ui.info("No memories match the filters.");
656
+ const rejectedCount = all.filter((m) => m.memory.frontmatter.status === "rejected").length;
657
+ if (rejectedCount > 0 && !opts.showRejected) {
658
+ ui.info(`(${rejectedCount} rejected hidden \u2014 use --show-rejected to include)`);
659
+ }
521
660
  return;
522
661
  }
523
662
  for (const { memory: mem, filePath } of filtered) {
524
663
  const fm = mem.frontmatter;
525
664
  const tagStr = fm.tags.length ? ui.dim(` [${fm.tags.join(", ")}]`) : "";
526
665
  const moduleStr = fm.module ? ui.dim(` (${fm.module})`) : "";
666
+ const statusBadge = ui.statusBadge(fm.status);
527
667
  console.log(
528
- `${ui.bold(fm.id)} ${ui.dim(fm.scope)}/${ui.dim(fm.type)}${moduleStr}${tagStr}`
668
+ `${ui.bold(fm.id)} ${ui.dim(fm.scope)}/${ui.dim(fm.type)} ${statusBadge}${moduleStr}${tagStr}`
529
669
  );
530
670
  console.log(` ${ui.dim(path8.relative(root, filePath))}`);
531
671
  }
532
672
  console.log(ui.dim(`
533
673
  ${filtered.length} memor${filtered.length === 1 ? "y" : "ies"}`));
674
+ const draftCount = filtered.filter((m) => m.memory.frontmatter.status === "draft").length;
675
+ if (draftCount > 0) {
676
+ console.log(
677
+ ui.dim(
678
+ `\u2139 ${draftCount} in draft \u2014 use \`haive memory approve <id>\` to activate or \`haive memory promote <id>\` to share with team`
679
+ )
680
+ );
681
+ }
534
682
  });
535
683
  }
536
684
  function matchesFilters(loaded, opts) {
@@ -544,25 +692,39 @@ function matchesFilters(loaded, opts) {
544
692
 
545
693
  // src/commands/memory-promote.ts
546
694
  import { mkdir as mkdir4, unlink, writeFile as writeFile5 } from "fs/promises";
547
- import { existsSync as existsSync8 } from "fs";
695
+ import { existsSync as existsSync9 } from "fs";
548
696
  import path9 from "path";
549
697
  import "commander";
550
698
  import {
551
- findProjectRoot as findProjectRoot9,
699
+ findProjectRoot as findProjectRoot10,
552
700
  memoryFilePath as memoryFilePath2,
553
- resolveHaivePaths as resolveHaivePaths7,
701
+ resolveHaivePaths as resolveHaivePaths8,
554
702
  serializeMemory as serializeMemory3
555
703
  } from "@hiveai/core";
556
704
  function registerMemoryPromote(memory2) {
557
705
  memory2.command("promote <id>").description("Promote a personal memory to team scope (status -> proposed)").option("-d, --dir <dir>", "project root").action(async (id, opts) => {
558
- const root = findProjectRoot9(opts.dir);
559
- const paths = resolveHaivePaths7(root);
560
- if (!existsSync8(paths.memoriesDir)) {
706
+ const root = findProjectRoot10(opts.dir);
707
+ const paths = resolveHaivePaths8(root);
708
+ if (!existsSync9(paths.memoriesDir)) {
561
709
  ui.error(`No memories directory at ${paths.memoriesDir}. Run \`haive init\` first.`);
562
710
  process.exitCode = 1;
563
711
  return;
564
712
  }
565
- const all = await loadMemoriesFromDir2(paths.personalDir);
713
+ const teamAndModule = await loadMemoriesFromDir3(paths.memoriesDir);
714
+ const alreadyShared = teamAndModule.find(
715
+ (m) => m.memory.frontmatter.id === id && (m.memory.frontmatter.scope === "team" || m.memory.frontmatter.scope === "module")
716
+ );
717
+ if (alreadyShared) {
718
+ const fm = alreadyShared.memory.frontmatter;
719
+ ui.warn(
720
+ `"${id}" is already in ${fm.scope} scope (status=${fm.status}).`
721
+ );
722
+ if (fm.status !== "validated") {
723
+ ui.info(`\u2192 run \`haive memory approve ${id}\` to validate it`);
724
+ }
725
+ return;
726
+ }
727
+ const all = await loadMemoriesFromDir3(paths.personalDir);
566
728
  const found = all.find((m) => m.memory.frontmatter.id === id);
567
729
  if (!found) {
568
730
  ui.error(`No personal memory with id "${id}". (Promotion only applies to personal scope.)`);
@@ -583,29 +745,57 @@ function registerMemoryPromote(memory2) {
583
745
  await unlink(found.filePath);
584
746
  ui.success(`Promoted ${id} to team scope (status=proposed)`);
585
747
  ui.info(`Now at ${path9.relative(root, newPath)}`);
748
+ console.log(ui.dim(`\u2192 next: haive memory approve ${id} (validate for team use)`));
586
749
  });
587
750
  }
588
751
 
589
752
  // src/commands/memory-approve.ts
590
- import { existsSync as existsSync9 } from "fs";
753
+ import { existsSync as existsSync10 } from "fs";
591
754
  import { writeFile as writeFile6 } from "fs/promises";
592
755
  import path10 from "path";
593
756
  import "commander";
594
757
  import {
595
- findProjectRoot as findProjectRoot10,
596
- resolveHaivePaths as resolveHaivePaths8,
758
+ findProjectRoot as findProjectRoot11,
759
+ resolveHaivePaths as resolveHaivePaths9,
597
760
  serializeMemory as serializeMemory4
598
761
  } from "@hiveai/core";
599
762
  function registerMemoryApprove(memory2) {
600
- memory2.command("approve <id>").description("Mark a 'proposed' memory as 'validated' immediately (explicit review)").option("-d, --dir <dir>", "project root").action(async (id, opts) => {
601
- const root = findProjectRoot10(opts.dir);
602
- const paths = resolveHaivePaths8(root);
603
- if (!existsSync9(paths.memoriesDir)) {
763
+ 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) => {
764
+ const root = findProjectRoot11(opts.dir);
765
+ const paths = resolveHaivePaths9(root);
766
+ if (!existsSync10(paths.memoriesDir)) {
604
767
  ui.error(`No .ai/memories at ${root}.`);
605
768
  process.exitCode = 1;
606
769
  return;
607
770
  }
608
- const all = await loadMemoriesFromDir2(paths.memoriesDir);
771
+ const all = await loadMemoriesFromDir3(paths.memoriesDir);
772
+ if (opts.all || opts.pending) {
773
+ const candidates = all.filter((m) => {
774
+ const s = m.memory.frontmatter.status;
775
+ if (opts.all) return s === "proposed" || s === "draft";
776
+ return s === "proposed";
777
+ });
778
+ if (candidates.length === 0) {
779
+ ui.info(opts.all ? "No draft or proposed memories to approve." : "No proposed memories to approve.");
780
+ return;
781
+ }
782
+ let count = 0;
783
+ for (const found2 of candidates) {
784
+ const next2 = {
785
+ frontmatter: { ...found2.memory.frontmatter, status: "validated" },
786
+ body: found2.memory.body
787
+ };
788
+ await writeFile6(found2.filePath, serializeMemory4(next2), "utf8");
789
+ count++;
790
+ }
791
+ ui.success(`Approved ${count} memor${count === 1 ? "y" : "ies"} (status=validated)`);
792
+ return;
793
+ }
794
+ if (!id) {
795
+ ui.error("Provide a memory id or use --all / --pending for bulk approval.");
796
+ process.exitCode = 1;
797
+ return;
798
+ }
609
799
  const found = all.find((m) => m.memory.frontmatter.id === id);
610
800
  if (!found) {
611
801
  ui.error(`No memory with id "${id}".`);
@@ -630,19 +820,103 @@ function registerMemoryApprove(memory2) {
630
820
  });
631
821
  }
632
822
 
633
- // src/commands/memory-auto-promote.ts
823
+ // src/commands/memory-update.ts
634
824
  import { writeFile as writeFile7 } from "fs/promises";
635
- import { existsSync as existsSync10 } from "fs";
825
+ import { existsSync as existsSync11 } from "fs";
636
826
  import path11 from "path";
637
827
  import "commander";
828
+ import {
829
+ findProjectRoot as findProjectRoot12,
830
+ resolveHaivePaths as resolveHaivePaths10,
831
+ serializeMemory as serializeMemory5
832
+ } from "@hiveai/core";
833
+ function registerMemoryUpdate(memory2) {
834
+ 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) => {
835
+ const root = findProjectRoot12(opts.dir);
836
+ const paths = resolveHaivePaths10(root);
837
+ if (!existsSync11(paths.memoriesDir)) {
838
+ ui.error(`No .ai/memories at ${root}. Run \`haive init\` first.`);
839
+ process.exitCode = 1;
840
+ return;
841
+ }
842
+ const memories = await loadMemoriesFromDir3(paths.memoriesDir);
843
+ const loaded = memories.find((m) => m.memory.frontmatter.id === id);
844
+ if (!loaded) {
845
+ ui.error(`No memory with id "${id}".`);
846
+ process.exitCode = 1;
847
+ return;
848
+ }
849
+ const updated = [];
850
+ const { frontmatter, body } = loaded.memory;
851
+ const newAnchor = { ...frontmatter.anchor };
852
+ if (opts.paths !== void 0) {
853
+ newAnchor.paths = parseCsv3(opts.paths);
854
+ updated.push("anchor.paths");
855
+ }
856
+ if (opts.symbols !== void 0) {
857
+ newAnchor.symbols = parseCsv3(opts.symbols);
858
+ updated.push("anchor.symbols");
859
+ }
860
+ if (opts.commit !== void 0) {
861
+ newAnchor.commit = opts.commit;
862
+ updated.push("anchor.commit");
863
+ }
864
+ const newFrontmatter = {
865
+ ...frontmatter,
866
+ anchor: newAnchor,
867
+ ...opts.tags !== void 0 ? { tags: parseCsv3(opts.tags) } : {},
868
+ ...opts.domain !== void 0 ? { domain: opts.domain } : {},
869
+ ...opts.author !== void 0 ? { author: opts.author } : {}
870
+ };
871
+ if (opts.tags !== void 0) updated.push("tags");
872
+ if (opts.domain !== void 0) updated.push("domain");
873
+ if (opts.author !== void 0) updated.push("author");
874
+ let newBody = opts.body !== void 0 ? opts.body : body;
875
+ if (opts.title !== void 0) {
876
+ newBody = replaceFirstHeading(newBody, opts.title);
877
+ updated.push("title");
878
+ }
879
+ if (opts.body !== void 0) updated.push("body");
880
+ if (updated.length === 0) {
881
+ ui.warn("Nothing to update \u2014 provide at least one option.");
882
+ return;
883
+ }
884
+ await writeFile7(
885
+ loaded.filePath,
886
+ serializeMemory5({ frontmatter: newFrontmatter, body: newBody }),
887
+ "utf8"
888
+ );
889
+ ui.success(`Updated ${path11.relative(root, loaded.filePath)}`);
890
+ ui.info(`fields: ${updated.join(", ")}`);
891
+ });
892
+ }
893
+ function replaceFirstHeading(body, title) {
894
+ const headingRe = /^#\s+.+$/m;
895
+ const replacement = `# ${title}`;
896
+ if (headingRe.test(body)) {
897
+ return body.replace(headingRe, replacement);
898
+ }
899
+ return `${replacement}
900
+
901
+ ${body}`;
902
+ }
903
+ function parseCsv3(value) {
904
+ return value.split(",").map((s) => s.trim()).filter(Boolean);
905
+ }
906
+
907
+ // src/commands/memory-auto-promote.ts
908
+ import { writeFile as writeFile8 } from "fs/promises";
909
+ import { existsSync as existsSync12 } from "fs";
910
+ import path12 from "path";
911
+ import "commander";
638
912
  import {
639
913
  DEFAULT_AUTO_PROMOTE_RULE as DEFAULT_AUTO_PROMOTE_RULE2,
640
- findProjectRoot as findProjectRoot11,
914
+ findProjectRoot as findProjectRoot13,
641
915
  getUsage as getUsage2,
642
916
  isAutoPromoteEligible as isAutoPromoteEligible2,
643
917
  loadUsageIndex as loadUsageIndex2,
644
- resolveHaivePaths as resolveHaivePaths9,
645
- serializeMemory as serializeMemory5
918
+ resolveHaivePaths as resolveHaivePaths11,
919
+ serializeMemory as serializeMemory6
646
920
  } from "@hiveai/core";
647
921
  function registerMemoryAutoPromote(memory2) {
648
922
  memory2.command("auto-promote").description("Promote eligible 'proposed' memories to 'validated' based on usage").option("--min-reads <n>", "minimum read_count to qualify", String(DEFAULT_AUTO_PROMOTE_RULE2.minReads)).option(
@@ -650,9 +924,9 @@ function registerMemoryAutoPromote(memory2) {
650
924
  "memories with more rejections than this are skipped",
651
925
  String(DEFAULT_AUTO_PROMOTE_RULE2.maxRejections)
652
926
  ).option("--apply", "actually write status=validated to disk (default: dry-run)").option("-d, --dir <dir>", "project root").action(async (opts) => {
653
- const root = findProjectRoot11(opts.dir);
654
- const paths = resolveHaivePaths9(root);
655
- if (!existsSync10(paths.memoriesDir)) {
927
+ const root = findProjectRoot13(opts.dir);
928
+ const paths = resolveHaivePaths11(root);
929
+ if (!existsSync12(paths.memoriesDir)) {
656
930
  ui.error(`No .ai/memories at ${root}.`);
657
931
  process.exitCode = 1;
658
932
  return;
@@ -661,7 +935,7 @@ function registerMemoryAutoPromote(memory2) {
661
935
  minReads: Number(opts.minReads ?? DEFAULT_AUTO_PROMOTE_RULE2.minReads),
662
936
  maxRejections: Number(opts.maxRejections ?? DEFAULT_AUTO_PROMOTE_RULE2.maxRejections)
663
937
  };
664
- const memories = await loadMemoriesFromDir2(paths.memoriesDir);
938
+ const memories = await loadMemoriesFromDir3(paths.memoriesDir);
665
939
  const usage = await loadUsageIndex2(paths);
666
940
  const eligible = memories.filter(
667
941
  ({ memory: memory3 }) => isAutoPromoteEligible2(memory3.frontmatter, getUsage2(usage, memory3.frontmatter.id), rule)
@@ -678,13 +952,13 @@ function registerMemoryAutoPromote(memory2) {
678
952
  console.log(
679
953
  `${ui.bold(opts.apply ? "PROMOTE" : "would promote")} ${mem.frontmatter.id} ${ui.dim(`reads=${u.read_count} rejections=${u.rejected_count}`)}`
680
954
  );
681
- console.log(` ${ui.dim(path11.relative(root, filePath))}`);
955
+ console.log(` ${ui.dim(path12.relative(root, filePath))}`);
682
956
  if (opts.apply) {
683
957
  const next = {
684
958
  frontmatter: { ...mem.frontmatter, status: "validated" },
685
959
  body: mem.body
686
960
  };
687
- await writeFile7(filePath, serializeMemory5(next), "utf8");
961
+ await writeFile8(filePath, serializeMemory6(next), "utf8");
688
962
  written++;
689
963
  }
690
964
  }
@@ -695,25 +969,25 @@ function registerMemoryAutoPromote(memory2) {
695
969
 
696
970
  // src/commands/memory-edit.ts
697
971
  import { spawn as spawn2 } from "child_process";
698
- import { existsSync as existsSync11 } from "fs";
699
- import { readFile as readFile2 } from "fs/promises";
700
- import path12 from "path";
972
+ import { existsSync as existsSync13 } from "fs";
973
+ import { readFile as readFile3 } from "fs/promises";
974
+ import path13 from "path";
701
975
  import "commander";
702
976
  import {
703
- findProjectRoot as findProjectRoot12,
977
+ findProjectRoot as findProjectRoot14,
704
978
  parseMemory,
705
- resolveHaivePaths as resolveHaivePaths10
979
+ resolveHaivePaths as resolveHaivePaths12
706
980
  } from "@hiveai/core";
707
981
  function registerMemoryEdit(memory2) {
708
982
  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) => {
709
- const root = findProjectRoot12(opts.dir);
710
- const paths = resolveHaivePaths10(root);
711
- if (!existsSync11(paths.memoriesDir)) {
983
+ const root = findProjectRoot14(opts.dir);
984
+ const paths = resolveHaivePaths12(root);
985
+ if (!existsSync13(paths.memoriesDir)) {
712
986
  ui.error(`No .ai/memories at ${root}.`);
713
987
  process.exitCode = 1;
714
988
  return;
715
989
  }
716
- const all = await loadMemoriesFromDir2(paths.memoriesDir);
990
+ const all = await loadMemoriesFromDir3(paths.memoriesDir);
717
991
  const found = all.find((m) => m.memory.frontmatter.id === id);
718
992
  if (!found) {
719
993
  ui.error(`No memory with id "${id}".`);
@@ -721,13 +995,13 @@ function registerMemoryEdit(memory2) {
721
995
  return;
722
996
  }
723
997
  const editor = opts.editor ?? process.env.EDITOR ?? process.env.VISUAL ?? "vi";
724
- ui.info(`Opening ${path12.relative(root, found.filePath)} with ${editor}\u2026`);
998
+ ui.info(`Opening ${path13.relative(root, found.filePath)} with ${editor}\u2026`);
725
999
  const code = await runEditor(editor, found.filePath);
726
1000
  if (code !== 0) {
727
1001
  ui.warn(`Editor exited with status ${code}.`);
728
1002
  }
729
1003
  try {
730
- const fresh = await readFile2(found.filePath, "utf8");
1004
+ const fresh = await readFile3(found.filePath, "utf8");
731
1005
  parseMemory(fresh);
732
1006
  ui.success("Memory still parses cleanly.");
733
1007
  } catch (err) {
@@ -748,28 +1022,28 @@ function runEditor(editor, file) {
748
1022
  }
749
1023
 
750
1024
  // src/commands/memory-for-files.ts
751
- import { existsSync as existsSync12 } from "fs";
752
- import path13 from "path";
1025
+ import { existsSync as existsSync14 } from "fs";
1026
+ import path14 from "path";
753
1027
  import "commander";
754
1028
  import {
755
1029
  deriveConfidence,
756
- findProjectRoot as findProjectRoot13,
1030
+ findProjectRoot as findProjectRoot15,
757
1031
  getUsage as getUsage3,
758
1032
  inferModulesFromPaths as inferModulesFromPaths2,
759
1033
  loadUsageIndex as loadUsageIndex3,
760
- memoryMatchesAnchorPaths,
761
- resolveHaivePaths as resolveHaivePaths11
1034
+ memoryMatchesAnchorPaths as memoryMatchesAnchorPaths2,
1035
+ resolveHaivePaths as resolveHaivePaths13
762
1036
  } from "@hiveai/core";
763
1037
  function registerMemoryForFiles(memory2) {
764
1038
  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) => {
765
- const root = findProjectRoot13(opts.dir);
766
- const paths = resolveHaivePaths11(root);
767
- if (!existsSync12(paths.memoriesDir)) {
1039
+ const root = findProjectRoot15(opts.dir);
1040
+ const paths = resolveHaivePaths13(root);
1041
+ if (!existsSync14(paths.memoriesDir)) {
768
1042
  ui.error(`No .ai/memories at ${root}.`);
769
1043
  process.exitCode = 1;
770
1044
  return;
771
1045
  }
772
- const all = await loadMemoriesFromDir2(paths.memoriesDir);
1046
+ const all = await loadMemoriesFromDir3(paths.memoriesDir);
773
1047
  const usage = await loadUsageIndex3(paths);
774
1048
  const inferred = inferModulesFromPaths2(files);
775
1049
  const byAnchor = [];
@@ -777,7 +1051,7 @@ function registerMemoryForFiles(memory2) {
777
1051
  const byDomain = [];
778
1052
  const seen = /* @__PURE__ */ new Set();
779
1053
  for (const loaded of all) {
780
- if (memoryMatchesAnchorPaths(loaded.memory, files)) {
1054
+ if (memoryMatchesAnchorPaths2(loaded.memory, files)) {
781
1055
  byAnchor.push(loaded);
782
1056
  seen.add(loaded.memory.frontmatter.id);
783
1057
  }
@@ -817,31 +1091,31 @@ function printGroup(root, label, loaded, usage) {
817
1091
  const u = getUsage3(usage, fm.id);
818
1092
  const conf = deriveConfidence(fm, u);
819
1093
  console.log(`${ui.bold(fm.id)} ${ui.dim(`${fm.scope}/${fm.type}`)} ${ui.bold(conf)}`);
820
- console.log(` ${ui.dim(path13.relative(root, filePath))}`);
1094
+ console.log(` ${ui.dim(path14.relative(root, filePath))}`);
821
1095
  }
822
1096
  }
823
1097
 
824
1098
  // src/commands/memory-hot.ts
825
- import { existsSync as existsSync13 } from "fs";
826
- import path14 from "path";
1099
+ import { existsSync as existsSync15 } from "fs";
1100
+ import path15 from "path";
827
1101
  import "commander";
828
1102
  import {
829
- findProjectRoot as findProjectRoot14,
1103
+ findProjectRoot as findProjectRoot16,
830
1104
  getUsage as getUsage4,
831
1105
  loadUsageIndex as loadUsageIndex4,
832
- resolveHaivePaths as resolveHaivePaths12
1106
+ resolveHaivePaths as resolveHaivePaths14
833
1107
  } from "@hiveai/core";
834
1108
  function registerMemoryHot(memory2) {
835
1109
  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) => {
836
- const root = findProjectRoot14(opts.dir);
837
- const paths = resolveHaivePaths12(root);
838
- if (!existsSync13(paths.memoriesDir)) {
1110
+ const root = findProjectRoot16(opts.dir);
1111
+ const paths = resolveHaivePaths14(root);
1112
+ if (!existsSync15(paths.memoriesDir)) {
839
1113
  ui.error(`No .ai/memories at ${root}.`);
840
1114
  process.exitCode = 1;
841
1115
  return;
842
1116
  }
843
1117
  const threshold = Math.max(1, Number(opts.threshold ?? 3));
844
- const all = await loadMemoriesFromDir2(paths.memoriesDir);
1118
+ const all = await loadMemoriesFromDir3(paths.memoriesDir);
845
1119
  const usage = await loadUsageIndex4(paths);
846
1120
  const candidates = all.filter(({ memory: mem }) => {
847
1121
  const fm = mem.frontmatter;
@@ -863,7 +1137,7 @@ function registerMemoryHot(memory2) {
863
1137
  console.log(
864
1138
  `${ui.bold(fm.id)} ${ui.dim(`${fm.scope}/${fm.type}`)} ${ui.bold(fm.status)} ${ui.dim(`reads=${u.read_count} rejections=${u.rejected_count}`)}`
865
1139
  );
866
- console.log(` ${ui.dim(path14.relative(root, filePath))}`);
1140
+ console.log(` ${ui.dim(path15.relative(root, filePath))}`);
867
1141
  }
868
1142
  ui.info(
869
1143
  `${candidates.length} hot \u2014 promote drafts with \`haive memory promote <id>\`, then \`haive memory auto-promote --apply\`.`
@@ -872,25 +1146,25 @@ function registerMemoryHot(memory2) {
872
1146
  }
873
1147
 
874
1148
  // src/commands/memory-pending.ts
875
- import { existsSync as existsSync14 } from "fs";
876
- import path15 from "path";
1149
+ import { existsSync as existsSync16 } from "fs";
1150
+ import path16 from "path";
877
1151
  import "commander";
878
1152
  import {
879
- findProjectRoot as findProjectRoot15,
1153
+ findProjectRoot as findProjectRoot17,
880
1154
  getUsage as getUsage5,
881
1155
  loadUsageIndex as loadUsageIndex5,
882
- resolveHaivePaths as resolveHaivePaths13
1156
+ resolveHaivePaths as resolveHaivePaths15
883
1157
  } from "@hiveai/core";
884
1158
  function registerMemoryPending(memory2) {
885
1159
  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) => {
886
- const root = findProjectRoot15(opts.dir);
887
- const paths = resolveHaivePaths13(root);
888
- if (!existsSync14(paths.memoriesDir)) {
1160
+ const root = findProjectRoot17(opts.dir);
1161
+ const paths = resolveHaivePaths15(root);
1162
+ if (!existsSync16(paths.memoriesDir)) {
889
1163
  ui.error(`No .ai/memories at ${root}.`);
890
1164
  process.exitCode = 1;
891
1165
  return;
892
1166
  }
893
- const all = await loadMemoriesFromDir2(paths.memoriesDir);
1167
+ const all = await loadMemoriesFromDir3(paths.memoriesDir);
894
1168
  const usage = await loadUsageIndex5(paths);
895
1169
  const proposed = all.filter(({ memory: mem }) => {
896
1170
  if (mem.frontmatter.status !== "proposed") return false;
@@ -913,36 +1187,42 @@ function registerMemoryPending(memory2) {
913
1187
  console.log(
914
1188
  `${ui.bold(fm.id)} ${ui.dim(`${fm.scope}/${fm.type}`)} ${ui.dim(`age=${ageStr} reads=${u.read_count} rejections=${u.rejected_count}`)}`
915
1189
  );
916
- console.log(` ${ui.dim(path15.relative(root, filePath))}`);
1190
+ console.log(` ${ui.dim(path16.relative(root, filePath))}`);
917
1191
  }
918
1192
  ui.info(`${proposed.length} pending`);
919
1193
  });
920
1194
  }
921
1195
 
922
1196
  // src/commands/memory-query.ts
923
- import { existsSync as existsSync15 } from "fs";
924
- import path16 from "path";
1197
+ import { existsSync as existsSync17 } from "fs";
1198
+ import path17 from "path";
925
1199
  import "commander";
926
1200
  import {
927
1201
  extractSnippet,
928
- findProjectRoot as findProjectRoot16,
929
- literalMatchesAllTokens,
1202
+ findProjectRoot as findProjectRoot18,
1203
+ literalMatchesAllTokens as literalMatchesAllTokens2,
930
1204
  pickSnippetNeedle,
931
- resolveHaivePaths as resolveHaivePaths14,
932
- tokenizeQuery
1205
+ resolveHaivePaths as resolveHaivePaths16,
1206
+ tokenizeQuery as tokenizeQuery2
933
1207
  } from "@hiveai/core";
934
1208
  function registerMemoryQuery(memory2) {
935
- memory2.command("query <text>").description("Search memories by id, tag, or substring (multi-word AND)").option("-d, --dir <dir>", "project root").option("--limit <n>", "max results", "20").action(async (text, opts) => {
936
- const root = findProjectRoot16(opts.dir);
937
- const paths = resolveHaivePaths14(root);
938
- if (!existsSync15(paths.memoriesDir)) {
1209
+ memory2.command("query <text>").description("Search memories by id, tag, or substring (multi-word AND)").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)").action(async (text, opts) => {
1210
+ const root = findProjectRoot18(opts.dir);
1211
+ const paths = resolveHaivePaths16(root);
1212
+ if (!existsSync17(paths.memoriesDir)) {
939
1213
  ui.error(`No memories directory at ${paths.memoriesDir}. Run \`haive init\` first.`);
940
1214
  process.exitCode = 1;
941
1215
  return;
942
1216
  }
943
- const tokens = tokenizeQuery(text);
944
- const all = await loadMemoriesFromDir2(paths.memoriesDir);
945
- const matches = all.filter(({ memory: mem }) => literalMatchesAllTokens(mem, tokens));
1217
+ const tokens = tokenizeQuery2(text);
1218
+ const statusFilter = opts.status ? opts.status.split(",").map((s) => s.trim()) : null;
1219
+ const all = await loadMemoriesFromDir3(paths.memoriesDir);
1220
+ const matches = all.filter(({ memory: mem }) => {
1221
+ const fm = mem.frontmatter;
1222
+ if (opts.scope && fm.scope !== opts.scope) return false;
1223
+ if (statusFilter && !statusFilter.includes(fm.status)) return false;
1224
+ return literalMatchesAllTokens2(mem, tokens);
1225
+ });
946
1226
  const limit = Math.max(1, Number(opts.limit ?? 20));
947
1227
  const top = matches.slice(0, limit);
948
1228
  if (top.length === 0) {
@@ -951,9 +1231,11 @@ function registerMemoryQuery(memory2) {
951
1231
  }
952
1232
  const snippetNeedle = pickSnippetNeedle(text);
953
1233
  for (const { memory: mem, filePath } of top) {
1234
+ const fm = mem.frontmatter;
1235
+ const statusBadge = ui.statusBadge(fm.status);
1236
+ console.log(`${ui.bold(fm.id)} ${ui.dim(fm.scope)} ${statusBadge}`);
1237
+ console.log(` ${ui.dim(path17.relative(root, filePath))}`);
954
1238
  const snippet = extractSnippet(mem.body, snippetNeedle);
955
- console.log(`${ui.bold(mem.frontmatter.id)} ${ui.dim(mem.frontmatter.scope)}`);
956
- console.log(` ${ui.dim(path16.relative(root, filePath))}`);
957
1239
  if (snippet) console.log(` ${snippet}`);
958
1240
  }
959
1241
  console.log(
@@ -964,70 +1246,81 @@ ${top.length} of ${matches.length} match${matches.length === 1 ? "" : "es"}`)
964
1246
  }
965
1247
 
966
1248
  // src/commands/memory-reject.ts
967
- import { existsSync as existsSync16 } from "fs";
1249
+ import { writeFile as writeFile9 } from "fs/promises";
1250
+ import { existsSync as existsSync18 } from "fs";
968
1251
  import "commander";
969
1252
  import {
970
- findProjectRoot as findProjectRoot17,
1253
+ findProjectRoot as findProjectRoot19,
971
1254
  loadUsageIndex as loadUsageIndex6,
972
1255
  recordRejection,
973
- resolveHaivePaths as resolveHaivePaths15,
974
- saveUsageIndex
1256
+ resolveHaivePaths as resolveHaivePaths17,
1257
+ saveUsageIndex,
1258
+ serializeMemory as serializeMemory7
975
1259
  } from "@hiveai/core";
976
1260
  function registerMemoryReject(memory2) {
977
1261
  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) => {
978
- const root = findProjectRoot17(opts.dir);
979
- const paths = resolveHaivePaths15(root);
980
- if (!existsSync16(paths.memoriesDir)) {
1262
+ const root = findProjectRoot19(opts.dir);
1263
+ const paths = resolveHaivePaths17(root);
1264
+ if (!existsSync18(paths.memoriesDir)) {
981
1265
  ui.error(`No .ai/memories at ${root}.`);
982
1266
  process.exitCode = 1;
983
1267
  return;
984
1268
  }
985
- const memories = await loadMemoriesFromDir2(paths.memoriesDir);
986
- if (!memories.some((m) => m.memory.frontmatter.id === id)) {
1269
+ const memories = await loadMemoriesFromDir3(paths.memoriesDir);
1270
+ const loaded = memories.find((m) => m.memory.frontmatter.id === id);
1271
+ if (!loaded) {
987
1272
  ui.error(`No memory with id "${id}".`);
988
1273
  process.exitCode = 1;
989
1274
  return;
990
1275
  }
1276
+ await writeFile9(
1277
+ loaded.filePath,
1278
+ serializeMemory7({
1279
+ frontmatter: { ...loaded.memory.frontmatter, status: "rejected" },
1280
+ body: loaded.memory.body
1281
+ }),
1282
+ "utf8"
1283
+ );
991
1284
  const idx = await loadUsageIndex6(paths);
992
1285
  recordRejection(idx, id, opts.reason ?? null);
993
1286
  await saveUsageIndex(paths, idx);
994
1287
  const u = idx.by_id[id];
995
1288
  ui.success(
996
- `Recorded rejection for ${id} (now ${u.rejected_count} rejection${u.rejected_count === 1 ? "" : "s"})`
1289
+ `Rejected ${id} (status=rejected, ${u.rejected_count} rejection${u.rejected_count === 1 ? "" : "s"})`
997
1290
  );
998
1291
  if (opts.reason) ui.info(`reason: ${opts.reason}`);
999
1292
  });
1000
1293
  }
1001
1294
 
1002
1295
  // src/commands/memory-rm.ts
1003
- import { existsSync as existsSync17 } from "fs";
1296
+ import { existsSync as existsSync19 } from "fs";
1004
1297
  import { unlink as unlink2 } from "fs/promises";
1005
- import path17 from "path";
1298
+ import path18 from "path";
1006
1299
  import { createInterface } from "readline/promises";
1007
1300
  import "commander";
1008
1301
  import {
1009
- findProjectRoot as findProjectRoot18,
1302
+ findProjectRoot as findProjectRoot20,
1010
1303
  loadUsageIndex as loadUsageIndex7,
1011
- resolveHaivePaths as resolveHaivePaths16,
1304
+ resolveHaivePaths as resolveHaivePaths18,
1012
1305
  saveUsageIndex as saveUsageIndex2
1013
1306
  } from "@hiveai/core";
1014
1307
  function registerMemoryRm(memory2) {
1015
1308
  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) => {
1016
- const root = findProjectRoot18(opts.dir);
1017
- const paths = resolveHaivePaths16(root);
1018
- if (!existsSync17(paths.memoriesDir)) {
1309
+ const root = findProjectRoot20(opts.dir);
1310
+ const paths = resolveHaivePaths18(root);
1311
+ if (!existsSync19(paths.memoriesDir)) {
1019
1312
  ui.error(`No .ai/memories at ${root}.`);
1020
1313
  process.exitCode = 1;
1021
1314
  return;
1022
1315
  }
1023
- const all = await loadMemoriesFromDir2(paths.memoriesDir);
1316
+ const all = await loadMemoriesFromDir3(paths.memoriesDir);
1024
1317
  const found = all.find((m) => m.memory.frontmatter.id === id);
1025
1318
  if (!found) {
1026
1319
  ui.error(`No memory with id "${id}".`);
1027
1320
  process.exitCode = 1;
1028
1321
  return;
1029
1322
  }
1030
- const rel = path17.relative(root, found.filePath);
1323
+ const rel = path18.relative(root, found.filePath);
1031
1324
  if (!opts.yes) {
1032
1325
  const rl = createInterface({ input: process.stdin, output: process.stdout });
1033
1326
  const answer = (await rl.question(`Delete ${rel}? [y/N] `)).trim().toLowerCase();
@@ -1051,27 +1344,27 @@ function registerMemoryRm(memory2) {
1051
1344
  }
1052
1345
 
1053
1346
  // src/commands/memory-show.ts
1054
- import { existsSync as existsSync18 } from "fs";
1055
- import { readFile as readFile3 } from "fs/promises";
1056
- import path18 from "path";
1347
+ import { existsSync as existsSync20 } from "fs";
1348
+ import { readFile as readFile4 } from "fs/promises";
1349
+ import path19 from "path";
1057
1350
  import "commander";
1058
1351
  import {
1059
1352
  deriveConfidence as deriveConfidence2,
1060
- findProjectRoot as findProjectRoot19,
1353
+ findProjectRoot as findProjectRoot21,
1061
1354
  getUsage as getUsage6,
1062
1355
  loadUsageIndex as loadUsageIndex8,
1063
- resolveHaivePaths as resolveHaivePaths17
1356
+ resolveHaivePaths as resolveHaivePaths19
1064
1357
  } from "@hiveai/core";
1065
1358
  function registerMemoryShow(memory2) {
1066
1359
  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) => {
1067
- const root = findProjectRoot19(opts.dir);
1068
- const paths = resolveHaivePaths17(root);
1069
- if (!existsSync18(paths.memoriesDir)) {
1360
+ const root = findProjectRoot21(opts.dir);
1361
+ const paths = resolveHaivePaths19(root);
1362
+ if (!existsSync20(paths.memoriesDir)) {
1070
1363
  ui.error(`No .ai/memories at ${root}.`);
1071
1364
  process.exitCode = 1;
1072
1365
  return;
1073
1366
  }
1074
- const all = await loadMemoriesFromDir2(paths.memoriesDir);
1367
+ const all = await loadMemoriesFromDir3(paths.memoriesDir);
1075
1368
  const found = all.find((m) => m.memory.frontmatter.id === id);
1076
1369
  if (!found) {
1077
1370
  ui.error(`No memory with id "${id}".`);
@@ -1079,7 +1372,7 @@ function registerMemoryShow(memory2) {
1079
1372
  return;
1080
1373
  }
1081
1374
  if (opts.raw) {
1082
- console.log(await readFile3(found.filePath, "utf8"));
1375
+ console.log(await readFile4(found.filePath, "utf8"));
1083
1376
  return;
1084
1377
  }
1085
1378
  const fm = found.memory.frontmatter;
@@ -1095,7 +1388,7 @@ function registerMemoryShow(memory2) {
1095
1388
  if (fm.verified_at) console.log(`${ui.dim("verified:")} ${fm.verified_at}`);
1096
1389
  if (fm.stale_reason) console.log(`${ui.dim("stale:")} ${fm.stale_reason}`);
1097
1390
  console.log(`${ui.dim("reads:")} ${u.read_count} ${ui.dim("rejections:")} ${u.rejected_count}`);
1098
- console.log(`${ui.dim("file:")} ${path18.relative(root, found.filePath)}`);
1391
+ console.log(`${ui.dim("file:")} ${path19.relative(root, found.filePath)}`);
1099
1392
  if (fm.anchor.paths.length || fm.anchor.symbols.length) {
1100
1393
  console.log(ui.dim("anchor:"));
1101
1394
  if (fm.anchor.commit) console.log(` ${ui.dim("commit:")} ${fm.anchor.commit}`);
@@ -1110,26 +1403,26 @@ function registerMemoryShow(memory2) {
1110
1403
  }
1111
1404
 
1112
1405
  // src/commands/memory-stats.ts
1113
- import { existsSync as existsSync19 } from "fs";
1114
- import path19 from "path";
1406
+ import { existsSync as existsSync21 } from "fs";
1407
+ import path20 from "path";
1115
1408
  import "commander";
1116
1409
  import {
1117
1410
  deriveConfidence as deriveConfidence3,
1118
- findProjectRoot as findProjectRoot20,
1411
+ findProjectRoot as findProjectRoot22,
1119
1412
  getUsage as getUsage7,
1120
1413
  loadUsageIndex as loadUsageIndex9,
1121
- resolveHaivePaths as resolveHaivePaths18
1414
+ resolveHaivePaths as resolveHaivePaths20
1122
1415
  } from "@hiveai/core";
1123
1416
  function registerMemoryStats(memory2) {
1124
1417
  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) => {
1125
- const root = findProjectRoot20(opts.dir);
1126
- const paths = resolveHaivePaths18(root);
1127
- if (!existsSync19(paths.memoriesDir)) {
1418
+ const root = findProjectRoot22(opts.dir);
1419
+ const paths = resolveHaivePaths20(root);
1420
+ if (!existsSync21(paths.memoriesDir)) {
1128
1421
  ui.error(`No .ai/memories at ${root}. Run \`haive init\` first.`);
1129
1422
  process.exitCode = 1;
1130
1423
  return;
1131
1424
  }
1132
- const all = await loadMemoriesFromDir2(paths.memoriesDir);
1425
+ const all = await loadMemoriesFromDir3(paths.memoriesDir);
1133
1426
  const usage = await loadUsageIndex9(paths);
1134
1427
  const target = opts.id ? all.filter((m) => m.memory.frontmatter.id === opts.id) : all;
1135
1428
  if (target.length === 0) {
@@ -1149,32 +1442,32 @@ function registerMemoryStats(memory2) {
1149
1442
  console.log(
1150
1443
  ` ${ui.dim("status:")} ${fm.status} ${ui.dim("reads:")} ${u.read_count} ${ui.dim("rejections:")} ${u.rejected_count}`
1151
1444
  );
1152
- console.log(` ${ui.dim(path19.relative(root, filePath))}`);
1445
+ console.log(` ${ui.dim(path20.relative(root, filePath))}`);
1153
1446
  }
1154
1447
  });
1155
1448
  }
1156
1449
 
1157
1450
  // src/commands/memory-verify.ts
1158
- import { writeFile as writeFile8 } from "fs/promises";
1159
- import { existsSync as existsSync20 } from "fs";
1160
- import path20 from "path";
1451
+ import { writeFile as writeFile10 } from "fs/promises";
1452
+ import { existsSync as existsSync22 } from "fs";
1453
+ import path21 from "path";
1161
1454
  import "commander";
1162
1455
  import {
1163
- findProjectRoot as findProjectRoot21,
1164
- resolveHaivePaths as resolveHaivePaths19,
1165
- serializeMemory as serializeMemory6,
1456
+ findProjectRoot as findProjectRoot23,
1457
+ resolveHaivePaths as resolveHaivePaths21,
1458
+ serializeMemory as serializeMemory8,
1166
1459
  verifyAnchor as verifyAnchor2
1167
1460
  } from "@hiveai/core";
1168
1461
  function registerMemoryVerify(memory2) {
1169
1462
  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) => {
1170
- const root = findProjectRoot21(opts.dir);
1171
- const paths = resolveHaivePaths19(root);
1172
- if (!existsSync20(paths.memoriesDir)) {
1463
+ const root = findProjectRoot23(opts.dir);
1464
+ const paths = resolveHaivePaths21(root);
1465
+ if (!existsSync22(paths.memoriesDir)) {
1173
1466
  ui.error(`No .ai/memories at ${root}. Run \`haive init\` first.`);
1174
1467
  process.exitCode = 1;
1175
1468
  return;
1176
1469
  }
1177
- const all = await loadMemoriesFromDir2(paths.memoriesDir);
1470
+ const all = await loadMemoriesFromDir3(paths.memoriesDir);
1178
1471
  const targets = opts.id ? all.filter((m) => m.memory.frontmatter.id === opts.id) : all;
1179
1472
  if (opts.id && targets.length === 0) {
1180
1473
  ui.error(`No memory with id "${opts.id}".`);
@@ -1192,7 +1485,7 @@ function registerMemoryVerify(memory2) {
1192
1485
  anchorless++;
1193
1486
  continue;
1194
1487
  }
1195
- const rel = path20.relative(root, filePath);
1488
+ const rel = path21.relative(root, filePath);
1196
1489
  if (result.stale) {
1197
1490
  staleCount++;
1198
1491
  console.log(`${ui.bold("STALE")} ${mem.frontmatter.id}`);
@@ -1204,7 +1497,7 @@ function registerMemoryVerify(memory2) {
1204
1497
  }
1205
1498
  if (opts.update) {
1206
1499
  const next = applyVerification(mem, result);
1207
- await writeFile8(filePath, serializeMemory6(next), "utf8");
1500
+ await writeFile10(filePath, serializeMemory8(next), "utf8");
1208
1501
  updated++;
1209
1502
  }
1210
1503
  }
@@ -1243,10 +1536,11 @@ function applyVerification(mem, result) {
1243
1536
  }
1244
1537
 
1245
1538
  // src/index.ts
1246
- var program = new Command22();
1247
- program.name("haive").description("hAIve \u2014 team-first persistent memory layer for AI coding agents").version("0.2.1");
1539
+ var program = new Command24();
1540
+ program.name("haive").description("hAIve \u2014 team-first persistent memory layer for AI coding agents").version("0.2.3");
1248
1541
  registerInit(program);
1249
1542
  registerMcp(program);
1543
+ registerBriefing(program);
1250
1544
  registerEmbeddings(program);
1251
1545
  registerSync(program);
1252
1546
  registerInstallHooks(program);
@@ -1266,6 +1560,7 @@ registerMemoryEdit(memory);
1266
1560
  registerMemoryRm(memory);
1267
1561
  registerMemoryPending(memory);
1268
1562
  registerMemoryApprove(memory);
1563
+ registerMemoryUpdate(memory);
1269
1564
  registerMemoryHot(memory);
1270
1565
  program.parseAsync(process.argv).catch((err) => {
1271
1566
  if (isZodError(err)) {