@hiveai/cli 0.2.3 → 0.2.5

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,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { Command as Command24 } from "commander";
4
+ import { Command as Command25 } from "commander";
5
5
 
6
6
  // src/commands/briefing.ts
7
7
  import { existsSync } from "fs";
@@ -52,9 +52,9 @@ function registerBriefing(program2) {
52
52
  "Print project context + relevant memories in one shot \u2014 ideal for agent onboarding"
53
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
54
  "--scope <scope>",
55
- "personal | team | module (default: team + validated only)",
55
+ "personal | team | module | all (default: team)",
56
56
  "team"
57
- ).option("-d, --dir <dir>", "project root").action(async (opts) => {
57
+ ).option("--include-draft", "include draft memories (excluded by default)").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)) {
@@ -77,6 +77,7 @@ function registerBriefing(program2) {
77
77
  const candidates = all.filter(({ memory: mem }) => {
78
78
  const fm = mem.frontmatter;
79
79
  if (fm.status === "rejected" || fm.status === "deprecated") return false;
80
+ if (!opts.includeDraft && fm.status === "draft") return false;
80
81
  if (scopeFilter !== "all" && fm.scope !== scopeFilter) return false;
81
82
  return true;
82
83
  });
@@ -93,6 +94,12 @@ function registerBriefing(program2) {
93
94
  const top = scored.slice(0, maxMemories);
94
95
  if (top.length === 0) {
95
96
  ui.info("No relevant memories found.");
97
+ const draftCount = all.filter(
98
+ (m) => m.memory.frontmatter.status === "draft" && (scopeFilter === "all" || m.memory.frontmatter.scope === scopeFilter)
99
+ ).length;
100
+ if (draftCount > 0) {
101
+ ui.info(`(${draftCount} draft memories excluded \u2014 use --include-draft to show)`);
102
+ }
96
103
  return;
97
104
  }
98
105
  console.log(`${ui.bold("=== Relevant Memories ===")}
@@ -100,8 +107,9 @@ function registerBriefing(program2) {
100
107
  for (const { memory: mem } of top) {
101
108
  const fm = mem.frontmatter;
102
109
  const badge = ui.statusBadge(fm.status);
110
+ const draftMarker = fm.status === "draft" ? ui.yellow(" [DRAFT]") : "";
103
111
  console.log(
104
- `${ui.bold(fm.id)} ${ui.dim(fm.scope + "/" + fm.type)} ${badge}`
112
+ `${ui.bold(fm.id)} ${ui.dim(fm.scope + "/" + fm.type)} ${badge}${draftMarker}`
105
113
  );
106
114
  console.log(mem.body.trim());
107
115
  console.log();
@@ -114,15 +122,34 @@ function parseCsv(value) {
114
122
  return value.split(",").map((s) => s.trim()).filter(Boolean);
115
123
  }
116
124
 
125
+ // src/commands/tui.ts
126
+ import "commander";
127
+ import { findProjectRoot as findProjectRoot2 } from "@hiveai/core";
128
+ function registerTui(program2) {
129
+ 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) => {
130
+ if (!process.stdout.isTTY) {
131
+ console.error("haive tui requires an interactive terminal (TTY).");
132
+ process.exitCode = 1;
133
+ return;
134
+ }
135
+ const root = findProjectRoot2(opts.dir);
136
+ const { render } = await import("ink");
137
+ const { createElement } = await import("react");
138
+ const { Dashboard } = await import("./Dashboard-SRPCHP7Z.js");
139
+ const { waitUntilExit } = render(createElement(Dashboard, { root }));
140
+ await waitUntilExit();
141
+ });
142
+ }
143
+
117
144
  // src/commands/embeddings.ts
118
145
  import { existsSync as existsSync2 } from "fs";
119
146
  import path from "path";
120
147
  import "commander";
121
- import { findProjectRoot as findProjectRoot2, resolveHaivePaths as resolveHaivePaths2 } from "@hiveai/core";
148
+ import { findProjectRoot as findProjectRoot3, resolveHaivePaths as resolveHaivePaths2 } from "@hiveai/core";
122
149
  function registerEmbeddings(program2) {
123
150
  const embeddings = program2.command("embeddings").description("Manage local embeddings index for semantic search");
124
151
  embeddings.command("index").description("Generate or refresh the embeddings index for all memories").option("-d, --dir <dir>", "project root").action(async (opts) => {
125
- const root = findProjectRoot2(opts.dir);
152
+ const root = findProjectRoot3(opts.dir);
126
153
  const paths = resolveHaivePaths2(root);
127
154
  if (!existsSync2(paths.memoriesDir)) {
128
155
  ui.error(`No .ai/memories at ${root}. Run \`haive init\` first.`);
@@ -139,7 +166,7 @@ function registerEmbeddings(program2) {
139
166
  );
140
167
  });
141
168
  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) => {
142
- const root = findProjectRoot2(opts.dir);
169
+ const root = findProjectRoot3(opts.dir);
143
170
  const paths = resolveHaivePaths2(root);
144
171
  const { semanticSearch } = await loadEmbeddings();
145
172
  const result = await semanticSearch(paths, text, {
@@ -162,7 +189,7 @@ function registerEmbeddings(program2) {
162
189
  }
163
190
  });
164
191
  embeddings.command("status").description("Show the embeddings index status").option("-d, --dir <dir>", "project root").action(async (opts) => {
165
- const root = findProjectRoot2(opts.dir);
192
+ const root = findProjectRoot3(opts.dir);
166
193
  const paths = resolveHaivePaths2(root);
167
194
  const { indexStat } = await loadEmbeddings();
168
195
  const stat = await indexStat(paths);
@@ -193,7 +220,7 @@ import "commander";
193
220
  import {
194
221
  buildCodeMap,
195
222
  codeMapPath,
196
- findProjectRoot as findProjectRoot3,
223
+ findProjectRoot as findProjectRoot4,
197
224
  resolveHaivePaths as resolveHaivePaths3,
198
225
  saveCodeMap
199
226
  } from "@hiveai/core";
@@ -205,7 +232,7 @@ function registerIndexCode(program2) {
205
232
  "extra directory names to skip (comma-separated)",
206
233
  ""
207
234
  ).action(async (opts) => {
208
- const root = findProjectRoot3(opts.dir);
235
+ const root = findProjectRoot4(opts.dir);
209
236
  const paths = resolveHaivePaths3(root);
210
237
  const extraExcludes = (opts.exclude ?? "").split(",").map((s) => s.trim()).filter(Boolean);
211
238
  ui.info(`Indexing source files in ${root}\u2026`);
@@ -303,7 +330,7 @@ import { mkdir as mkdir2, writeFile as writeFile2, chmod, readFile as readFile2
303
330
  import { existsSync as existsSync4 } from "fs";
304
331
  import path4 from "path";
305
332
  import "commander";
306
- import { findProjectRoot as findProjectRoot5 } from "@hiveai/core";
333
+ import { findProjectRoot as findProjectRoot6 } from "@hiveai/core";
307
334
  var HOOK_MARKER = "# hAIve auto-generated";
308
335
  var HOOK_BODY = `#!/bin/sh
309
336
  ${HOOK_MARKER} \u2014 keep this block to allow upgrades. Hand-edit anything outside it.
@@ -319,7 +346,7 @@ fi
319
346
  var HOOKS = ["post-merge", "post-rewrite"];
320
347
  function registerInstallHooks(program2) {
321
348
  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) => {
322
- const root = findProjectRoot5(opts.dir);
349
+ const root = findProjectRoot6(opts.dir);
323
350
  const gitDir = path4.join(root, ".git");
324
351
  if (!existsSync4(gitDir)) {
325
352
  ui.error(`No .git directory at ${root}.`);
@@ -356,11 +383,11 @@ import { createRequire } from "module";
356
383
  import path5 from "path";
357
384
  import { fileURLToPath } from "url";
358
385
  import "commander";
359
- import { findProjectRoot as findProjectRoot6 } from "@hiveai/core";
386
+ import { findProjectRoot as findProjectRoot7 } from "@hiveai/core";
360
387
  var require2 = createRequire(import.meta.url);
361
388
  function registerMcp(program2) {
362
389
  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) => {
363
- const root = findProjectRoot6(opts.dir);
390
+ const root = findProjectRoot7(opts.dir);
364
391
  const bin = locateMcpBin();
365
392
  if (!bin) {
366
393
  ui.error(
@@ -397,7 +424,7 @@ import "path";
397
424
  import "commander";
398
425
  import {
399
426
  DEFAULT_AUTO_PROMOTE_RULE,
400
- findProjectRoot as findProjectRoot7,
427
+ findProjectRoot as findProjectRoot8,
401
428
  getUsage,
402
429
  isAutoPromoteEligible,
403
430
  loadMemoriesFromDir as loadMemoriesFromDir2,
@@ -411,7 +438,7 @@ function registerSync(program2) {
411
438
  "--since <ref>",
412
439
  "git ref/commit to compare against; report memories added/modified/removed since"
413
440
  ).option("--no-verify", "skip the anchor verification step").option("--no-promote", "skip the auto-promotion step").action(async (opts) => {
414
- const root = findProjectRoot7(opts.dir);
441
+ const root = findProjectRoot8(opts.dir);
415
442
  const paths = resolveHaivePaths5(root);
416
443
  if (!existsSync6(paths.memoriesDir)) {
417
444
  if (!opts.quiet) ui.warn(`No .ai/memories at ${root}. Run \`haive init\` first.`);
@@ -544,7 +571,7 @@ import path7 from "path";
544
571
  import "commander";
545
572
  import {
546
573
  buildFrontmatter,
547
- findProjectRoot as findProjectRoot8,
574
+ findProjectRoot as findProjectRoot9,
548
575
  inferModulesFromPaths,
549
576
  memoryFilePath,
550
577
  resolveHaivePaths as resolveHaivePaths6,
@@ -552,7 +579,7 @@ import {
552
579
  } from "@hiveai/core";
553
580
  function registerMemoryAdd(memory2) {
554
581
  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);
582
+ const root = findProjectRoot9(opts.dir);
556
583
  const paths = resolveHaivePaths6(root);
557
584
  if (!existsSync7(paths.haiveDir)) {
558
585
  ui.error(`No .ai/ found at ${root}. Run \`haive init\` first.`);
@@ -623,7 +650,7 @@ function parseCsv2(value) {
623
650
  import { existsSync as existsSync8 } from "fs";
624
651
  import path8 from "path";
625
652
  import "commander";
626
- import { findProjectRoot as findProjectRoot9, resolveHaivePaths as resolveHaivePaths7 } from "@hiveai/core";
653
+ import { findProjectRoot as findProjectRoot10, resolveHaivePaths as resolveHaivePaths7 } from "@hiveai/core";
627
654
 
628
655
  // src/utils/fs.ts
629
656
  import {
@@ -635,7 +662,7 @@ import {
635
662
  // src/commands/memory-list.ts
636
663
  function registerMemoryList(memory2) {
637
664
  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);
665
+ const root = findProjectRoot10(opts.dir);
639
666
  const paths = resolveHaivePaths7(root);
640
667
  if (!existsSync8(paths.memoriesDir)) {
641
668
  ui.error(`No memories directory at ${paths.memoriesDir}. Run \`haive init\` first.`);
@@ -647,15 +674,17 @@ function registerMemoryList(memory2) {
647
674
  const filtered = all.filter((m) => {
648
675
  if (!matchesFilters(m, opts)) return false;
649
676
  const status = m.memory.frontmatter.status;
650
- if (!opts.showRejected && status === "rejected") return false;
677
+ if (!opts.showRejected && !statusFilter && status === "rejected") return false;
651
678
  if (statusFilter && !statusFilter.includes(status)) return false;
652
679
  return true;
653
680
  });
681
+ const hiddenRejectedCount = !opts.showRejected && !statusFilter ? all.filter(
682
+ (m) => matchesFilters(m, opts) && m.memory.frontmatter.status === "rejected"
683
+ ).length : 0;
654
684
  if (filtered.length === 0) {
655
685
  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)`);
686
+ if (hiddenRejectedCount > 0) {
687
+ ui.info(`(${hiddenRejectedCount} rejected hidden \u2014 use --show-rejected to include)`);
659
688
  }
660
689
  return;
661
690
  }
@@ -671,13 +700,24 @@ function registerMemoryList(memory2) {
671
700
  }
672
701
  console.log(ui.dim(`
673
702
  ${filtered.length} memor${filtered.length === 1 ? "y" : "ies"}`));
674
- const draftCount = filtered.filter((m) => m.memory.frontmatter.status === "draft").length;
675
- if (draftCount > 0) {
703
+ if (hiddenRejectedCount > 0) {
676
704
  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
- )
705
+ ui.dim(`(${hiddenRejectedCount} rejected hidden \u2014 use --show-rejected to include)`)
706
+ );
707
+ }
708
+ const draftItems = filtered.filter((m) => m.memory.frontmatter.status === "draft");
709
+ if (draftItems.length > 0) {
710
+ const hasPersonalDrafts = draftItems.some(
711
+ (m) => m.memory.frontmatter.scope === "personal"
680
712
  );
713
+ const hasTeamDrafts = draftItems.some(
714
+ (m) => m.memory.frontmatter.scope !== "personal"
715
+ );
716
+ let hint = `\u2139 ${draftItems.length} in draft \u2014 use \`haive memory approve <id>\` to activate`;
717
+ if (hasPersonalDrafts && !hasTeamDrafts) {
718
+ hint += " or `haive memory promote <id>` to share with team";
719
+ }
720
+ console.log(ui.dim(hint));
681
721
  }
682
722
  });
683
723
  }
@@ -696,14 +736,14 @@ import { existsSync as existsSync9 } from "fs";
696
736
  import path9 from "path";
697
737
  import "commander";
698
738
  import {
699
- findProjectRoot as findProjectRoot10,
739
+ findProjectRoot as findProjectRoot11,
700
740
  memoryFilePath as memoryFilePath2,
701
741
  resolveHaivePaths as resolveHaivePaths8,
702
742
  serializeMemory as serializeMemory3
703
743
  } from "@hiveai/core";
704
744
  function registerMemoryPromote(memory2) {
705
745
  memory2.command("promote <id>").description("Promote a personal memory to team scope (status -> proposed)").option("-d, --dir <dir>", "project root").action(async (id, opts) => {
706
- const root = findProjectRoot10(opts.dir);
746
+ const root = findProjectRoot11(opts.dir);
707
747
  const paths = resolveHaivePaths8(root);
708
748
  if (!existsSync9(paths.memoriesDir)) {
709
749
  ui.error(`No memories directory at ${paths.memoriesDir}. Run \`haive init\` first.`);
@@ -755,13 +795,13 @@ import { writeFile as writeFile6 } from "fs/promises";
755
795
  import path10 from "path";
756
796
  import "commander";
757
797
  import {
758
- findProjectRoot as findProjectRoot11,
798
+ findProjectRoot as findProjectRoot12,
759
799
  resolveHaivePaths as resolveHaivePaths9,
760
800
  serializeMemory as serializeMemory4
761
801
  } from "@hiveai/core";
762
802
  function registerMemoryApprove(memory2) {
763
803
  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);
804
+ const root = findProjectRoot12(opts.dir);
765
805
  const paths = resolveHaivePaths9(root);
766
806
  if (!existsSync10(paths.memoriesDir)) {
767
807
  ui.error(`No .ai/memories at ${root}.`);
@@ -826,13 +866,13 @@ import { existsSync as existsSync11 } from "fs";
826
866
  import path11 from "path";
827
867
  import "commander";
828
868
  import {
829
- findProjectRoot as findProjectRoot12,
869
+ findProjectRoot as findProjectRoot13,
830
870
  resolveHaivePaths as resolveHaivePaths10,
831
871
  serializeMemory as serializeMemory5
832
872
  } from "@hiveai/core";
833
873
  function registerMemoryUpdate(memory2) {
834
874
  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);
875
+ const root = findProjectRoot13(opts.dir);
836
876
  const paths = resolveHaivePaths10(root);
837
877
  if (!existsSync11(paths.memoriesDir)) {
838
878
  ui.error(`No .ai/memories at ${root}. Run \`haive init\` first.`);
@@ -911,7 +951,7 @@ import path12 from "path";
911
951
  import "commander";
912
952
  import {
913
953
  DEFAULT_AUTO_PROMOTE_RULE as DEFAULT_AUTO_PROMOTE_RULE2,
914
- findProjectRoot as findProjectRoot13,
954
+ findProjectRoot as findProjectRoot14,
915
955
  getUsage as getUsage2,
916
956
  isAutoPromoteEligible as isAutoPromoteEligible2,
917
957
  loadUsageIndex as loadUsageIndex2,
@@ -924,7 +964,7 @@ function registerMemoryAutoPromote(memory2) {
924
964
  "memories with more rejections than this are skipped",
925
965
  String(DEFAULT_AUTO_PROMOTE_RULE2.maxRejections)
926
966
  ).option("--apply", "actually write status=validated to disk (default: dry-run)").option("-d, --dir <dir>", "project root").action(async (opts) => {
927
- const root = findProjectRoot13(opts.dir);
967
+ const root = findProjectRoot14(opts.dir);
928
968
  const paths = resolveHaivePaths11(root);
929
969
  if (!existsSync12(paths.memoriesDir)) {
930
970
  ui.error(`No .ai/memories at ${root}.`);
@@ -974,13 +1014,13 @@ import { readFile as readFile3 } from "fs/promises";
974
1014
  import path13 from "path";
975
1015
  import "commander";
976
1016
  import {
977
- findProjectRoot as findProjectRoot14,
1017
+ findProjectRoot as findProjectRoot15,
978
1018
  parseMemory,
979
1019
  resolveHaivePaths as resolveHaivePaths12
980
1020
  } from "@hiveai/core";
981
1021
  function registerMemoryEdit(memory2) {
982
1022
  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) => {
983
- const root = findProjectRoot14(opts.dir);
1023
+ const root = findProjectRoot15(opts.dir);
984
1024
  const paths = resolveHaivePaths12(root);
985
1025
  if (!existsSync13(paths.memoriesDir)) {
986
1026
  ui.error(`No .ai/memories at ${root}.`);
@@ -1027,7 +1067,7 @@ import path14 from "path";
1027
1067
  import "commander";
1028
1068
  import {
1029
1069
  deriveConfidence,
1030
- findProjectRoot as findProjectRoot15,
1070
+ findProjectRoot as findProjectRoot16,
1031
1071
  getUsage as getUsage3,
1032
1072
  inferModulesFromPaths as inferModulesFromPaths2,
1033
1073
  loadUsageIndex as loadUsageIndex3,
@@ -1036,7 +1076,7 @@ import {
1036
1076
  } from "@hiveai/core";
1037
1077
  function registerMemoryForFiles(memory2) {
1038
1078
  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) => {
1039
- const root = findProjectRoot15(opts.dir);
1079
+ const root = findProjectRoot16(opts.dir);
1040
1080
  const paths = resolveHaivePaths13(root);
1041
1081
  if (!existsSync14(paths.memoriesDir)) {
1042
1082
  ui.error(`No .ai/memories at ${root}.`);
@@ -1100,14 +1140,14 @@ import { existsSync as existsSync15 } from "fs";
1100
1140
  import path15 from "path";
1101
1141
  import "commander";
1102
1142
  import {
1103
- findProjectRoot as findProjectRoot16,
1143
+ findProjectRoot as findProjectRoot17,
1104
1144
  getUsage as getUsage4,
1105
1145
  loadUsageIndex as loadUsageIndex4,
1106
1146
  resolveHaivePaths as resolveHaivePaths14
1107
1147
  } from "@hiveai/core";
1108
1148
  function registerMemoryHot(memory2) {
1109
1149
  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) => {
1110
- const root = findProjectRoot16(opts.dir);
1150
+ const root = findProjectRoot17(opts.dir);
1111
1151
  const paths = resolveHaivePaths14(root);
1112
1152
  if (!existsSync15(paths.memoriesDir)) {
1113
1153
  ui.error(`No .ai/memories at ${root}.`);
@@ -1150,14 +1190,14 @@ import { existsSync as existsSync16 } from "fs";
1150
1190
  import path16 from "path";
1151
1191
  import "commander";
1152
1192
  import {
1153
- findProjectRoot as findProjectRoot17,
1193
+ findProjectRoot as findProjectRoot18,
1154
1194
  getUsage as getUsage5,
1155
1195
  loadUsageIndex as loadUsageIndex5,
1156
1196
  resolveHaivePaths as resolveHaivePaths15
1157
1197
  } from "@hiveai/core";
1158
1198
  function registerMemoryPending(memory2) {
1159
1199
  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) => {
1160
- const root = findProjectRoot17(opts.dir);
1200
+ const root = findProjectRoot18(opts.dir);
1161
1201
  const paths = resolveHaivePaths15(root);
1162
1202
  if (!existsSync16(paths.memoriesDir)) {
1163
1203
  ui.error(`No .ai/memories at ${root}.`);
@@ -1199,15 +1239,15 @@ import path17 from "path";
1199
1239
  import "commander";
1200
1240
  import {
1201
1241
  extractSnippet,
1202
- findProjectRoot as findProjectRoot18,
1242
+ findProjectRoot as findProjectRoot19,
1203
1243
  literalMatchesAllTokens as literalMatchesAllTokens2,
1204
1244
  pickSnippetNeedle,
1205
1245
  resolveHaivePaths as resolveHaivePaths16,
1206
1246
  tokenizeQuery as tokenizeQuery2
1207
1247
  } from "@hiveai/core";
1208
1248
  function registerMemoryQuery(memory2) {
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);
1249
+ 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)").option("--show-rejected", "include rejected memories (hidden by default)").action(async (text, opts) => {
1250
+ const root = findProjectRoot19(opts.dir);
1211
1251
  const paths = resolveHaivePaths16(root);
1212
1252
  if (!existsSync17(paths.memoriesDir)) {
1213
1253
  ui.error(`No memories directory at ${paths.memoriesDir}. Run \`haive init\` first.`);
@@ -1220,6 +1260,7 @@ function registerMemoryQuery(memory2) {
1220
1260
  const matches = all.filter(({ memory: mem }) => {
1221
1261
  const fm = mem.frontmatter;
1222
1262
  if (opts.scope && fm.scope !== opts.scope) return false;
1263
+ if (!opts.showRejected && !statusFilter && fm.status === "rejected") return false;
1223
1264
  if (statusFilter && !statusFilter.includes(fm.status)) return false;
1224
1265
  return literalMatchesAllTokens2(mem, tokens);
1225
1266
  });
@@ -1250,7 +1291,7 @@ import { writeFile as writeFile9 } from "fs/promises";
1250
1291
  import { existsSync as existsSync18 } from "fs";
1251
1292
  import "commander";
1252
1293
  import {
1253
- findProjectRoot as findProjectRoot19,
1294
+ findProjectRoot as findProjectRoot20,
1254
1295
  loadUsageIndex as loadUsageIndex6,
1255
1296
  recordRejection,
1256
1297
  resolveHaivePaths as resolveHaivePaths17,
@@ -1259,7 +1300,7 @@ import {
1259
1300
  } from "@hiveai/core";
1260
1301
  function registerMemoryReject(memory2) {
1261
1302
  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) => {
1262
- const root = findProjectRoot19(opts.dir);
1303
+ const root = findProjectRoot20(opts.dir);
1263
1304
  const paths = resolveHaivePaths17(root);
1264
1305
  if (!existsSync18(paths.memoriesDir)) {
1265
1306
  ui.error(`No .ai/memories at ${root}.`);
@@ -1276,7 +1317,11 @@ function registerMemoryReject(memory2) {
1276
1317
  await writeFile9(
1277
1318
  loaded.filePath,
1278
1319
  serializeMemory7({
1279
- frontmatter: { ...loaded.memory.frontmatter, status: "rejected" },
1320
+ frontmatter: {
1321
+ ...loaded.memory.frontmatter,
1322
+ status: "rejected",
1323
+ stale_reason: opts.reason ?? loaded.memory.frontmatter.stale_reason ?? null
1324
+ },
1280
1325
  body: loaded.memory.body
1281
1326
  }),
1282
1327
  "utf8"
@@ -1299,14 +1344,14 @@ import path18 from "path";
1299
1344
  import { createInterface } from "readline/promises";
1300
1345
  import "commander";
1301
1346
  import {
1302
- findProjectRoot as findProjectRoot20,
1347
+ findProjectRoot as findProjectRoot21,
1303
1348
  loadUsageIndex as loadUsageIndex7,
1304
1349
  resolveHaivePaths as resolveHaivePaths18,
1305
1350
  saveUsageIndex as saveUsageIndex2
1306
1351
  } from "@hiveai/core";
1307
1352
  function registerMemoryRm(memory2) {
1308
1353
  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) => {
1309
- const root = findProjectRoot20(opts.dir);
1354
+ const root = findProjectRoot21(opts.dir);
1310
1355
  const paths = resolveHaivePaths18(root);
1311
1356
  if (!existsSync19(paths.memoriesDir)) {
1312
1357
  ui.error(`No .ai/memories at ${root}.`);
@@ -1350,14 +1395,14 @@ import path19 from "path";
1350
1395
  import "commander";
1351
1396
  import {
1352
1397
  deriveConfidence as deriveConfidence2,
1353
- findProjectRoot as findProjectRoot21,
1398
+ findProjectRoot as findProjectRoot22,
1354
1399
  getUsage as getUsage6,
1355
1400
  loadUsageIndex as loadUsageIndex8,
1356
1401
  resolveHaivePaths as resolveHaivePaths19
1357
1402
  } from "@hiveai/core";
1358
1403
  function registerMemoryShow(memory2) {
1359
1404
  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) => {
1360
- const root = findProjectRoot21(opts.dir);
1405
+ const root = findProjectRoot22(opts.dir);
1361
1406
  const paths = resolveHaivePaths19(root);
1362
1407
  if (!existsSync20(paths.memoriesDir)) {
1363
1408
  ui.error(`No .ai/memories at ${root}.`);
@@ -1408,14 +1453,14 @@ import path20 from "path";
1408
1453
  import "commander";
1409
1454
  import {
1410
1455
  deriveConfidence as deriveConfidence3,
1411
- findProjectRoot as findProjectRoot22,
1456
+ findProjectRoot as findProjectRoot23,
1412
1457
  getUsage as getUsage7,
1413
1458
  loadUsageIndex as loadUsageIndex9,
1414
1459
  resolveHaivePaths as resolveHaivePaths20
1415
1460
  } from "@hiveai/core";
1416
1461
  function registerMemoryStats(memory2) {
1417
1462
  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) => {
1418
- const root = findProjectRoot22(opts.dir);
1463
+ const root = findProjectRoot23(opts.dir);
1419
1464
  const paths = resolveHaivePaths20(root);
1420
1465
  if (!existsSync21(paths.memoriesDir)) {
1421
1466
  ui.error(`No .ai/memories at ${root}. Run \`haive init\` first.`);
@@ -1453,14 +1498,14 @@ import { existsSync as existsSync22 } from "fs";
1453
1498
  import path21 from "path";
1454
1499
  import "commander";
1455
1500
  import {
1456
- findProjectRoot as findProjectRoot23,
1501
+ findProjectRoot as findProjectRoot24,
1457
1502
  resolveHaivePaths as resolveHaivePaths21,
1458
1503
  serializeMemory as serializeMemory8,
1459
1504
  verifyAnchor as verifyAnchor2
1460
1505
  } from "@hiveai/core";
1461
1506
  function registerMemoryVerify(memory2) {
1462
1507
  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) => {
1463
- const root = findProjectRoot23(opts.dir);
1508
+ const root = findProjectRoot24(opts.dir);
1464
1509
  const paths = resolveHaivePaths21(root);
1465
1510
  if (!existsSync22(paths.memoriesDir)) {
1466
1511
  ui.error(`No .ai/memories at ${root}. Run \`haive init\` first.`);
@@ -1536,11 +1581,12 @@ function applyVerification(mem, result) {
1536
1581
  }
1537
1582
 
1538
1583
  // src/index.ts
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");
1584
+ var program = new Command25();
1585
+ program.name("haive").description("hAIve \u2014 team-first persistent memory layer for AI coding agents").version("0.2.5");
1541
1586
  registerInit(program);
1542
1587
  registerMcp(program);
1543
1588
  registerBriefing(program);
1589
+ registerTui(program);
1544
1590
  registerEmbeddings(program);
1545
1591
  registerSync(program);
1546
1592
  registerInstallHooks(program);