@hiveai/cli 0.2.16 → 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.
- package/dist/Dashboard-HVELRRC7.js +336 -0
- package/dist/Dashboard-HVELRRC7.js.map +1 -0
- package/dist/index.js +158 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/Dashboard-SRPCHP7Z.js +0 -194
- package/dist/Dashboard-SRPCHP7Z.js.map +0 -1
|
@@ -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 <id> --paths <files>` 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":[]}
|