@hiveai/cli 0.2.4 → 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.
@@ -0,0 +1,194 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/tui/Dashboard.tsx
4
+ import { useState, useEffect, useCallback } from "react";
5
+ import { Box, Text, useInput, useApp } from "ink";
6
+ import { existsSync } from "fs";
7
+ import { writeFile } from "fs/promises";
8
+ import {
9
+ loadMemoriesFromDir,
10
+ resolveHaivePaths,
11
+ serializeMemory
12
+ } from "@hiveai/core";
13
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
14
+ var FILTERS = ["all", "draft", "proposed", "validated", "stale", "rejected"];
15
+ var LIST_H = 12;
16
+ function statusColor(status) {
17
+ if (status === "validated") return "green";
18
+ if (status === "proposed" || status === "stale") return "yellow";
19
+ if (status === "rejected") return "red";
20
+ return void 0;
21
+ }
22
+ function Dashboard({ root }) {
23
+ const { exit } = useApp();
24
+ const paths = resolveHaivePaths(root);
25
+ const [memories, setMemories] = useState([]);
26
+ const [loading, setLoading] = useState(true);
27
+ const [filterIdx, setFilterIdx] = useState(0);
28
+ const [cursor, setCursor] = useState(0);
29
+ const [flash, setFlash] = useState(null);
30
+ const filter = FILTERS[filterIdx] ?? "all";
31
+ const reload = useCallback(async () => {
32
+ if (!existsSync(paths.memoriesDir)) {
33
+ setLoading(false);
34
+ return;
35
+ }
36
+ setMemories(await loadMemoriesFromDir(paths.memoriesDir));
37
+ setLoading(false);
38
+ }, [paths.memoriesDir]);
39
+ useEffect(() => {
40
+ void reload();
41
+ }, [reload]);
42
+ const filtered = memories.filter((m) => {
43
+ const s2 = m.memory.frontmatter.status;
44
+ if (filter === "all") return s2 !== "rejected";
45
+ return s2 === filter;
46
+ });
47
+ const selected = filtered[cursor];
48
+ const counts = memories.reduce((acc, m) => {
49
+ const s2 = m.memory.frontmatter.status;
50
+ acc[s2] = (acc[s2] ?? 0) + 1;
51
+ return acc;
52
+ }, {});
53
+ const flash_ = (text, color = "green") => {
54
+ setFlash({ text, color });
55
+ setTimeout(() => setFlash(null), 2e3);
56
+ };
57
+ const doApprove = useCallback(async () => {
58
+ if (!selected) return;
59
+ const fm = selected.memory.frontmatter;
60
+ if (fm.status === "validated") {
61
+ flash_("Already validated");
62
+ return;
63
+ }
64
+ await writeFile(
65
+ selected.filePath,
66
+ serializeMemory({ frontmatter: { ...fm, status: "validated" }, body: selected.memory.body }),
67
+ "utf8"
68
+ );
69
+ flash_(`\u2713 Approved ${fm.id.slice(0, 32)}\u2026`);
70
+ const prev = cursor;
71
+ await reload();
72
+ setCursor(prev);
73
+ }, [selected, cursor, reload]);
74
+ const doReject = useCallback(async () => {
75
+ if (!selected) return;
76
+ const fm = selected.memory.frontmatter;
77
+ if (fm.status === "rejected") {
78
+ flash_("Already rejected", "red");
79
+ return;
80
+ }
81
+ await writeFile(
82
+ selected.filePath,
83
+ serializeMemory({ frontmatter: { ...fm, status: "rejected" }, body: selected.memory.body }),
84
+ "utf8"
85
+ );
86
+ flash_(`\u2717 Rejected ${fm.id.slice(0, 32)}\u2026`, "red");
87
+ await reload();
88
+ setCursor((c) => Math.min(c, Math.max(0, filtered.length - 2)));
89
+ }, [selected, filtered.length, reload]);
90
+ useInput((input, key) => {
91
+ if (input === "q") {
92
+ exit();
93
+ return;
94
+ }
95
+ if (key.upArrow) setCursor((c) => Math.max(0, c - 1));
96
+ if (key.downArrow) setCursor((c) => Math.min(filtered.length - 1, c + 1));
97
+ if (key.tab) {
98
+ setFilterIdx((i) => (i + 1) % FILTERS.length);
99
+ setCursor(0);
100
+ }
101
+ if (input === "a") void doApprove();
102
+ if (input === "r") void doReject();
103
+ });
104
+ if (loading) {
105
+ return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Loading memories\u2026" });
106
+ }
107
+ if (!existsSync(paths.memoriesDir)) {
108
+ return /* @__PURE__ */ jsx(Text, { color: "red", children: "No .ai/memories found \u2014 run `haive init` first." });
109
+ }
110
+ const half = Math.floor(LIST_H / 2);
111
+ const start = Math.max(0, Math.min(cursor - half, Math.max(0, filtered.length - LIST_H)));
112
+ const visible = filtered.slice(start, start + LIST_H);
113
+ const v = counts["validated"] ?? 0;
114
+ const p = counts["proposed"] ?? 0;
115
+ const d = counts["draft"] ?? 0;
116
+ const s = counts["stale"] ?? 0;
117
+ const rej = counts["rejected"] ?? 0;
118
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
119
+ /* @__PURE__ */ jsxs(Box, { borderStyle: "round", paddingX: 1, gap: 2, children: [
120
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "hAIve" }),
121
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: root }),
122
+ /* @__PURE__ */ jsx(Text, { children: " " }),
123
+ /* @__PURE__ */ jsxs(Text, { color: "green", children: [
124
+ "\u2713 ",
125
+ v
126
+ ] }),
127
+ /* @__PURE__ */ jsx(Text, { children: " \xB7 " }),
128
+ /* @__PURE__ */ jsxs(Text, { color: p > 0 ? "yellow" : void 0, children: [
129
+ "~ ",
130
+ p
131
+ ] }),
132
+ /* @__PURE__ */ jsx(Text, { children: " \xB7 " }),
133
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
134
+ "\xB7 ",
135
+ d
136
+ ] }),
137
+ s > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
138
+ /* @__PURE__ */ jsx(Text, { children: " \xB7 " }),
139
+ /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
140
+ "\u26A0 ",
141
+ s
142
+ ] })
143
+ ] }),
144
+ rej > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
145
+ /* @__PURE__ */ jsx(Text, { children: " \xB7 " }),
146
+ /* @__PURE__ */ jsxs(Text, { color: "red", children: [
147
+ "\u2717 ",
148
+ rej
149
+ ] })
150
+ ] })
151
+ ] }),
152
+ /* @__PURE__ */ jsxs(Box, { paddingX: 1, gap: 2, children: [
153
+ FILTERS.map((f) => /* @__PURE__ */ jsx(Text, { color: filter === f ? "cyan" : void 0, bold: filter === f, children: filter === f ? `[${f}]` : f }, f)),
154
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " tab\u2192cycle" })
155
+ ] }),
156
+ /* @__PURE__ */ jsxs(Box, { children: [
157
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 64, borderStyle: "single", paddingX: 1, children: [
158
+ /* @__PURE__ */ jsx(Text, { bold: true, dimColor: true, children: `MEMORIES ${filtered.length}/${memories.length}` }),
159
+ filtered.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " (no memories)" }) : visible.map((m, vi) => {
160
+ const absIdx = start + vi;
161
+ const fm = m.memory.frontmatter;
162
+ const sel = absIdx === cursor;
163
+ const idShort = fm.id.length > 43 ? fm.id.slice(0, 40) + "\u2026" : fm.id;
164
+ return /* @__PURE__ */ jsxs(Box, { children: [
165
+ /* @__PURE__ */ jsxs(Text, { color: sel ? "cyan" : void 0, bold: sel, children: [
166
+ sel ? "\u25B6 " : " ",
167
+ idShort.padEnd(43)
168
+ ] }),
169
+ /* @__PURE__ */ jsx(Text, { color: statusColor(fm.status), children: fm.status.slice(0, 9) })
170
+ ] }, fm.id);
171
+ })
172
+ ] }),
173
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 36, borderStyle: "single", paddingX: 1, children: [
174
+ /* @__PURE__ */ jsx(Text, { bold: true, dimColor: true, children: "PREVIEW" }),
175
+ selected ? /* @__PURE__ */ jsxs(Fragment, { children: [
176
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
177
+ selected.memory.frontmatter.scope,
178
+ "/",
179
+ selected.memory.frontmatter.type
180
+ ] }),
181
+ /* @__PURE__ */ jsx(Text, { color: statusColor(selected.memory.frontmatter.status), children: selected.memory.frontmatter.status }),
182
+ /* @__PURE__ */ jsx(Text, { children: " " }),
183
+ selected.memory.body.split("\n").slice(0, LIST_H - 1).map((line, i) => /* @__PURE__ */ jsx(Text, { wrap: "truncate-end", children: line || " " }, i))
184
+ ] }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: "select a memory" })
185
+ ] })
186
+ ] }),
187
+ flash && /* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { color: flash.color, children: flash.text }) }),
188
+ /* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191\u2193 navigate [tab] filter [a] approve [r] reject [q] quit" }) })
189
+ ] });
190
+ }
191
+ export {
192
+ Dashboard
193
+ };
194
+ //# sourceMappingURL=Dashboard-SRPCHP7Z.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tui/Dashboard.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from \"react\";\nimport { Box, Text, useInput, useApp } from \"ink\";\nimport { existsSync } from \"node:fs\";\nimport { writeFile } from \"node:fs/promises\";\nimport {\n loadMemoriesFromDir,\n resolveHaivePaths,\n serializeMemory,\n type LoadedMemory,\n} from \"@hiveai/core\";\n\ntype FilterStatus = \"all\" | \"draft\" | \"proposed\" | \"validated\" | \"stale\" | \"rejected\";\nconst FILTERS: FilterStatus[] = [\"all\", \"draft\", \"proposed\", \"validated\", \"stale\", \"rejected\"];\nconst LIST_H = 12;\n\nfunction statusColor(status: string): \"green\" | \"yellow\" | \"red\" | undefined {\n if (status === \"validated\") return \"green\";\n if (status === \"proposed\" || status === \"stale\") return \"yellow\";\n if (status === \"rejected\") return \"red\";\n return undefined;\n}\n\ninterface Props {\n root: string;\n}\n\nexport function Dashboard({ root }: Props) {\n const { exit } = useApp();\n const paths = resolveHaivePaths(root);\n\n const [memories, setMemories] = useState<LoadedMemory[]>([]);\n const [loading, setLoading] = useState(true);\n const [filterIdx, setFilterIdx] = useState(0);\n const [cursor, setCursor] = useState(0);\n const [flash, setFlash] = useState<{ text: string; color: \"green\" | \"red\" } | null>(null);\n\n const filter: FilterStatus = FILTERS[filterIdx] ?? \"all\";\n\n const reload = useCallback(async () => {\n if (!existsSync(paths.memoriesDir)) {\n setLoading(false);\n return;\n }\n setMemories(await loadMemoriesFromDir(paths.memoriesDir));\n setLoading(false);\n }, [paths.memoriesDir]);\n\n useEffect(() => {\n void reload();\n }, [reload]);\n\n const filtered = memories.filter((m) => {\n const s = m.memory.frontmatter.status;\n if (filter === \"all\") return s !== \"rejected\";\n return s === filter;\n });\n\n const selected = filtered[cursor];\n\n const counts = memories.reduce<Record<string, number>>((acc, m) => {\n const s = m.memory.frontmatter.status;\n acc[s] = (acc[s] ?? 0) + 1;\n return acc;\n }, {});\n\n const flash_ = (text: string, color: \"green\" | \"red\" = \"green\") => {\n setFlash({ text, color });\n setTimeout(() => setFlash(null), 2000);\n };\n\n const doApprove = useCallback(async () => {\n if (!selected) return;\n const fm = selected.memory.frontmatter;\n if (fm.status === \"validated\") { flash_(\"Already validated\"); return; }\n await writeFile(\n selected.filePath,\n serializeMemory({ frontmatter: { ...fm, status: \"validated\" as const }, body: selected.memory.body }),\n \"utf8\",\n );\n flash_(`✓ Approved ${fm.id.slice(0, 32)}…`);\n const prev = cursor;\n await reload();\n setCursor(prev);\n }, [selected, cursor, reload]);\n\n const doReject = useCallback(async () => {\n if (!selected) return;\n const fm = selected.memory.frontmatter;\n if (fm.status === \"rejected\") { flash_(\"Already rejected\", \"red\"); return; }\n await writeFile(\n selected.filePath,\n serializeMemory({ frontmatter: { ...fm, status: \"rejected\" as const }, body: selected.memory.body }),\n \"utf8\",\n );\n flash_(`✗ Rejected ${fm.id.slice(0, 32)}…`, \"red\");\n await reload();\n setCursor((c) => Math.min(c, Math.max(0, filtered.length - 2)));\n }, [selected, filtered.length, reload]);\n\n useInput((input, key) => {\n if (input === \"q\") { exit(); return; }\n if (key.upArrow) setCursor((c) => Math.max(0, c - 1));\n if (key.downArrow) setCursor((c) => Math.min(filtered.length - 1, c + 1));\n if (key.tab) {\n setFilterIdx((i) => (i + 1) % FILTERS.length);\n setCursor(0);\n }\n if (input === \"a\") void doApprove();\n if (input === \"r\") void doReject();\n });\n\n if (loading) {\n return <Text dimColor>Loading memories…</Text>;\n }\n\n if (!existsSync(paths.memoriesDir)) {\n return <Text color=\"red\">No .ai/memories found — run `haive init` first.</Text>;\n }\n\n // Compute scrolling window\n const half = Math.floor(LIST_H / 2);\n const start = Math.max(0, Math.min(cursor - half, Math.max(0, filtered.length - LIST_H)));\n const visible = filtered.slice(start, start + LIST_H);\n\n const v = counts[\"validated\"] ?? 0;\n const p = counts[\"proposed\"] ?? 0;\n const d = counts[\"draft\"] ?? 0;\n const s = counts[\"stale\"] ?? 0;\n const rej = counts[\"rejected\"] ?? 0;\n\n return (\n <Box flexDirection=\"column\">\n\n {/* ── Header ── */}\n <Box borderStyle=\"round\" paddingX={1} gap={2}>\n <Text bold color=\"cyan\">hAIve</Text>\n <Text dimColor>{root}</Text>\n <Text> </Text>\n <Text color=\"green\">✓ {v}</Text>\n <Text> · </Text>\n <Text color={p > 0 ? \"yellow\" : undefined}>~ {p}</Text>\n <Text> · </Text>\n <Text dimColor>· {d}</Text>\n {s > 0 && <><Text> · </Text><Text color=\"yellow\">⚠ {s}</Text></>}\n {rej > 0 && <><Text> · </Text><Text color=\"red\">✗ {rej}</Text></>}\n </Box>\n\n {/* ── Filter bar ── */}\n <Box paddingX={1} gap={2}>\n {FILTERS.map((f) => (\n <Text key={f} color={filter === f ? \"cyan\" : undefined} bold={filter === f}>\n {filter === f ? `[${f}]` : f}\n </Text>\n ))}\n <Text dimColor> tab→cycle</Text>\n </Box>\n\n {/* ── List + Preview ── */}\n <Box>\n\n {/* List panel */}\n <Box flexDirection=\"column\" width={64} borderStyle=\"single\" paddingX={1}>\n <Text bold dimColor>{`MEMORIES ${filtered.length}/${memories.length}`}</Text>\n {filtered.length === 0 ? (\n <Text dimColor> (no memories)</Text>\n ) : (\n visible.map((m, vi) => {\n const absIdx = start + vi;\n const fm = m.memory.frontmatter;\n const sel = absIdx === cursor;\n const idShort = fm.id.length > 43 ? fm.id.slice(0, 40) + \"…\" : fm.id;\n return (\n <Box key={fm.id}>\n <Text color={sel ? \"cyan\" : undefined} bold={sel}>\n {sel ? \"▶ \" : \" \"}\n {idShort.padEnd(43)}\n </Text>\n <Text color={statusColor(fm.status)}>{fm.status.slice(0, 9)}</Text>\n </Box>\n );\n })\n )}\n </Box>\n\n {/* Preview panel */}\n <Box flexDirection=\"column\" width={36} borderStyle=\"single\" paddingX={1}>\n <Text bold dimColor>PREVIEW</Text>\n {selected ? (\n <>\n <Text color=\"cyan\">\n {selected.memory.frontmatter.scope}/{selected.memory.frontmatter.type}\n </Text>\n <Text color={statusColor(selected.memory.frontmatter.status)}>\n {selected.memory.frontmatter.status}\n </Text>\n <Text> </Text>\n {selected.memory.body\n .split(\"\\n\")\n .slice(0, LIST_H - 1)\n .map((line, i) => (\n <Text key={i} wrap=\"truncate-end\">\n {line || \" \"}\n </Text>\n ))}\n </>\n ) : (\n <Text dimColor>select a memory</Text>\n )}\n </Box>\n\n </Box>\n\n {/* ── Flash message ── */}\n {flash && (\n <Box paddingX={1}>\n <Text color={flash.color}>{flash.text}</Text>\n </Box>\n )}\n\n {/* ── Footer ── */}\n <Box paddingX={1}>\n <Text dimColor>\n ↑↓ navigate [tab] filter [a] approve [r] reject [q] quit\n </Text>\n </Box>\n\n </Box>\n );\n}\n"],"mappings":";;;AAAA,SAAS,UAAU,WAAW,mBAAmB;AACjD,SAAS,KAAK,MAAM,UAAU,cAAc;AAC5C,SAAS,kBAAkB;AAC3B,SAAS,iBAAiB;AAC1B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAuGI,SA+BO,UA/BP,KA0BH,YA1BG;AApGX,IAAM,UAA0B,CAAC,OAAO,SAAS,YAAY,aAAa,SAAS,UAAU;AAC7F,IAAM,SAAS;AAEf,SAAS,YAAY,QAAwD;AAC3E,MAAI,WAAW,YAAa,QAAO;AACnC,MAAI,WAAW,cAAc,WAAW,QAAS,QAAO;AACxD,MAAI,WAAW,WAAY,QAAO;AAClC,SAAO;AACT;AAMO,SAAS,UAAU,EAAE,KAAK,GAAU;AACzC,QAAM,EAAE,KAAK,IAAI,OAAO;AACxB,QAAM,QAAQ,kBAAkB,IAAI;AAEpC,QAAM,CAAC,UAAU,WAAW,IAAI,SAAyB,CAAC,CAAC;AAC3D,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,IAAI;AAC3C,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,CAAC;AAC5C,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,CAAC;AACtC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAA0D,IAAI;AAExF,QAAM,SAAuB,QAAQ,SAAS,KAAK;AAEnD,QAAM,SAAS,YAAY,YAAY;AACrC,QAAI,CAAC,WAAW,MAAM,WAAW,GAAG;AAClC,iBAAW,KAAK;AAChB;AAAA,IACF;AACA,gBAAY,MAAM,oBAAoB,MAAM,WAAW,CAAC;AACxD,eAAW,KAAK;AAAA,EAClB,GAAG,CAAC,MAAM,WAAW,CAAC;AAEtB,YAAU,MAAM;AACd,SAAK,OAAO;AAAA,EACd,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,WAAW,SAAS,OAAO,CAAC,MAAM;AACtC,UAAMA,KAAI,EAAE,OAAO,YAAY;AAC/B,QAAI,WAAW,MAAO,QAAOA,OAAM;AACnC,WAAOA,OAAM;AAAA,EACf,CAAC;AAED,QAAM,WAAW,SAAS,MAAM;AAEhC,QAAM,SAAS,SAAS,OAA+B,CAAC,KAAK,MAAM;AACjE,UAAMA,KAAI,EAAE,OAAO,YAAY;AAC/B,QAAIA,EAAC,KAAK,IAAIA,EAAC,KAAK,KAAK;AACzB,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AAEL,QAAM,SAAS,CAAC,MAAc,QAAyB,YAAY;AACjE,aAAS,EAAE,MAAM,MAAM,CAAC;AACxB,eAAW,MAAM,SAAS,IAAI,GAAG,GAAI;AAAA,EACvC;AAEA,QAAM,YAAY,YAAY,YAAY;AACxC,QAAI,CAAC,SAAU;AACf,UAAM,KAAK,SAAS,OAAO;AAC3B,QAAI,GAAG,WAAW,aAAa;AAAE,aAAO,mBAAmB;AAAG;AAAA,IAAQ;AACtE,UAAM;AAAA,MACJ,SAAS;AAAA,MACT,gBAAgB,EAAE,aAAa,EAAE,GAAG,IAAI,QAAQ,YAAqB,GAAG,MAAM,SAAS,OAAO,KAAK,CAAC;AAAA,MACpG;AAAA,IACF;AACA,WAAO,mBAAc,GAAG,GAAG,MAAM,GAAG,EAAE,CAAC,QAAG;AAC1C,UAAM,OAAO;AACb,UAAM,OAAO;AACb,cAAU,IAAI;AAAA,EAChB,GAAG,CAAC,UAAU,QAAQ,MAAM,CAAC;AAE7B,QAAM,WAAW,YAAY,YAAY;AACvC,QAAI,CAAC,SAAU;AACf,UAAM,KAAK,SAAS,OAAO;AAC3B,QAAI,GAAG,WAAW,YAAY;AAAE,aAAO,oBAAoB,KAAK;AAAG;AAAA,IAAQ;AAC3E,UAAM;AAAA,MACJ,SAAS;AAAA,MACT,gBAAgB,EAAE,aAAa,EAAE,GAAG,IAAI,QAAQ,WAAoB,GAAG,MAAM,SAAS,OAAO,KAAK,CAAC;AAAA,MACnG;AAAA,IACF;AACA,WAAO,mBAAc,GAAG,GAAG,MAAM,GAAG,EAAE,CAAC,UAAK,KAAK;AACjD,UAAM,OAAO;AACb,cAAU,CAAC,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,SAAS,SAAS,CAAC,CAAC,CAAC;AAAA,EAChE,GAAG,CAAC,UAAU,SAAS,QAAQ,MAAM,CAAC;AAEtC,WAAS,CAAC,OAAO,QAAQ;AACvB,QAAI,UAAU,KAAK;AAAE,WAAK;AAAG;AAAA,IAAQ;AACrC,QAAI,IAAI,QAAS,WAAU,CAAC,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;AACpD,QAAI,IAAI,UAAW,WAAU,CAAC,MAAM,KAAK,IAAI,SAAS,SAAS,GAAG,IAAI,CAAC,CAAC;AACxE,QAAI,IAAI,KAAK;AACX,mBAAa,CAAC,OAAO,IAAI,KAAK,QAAQ,MAAM;AAC5C,gBAAU,CAAC;AAAA,IACb;AACA,QAAI,UAAU,IAAK,MAAK,UAAU;AAClC,QAAI,UAAU,IAAK,MAAK,SAAS;AAAA,EACnC,CAAC;AAED,MAAI,SAAS;AACX,WAAO,oBAAC,QAAK,UAAQ,MAAC,oCAAiB;AAAA,EACzC;AAEA,MAAI,CAAC,WAAW,MAAM,WAAW,GAAG;AAClC,WAAO,oBAAC,QAAK,OAAM,OAAM,kEAA+C;AAAA,EAC1E;AAGA,QAAM,OAAO,KAAK,MAAM,SAAS,CAAC;AAClC,QAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,SAAS,MAAM,KAAK,IAAI,GAAG,SAAS,SAAS,MAAM,CAAC,CAAC;AACxF,QAAM,UAAU,SAAS,MAAM,OAAO,QAAQ,MAAM;AAEpD,QAAM,IAAI,OAAO,WAAW,KAAK;AACjC,QAAM,IAAI,OAAO,UAAU,KAAK;AAChC,QAAM,IAAI,OAAO,OAAO,KAAK;AAC7B,QAAM,IAAI,OAAO,OAAO,KAAK;AAC7B,QAAM,MAAM,OAAO,UAAU,KAAK;AAElC,SACE,qBAAC,OAAI,eAAc,UAGjB;AAAA,yBAAC,OAAI,aAAY,SAAQ,UAAU,GAAG,KAAK,GACzC;AAAA,0BAAC,QAAK,MAAI,MAAC,OAAM,QAAO,mBAAK;AAAA,MAC7B,oBAAC,QAAK,UAAQ,MAAE,gBAAK;AAAA,MACrB,oBAAC,QAAK,gBAAE;AAAA,MACR,qBAAC,QAAK,OAAM,SAAQ;AAAA;AAAA,QAAG;AAAA,SAAE;AAAA,MACzB,oBAAC,QAAK,oBAAG;AAAA,MACT,qBAAC,QAAK,OAAO,IAAI,IAAI,WAAW,QAAW;AAAA;AAAA,QAAG;AAAA,SAAE;AAAA,MAChD,oBAAC,QAAK,oBAAG;AAAA,MACT,qBAAC,QAAK,UAAQ,MAAC;AAAA;AAAA,QAAG;AAAA,SAAE;AAAA,MACnB,IAAI,KAAK,iCAAE;AAAA,4BAAC,QAAK,oBAAG;AAAA,QAAO,qBAAC,QAAK,OAAM,UAAS;AAAA;AAAA,UAAG;AAAA,WAAE;AAAA,SAAO;AAAA,MAC5D,MAAM,KAAK,iCAAE;AAAA,4BAAC,QAAK,oBAAG;AAAA,QAAO,qBAAC,QAAK,OAAM,OAAM;AAAA;AAAA,UAAG;AAAA,WAAI;AAAA,SAAO;AAAA,OAChE;AAAA,IAGA,qBAAC,OAAI,UAAU,GAAG,KAAK,GACpB;AAAA,cAAQ,IAAI,CAAC,MACZ,oBAAC,QAAa,OAAO,WAAW,IAAI,SAAS,QAAW,MAAM,WAAW,GACtE,qBAAW,IAAI,IAAI,CAAC,MAAM,KADlB,CAEX,CACD;AAAA,MACD,oBAAC,QAAK,UAAQ,MAAC,8BAAW;AAAA,OAC5B;AAAA,IAGA,qBAAC,OAGC;AAAA,2BAAC,OAAI,eAAc,UAAS,OAAO,IAAI,aAAY,UAAS,UAAU,GACpE;AAAA,4BAAC,QAAK,MAAI,MAAC,UAAQ,MAAE,uBAAa,SAAS,MAAM,IAAI,SAAS,MAAM,IAAG;AAAA,QACtE,SAAS,WAAW,IACnB,oBAAC,QAAK,UAAQ,MAAC,6BAAe,IAE9B,QAAQ,IAAI,CAAC,GAAG,OAAO;AACrB,gBAAM,SAAS,QAAQ;AACvB,gBAAM,KAAK,EAAE,OAAO;AACpB,gBAAM,MAAM,WAAW;AACvB,gBAAM,UAAU,GAAG,GAAG,SAAS,KAAK,GAAG,GAAG,MAAM,GAAG,EAAE,IAAI,WAAM,GAAG;AAClE,iBACE,qBAAC,OACC;AAAA,iCAAC,QAAK,OAAO,MAAM,SAAS,QAAW,MAAM,KAC1C;AAAA,oBAAM,YAAO;AAAA,cACb,QAAQ,OAAO,EAAE;AAAA,eACpB;AAAA,YACA,oBAAC,QAAK,OAAO,YAAY,GAAG,MAAM,GAAI,aAAG,OAAO,MAAM,GAAG,CAAC,GAAE;AAAA,eALpD,GAAG,EAMb;AAAA,QAEJ,CAAC;AAAA,SAEL;AAAA,MAGA,qBAAC,OAAI,eAAc,UAAS,OAAO,IAAI,aAAY,UAAS,UAAU,GACpE;AAAA,4BAAC,QAAK,MAAI,MAAC,UAAQ,MAAC,qBAAO;AAAA,QAC1B,WACC,iCACE;AAAA,+BAAC,QAAK,OAAM,QACT;AAAA,qBAAS,OAAO,YAAY;AAAA,YAAM;AAAA,YAAE,SAAS,OAAO,YAAY;AAAA,aACnE;AAAA,UACA,oBAAC,QAAK,OAAO,YAAY,SAAS,OAAO,YAAY,MAAM,GACxD,mBAAS,OAAO,YAAY,QAC/B;AAAA,UACA,oBAAC,QAAK,eAAC;AAAA,UACN,SAAS,OAAO,KACd,MAAM,IAAI,EACV,MAAM,GAAG,SAAS,CAAC,EACnB,IAAI,CAAC,MAAM,MACV,oBAAC,QAAa,MAAK,gBAChB,kBAAQ,OADA,CAEX,CACD;AAAA,WACL,IAEA,oBAAC,QAAK,UAAQ,MAAC,6BAAe;AAAA,SAElC;AAAA,OAEF;AAAA,IAGC,SACC,oBAAC,OAAI,UAAU,GACb,8BAAC,QAAK,OAAO,MAAM,OAAQ,gBAAM,MAAK,GACxC;AAAA,IAIF,oBAAC,OAAI,UAAU,GACb,8BAAC,QAAK,UAAQ,MAAC,oFAEf,GACF;AAAA,KAEF;AAEJ;","names":["s"]}
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";
@@ -122,15 +122,34 @@ function parseCsv(value) {
122
122
  return value.split(",").map((s) => s.trim()).filter(Boolean);
123
123
  }
124
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
+
125
144
  // src/commands/embeddings.ts
126
145
  import { existsSync as existsSync2 } from "fs";
127
146
  import path from "path";
128
147
  import "commander";
129
- import { findProjectRoot as findProjectRoot2, resolveHaivePaths as resolveHaivePaths2 } from "@hiveai/core";
148
+ import { findProjectRoot as findProjectRoot3, resolveHaivePaths as resolveHaivePaths2 } from "@hiveai/core";
130
149
  function registerEmbeddings(program2) {
131
150
  const embeddings = program2.command("embeddings").description("Manage local embeddings index for semantic search");
132
151
  embeddings.command("index").description("Generate or refresh the embeddings index for all memories").option("-d, --dir <dir>", "project root").action(async (opts) => {
133
- const root = findProjectRoot2(opts.dir);
152
+ const root = findProjectRoot3(opts.dir);
134
153
  const paths = resolveHaivePaths2(root);
135
154
  if (!existsSync2(paths.memoriesDir)) {
136
155
  ui.error(`No .ai/memories at ${root}. Run \`haive init\` first.`);
@@ -147,7 +166,7 @@ function registerEmbeddings(program2) {
147
166
  );
148
167
  });
149
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) => {
150
- const root = findProjectRoot2(opts.dir);
169
+ const root = findProjectRoot3(opts.dir);
151
170
  const paths = resolveHaivePaths2(root);
152
171
  const { semanticSearch } = await loadEmbeddings();
153
172
  const result = await semanticSearch(paths, text, {
@@ -170,7 +189,7 @@ function registerEmbeddings(program2) {
170
189
  }
171
190
  });
172
191
  embeddings.command("status").description("Show the embeddings index status").option("-d, --dir <dir>", "project root").action(async (opts) => {
173
- const root = findProjectRoot2(opts.dir);
192
+ const root = findProjectRoot3(opts.dir);
174
193
  const paths = resolveHaivePaths2(root);
175
194
  const { indexStat } = await loadEmbeddings();
176
195
  const stat = await indexStat(paths);
@@ -201,7 +220,7 @@ import "commander";
201
220
  import {
202
221
  buildCodeMap,
203
222
  codeMapPath,
204
- findProjectRoot as findProjectRoot3,
223
+ findProjectRoot as findProjectRoot4,
205
224
  resolveHaivePaths as resolveHaivePaths3,
206
225
  saveCodeMap
207
226
  } from "@hiveai/core";
@@ -213,7 +232,7 @@ function registerIndexCode(program2) {
213
232
  "extra directory names to skip (comma-separated)",
214
233
  ""
215
234
  ).action(async (opts) => {
216
- const root = findProjectRoot3(opts.dir);
235
+ const root = findProjectRoot4(opts.dir);
217
236
  const paths = resolveHaivePaths3(root);
218
237
  const extraExcludes = (opts.exclude ?? "").split(",").map((s) => s.trim()).filter(Boolean);
219
238
  ui.info(`Indexing source files in ${root}\u2026`);
@@ -311,7 +330,7 @@ import { mkdir as mkdir2, writeFile as writeFile2, chmod, readFile as readFile2
311
330
  import { existsSync as existsSync4 } from "fs";
312
331
  import path4 from "path";
313
332
  import "commander";
314
- import { findProjectRoot as findProjectRoot5 } from "@hiveai/core";
333
+ import { findProjectRoot as findProjectRoot6 } from "@hiveai/core";
315
334
  var HOOK_MARKER = "# hAIve auto-generated";
316
335
  var HOOK_BODY = `#!/bin/sh
317
336
  ${HOOK_MARKER} \u2014 keep this block to allow upgrades. Hand-edit anything outside it.
@@ -327,7 +346,7 @@ fi
327
346
  var HOOKS = ["post-merge", "post-rewrite"];
328
347
  function registerInstallHooks(program2) {
329
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) => {
330
- const root = findProjectRoot5(opts.dir);
349
+ const root = findProjectRoot6(opts.dir);
331
350
  const gitDir = path4.join(root, ".git");
332
351
  if (!existsSync4(gitDir)) {
333
352
  ui.error(`No .git directory at ${root}.`);
@@ -364,11 +383,11 @@ import { createRequire } from "module";
364
383
  import path5 from "path";
365
384
  import { fileURLToPath } from "url";
366
385
  import "commander";
367
- import { findProjectRoot as findProjectRoot6 } from "@hiveai/core";
386
+ import { findProjectRoot as findProjectRoot7 } from "@hiveai/core";
368
387
  var require2 = createRequire(import.meta.url);
369
388
  function registerMcp(program2) {
370
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) => {
371
- const root = findProjectRoot6(opts.dir);
390
+ const root = findProjectRoot7(opts.dir);
372
391
  const bin = locateMcpBin();
373
392
  if (!bin) {
374
393
  ui.error(
@@ -405,7 +424,7 @@ import "path";
405
424
  import "commander";
406
425
  import {
407
426
  DEFAULT_AUTO_PROMOTE_RULE,
408
- findProjectRoot as findProjectRoot7,
427
+ findProjectRoot as findProjectRoot8,
409
428
  getUsage,
410
429
  isAutoPromoteEligible,
411
430
  loadMemoriesFromDir as loadMemoriesFromDir2,
@@ -419,7 +438,7 @@ function registerSync(program2) {
419
438
  "--since <ref>",
420
439
  "git ref/commit to compare against; report memories added/modified/removed since"
421
440
  ).option("--no-verify", "skip the anchor verification step").option("--no-promote", "skip the auto-promotion step").action(async (opts) => {
422
- const root = findProjectRoot7(opts.dir);
441
+ const root = findProjectRoot8(opts.dir);
423
442
  const paths = resolveHaivePaths5(root);
424
443
  if (!existsSync6(paths.memoriesDir)) {
425
444
  if (!opts.quiet) ui.warn(`No .ai/memories at ${root}. Run \`haive init\` first.`);
@@ -552,7 +571,7 @@ import path7 from "path";
552
571
  import "commander";
553
572
  import {
554
573
  buildFrontmatter,
555
- findProjectRoot as findProjectRoot8,
574
+ findProjectRoot as findProjectRoot9,
556
575
  inferModulesFromPaths,
557
576
  memoryFilePath,
558
577
  resolveHaivePaths as resolveHaivePaths6,
@@ -560,7 +579,7 @@ import {
560
579
  } from "@hiveai/core";
561
580
  function registerMemoryAdd(memory2) {
562
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) => {
563
- const root = findProjectRoot8(opts.dir);
582
+ const root = findProjectRoot9(opts.dir);
564
583
  const paths = resolveHaivePaths6(root);
565
584
  if (!existsSync7(paths.haiveDir)) {
566
585
  ui.error(`No .ai/ found at ${root}. Run \`haive init\` first.`);
@@ -631,7 +650,7 @@ function parseCsv2(value) {
631
650
  import { existsSync as existsSync8 } from "fs";
632
651
  import path8 from "path";
633
652
  import "commander";
634
- import { findProjectRoot as findProjectRoot9, resolveHaivePaths as resolveHaivePaths7 } from "@hiveai/core";
653
+ import { findProjectRoot as findProjectRoot10, resolveHaivePaths as resolveHaivePaths7 } from "@hiveai/core";
635
654
 
636
655
  // src/utils/fs.ts
637
656
  import {
@@ -643,7 +662,7 @@ import {
643
662
  // src/commands/memory-list.ts
644
663
  function registerMemoryList(memory2) {
645
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) => {
646
- const root = findProjectRoot9(opts.dir);
665
+ const root = findProjectRoot10(opts.dir);
647
666
  const paths = resolveHaivePaths7(root);
648
667
  if (!existsSync8(paths.memoriesDir)) {
649
668
  ui.error(`No memories directory at ${paths.memoriesDir}. Run \`haive init\` first.`);
@@ -717,14 +736,14 @@ import { existsSync as existsSync9 } from "fs";
717
736
  import path9 from "path";
718
737
  import "commander";
719
738
  import {
720
- findProjectRoot as findProjectRoot10,
739
+ findProjectRoot as findProjectRoot11,
721
740
  memoryFilePath as memoryFilePath2,
722
741
  resolveHaivePaths as resolveHaivePaths8,
723
742
  serializeMemory as serializeMemory3
724
743
  } from "@hiveai/core";
725
744
  function registerMemoryPromote(memory2) {
726
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) => {
727
- const root = findProjectRoot10(opts.dir);
746
+ const root = findProjectRoot11(opts.dir);
728
747
  const paths = resolveHaivePaths8(root);
729
748
  if (!existsSync9(paths.memoriesDir)) {
730
749
  ui.error(`No memories directory at ${paths.memoriesDir}. Run \`haive init\` first.`);
@@ -776,13 +795,13 @@ import { writeFile as writeFile6 } from "fs/promises";
776
795
  import path10 from "path";
777
796
  import "commander";
778
797
  import {
779
- findProjectRoot as findProjectRoot11,
798
+ findProjectRoot as findProjectRoot12,
780
799
  resolveHaivePaths as resolveHaivePaths9,
781
800
  serializeMemory as serializeMemory4
782
801
  } from "@hiveai/core";
783
802
  function registerMemoryApprove(memory2) {
784
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) => {
785
- const root = findProjectRoot11(opts.dir);
804
+ const root = findProjectRoot12(opts.dir);
786
805
  const paths = resolveHaivePaths9(root);
787
806
  if (!existsSync10(paths.memoriesDir)) {
788
807
  ui.error(`No .ai/memories at ${root}.`);
@@ -847,13 +866,13 @@ import { existsSync as existsSync11 } from "fs";
847
866
  import path11 from "path";
848
867
  import "commander";
849
868
  import {
850
- findProjectRoot as findProjectRoot12,
869
+ findProjectRoot as findProjectRoot13,
851
870
  resolveHaivePaths as resolveHaivePaths10,
852
871
  serializeMemory as serializeMemory5
853
872
  } from "@hiveai/core";
854
873
  function registerMemoryUpdate(memory2) {
855
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) => {
856
- const root = findProjectRoot12(opts.dir);
875
+ const root = findProjectRoot13(opts.dir);
857
876
  const paths = resolveHaivePaths10(root);
858
877
  if (!existsSync11(paths.memoriesDir)) {
859
878
  ui.error(`No .ai/memories at ${root}. Run \`haive init\` first.`);
@@ -932,7 +951,7 @@ import path12 from "path";
932
951
  import "commander";
933
952
  import {
934
953
  DEFAULT_AUTO_PROMOTE_RULE as DEFAULT_AUTO_PROMOTE_RULE2,
935
- findProjectRoot as findProjectRoot13,
954
+ findProjectRoot as findProjectRoot14,
936
955
  getUsage as getUsage2,
937
956
  isAutoPromoteEligible as isAutoPromoteEligible2,
938
957
  loadUsageIndex as loadUsageIndex2,
@@ -945,7 +964,7 @@ function registerMemoryAutoPromote(memory2) {
945
964
  "memories with more rejections than this are skipped",
946
965
  String(DEFAULT_AUTO_PROMOTE_RULE2.maxRejections)
947
966
  ).option("--apply", "actually write status=validated to disk (default: dry-run)").option("-d, --dir <dir>", "project root").action(async (opts) => {
948
- const root = findProjectRoot13(opts.dir);
967
+ const root = findProjectRoot14(opts.dir);
949
968
  const paths = resolveHaivePaths11(root);
950
969
  if (!existsSync12(paths.memoriesDir)) {
951
970
  ui.error(`No .ai/memories at ${root}.`);
@@ -995,13 +1014,13 @@ import { readFile as readFile3 } from "fs/promises";
995
1014
  import path13 from "path";
996
1015
  import "commander";
997
1016
  import {
998
- findProjectRoot as findProjectRoot14,
1017
+ findProjectRoot as findProjectRoot15,
999
1018
  parseMemory,
1000
1019
  resolveHaivePaths as resolveHaivePaths12
1001
1020
  } from "@hiveai/core";
1002
1021
  function registerMemoryEdit(memory2) {
1003
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) => {
1004
- const root = findProjectRoot14(opts.dir);
1023
+ const root = findProjectRoot15(opts.dir);
1005
1024
  const paths = resolveHaivePaths12(root);
1006
1025
  if (!existsSync13(paths.memoriesDir)) {
1007
1026
  ui.error(`No .ai/memories at ${root}.`);
@@ -1048,7 +1067,7 @@ import path14 from "path";
1048
1067
  import "commander";
1049
1068
  import {
1050
1069
  deriveConfidence,
1051
- findProjectRoot as findProjectRoot15,
1070
+ findProjectRoot as findProjectRoot16,
1052
1071
  getUsage as getUsage3,
1053
1072
  inferModulesFromPaths as inferModulesFromPaths2,
1054
1073
  loadUsageIndex as loadUsageIndex3,
@@ -1057,7 +1076,7 @@ import {
1057
1076
  } from "@hiveai/core";
1058
1077
  function registerMemoryForFiles(memory2) {
1059
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) => {
1060
- const root = findProjectRoot15(opts.dir);
1079
+ const root = findProjectRoot16(opts.dir);
1061
1080
  const paths = resolveHaivePaths13(root);
1062
1081
  if (!existsSync14(paths.memoriesDir)) {
1063
1082
  ui.error(`No .ai/memories at ${root}.`);
@@ -1121,14 +1140,14 @@ import { existsSync as existsSync15 } from "fs";
1121
1140
  import path15 from "path";
1122
1141
  import "commander";
1123
1142
  import {
1124
- findProjectRoot as findProjectRoot16,
1143
+ findProjectRoot as findProjectRoot17,
1125
1144
  getUsage as getUsage4,
1126
1145
  loadUsageIndex as loadUsageIndex4,
1127
1146
  resolveHaivePaths as resolveHaivePaths14
1128
1147
  } from "@hiveai/core";
1129
1148
  function registerMemoryHot(memory2) {
1130
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) => {
1131
- const root = findProjectRoot16(opts.dir);
1150
+ const root = findProjectRoot17(opts.dir);
1132
1151
  const paths = resolveHaivePaths14(root);
1133
1152
  if (!existsSync15(paths.memoriesDir)) {
1134
1153
  ui.error(`No .ai/memories at ${root}.`);
@@ -1171,14 +1190,14 @@ import { existsSync as existsSync16 } from "fs";
1171
1190
  import path16 from "path";
1172
1191
  import "commander";
1173
1192
  import {
1174
- findProjectRoot as findProjectRoot17,
1193
+ findProjectRoot as findProjectRoot18,
1175
1194
  getUsage as getUsage5,
1176
1195
  loadUsageIndex as loadUsageIndex5,
1177
1196
  resolveHaivePaths as resolveHaivePaths15
1178
1197
  } from "@hiveai/core";
1179
1198
  function registerMemoryPending(memory2) {
1180
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) => {
1181
- const root = findProjectRoot17(opts.dir);
1200
+ const root = findProjectRoot18(opts.dir);
1182
1201
  const paths = resolveHaivePaths15(root);
1183
1202
  if (!existsSync16(paths.memoriesDir)) {
1184
1203
  ui.error(`No .ai/memories at ${root}.`);
@@ -1220,7 +1239,7 @@ import path17 from "path";
1220
1239
  import "commander";
1221
1240
  import {
1222
1241
  extractSnippet,
1223
- findProjectRoot as findProjectRoot18,
1242
+ findProjectRoot as findProjectRoot19,
1224
1243
  literalMatchesAllTokens as literalMatchesAllTokens2,
1225
1244
  pickSnippetNeedle,
1226
1245
  resolveHaivePaths as resolveHaivePaths16,
@@ -1228,7 +1247,7 @@ import {
1228
1247
  } from "@hiveai/core";
1229
1248
  function registerMemoryQuery(memory2) {
1230
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) => {
1231
- const root = findProjectRoot18(opts.dir);
1250
+ const root = findProjectRoot19(opts.dir);
1232
1251
  const paths = resolveHaivePaths16(root);
1233
1252
  if (!existsSync17(paths.memoriesDir)) {
1234
1253
  ui.error(`No memories directory at ${paths.memoriesDir}. Run \`haive init\` first.`);
@@ -1272,7 +1291,7 @@ import { writeFile as writeFile9 } from "fs/promises";
1272
1291
  import { existsSync as existsSync18 } from "fs";
1273
1292
  import "commander";
1274
1293
  import {
1275
- findProjectRoot as findProjectRoot19,
1294
+ findProjectRoot as findProjectRoot20,
1276
1295
  loadUsageIndex as loadUsageIndex6,
1277
1296
  recordRejection,
1278
1297
  resolveHaivePaths as resolveHaivePaths17,
@@ -1281,7 +1300,7 @@ import {
1281
1300
  } from "@hiveai/core";
1282
1301
  function registerMemoryReject(memory2) {
1283
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) => {
1284
- const root = findProjectRoot19(opts.dir);
1303
+ const root = findProjectRoot20(opts.dir);
1285
1304
  const paths = resolveHaivePaths17(root);
1286
1305
  if (!existsSync18(paths.memoriesDir)) {
1287
1306
  ui.error(`No .ai/memories at ${root}.`);
@@ -1325,14 +1344,14 @@ import path18 from "path";
1325
1344
  import { createInterface } from "readline/promises";
1326
1345
  import "commander";
1327
1346
  import {
1328
- findProjectRoot as findProjectRoot20,
1347
+ findProjectRoot as findProjectRoot21,
1329
1348
  loadUsageIndex as loadUsageIndex7,
1330
1349
  resolveHaivePaths as resolveHaivePaths18,
1331
1350
  saveUsageIndex as saveUsageIndex2
1332
1351
  } from "@hiveai/core";
1333
1352
  function registerMemoryRm(memory2) {
1334
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) => {
1335
- const root = findProjectRoot20(opts.dir);
1354
+ const root = findProjectRoot21(opts.dir);
1336
1355
  const paths = resolveHaivePaths18(root);
1337
1356
  if (!existsSync19(paths.memoriesDir)) {
1338
1357
  ui.error(`No .ai/memories at ${root}.`);
@@ -1376,14 +1395,14 @@ import path19 from "path";
1376
1395
  import "commander";
1377
1396
  import {
1378
1397
  deriveConfidence as deriveConfidence2,
1379
- findProjectRoot as findProjectRoot21,
1398
+ findProjectRoot as findProjectRoot22,
1380
1399
  getUsage as getUsage6,
1381
1400
  loadUsageIndex as loadUsageIndex8,
1382
1401
  resolveHaivePaths as resolveHaivePaths19
1383
1402
  } from "@hiveai/core";
1384
1403
  function registerMemoryShow(memory2) {
1385
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) => {
1386
- const root = findProjectRoot21(opts.dir);
1405
+ const root = findProjectRoot22(opts.dir);
1387
1406
  const paths = resolveHaivePaths19(root);
1388
1407
  if (!existsSync20(paths.memoriesDir)) {
1389
1408
  ui.error(`No .ai/memories at ${root}.`);
@@ -1434,14 +1453,14 @@ import path20 from "path";
1434
1453
  import "commander";
1435
1454
  import {
1436
1455
  deriveConfidence as deriveConfidence3,
1437
- findProjectRoot as findProjectRoot22,
1456
+ findProjectRoot as findProjectRoot23,
1438
1457
  getUsage as getUsage7,
1439
1458
  loadUsageIndex as loadUsageIndex9,
1440
1459
  resolveHaivePaths as resolveHaivePaths20
1441
1460
  } from "@hiveai/core";
1442
1461
  function registerMemoryStats(memory2) {
1443
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) => {
1444
- const root = findProjectRoot22(opts.dir);
1463
+ const root = findProjectRoot23(opts.dir);
1445
1464
  const paths = resolveHaivePaths20(root);
1446
1465
  if (!existsSync21(paths.memoriesDir)) {
1447
1466
  ui.error(`No .ai/memories at ${root}. Run \`haive init\` first.`);
@@ -1479,14 +1498,14 @@ import { existsSync as existsSync22 } from "fs";
1479
1498
  import path21 from "path";
1480
1499
  import "commander";
1481
1500
  import {
1482
- findProjectRoot as findProjectRoot23,
1501
+ findProjectRoot as findProjectRoot24,
1483
1502
  resolveHaivePaths as resolveHaivePaths21,
1484
1503
  serializeMemory as serializeMemory8,
1485
1504
  verifyAnchor as verifyAnchor2
1486
1505
  } from "@hiveai/core";
1487
1506
  function registerMemoryVerify(memory2) {
1488
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) => {
1489
- const root = findProjectRoot23(opts.dir);
1508
+ const root = findProjectRoot24(opts.dir);
1490
1509
  const paths = resolveHaivePaths21(root);
1491
1510
  if (!existsSync22(paths.memoriesDir)) {
1492
1511
  ui.error(`No .ai/memories at ${root}. Run \`haive init\` first.`);
@@ -1562,11 +1581,12 @@ function applyVerification(mem, result) {
1562
1581
  }
1563
1582
 
1564
1583
  // src/index.ts
1565
- var program = new Command24();
1566
- program.name("haive").description("hAIve \u2014 team-first persistent memory layer for AI coding agents").version("0.2.4");
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");
1567
1586
  registerInit(program);
1568
1587
  registerMcp(program);
1569
1588
  registerBriefing(program);
1589
+ registerTui(program);
1570
1590
  registerEmbeddings(program);
1571
1591
  registerSync(program);
1572
1592
  registerInstallHooks(program);