@hiveai/cli 0.2.16 β†’ 0.3.2

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/README.md CHANGED
@@ -252,14 +252,22 @@ Show memories relevant to specific files you're about to edit.
252
252
  haive memory for-files src/payments/PaymentService.java src/payments/PaymentController.java
253
253
  ```
254
254
 
255
- #### `haive memory stats` / `hot` / `pending`
255
+ #### `haive memory stats` / `hot` / `pending` / `digest`
256
256
 
257
257
  ```bash
258
258
  haive memory stats # Usage stats and confidence levels for all memories
259
259
  haive memory hot # Most-read unvalidated memories (good promotion candidates)
260
260
  haive memory pending # Proposed memories awaiting review
261
+
262
+ # Generate a Markdown review digest for bulk approval/rejection:
263
+ haive memory digest # Last 7 days, team scope (prints to stdout)
264
+ haive memory digest --days 14 # Last 14 days
265
+ haive memory digest --scope all # All scopes
266
+ haive memory digest --out digest.md # Write to file
261
267
  ```
262
268
 
269
+ The digest groups memories by type, shows confidence level (⬜ unverified / 🟑 low / 🟒 trusted / ⭐ authoritative), anchor, read count, and action checkboxes for easy bulk review.
270
+
263
271
  ---
264
272
 
265
273
  ### `haive briefing`
@@ -267,12 +275,20 @@ haive memory pending # Proposed memories awaiting review
267
275
  Print the full project briefing β€” project context + relevant memories β€” in one shot. Use before starting a task.
268
276
 
269
277
  ```bash
270
- haive briefing # Full briefing, team scope
271
- haive briefing --task "add a Stripe payment" # Filter by task relevance
278
+ haive briefing # Full briefing, team scope
279
+ haive briefing --task "add a Stripe payment" # Filter by task relevance
272
280
  haive briefing --files src/payments/PaymentService.java # Filter by files
273
- haive briefing --scope all # Include personal memories
274
- haive briefing --include-stale # Include stale memories
275
- haive briefing --max-memories 15 # Show more memories
281
+ haive briefing --symbols PaymentService,TenantFilter # Look up symbol locations in code-map
282
+ haive briefing --scope all # Include personal memories
283
+ haive briefing --include-stale # Include stale memories
284
+ haive briefing --max-memories 15 # Show more memories
285
+ ```
286
+
287
+ **`--symbols` (requires `haive index code`):** look up where specific symbols are defined across your entire codebase β€” no grep needed. Returns file, line number, kind (class/interface/function/enum), and JSDoc description for each match.
288
+
289
+ ```
290
+ PaymentProvider src/payments/PaymentProvider.java:12 [interface] β€” Abstract payment provider
291
+ PaymentProvider src/frontend/payment.types.ts:4 [enum] β€” Mobile payment provider enum
276
292
  ```
277
293
 
278
294
  ---
@@ -337,13 +353,51 @@ The code map lets AI agents find where a function lives without grepping β€” dra
337
353
 
338
354
  ### `haive tui`
339
355
 
340
- Interactive terminal dashboard to browse, filter, and manage memories.
356
+ Interactive terminal dashboard with 3 screens β€” browse, filter, and manage memories without leaving the terminal.
341
357
 
342
358
  ```bash
343
- haive tui # Open the TUI (q to quit, arrow keys to navigate)
359
+ haive tui # Open the TUI
344
360
  haive tui --dir /path/to/project
345
361
  ```
346
362
 
363
+ **Screens (switch with `1` `2` `3`):**
364
+
365
+ | Screen | Key | What it shows |
366
+ |---|---|---|
367
+ | Memories | `1` | Full list + preview panel, filter by status (Tab), actions |
368
+ | Health | `2` | Stale memories, pending review, anchorless memories |
369
+ | Stats | `3` | Top-read memories, decaying (>90d unused), totals by status |
370
+
371
+ **Actions (in Memories screen):**
372
+
373
+ | Key | Action |
374
+ |---|---|
375
+ | `↑` `↓` | Navigate |
376
+ | `Tab` | Cycle filter (all / draft / proposed / validated / stale / rejected) |
377
+ | `a` | Approve (β†’ validated) |
378
+ | `r` | Reject |
379
+ | `p` | Propose (β†’ proposed) |
380
+ | `d` | Delete |
381
+ | `q` | Quit |
382
+
383
+ ---
384
+
385
+ ### `haive session end`
386
+
387
+ Save a structured end-of-session recap. Surfaced automatically at the start of the next session via `get_briefing`.
388
+
389
+ ```bash
390
+ haive session end \
391
+ --goal "Add Stripe payment integration" \
392
+ --accomplished "Implemented PaymentService, added tests, deployed to staging" \
393
+ --discoveries "The webhook signature must use the raw request body, not parsed JSON" \
394
+ --files "src/payments/PaymentService.ts,src/payments/webhook.ts" \
395
+ --next "Add retry logic for failed webhooks" \
396
+ --scope team
397
+ ```
398
+
399
+ One recap is kept per scope (topic-upsert: `revision_count` increments on each call).
400
+
347
401
  ---
348
402
 
349
403
  ## Memory lifecycle
@@ -0,0 +1,361 @@
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 path from "path";
9
+ import {
10
+ getUsage,
11
+ isDecaying,
12
+ loadMemoriesFromDir,
13
+ loadUsageIndex,
14
+ resolveHaivePaths,
15
+ serializeMemory
16
+ } from "@hiveai/core";
17
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
18
+ var FILTERS = ["all", "draft", "proposed", "validated", "stale", "rejected"];
19
+ var LIST_H = 14;
20
+ function statusColor(status) {
21
+ if (status === "validated") return "green";
22
+ if (status === "proposed" || status === "stale") return "yellow";
23
+ if (status === "rejected") return "red";
24
+ return void 0;
25
+ }
26
+ function Dashboard({ root }) {
27
+ const { exit } = useApp();
28
+ const paths = resolveHaivePaths(root);
29
+ const [screen, setScreen] = useState("memories");
30
+ const [memories, setMemories] = useState([]);
31
+ const [usage, setUsage] = useState({ version: 1, updated_at: "", by_id: {} });
32
+ const [loading, setLoading] = useState(true);
33
+ const [filterIdx, setFilterIdx] = useState(0);
34
+ const [cursor, setCursor] = useState(0);
35
+ const [flash, setFlash] = useState(null);
36
+ const filter = FILTERS[filterIdx] ?? "all";
37
+ const reload = useCallback(async () => {
38
+ setLoading(true);
39
+ const [mems, u] = await Promise.all([
40
+ existsSync(paths.memoriesDir) ? loadMemoriesFromDir(paths.memoriesDir) : Promise.resolve([]),
41
+ loadUsageIndex(paths)
42
+ ]);
43
+ setMemories(mems);
44
+ setUsage(u);
45
+ setLoading(false);
46
+ }, [paths.memoriesDir]);
47
+ useEffect(() => {
48
+ void reload();
49
+ }, [reload]);
50
+ const nonRecap = memories.filter((m) => m.memory.frontmatter.type !== "session_recap");
51
+ const filtered = nonRecap.filter((m) => {
52
+ const s = m.memory.frontmatter.status;
53
+ if (filter === "all") return s !== "rejected";
54
+ return s === filter;
55
+ });
56
+ const staleMemories = nonRecap.filter((m) => m.memory.frontmatter.status === "stale");
57
+ const anchorless = nonRecap.filter(
58
+ (m) => m.memory.frontmatter.anchor.paths.length === 0 && m.memory.frontmatter.anchor.symbols.length === 0 && m.memory.frontmatter.status !== "rejected"
59
+ );
60
+ const pending = nonRecap.filter((m) => m.memory.frontmatter.status === "proposed");
61
+ 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);
62
+ const decaying = nonRecap.filter(({ memory: mem }) => {
63
+ const u = getUsage(usage, mem.frontmatter.id);
64
+ return isDecaying(u, mem.frontmatter.created_at);
65
+ });
66
+ const selected = filtered[cursor];
67
+ const counts = nonRecap.reduce((acc, m) => {
68
+ acc[m.memory.frontmatter.status] = (acc[m.memory.frontmatter.status] ?? 0) + 1;
69
+ return acc;
70
+ }, {});
71
+ const flash_ = (text, color = "green") => {
72
+ setFlash({ text, color });
73
+ setTimeout(() => setFlash(null), 2500);
74
+ };
75
+ const doStatusChange = useCallback(async (newStatus) => {
76
+ if (!selected) return;
77
+ const fm = selected.memory.frontmatter;
78
+ if (fm.status === newStatus) {
79
+ flash_(`Already ${newStatus}`, "yellow");
80
+ return;
81
+ }
82
+ await writeFile(
83
+ selected.filePath,
84
+ serializeMemory({ frontmatter: { ...fm, status: newStatus }, body: selected.memory.body }),
85
+ "utf8"
86
+ );
87
+ const label = newStatus === "validated" ? "\u2713 Approved" : "\u2717 Rejected";
88
+ const color = newStatus === "validated" ? "green" : "red";
89
+ flash_(`${label}: ${fm.id.slice(0, 40)}`, color);
90
+ const prev = cursor;
91
+ await reload();
92
+ setCursor(Math.min(prev, Math.max(0, filtered.length - 2)));
93
+ }, [selected, cursor, filtered.length, reload]);
94
+ const doPromote = useCallback(async () => {
95
+ if (!selected) return;
96
+ const fm = selected.memory.frontmatter;
97
+ if (fm.scope === "team") {
98
+ flash_("Already team scope", "yellow");
99
+ return;
100
+ }
101
+ const teamDir = path.join(path.dirname(path.dirname(selected.filePath)), "team");
102
+ const newFilePath = path.join(teamDir, path.basename(selected.filePath));
103
+ const { mkdir } = await import("fs/promises");
104
+ await mkdir(teamDir, { recursive: true });
105
+ await writeFile(
106
+ newFilePath,
107
+ serializeMemory({
108
+ frontmatter: { ...fm, scope: "team", status: "proposed" },
109
+ body: selected.memory.body
110
+ }),
111
+ "utf8"
112
+ );
113
+ await unlink(selected.filePath);
114
+ flash_(`\u2191 Promoted to team: ${fm.id.slice(0, 36)}`, "yellow");
115
+ await reload();
116
+ setCursor((c) => Math.max(0, c - 1));
117
+ }, [selected, reload]);
118
+ const doDelete = useCallback(async () => {
119
+ if (!selected) return;
120
+ const fm = selected.memory.frontmatter;
121
+ await unlink(selected.filePath);
122
+ flash_(`\u{1F5D1} Deleted: ${fm.id.slice(0, 40)}`, "red");
123
+ await reload();
124
+ setCursor((c) => Math.max(0, c - 1));
125
+ }, [selected, reload]);
126
+ useInput((input, key) => {
127
+ if (input === "q") {
128
+ exit();
129
+ return;
130
+ }
131
+ if (input === "1") {
132
+ setScreen("memories");
133
+ setCursor(0);
134
+ return;
135
+ }
136
+ if (input === "2") {
137
+ setScreen("health");
138
+ return;
139
+ }
140
+ if (input === "3") {
141
+ setScreen("stats");
142
+ return;
143
+ }
144
+ if (screen === "memories") {
145
+ if (key.upArrow) setCursor((c) => Math.max(0, c - 1));
146
+ if (key.downArrow) setCursor((c) => Math.min(filtered.length - 1, c + 1));
147
+ if (key.tab) {
148
+ setFilterIdx((i) => (i + 1) % FILTERS.length);
149
+ setCursor(0);
150
+ }
151
+ if (input === "a") void doStatusChange("validated");
152
+ if (input === "r") void doStatusChange("rejected");
153
+ if (input === "p") void doPromote();
154
+ if (input === "d") void doDelete();
155
+ }
156
+ });
157
+ if (loading) return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Loading memories\u2026" });
158
+ if (!existsSync(paths.memoriesDir)) {
159
+ return /* @__PURE__ */ jsx(Text, { color: "red", children: "No .ai/memories found \u2014 run `haive init` first." });
160
+ }
161
+ const v = counts["validated"] ?? 0;
162
+ const p = counts["proposed"] ?? 0;
163
+ const d = counts["draft"] ?? 0;
164
+ const st = counts["stale"] ?? 0;
165
+ const rej = counts["rejected"] ?? 0;
166
+ const Header = () => /* @__PURE__ */ jsxs(Box, { borderStyle: "round", paddingX: 1, gap: 2, children: [
167
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "hAIve" }),
168
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: root.length > 40 ? "\u2026" + root.slice(-38) : root }),
169
+ /* @__PURE__ */ jsx(Text, { children: " " }),
170
+ /* @__PURE__ */ jsxs(Text, { color: "green", children: [
171
+ "\u2713 ",
172
+ v
173
+ ] }),
174
+ /* @__PURE__ */ jsxs(Text, { color: p > 0 ? "yellow" : void 0, children: [
175
+ " ~ ",
176
+ p
177
+ ] }),
178
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
179
+ " \xB7 ",
180
+ d
181
+ ] }),
182
+ st > 0 && /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
183
+ " \u26A0 ",
184
+ st
185
+ ] }),
186
+ rej > 0 && /* @__PURE__ */ jsxs(Text, { color: "red", children: [
187
+ " \u2717 ",
188
+ rej
189
+ ] })
190
+ ] });
191
+ const ScreenTabs = () => /* @__PURE__ */ jsxs(Box, { paddingX: 1, gap: 3, marginBottom: 0, children: [
192
+ ["memories", "health", "stats"].map((s, i) => /* @__PURE__ */ jsxs(Text, { color: screen === s ? "cyan" : void 0, bold: screen === s, children: [
193
+ "[",
194
+ i + 1,
195
+ "] ",
196
+ screen === s ? `[${s}]` : s
197
+ ] }, s)),
198
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " [q] quit" })
199
+ ] });
200
+ const FlashBar = () => flash ? /* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { color: flash.color, children: flash.text }) }) : null;
201
+ if (screen === "memories") {
202
+ const half = Math.floor(LIST_H / 2);
203
+ const start = Math.max(0, Math.min(cursor - half, Math.max(0, filtered.length - LIST_H)));
204
+ const visible = filtered.slice(start, start + LIST_H);
205
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
206
+ /* @__PURE__ */ jsx(Header, {}),
207
+ /* @__PURE__ */ jsx(ScreenTabs, {}),
208
+ /* @__PURE__ */ jsxs(Box, { paddingX: 1, gap: 2, marginBottom: 0, children: [
209
+ FILTERS.map((f) => /* @__PURE__ */ jsx(Text, { color: filter === f ? "cyan" : void 0, bold: filter === f, children: filter === f ? `[${f}]` : f }, f)),
210
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " [tab] cycle" })
211
+ ] }),
212
+ /* @__PURE__ */ jsxs(Box, { children: [
213
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 64, borderStyle: "single", paddingX: 1, children: [
214
+ /* @__PURE__ */ jsx(Text, { bold: true, dimColor: true, children: `MEMORIES ${filtered.length}/${nonRecap.length}` }),
215
+ filtered.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " (no memories in this filter)" }) : visible.map((m, vi) => {
216
+ const absIdx = start + vi;
217
+ const fm = m.memory.frontmatter;
218
+ const sel = absIdx === cursor;
219
+ const idShort = fm.id.length > 43 ? fm.id.slice(0, 40) + "\u2026" : fm.id;
220
+ return /* @__PURE__ */ jsxs(Box, { children: [
221
+ /* @__PURE__ */ jsxs(Text, { color: sel ? "cyan" : void 0, bold: sel, children: [
222
+ sel ? "\u25B6 " : " ",
223
+ idShort.padEnd(43)
224
+ ] }),
225
+ /* @__PURE__ */ jsx(Text, { color: statusColor(fm.status), children: fm.status.slice(0, 9) })
226
+ ] }, fm.id);
227
+ })
228
+ ] }),
229
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 40, borderStyle: "single", paddingX: 1, children: [
230
+ /* @__PURE__ */ jsx(Text, { bold: true, dimColor: true, children: "PREVIEW" }),
231
+ selected ? /* @__PURE__ */ jsxs(Fragment, { children: [
232
+ /* @__PURE__ */ jsx(Text, { bold: true, children: selected.memory.frontmatter.id.slice(0, 36) }),
233
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
234
+ selected.memory.frontmatter.scope,
235
+ "/",
236
+ selected.memory.frontmatter.type,
237
+ selected.memory.frontmatter.module ? ` [${selected.memory.frontmatter.module}]` : ""
238
+ ] }),
239
+ /* @__PURE__ */ jsxs(Text, { color: statusColor(selected.memory.frontmatter.status), children: [
240
+ selected.memory.frontmatter.status,
241
+ selected.memory.frontmatter.revision_count ? ` (rev ${selected.memory.frontmatter.revision_count})` : ""
242
+ ] }),
243
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
244
+ "tags: ",
245
+ selected.memory.frontmatter.tags.slice(0, 5).join(", ") || "(none)"
246
+ ] }),
247
+ /* @__PURE__ */ jsx(Text, { children: " " }),
248
+ selected.memory.body.split("\n").slice(0, LIST_H - 4).map((line, i) => /* @__PURE__ */ jsx(Text, { wrap: "truncate-end", children: line || " " }, i))
249
+ ] }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: "select a memory" })
250
+ ] })
251
+ ] }),
252
+ /* @__PURE__ */ jsx(FlashBar, {}),
253
+ /* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191\u2193 navigate [tab] filter [a] approve [r] reject [p] promote personal\u2192team [d] delete" }) })
254
+ ] });
255
+ }
256
+ if (screen === "health") {
257
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
258
+ /* @__PURE__ */ jsx(Header, {}),
259
+ /* @__PURE__ */ jsx(ScreenTabs, {}),
260
+ /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
261
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 40, borderStyle: "single", paddingX: 1, children: [
262
+ /* @__PURE__ */ jsxs(Text, { bold: true, color: staleMemories.length > 0 ? "yellow" : "green", children: [
263
+ "\u26A0 STALE (",
264
+ staleMemories.length,
265
+ ")"
266
+ ] }),
267
+ 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)),
268
+ staleMemories.length > LIST_H && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
269
+ " \u2026 +",
270
+ staleMemories.length - LIST_H,
271
+ " more"
272
+ ] })
273
+ ] }),
274
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
275
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 44, borderStyle: "single", paddingX: 1, children: [
276
+ /* @__PURE__ */ jsxs(Text, { bold: true, color: pending.length > 0 ? "yellow" : "green", children: [
277
+ "~ PENDING REVIEW (",
278
+ pending.length,
279
+ ")"
280
+ ] }),
281
+ 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))
282
+ ] }),
283
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 44, borderStyle: "single", paddingX: 1, children: [
284
+ /* @__PURE__ */ jsxs(Text, { bold: true, dimColor: true, children: [
285
+ "\u2298 ANCHORLESS (",
286
+ anchorless.length,
287
+ ")"
288
+ ] }),
289
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " No paths/symbols \u2014 staleness undetectable" }),
290
+ 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)),
291
+ anchorless.length > 5 && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
292
+ " \u2026 +",
293
+ anchorless.length - 5,
294
+ " more"
295
+ ] })
296
+ ] })
297
+ ] })
298
+ ] }),
299
+ /* @__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" }) }),
300
+ /* @__PURE__ */ jsx(FlashBar, {})
301
+ ] });
302
+ }
303
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
304
+ /* @__PURE__ */ jsx(Header, {}),
305
+ /* @__PURE__ */ jsx(ScreenTabs, {}),
306
+ /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
307
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 44, borderStyle: "single", paddingX: 1, children: [
308
+ /* @__PURE__ */ jsx(Text, { bold: true, dimColor: true, children: "\u{1F4D6} TOP READ MEMORIES" }),
309
+ topRead.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " No read data yet (use `get_briefing`)" }) : topRead.map(({ m, u }) => /* @__PURE__ */ jsxs(Box, { children: [
310
+ /* @__PURE__ */ jsx(Text, { wrap: "truncate-end", children: m.memory.frontmatter.id.slice(0, 32).padEnd(32) }),
311
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
312
+ " \xD7",
313
+ u.read_count
314
+ ] })
315
+ ] }, m.memory.frontmatter.id))
316
+ ] }),
317
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
318
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 44, borderStyle: "single", paddingX: 1, children: [
319
+ /* @__PURE__ */ jsxs(Text, { bold: true, color: decaying.length > 0 ? "yellow" : "green", children: [
320
+ "\u23F3 DECAYING (not read in 90d) (",
321
+ decaying.length,
322
+ ")"
323
+ ] }),
324
+ 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))
325
+ ] }),
326
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 44, borderStyle: "single", paddingX: 1, children: [
327
+ /* @__PURE__ */ jsx(Text, { bold: true, dimColor: true, children: "\u{1F4CA} MEMORY TOTALS" }),
328
+ /* @__PURE__ */ jsxs(Text, { children: [
329
+ " Validated: ",
330
+ /* @__PURE__ */ jsx(Text, { color: "green", children: v })
331
+ ] }),
332
+ /* @__PURE__ */ jsxs(Text, { children: [
333
+ " Proposed: ",
334
+ /* @__PURE__ */ jsx(Text, { color: "yellow", children: p })
335
+ ] }),
336
+ /* @__PURE__ */ jsxs(Text, { children: [
337
+ " Draft: ",
338
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: d })
339
+ ] }),
340
+ /* @__PURE__ */ jsxs(Text, { children: [
341
+ " Stale: ",
342
+ /* @__PURE__ */ jsx(Text, { color: "yellow", children: st })
343
+ ] }),
344
+ /* @__PURE__ */ jsxs(Text, { children: [
345
+ " Rejected: ",
346
+ /* @__PURE__ */ jsx(Text, { color: "red", children: rej })
347
+ ] }),
348
+ /* @__PURE__ */ jsxs(Text, { children: [
349
+ " Total: ",
350
+ /* @__PURE__ */ jsx(Text, { bold: true, children: nonRecap.length })
351
+ ] })
352
+ ] })
353
+ ] })
354
+ ] }),
355
+ /* @__PURE__ */ jsx(FlashBar, {})
356
+ ] });
357
+ }
358
+ export {
359
+ Dashboard
360
+ };
361
+ //# sourceMappingURL=Dashboard-Y2AIWFZK.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 path from \"node:path\";\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\") => {\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\" : \"βœ— Rejected\";\n const color = newStatus === \"validated\" ? \"green\" : \"red\";\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 // Promote = move personal β†’ team (scope change) + set status proposed\n const doPromote = useCallback(async () => {\n if (!selected) return;\n const fm = selected.memory.frontmatter;\n if (fm.scope === \"team\") { flash_(\"Already team scope\", \"yellow\"); return; }\n const teamDir = path.join(path.dirname(path.dirname(selected.filePath)), \"team\");\n const newFilePath = path.join(teamDir, path.basename(selected.filePath));\n const { mkdir } = await import(\"node:fs/promises\");\n await mkdir(teamDir, { recursive: true });\n await writeFile(\n newFilePath,\n serializeMemory({\n frontmatter: { ...fm, scope: \"team\" as const, status: \"proposed\" as const },\n body: selected.memory.body,\n }),\n \"utf8\",\n );\n await unlink(selected.filePath);\n flash_(`↑ Promoted to team: ${fm.id.slice(0, 36)}`, \"yellow\");\n await reload();\n setCursor((c) => Math.max(0, c - 1));\n }, [selected, 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 doPromote();\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] promote personalβ†’team [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":[]}