@hiveai/cli 0.2.15 → 0.3.0

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,336 @@
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, unlink } from "fs/promises";
8
+ import {
9
+ getUsage,
10
+ isDecaying,
11
+ loadMemoriesFromDir,
12
+ loadUsageIndex,
13
+ resolveHaivePaths,
14
+ serializeMemory
15
+ } from "@hiveai/core";
16
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
17
+ var FILTERS = ["all", "draft", "proposed", "validated", "stale", "rejected"];
18
+ var LIST_H = 14;
19
+ function statusColor(status) {
20
+ if (status === "validated") return "green";
21
+ if (status === "proposed" || status === "stale") return "yellow";
22
+ if (status === "rejected") return "red";
23
+ return void 0;
24
+ }
25
+ function Dashboard({ root }) {
26
+ const { exit } = useApp();
27
+ const paths = resolveHaivePaths(root);
28
+ const [screen, setScreen] = useState("memories");
29
+ const [memories, setMemories] = useState([]);
30
+ const [usage, setUsage] = useState({ version: 1, updated_at: "", by_id: {} });
31
+ const [loading, setLoading] = useState(true);
32
+ const [filterIdx, setFilterIdx] = useState(0);
33
+ const [cursor, setCursor] = useState(0);
34
+ const [flash, setFlash] = useState(null);
35
+ const filter = FILTERS[filterIdx] ?? "all";
36
+ const reload = useCallback(async () => {
37
+ setLoading(true);
38
+ const [mems, u] = await Promise.all([
39
+ existsSync(paths.memoriesDir) ? loadMemoriesFromDir(paths.memoriesDir) : Promise.resolve([]),
40
+ loadUsageIndex(paths)
41
+ ]);
42
+ setMemories(mems);
43
+ setUsage(u);
44
+ setLoading(false);
45
+ }, [paths.memoriesDir]);
46
+ useEffect(() => {
47
+ void reload();
48
+ }, [reload]);
49
+ const nonRecap = memories.filter((m) => m.memory.frontmatter.type !== "session_recap");
50
+ const filtered = nonRecap.filter((m) => {
51
+ const s = m.memory.frontmatter.status;
52
+ if (filter === "all") return s !== "rejected";
53
+ return s === filter;
54
+ });
55
+ const staleMemories = nonRecap.filter((m) => m.memory.frontmatter.status === "stale");
56
+ const anchorless = nonRecap.filter(
57
+ (m) => m.memory.frontmatter.anchor.paths.length === 0 && m.memory.frontmatter.anchor.symbols.length === 0 && m.memory.frontmatter.status !== "rejected"
58
+ );
59
+ const pending = nonRecap.filter((m) => m.memory.frontmatter.status === "proposed");
60
+ const topRead = [...nonRecap].map((m) => ({ m, u: getUsage(usage, m.memory.frontmatter.id) })).filter(({ u }) => u.read_count > 0).sort((a, b) => b.u.read_count - a.u.read_count).slice(0, 5);
61
+ const decaying = nonRecap.filter(({ memory: mem }) => {
62
+ const u = getUsage(usage, mem.frontmatter.id);
63
+ return isDecaying(u, mem.frontmatter.created_at);
64
+ });
65
+ const selected = filtered[cursor];
66
+ const counts = nonRecap.reduce((acc, m) => {
67
+ acc[m.memory.frontmatter.status] = (acc[m.memory.frontmatter.status] ?? 0) + 1;
68
+ return acc;
69
+ }, {});
70
+ const flash_ = (text, color = "green") => {
71
+ setFlash({ text, color });
72
+ setTimeout(() => setFlash(null), 2500);
73
+ };
74
+ const doStatusChange = useCallback(async (newStatus) => {
75
+ if (!selected) return;
76
+ const fm = selected.memory.frontmatter;
77
+ if (fm.status === newStatus) {
78
+ flash_(`Already ${newStatus}`, "yellow");
79
+ return;
80
+ }
81
+ await writeFile(
82
+ selected.filePath,
83
+ serializeMemory({ frontmatter: { ...fm, status: newStatus }, body: selected.memory.body }),
84
+ "utf8"
85
+ );
86
+ const label = newStatus === "validated" ? "\u2713 Approved" : newStatus === "rejected" ? "\u2717 Rejected" : "\u2191 Promoted";
87
+ const color = newStatus === "validated" ? "green" : newStatus === "rejected" ? "red" : "yellow";
88
+ flash_(`${label}: ${fm.id.slice(0, 40)}`, color);
89
+ const prev = cursor;
90
+ await reload();
91
+ setCursor(Math.min(prev, Math.max(0, filtered.length - 2)));
92
+ }, [selected, cursor, filtered.length, reload]);
93
+ const doDelete = useCallback(async () => {
94
+ if (!selected) return;
95
+ const fm = selected.memory.frontmatter;
96
+ await unlink(selected.filePath);
97
+ flash_(`\u{1F5D1} Deleted: ${fm.id.slice(0, 40)}`, "red");
98
+ await reload();
99
+ setCursor((c) => Math.max(0, c - 1));
100
+ }, [selected, reload]);
101
+ useInput((input, key) => {
102
+ if (input === "q") {
103
+ exit();
104
+ return;
105
+ }
106
+ if (input === "1") {
107
+ setScreen("memories");
108
+ setCursor(0);
109
+ return;
110
+ }
111
+ if (input === "2") {
112
+ setScreen("health");
113
+ return;
114
+ }
115
+ if (input === "3") {
116
+ setScreen("stats");
117
+ return;
118
+ }
119
+ if (screen === "memories") {
120
+ if (key.upArrow) setCursor((c) => Math.max(0, c - 1));
121
+ if (key.downArrow) setCursor((c) => Math.min(filtered.length - 1, c + 1));
122
+ if (key.tab) {
123
+ setFilterIdx((i) => (i + 1) % FILTERS.length);
124
+ setCursor(0);
125
+ }
126
+ if (input === "a") void doStatusChange("validated");
127
+ if (input === "r") void doStatusChange("rejected");
128
+ if (input === "p") void doStatusChange("proposed");
129
+ if (input === "d") void doDelete();
130
+ }
131
+ });
132
+ if (loading) return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Loading memories\u2026" });
133
+ if (!existsSync(paths.memoriesDir)) {
134
+ return /* @__PURE__ */ jsx(Text, { color: "red", children: "No .ai/memories found \u2014 run `haive init` first." });
135
+ }
136
+ const v = counts["validated"] ?? 0;
137
+ const p = counts["proposed"] ?? 0;
138
+ const d = counts["draft"] ?? 0;
139
+ const st = counts["stale"] ?? 0;
140
+ const rej = counts["rejected"] ?? 0;
141
+ const Header = () => /* @__PURE__ */ jsxs(Box, { borderStyle: "round", paddingX: 1, gap: 2, children: [
142
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "hAIve" }),
143
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: root.length > 40 ? "\u2026" + root.slice(-38) : root }),
144
+ /* @__PURE__ */ jsx(Text, { children: " " }),
145
+ /* @__PURE__ */ jsxs(Text, { color: "green", children: [
146
+ "\u2713 ",
147
+ v
148
+ ] }),
149
+ /* @__PURE__ */ jsxs(Text, { color: p > 0 ? "yellow" : void 0, children: [
150
+ " ~ ",
151
+ p
152
+ ] }),
153
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
154
+ " \xB7 ",
155
+ d
156
+ ] }),
157
+ st > 0 && /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
158
+ " \u26A0 ",
159
+ st
160
+ ] }),
161
+ rej > 0 && /* @__PURE__ */ jsxs(Text, { color: "red", children: [
162
+ " \u2717 ",
163
+ rej
164
+ ] })
165
+ ] });
166
+ const ScreenTabs = () => /* @__PURE__ */ jsxs(Box, { paddingX: 1, gap: 3, marginBottom: 0, children: [
167
+ ["memories", "health", "stats"].map((s, i) => /* @__PURE__ */ jsxs(Text, { color: screen === s ? "cyan" : void 0, bold: screen === s, children: [
168
+ "[",
169
+ i + 1,
170
+ "] ",
171
+ screen === s ? `[${s}]` : s
172
+ ] }, s)),
173
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " [q] quit" })
174
+ ] });
175
+ const FlashBar = () => flash ? /* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { color: flash.color, children: flash.text }) }) : null;
176
+ if (screen === "memories") {
177
+ const half = Math.floor(LIST_H / 2);
178
+ const start = Math.max(0, Math.min(cursor - half, Math.max(0, filtered.length - LIST_H)));
179
+ const visible = filtered.slice(start, start + LIST_H);
180
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
181
+ /* @__PURE__ */ jsx(Header, {}),
182
+ /* @__PURE__ */ jsx(ScreenTabs, {}),
183
+ /* @__PURE__ */ jsxs(Box, { paddingX: 1, gap: 2, marginBottom: 0, children: [
184
+ FILTERS.map((f) => /* @__PURE__ */ jsx(Text, { color: filter === f ? "cyan" : void 0, bold: filter === f, children: filter === f ? `[${f}]` : f }, f)),
185
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " [tab] cycle" })
186
+ ] }),
187
+ /* @__PURE__ */ jsxs(Box, { children: [
188
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 64, borderStyle: "single", paddingX: 1, children: [
189
+ /* @__PURE__ */ jsx(Text, { bold: true, dimColor: true, children: `MEMORIES ${filtered.length}/${nonRecap.length}` }),
190
+ filtered.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " (no memories in this filter)" }) : visible.map((m, vi) => {
191
+ const absIdx = start + vi;
192
+ const fm = m.memory.frontmatter;
193
+ const sel = absIdx === cursor;
194
+ const idShort = fm.id.length > 43 ? fm.id.slice(0, 40) + "\u2026" : fm.id;
195
+ return /* @__PURE__ */ jsxs(Box, { children: [
196
+ /* @__PURE__ */ jsxs(Text, { color: sel ? "cyan" : void 0, bold: sel, children: [
197
+ sel ? "\u25B6 " : " ",
198
+ idShort.padEnd(43)
199
+ ] }),
200
+ /* @__PURE__ */ jsx(Text, { color: statusColor(fm.status), children: fm.status.slice(0, 9) })
201
+ ] }, fm.id);
202
+ })
203
+ ] }),
204
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 40, borderStyle: "single", paddingX: 1, children: [
205
+ /* @__PURE__ */ jsx(Text, { bold: true, dimColor: true, children: "PREVIEW" }),
206
+ selected ? /* @__PURE__ */ jsxs(Fragment, { children: [
207
+ /* @__PURE__ */ jsx(Text, { bold: true, children: selected.memory.frontmatter.id.slice(0, 36) }),
208
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
209
+ selected.memory.frontmatter.scope,
210
+ "/",
211
+ selected.memory.frontmatter.type,
212
+ selected.memory.frontmatter.module ? ` [${selected.memory.frontmatter.module}]` : ""
213
+ ] }),
214
+ /* @__PURE__ */ jsxs(Text, { color: statusColor(selected.memory.frontmatter.status), children: [
215
+ selected.memory.frontmatter.status,
216
+ selected.memory.frontmatter.revision_count ? ` (rev ${selected.memory.frontmatter.revision_count})` : ""
217
+ ] }),
218
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
219
+ "tags: ",
220
+ selected.memory.frontmatter.tags.slice(0, 5).join(", ") || "(none)"
221
+ ] }),
222
+ /* @__PURE__ */ jsx(Text, { children: " " }),
223
+ selected.memory.body.split("\n").slice(0, LIST_H - 4).map((line, i) => /* @__PURE__ */ jsx(Text, { wrap: "truncate-end", children: line || " " }, i))
224
+ ] }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: "select a memory" })
225
+ ] })
226
+ ] }),
227
+ /* @__PURE__ */ jsx(FlashBar, {}),
228
+ /* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191\u2193 navigate [tab] filter [a] approve [r] reject [p] propose [d] delete" }) })
229
+ ] });
230
+ }
231
+ if (screen === "health") {
232
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
233
+ /* @__PURE__ */ jsx(Header, {}),
234
+ /* @__PURE__ */ jsx(ScreenTabs, {}),
235
+ /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
236
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 40, borderStyle: "single", paddingX: 1, children: [
237
+ /* @__PURE__ */ jsxs(Text, { bold: true, color: staleMemories.length > 0 ? "yellow" : "green", children: [
238
+ "\u26A0 STALE (",
239
+ staleMemories.length,
240
+ ")"
241
+ ] }),
242
+ staleMemories.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " All memories are fresh" }) : staleMemories.slice(0, LIST_H).map((m) => /* @__PURE__ */ jsx(Text, { wrap: "truncate-end", color: "yellow", children: m.memory.frontmatter.id.slice(0, 36) }, m.memory.frontmatter.id)),
243
+ staleMemories.length > LIST_H && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
244
+ " \u2026 +",
245
+ staleMemories.length - LIST_H,
246
+ " more"
247
+ ] })
248
+ ] }),
249
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
250
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 44, borderStyle: "single", paddingX: 1, children: [
251
+ /* @__PURE__ */ jsxs(Text, { bold: true, color: pending.length > 0 ? "yellow" : "green", children: [
252
+ "~ PENDING REVIEW (",
253
+ pending.length,
254
+ ")"
255
+ ] }),
256
+ pending.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " No memories pending review" }) : pending.slice(0, 6).map((m) => /* @__PURE__ */ jsx(Text, { wrap: "truncate-end", children: m.memory.frontmatter.id.slice(0, 40) }, m.memory.frontmatter.id))
257
+ ] }),
258
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 44, borderStyle: "single", paddingX: 1, children: [
259
+ /* @__PURE__ */ jsxs(Text, { bold: true, dimColor: true, children: [
260
+ "\u2298 ANCHORLESS (",
261
+ anchorless.length,
262
+ ")"
263
+ ] }),
264
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " No paths/symbols \u2014 staleness undetectable" }),
265
+ anchorless.slice(0, 5).map((m) => /* @__PURE__ */ jsx(Text, { wrap: "truncate-end", dimColor: true, children: m.memory.frontmatter.id.slice(0, 40) }, m.memory.frontmatter.id)),
266
+ anchorless.length > 5 && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
267
+ " \u2026 +",
268
+ anchorless.length - 5,
269
+ " more"
270
+ ] })
271
+ ] })
272
+ ] })
273
+ ] }),
274
+ /* @__PURE__ */ jsx(Box, { paddingX: 1, marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Run `haive memory verify --update` to recheck anchors | `haive memory update <id> --paths <files>` to add anchors" }) }),
275
+ /* @__PURE__ */ jsx(FlashBar, {})
276
+ ] });
277
+ }
278
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
279
+ /* @__PURE__ */ jsx(Header, {}),
280
+ /* @__PURE__ */ jsx(ScreenTabs, {}),
281
+ /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
282
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 44, borderStyle: "single", paddingX: 1, children: [
283
+ /* @__PURE__ */ jsx(Text, { bold: true, dimColor: true, children: "\u{1F4D6} TOP READ MEMORIES" }),
284
+ topRead.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " No read data yet (use `get_briefing`)" }) : topRead.map(({ m, u }) => /* @__PURE__ */ jsxs(Box, { children: [
285
+ /* @__PURE__ */ jsx(Text, { wrap: "truncate-end", children: m.memory.frontmatter.id.slice(0, 32).padEnd(32) }),
286
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
287
+ " \xD7",
288
+ u.read_count
289
+ ] })
290
+ ] }, m.memory.frontmatter.id))
291
+ ] }),
292
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
293
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 44, borderStyle: "single", paddingX: 1, children: [
294
+ /* @__PURE__ */ jsxs(Text, { bold: true, color: decaying.length > 0 ? "yellow" : "green", children: [
295
+ "\u23F3 DECAYING (not read in 90d) (",
296
+ decaying.length,
297
+ ")"
298
+ ] }),
299
+ decaying.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " All memories are actively used" }) : decaying.slice(0, 5).map((m) => /* @__PURE__ */ jsx(Text, { wrap: "truncate-end", color: "yellow", children: m.memory.frontmatter.id.slice(0, 40) }, m.memory.frontmatter.id))
300
+ ] }),
301
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 44, borderStyle: "single", paddingX: 1, children: [
302
+ /* @__PURE__ */ jsx(Text, { bold: true, dimColor: true, children: "\u{1F4CA} MEMORY TOTALS" }),
303
+ /* @__PURE__ */ jsxs(Text, { children: [
304
+ " Validated: ",
305
+ /* @__PURE__ */ jsx(Text, { color: "green", children: v })
306
+ ] }),
307
+ /* @__PURE__ */ jsxs(Text, { children: [
308
+ " Proposed: ",
309
+ /* @__PURE__ */ jsx(Text, { color: "yellow", children: p })
310
+ ] }),
311
+ /* @__PURE__ */ jsxs(Text, { children: [
312
+ " Draft: ",
313
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: d })
314
+ ] }),
315
+ /* @__PURE__ */ jsxs(Text, { children: [
316
+ " Stale: ",
317
+ /* @__PURE__ */ jsx(Text, { color: "yellow", children: st })
318
+ ] }),
319
+ /* @__PURE__ */ jsxs(Text, { children: [
320
+ " Rejected: ",
321
+ /* @__PURE__ */ jsx(Text, { color: "red", children: rej })
322
+ ] }),
323
+ /* @__PURE__ */ jsxs(Text, { children: [
324
+ " Total: ",
325
+ /* @__PURE__ */ jsx(Text, { bold: true, children: nonRecap.length })
326
+ ] })
327
+ ] })
328
+ ] })
329
+ ] }),
330
+ /* @__PURE__ */ jsx(FlashBar, {})
331
+ ] });
332
+ }
333
+ export {
334
+ Dashboard
335
+ };
336
+ //# sourceMappingURL=Dashboard-HVELRRC7.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, unlink } from \"node:fs/promises\";\nimport {\n getUsage,\n isDecaying,\n loadMemoriesFromDir,\n loadUsageIndex,\n resolveHaivePaths,\n serializeMemory,\n type LoadedMemory,\n type UsageIndex,\n} from \"@hiveai/core\";\n\ntype Screen = \"memories\" | \"health\" | \"stats\";\ntype FilterStatus = \"all\" | \"draft\" | \"proposed\" | \"validated\" | \"stale\" | \"rejected\";\nconst FILTERS: FilterStatus[] = [\"all\", \"draft\", \"proposed\", \"validated\", \"stale\", \"rejected\"];\nconst LIST_H = 14;\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 { root: string; }\n\nexport function Dashboard({ root }: Props) {\n const { exit } = useApp();\n const paths = resolveHaivePaths(root);\n\n const [screen, setScreen] = useState<Screen>(\"memories\");\n const [memories, setMemories] = useState<LoadedMemory[]>([]);\n const [usage, setUsage] = useState<UsageIndex>({ version: 1, updated_at: \"\", by_id: {} });\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\" | \"yellow\" } | null>(null);\n\n const filter: FilterStatus = FILTERS[filterIdx] ?? \"all\";\n\n const reload = useCallback(async () => {\n setLoading(true);\n const [mems, u] = await Promise.all([\n existsSync(paths.memoriesDir) ? loadMemoriesFromDir(paths.memoriesDir) : Promise.resolve([]),\n loadUsageIndex(paths),\n ]);\n setMemories(mems);\n setUsage(u);\n setLoading(false);\n }, [paths.memoriesDir]);\n\n useEffect(() => { void reload(); }, [reload]);\n\n // ── Derived data ──────────────────────────────────────────────────────\n const nonRecap = memories.filter((m) => m.memory.frontmatter.type !== \"session_recap\");\n\n const filtered = nonRecap.filter((m) => {\n const s = m.memory.frontmatter.status;\n if (filter === \"all\") return s !== \"rejected\";\n return s === filter;\n });\n\n const staleMemories = nonRecap.filter((m) => m.memory.frontmatter.status === \"stale\");\n const anchorless = nonRecap.filter(\n (m) =>\n m.memory.frontmatter.anchor.paths.length === 0 &&\n m.memory.frontmatter.anchor.symbols.length === 0 &&\n m.memory.frontmatter.status !== \"rejected\",\n );\n const pending = nonRecap.filter((m) => m.memory.frontmatter.status === \"proposed\");\n\n // Top-5 by read_count\n const topRead = [...nonRecap]\n .map((m) => ({ m, u: getUsage(usage, m.memory.frontmatter.id) }))\n .filter(({ u }) => u.read_count > 0)\n .sort((a, b) => b.u.read_count - a.u.read_count)\n .slice(0, 5);\n\n // Decaying memories\n const decaying = nonRecap.filter(({ memory: mem }) => {\n const u = getUsage(usage, mem.frontmatter.id);\n return isDecaying(u, mem.frontmatter.created_at);\n });\n\n const selected = filtered[cursor];\n\n const counts = nonRecap.reduce<Record<string, number>>((acc, m) => {\n acc[m.memory.frontmatter.status] = (acc[m.memory.frontmatter.status] ?? 0) + 1;\n return acc;\n }, {});\n\n const flash_ = (text: string, color: \"green\" | \"red\" | \"yellow\" = \"green\") => {\n setFlash({ text, color });\n setTimeout(() => setFlash(null), 2500);\n };\n\n // ── Actions ───────────────────────────────────────────────────────────\n const doStatusChange = useCallback(async (newStatus: \"validated\" | \"rejected\" | \"proposed\") => {\n if (!selected) return;\n const fm = selected.memory.frontmatter;\n if (fm.status === newStatus) { flash_(`Already ${newStatus}`, \"yellow\"); return; }\n await writeFile(\n selected.filePath,\n serializeMemory({ frontmatter: { ...fm, status: newStatus }, body: selected.memory.body }),\n \"utf8\",\n );\n const label = newStatus === \"validated\" ? \"✓ Approved\" : newStatus === \"rejected\" ? \"✗ Rejected\" : \"↑ Promoted\";\n const color = newStatus === \"validated\" ? \"green\" : newStatus === \"rejected\" ? \"red\" : \"yellow\";\n flash_(`${label}: ${fm.id.slice(0, 40)}`, color);\n const prev = cursor;\n await reload();\n setCursor(Math.min(prev, Math.max(0, filtered.length - 2)));\n }, [selected, cursor, filtered.length, reload]);\n\n const doDelete = useCallback(async () => {\n if (!selected) return;\n const fm = selected.memory.frontmatter;\n await unlink(selected.filePath);\n flash_(`🗑 Deleted: ${fm.id.slice(0, 40)}`, \"red\");\n await reload();\n setCursor((c) => Math.max(0, c - 1));\n }, [selected, reload]);\n\n useInput((input, key) => {\n if (input === \"q\") { exit(); return; }\n if (input === \"1\") { setScreen(\"memories\"); setCursor(0); return; }\n if (input === \"2\") { setScreen(\"health\"); return; }\n if (input === \"3\") { setScreen(\"stats\"); return; }\n\n if (screen === \"memories\") {\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) { setFilterIdx((i) => (i + 1) % FILTERS.length); setCursor(0); }\n if (input === \"a\") void doStatusChange(\"validated\");\n if (input === \"r\") void doStatusChange(\"rejected\");\n if (input === \"p\") void doStatusChange(\"proposed\");\n if (input === \"d\") void doDelete();\n }\n });\n\n if (loading) return <Text dimColor>Loading memories…</Text>;\n if (!existsSync(paths.memoriesDir)) {\n return <Text color=\"red\">No .ai/memories found — run `haive init` first.</Text>;\n }\n\n // ── Header (shared) ───────────────────────────────────────────────────\n const v = counts[\"validated\"] ?? 0;\n const p = counts[\"proposed\"] ?? 0;\n const d = counts[\"draft\"] ?? 0;\n const st = counts[\"stale\"] ?? 0;\n const rej = counts[\"rejected\"] ?? 0;\n\n const Header = () => (\n <Box borderStyle=\"round\" paddingX={1} gap={2}>\n <Text bold color=\"cyan\">hAIve</Text>\n <Text dimColor>{root.length > 40 ? \"…\" + root.slice(-38) : root}</Text>\n <Text> </Text>\n <Text color=\"green\">✓ {v}</Text>\n <Text color={p > 0 ? \"yellow\" : undefined}> ~ {p}</Text>\n <Text dimColor> · {d}</Text>\n {st > 0 && <Text color=\"yellow\"> ⚠ {st}</Text>}\n {rej > 0 && <Text color=\"red\"> ✗ {rej}</Text>}\n </Box>\n );\n\n const ScreenTabs = () => (\n <Box paddingX={1} gap={3} marginBottom={0}>\n {([\"memories\", \"health\", \"stats\"] as Screen[]).map((s, i) => (\n <Text key={s} color={screen === s ? \"cyan\" : undefined} bold={screen === s}>\n [{i + 1}] {screen === s ? `[${s}]` : s}\n </Text>\n ))}\n <Text dimColor> [q] quit</Text>\n </Box>\n );\n\n const FlashBar = () => flash\n ? <Box paddingX={1}><Text color={flash.color}>{flash.text}</Text></Box>\n : null;\n\n // ── Screen: Memories ─────────────────────────────────────────────────\n if (screen === \"memories\") {\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 return (\n <Box flexDirection=\"column\">\n <Header />\n <ScreenTabs />\n\n {/* Filter bar */}\n <Box paddingX={1} gap={2} marginBottom={0}>\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 <Box flexDirection=\"column\" width={64} borderStyle=\"single\" paddingX={1}>\n <Text bold dimColor>{`MEMORIES ${filtered.length}/${nonRecap.length}`}</Text>\n {filtered.length === 0 ? (\n <Text dimColor> (no memories in this filter)</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 */}\n <Box flexDirection=\"column\" width={40} borderStyle=\"single\" paddingX={1}>\n <Text bold dimColor>PREVIEW</Text>\n {selected ? (\n <>\n <Text bold>{selected.memory.frontmatter.id.slice(0, 36)}</Text>\n <Text color=\"cyan\">\n {selected.memory.frontmatter.scope}/{selected.memory.frontmatter.type}\n {selected.memory.frontmatter.module ? ` [${selected.memory.frontmatter.module}]` : \"\"}\n </Text>\n <Text color={statusColor(selected.memory.frontmatter.status)}>\n {selected.memory.frontmatter.status}\n {selected.memory.frontmatter.revision_count ? ` (rev ${selected.memory.frontmatter.revision_count})` : \"\"}\n </Text>\n <Text dimColor>tags: {selected.memory.frontmatter.tags.slice(0, 5).join(\", \") || \"(none)\"}</Text>\n <Text> </Text>\n {selected.memory.body\n .split(\"\\n\")\n .slice(0, LIST_H - 4)\n .map((line, i) => (\n <Text key={i} wrap=\"truncate-end\">{line || \" \"}</Text>\n ))}\n </>\n ) : (\n <Text dimColor>select a memory</Text>\n )}\n </Box>\n </Box>\n\n <FlashBar />\n <Box paddingX={1}>\n <Text dimColor>↑↓ navigate [tab] filter [a] approve [r] reject [p] propose [d] delete</Text>\n </Box>\n </Box>\n );\n }\n\n // ── Screen: Health ────────────────────────────────────────────────────\n if (screen === \"health\") {\n return (\n <Box flexDirection=\"column\">\n <Header />\n <ScreenTabs />\n <Box gap={2}>\n\n {/* Stale memories */}\n <Box flexDirection=\"column\" width={40} borderStyle=\"single\" paddingX={1}>\n <Text bold color={staleMemories.length > 0 ? \"yellow\" : \"green\"}>\n ⚠ STALE ({staleMemories.length})\n </Text>\n {staleMemories.length === 0\n ? <Text dimColor> All memories are fresh</Text>\n : staleMemories.slice(0, LIST_H).map((m) => (\n <Text key={m.memory.frontmatter.id} wrap=\"truncate-end\" color=\"yellow\">\n {m.memory.frontmatter.id.slice(0, 36)}\n </Text>\n ))\n }\n {staleMemories.length > LIST_H && (\n <Text dimColor> … +{staleMemories.length - LIST_H} more</Text>\n )}\n </Box>\n\n <Box flexDirection=\"column\" gap={1}>\n {/* Pending review */}\n <Box flexDirection=\"column\" width={44} borderStyle=\"single\" paddingX={1}>\n <Text bold color={pending.length > 0 ? \"yellow\" : \"green\"}>\n ~ PENDING REVIEW ({pending.length})\n </Text>\n {pending.length === 0\n ? <Text dimColor> No memories pending review</Text>\n : pending.slice(0, 6).map((m) => (\n <Text key={m.memory.frontmatter.id} wrap=\"truncate-end\">\n {m.memory.frontmatter.id.slice(0, 40)}\n </Text>\n ))\n }\n </Box>\n\n {/* Anchorless */}\n <Box flexDirection=\"column\" width={44} borderStyle=\"single\" paddingX={1}>\n <Text bold dimColor>⊘ ANCHORLESS ({anchorless.length})</Text>\n <Text dimColor> No paths/symbols — staleness undetectable</Text>\n {anchorless.slice(0, 5).map((m) => (\n <Text key={m.memory.frontmatter.id} wrap=\"truncate-end\" dimColor>\n {m.memory.frontmatter.id.slice(0, 40)}\n </Text>\n ))}\n {anchorless.length > 5 && (\n <Text dimColor> … +{anchorless.length - 5} more</Text>\n )}\n </Box>\n </Box>\n </Box>\n\n <Box paddingX={1} marginTop={1}>\n <Text dimColor>\n Run `haive memory verify --update` to recheck anchors | `haive memory update &lt;id&gt; --paths &lt;files&gt;` to add anchors\n </Text>\n </Box>\n <FlashBar />\n </Box>\n );\n }\n\n // ── Screen: Stats ─────────────────────────────────────────────────────\n return (\n <Box flexDirection=\"column\">\n <Header />\n <ScreenTabs />\n <Box gap={2}>\n\n {/* Top read */}\n <Box flexDirection=\"column\" width={44} borderStyle=\"single\" paddingX={1}>\n <Text bold dimColor>📖 TOP READ MEMORIES</Text>\n {topRead.length === 0\n ? <Text dimColor> No read data yet (use `get_briefing`)</Text>\n : topRead.map(({ m, u }) => (\n <Box key={m.memory.frontmatter.id}>\n <Text wrap=\"truncate-end\">\n {m.memory.frontmatter.id.slice(0, 32).padEnd(32)}\n </Text>\n <Text color=\"cyan\"> ×{u.read_count}</Text>\n </Box>\n ))\n }\n </Box>\n\n <Box flexDirection=\"column\" gap={1}>\n {/* Decaying */}\n <Box flexDirection=\"column\" width={44} borderStyle=\"single\" paddingX={1}>\n <Text bold color={decaying.length > 0 ? \"yellow\" : \"green\"}>\n ⏳ DECAYING (not read in 90d) ({decaying.length})\n </Text>\n {decaying.length === 0\n ? <Text dimColor> All memories are actively used</Text>\n : decaying.slice(0, 5).map((m) => (\n <Text key={m.memory.frontmatter.id} wrap=\"truncate-end\" color=\"yellow\">\n {m.memory.frontmatter.id.slice(0, 40)}\n </Text>\n ))\n }\n </Box>\n\n {/* Memory totals */}\n <Box flexDirection=\"column\" width={44} borderStyle=\"single\" paddingX={1}>\n <Text bold dimColor>📊 MEMORY TOTALS</Text>\n <Text> Validated: <Text color=\"green\">{v}</Text></Text>\n <Text> Proposed: <Text color=\"yellow\">{p}</Text></Text>\n <Text> Draft: <Text dimColor>{d}</Text></Text>\n <Text> Stale: <Text color=\"yellow\">{st}</Text></Text>\n <Text> Rejected: <Text color=\"red\">{rej}</Text></Text>\n <Text> Total: <Text bold>{nonRecap.length}</Text></Text>\n </Box>\n </Box>\n </Box>\n <FlashBar />\n </Box>\n );\n}\n"],"mappings":"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","names":[]}