claude-launchpad 1.15.0 → 1.16.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.
@@ -63,7 +63,11 @@ var DashboardDataSource = class {
63
63
  }
64
64
  return results;
65
65
  }
66
- /** Get all relations for a specific memory. */
66
+ /** Resolve a memory id to its title for relation display (cache-only, no I/O). */
67
+ getMemoryTitle(id) {
68
+ const m = this.#cachedMemories.find((mem) => mem.id === id);
69
+ return m?.title ?? void 0;
70
+ }
67
71
  getRelationsForMemory(id) {
68
72
  return this.#relationRepo.getByMemory(id);
69
73
  }
@@ -230,7 +234,6 @@ function useDashboardState(dataSource) {
230
234
  const [currentProject, setCurrentProject] = useState();
231
235
  const [sortMode, setSortMode] = useState("importance");
232
236
  const [selectedIndex, setSelectedIndex] = useState(0);
233
- const [focusedPane, setFocusedPane] = useState("list");
234
237
  const [showHelp, setShowHelp] = useState(false);
235
238
  const [showProjectPicker, setShowProjectPicker] = useState(false);
236
239
  const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
@@ -258,7 +261,8 @@ function useDashboardState(dataSource) {
258
261
  ) : withLife;
259
262
  return sortMemories(withSearch, sortMode);
260
263
  }, [dataSource, revision, typeFilter, lifespanFilter, searchQuery, currentProject, sortMode]);
261
- const selectedMemory = filteredMemories[selectedIndex];
264
+ const clampedIndex = Math.max(0, Math.min(selectedIndex, Math.max(0, filteredMemories.length - 1)));
265
+ const selectedMemory = filteredMemories[clampedIndex];
262
266
  const relations = useMemo(
263
267
  () => selectedMemory ? dataSource.getRelationsForMemory(selectedMemory.id) : [],
264
268
  [dataSource, selectedMemory, revision]
@@ -268,10 +272,12 @@ function useDashboardState(dataSource) {
268
272
  return dataSource.getStats();
269
273
  }, [dataSource, revision]);
270
274
  const navigateUp = useCallback(() => {
271
- setSelectedIndex((i) => Math.max(0, i - 1));
272
- }, []);
275
+ const last = filteredMemories.length - 1;
276
+ setSelectedIndex((i) => Math.max(0, Math.min(i, last) - 1));
277
+ }, [filteredMemories.length]);
273
278
  const navigateDown = useCallback(() => {
274
- setSelectedIndex((i) => Math.min(filteredMemories.length - 1, i + 1));
279
+ const last = filteredMemories.length - 1;
280
+ setSelectedIndex((i) => Math.max(0, Math.min(last, Math.min(i, last) + 1)));
275
281
  }, [filteredMemories.length]);
276
282
  const cycleSort = useCallback(() => {
277
283
  setSortMode((m) => SORT_MODES[(SORT_MODES.indexOf(m) + 1) % SORT_MODES.length]);
@@ -296,14 +302,15 @@ function useDashboardState(dataSource) {
296
302
  });
297
303
  setSelectedIndex(0);
298
304
  }, [projects]);
299
- const focusNext = useCallback(() => {
300
- setFocusedPane((p) => p === "list" ? "projects" : p === "projects" ? "detail" : "list");
301
- }, []);
302
305
  const filterByType = useCallback((type) => {
303
306
  setTypeFilter(type);
304
307
  setSelectedIndex(0);
305
308
  }, []);
306
309
  const openSearch = useCallback(() => setSearchActive(true), []);
310
+ const submitSearch = useCallback(() => {
311
+ setSearchActive(false);
312
+ setSelectedIndex(0);
313
+ }, []);
307
314
  const closeSearch = useCallback(() => {
308
315
  setSearchActive(false);
309
316
  setSearchQuery("");
@@ -345,8 +352,6 @@ function useDashboardState(dataSource) {
345
352
  searchActive,
346
353
  currentProject,
347
354
  sortMode,
348
- selectedIndex,
349
- focusedPane,
350
355
  showHelp,
351
356
  showProjectPicker,
352
357
  showDeleteConfirm,
@@ -357,6 +362,7 @@ function useDashboardState(dataSource) {
357
362
  relations,
358
363
  projects,
359
364
  stats,
365
+ selectedIndex: clampedIndex,
360
366
  setSearchQuery,
361
367
  setCurrentProject,
362
368
  setSelectedIndex,
@@ -368,9 +374,9 @@ function useDashboardState(dataSource) {
368
374
  cycleLifespan,
369
375
  cycleProjectNext,
370
376
  cycleProjectPrev,
371
- focusNext,
372
377
  filterByType,
373
378
  openSearch,
379
+ submitSearch,
374
380
  closeSearch,
375
381
  promptDelete,
376
382
  confirmDelete,
@@ -405,6 +411,7 @@ var TYPE_KEYS = {
405
411
  };
406
412
  function useKeybindings(actions, opts) {
407
413
  useInput((input, key) => {
414
+ if (opts.modalOpen) return;
408
415
  if (opts.expandOpen) return;
409
416
  if (opts.searchActive) {
410
417
  if (key.escape) actions.closeSearch();
@@ -425,9 +432,8 @@ function useKeybindings(actions, opts) {
425
432
  if (input === "p") actions.openProjectPicker();
426
433
  if (input === "]" || key.rightArrow) actions.cycleProjectNext();
427
434
  if (input === "[" || key.leftArrow) actions.cycleProjectPrev();
428
- if (key.tab) actions.focusNext();
429
- if (input === "r") actions.removeMemory();
430
- if (input === "d") actions.purgeProject();
435
+ if (input === "r" || input === "d") actions.removeMemory();
436
+ if (input === "X") actions.purgeProject();
431
437
  if (input === "?") actions.showHelp();
432
438
  if (key.return) actions.expandMemory();
433
439
  if (input === "q") actions.quit();
@@ -466,9 +472,8 @@ var HINTS = [
466
472
  ["1-5", "type"],
467
473
  ["l", "life"],
468
474
  ["s", "sort"],
469
- ["r", "remove"],
470
- ["d", "delete project"],
471
- ["Tab", "focus"],
475
+ ["d", "delete"],
476
+ ["X", "purge project"],
472
477
  ["?", "help"],
473
478
  ["q", "quit"]
474
479
  ];
@@ -519,11 +524,11 @@ function Header({ project, typeFilter, lifespanFilter, sortMode, searchQuery, la
519
524
  import { Box as Box3, Text as Text3 } from "ink";
520
525
  import TextInput from "ink-text-input";
521
526
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
522
- function SearchBar({ query, onChange, onClose }) {
527
+ function SearchBar({ query, onChange, onSubmit }) {
523
528
  return /* @__PURE__ */ jsxs3(Box3, { children: [
524
529
  /* @__PURE__ */ jsx3(Text3, { color: "yellow", children: "Search: " }),
525
- /* @__PURE__ */ jsx3(TextInput, { value: query, onChange, onSubmit: onClose }),
526
- /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: " (Esc to clear, Enter to keep)" })
530
+ /* @__PURE__ */ jsx3(TextInput, { value: query, onChange, onSubmit }),
531
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: " (Enter apply \xB7 Esc cancel)" })
527
532
  ] });
528
533
  }
529
534
 
@@ -646,7 +651,7 @@ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
646
651
  var METADATA_ROWS = 18;
647
652
  var BORDER_ROWS = 2;
648
653
  var MIN_CONTENT_ROWS = 2;
649
- function MemoryDetail({ memory, relations, isFocused, height, width }) {
654
+ function MemoryDetail({ memory, relations, isFocused, height, width, resolveTitle }) {
650
655
  return /* @__PURE__ */ jsxs5(
651
656
  Box5,
652
657
  {
@@ -657,12 +662,12 @@ function MemoryDetail({ memory, relations, isFocused, height, width }) {
657
662
  height,
658
663
  children: [
659
664
  /* @__PURE__ */ jsx5(Text5, { bold: true, color: isFocused ? "blue" : "gray", children: " Detail " }),
660
- !memory ? /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Select a memory to view details" }) : /* @__PURE__ */ jsx5(DetailContent, { memory, relations, height, width })
665
+ !memory ? /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Select a memory to view details" }) : /* @__PURE__ */ jsx5(DetailContent, { resolveTitle, memory, relations, height, width })
661
666
  ]
662
667
  }
663
668
  );
664
669
  }
665
- function DetailContent({ memory, relations, height, width }) {
670
+ function DetailContent({ memory, relations, height, width, resolveTitle }) {
666
671
  const life = computeLifespan(memory);
667
672
  const typeColor = TYPE_COLORS[memory.type] ?? "white";
668
673
  const relationRows = relations.length > 0 ? relations.length + 2 : 0;
@@ -741,7 +746,7 @@ function DetailContent({ memory, relations, height, width }) {
741
746
  preview.remainingLines === 1 ? "" : "s",
742
747
  " \xB7 press Enter to view full"
743
748
  ] }),
744
- relations.length > 0 && /* @__PURE__ */ jsx5(RelationsList, { relations, memoryId: memory.id })
749
+ relations.length > 0 && /* @__PURE__ */ jsx5(RelationsList, { resolveTitle, relations, memoryId: memory.id })
745
750
  ] });
746
751
  }
747
752
  function truncateContent(content, maxRows, wrapWidth) {
@@ -756,7 +761,7 @@ function truncateContent(content, maxRows, wrapWidth) {
756
761
  remainingLines: allLines.length - visible
757
762
  };
758
763
  }
759
- function RelationsList({ relations, memoryId }) {
764
+ function RelationsList({ relations, memoryId, resolveTitle }) {
760
765
  return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
761
766
  /* @__PURE__ */ jsx5(Text5, { bold: true, children: "Relations" }),
762
767
  /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "\u2500".repeat(40) }),
@@ -764,13 +769,14 @@ function RelationsList({ relations, memoryId }) {
764
769
  const relColor = RELATION_COLORS[r.relationType] ?? "white";
765
770
  const direction = r.sourceId === memoryId ? "\u2192" : "\u2190";
766
771
  const otherId = r.sourceId === memoryId ? r.targetId : r.sourceId;
772
+ const label = resolveTitle?.(otherId) ?? otherId.slice(0, 8);
767
773
  return /* @__PURE__ */ jsxs5(Text5, { children: [
768
774
  " ",
769
775
  direction,
770
776
  " ",
771
777
  /* @__PURE__ */ jsx5(Text5, { color: relColor, children: r.relationType }),
772
778
  " ",
773
- otherId
779
+ label
774
780
  ] }, i);
775
781
  })
776
782
  ] });
@@ -916,9 +922,8 @@ var BINDINGS = [
916
922
  ["s", "Cycle sort mode"],
917
923
  ["p", "Open project picker"],
918
924
  ["[ / ]", "Previous / next project"],
919
- ["r", "Remove selected memory"],
920
- ["d", "Delete all memories for current project"],
921
- ["Tab", "Focus next pane"],
925
+ ["d / r", "Delete selected memory"],
926
+ ["X", "Purge all memories for current project"],
922
927
  ["?", "Show this help"],
923
928
  ["q", "Quit"]
924
929
  ];
@@ -1050,7 +1055,7 @@ function PurgeConfirm({ project, memoryCount, onConfirm, onCancel }) {
1050
1055
  import { useState as useState3, useEffect as useEffect3 } from "react";
1051
1056
  import { Box as Box12, Text as Text12, useInput as useInput6 } from "ink";
1052
1057
  import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
1053
- function ExpandMemory({ memory, relations, onClose }) {
1058
+ function ExpandMemory({ memory, relations, onClose, resolveTitle }) {
1054
1059
  const { columns, rows } = useTerminalSize();
1055
1060
  const [scroll, setScroll] = useState3(0);
1056
1061
  const contentWidth = Math.max(20, columns - 6);
@@ -1108,13 +1113,14 @@ function ExpandMemory({ memory, relations, onClose }) {
1108
1113
  const relColor = RELATION_COLORS[r.relationType] ?? "white";
1109
1114
  const direction = r.sourceId === memory.id ? "\u2192" : "\u2190";
1110
1115
  const otherId = r.sourceId === memory.id ? r.targetId : r.sourceId;
1116
+ const label = resolveTitle?.(otherId) ?? otherId.slice(0, 8);
1111
1117
  return /* @__PURE__ */ jsxs12(Text12, { children: [
1112
1118
  " ",
1113
1119
  direction,
1114
1120
  " ",
1115
1121
  /* @__PURE__ */ jsx12(Text12, { color: relColor, children: r.relationType }),
1116
1122
  " ",
1117
- otherId
1123
+ label
1118
1124
  ] }, i);
1119
1125
  })
1120
1126
  ] }),
@@ -1142,7 +1148,6 @@ function App({ dataSource }) {
1142
1148
  cycleProjectNext: state.cycleProjectNext,
1143
1149
  cycleProjectPrev: state.cycleProjectPrev,
1144
1150
  cycleSort: state.cycleSort,
1145
- focusNext: state.focusNext,
1146
1151
  removeMemory: state.promptDelete,
1147
1152
  purgeProject: state.promptPurge,
1148
1153
  openProjectPicker: () => state.setShowProjectPicker((v) => !v),
@@ -1152,7 +1157,8 @@ function App({ dataSource }) {
1152
1157
  }, {
1153
1158
  searchActive: state.searchActive,
1154
1159
  pickerOpen: state.showProjectPicker,
1155
- expandOpen: state.showExpand
1160
+ expandOpen: state.showExpand,
1161
+ modalOpen: state.showDeleteConfirm || state.showPurgeConfirm || state.showHelp
1156
1162
  });
1157
1163
  if (state.showHelp) {
1158
1164
  return /* @__PURE__ */ jsx13(HelpOverlay, { onClose: () => state.setShowHelp(false) });
@@ -1163,6 +1169,7 @@ function App({ dataSource }) {
1163
1169
  {
1164
1170
  memory: state.selectedMemory,
1165
1171
  relations: state.relations,
1172
+ resolveTitle: (id) => dataSource.getMemoryTitle(id),
1166
1173
  onClose: state.closeExpand
1167
1174
  }
1168
1175
  );
@@ -1228,7 +1235,7 @@ function App({ dataSource }) {
1228
1235
  {
1229
1236
  query: state.searchQuery,
1230
1237
  onChange: state.setSearchQuery,
1231
- onClose: () => state.setSearchQuery(state.searchQuery)
1238
+ onSubmit: state.submitSearch
1232
1239
  }
1233
1240
  ),
1234
1241
  /* @__PURE__ */ jsxs13(Box13, { flexDirection: isNarrow ? "column" : "row", height: isNarrow ? void 0 : contentHeight, children: [
@@ -1237,7 +1244,7 @@ function App({ dataSource }) {
1237
1244
  {
1238
1245
  memories: state.filteredMemories,
1239
1246
  selectedIndex: state.selectedIndex,
1240
- isFocused: state.focusedPane === "list",
1247
+ isFocused: true,
1241
1248
  height: listHeight
1242
1249
  }
1243
1250
  ) }),
@@ -1247,7 +1254,7 @@ function App({ dataSource }) {
1247
1254
  {
1248
1255
  memories: state.filteredMemories,
1249
1256
  activeProject: state.currentProject,
1250
- isFocused: state.focusedPane === "projects",
1257
+ isFocused: false,
1251
1258
  height: projectListHeight
1252
1259
  }
1253
1260
  ),
@@ -1256,7 +1263,8 @@ function App({ dataSource }) {
1256
1263
  {
1257
1264
  memory: state.selectedMemory,
1258
1265
  relations: state.relations,
1259
- isFocused: state.focusedPane === "detail",
1266
+ resolveTitle: (id) => dataSource.getMemoryTitle(id),
1267
+ isFocused: false,
1260
1268
  height: detailHeight,
1261
1269
  width: rightWidth
1262
1270
  }
@@ -1267,8 +1275,47 @@ function App({ dataSource }) {
1267
1275
  ] });
1268
1276
  }
1269
1277
 
1278
+ // src/commands/memory/dashboard/components/error-boundary.tsx
1279
+ import React6 from "react";
1280
+ import { Box as Box14, Text as Text13, useApp as useApp2, useInput as useInput7 } from "ink";
1281
+ import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
1282
+ function CrashScreen({
1283
+ message
1284
+ }) {
1285
+ const { exit } = useApp2();
1286
+ useInput7((input) => {
1287
+ if (input === "q") exit();
1288
+ });
1289
+ return /* @__PURE__ */ jsxs14(
1290
+ Box14,
1291
+ {
1292
+ flexDirection: "column",
1293
+ borderStyle: "round",
1294
+ borderColor: "red",
1295
+ padding: 1,
1296
+ children: [
1297
+ /* @__PURE__ */ jsx14(Text13, { bold: true, color: "red", children: "Dashboard crashed" }),
1298
+ /* @__PURE__ */ jsx14(Text13, { children: message }),
1299
+ /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Your data is untouched. Press q to quit." })
1300
+ ]
1301
+ }
1302
+ );
1303
+ }
1304
+ var DashboardErrorBoundary = class extends React6.Component {
1305
+ state = { error: null };
1306
+ static getDerivedStateFromError(error) {
1307
+ return { error };
1308
+ }
1309
+ render() {
1310
+ if (this.state.error) {
1311
+ return /* @__PURE__ */ jsx14(CrashScreen, { message: this.state.error.message });
1312
+ }
1313
+ return this.props.children;
1314
+ }
1315
+ };
1316
+
1270
1317
  // src/commands/memory/dashboard/tui.tsx
1271
- import { jsx as jsx14 } from "react/jsx-runtime";
1318
+ import { jsx as jsx15 } from "react/jsx-runtime";
1272
1319
  async function startTui(options) {
1273
1320
  const config = loadConfig(
1274
1321
  options?.dbPath ? { dataDir: options.dbPath } : void 0
@@ -1287,7 +1334,7 @@ async function startTui(options) {
1287
1334
  );
1288
1335
  let shuttingDown = false;
1289
1336
  const { waitUntilExit, unmount } = render(
1290
- /* @__PURE__ */ jsx14(App, { dataSource })
1337
+ /* @__PURE__ */ jsx15(DashboardErrorBoundary, { children: /* @__PURE__ */ jsx15(App, { dataSource }) })
1291
1338
  );
1292
1339
  function shutdown() {
1293
1340
  if (shuttingDown) return;
@@ -1310,4 +1357,4 @@ async function startTui(options) {
1310
1357
  export {
1311
1358
  startTui
1312
1359
  };
1313
- //# sourceMappingURL=tui-3KITZCNS.js.map
1360
+ //# sourceMappingURL=tui-BS4XXLOC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/memory/dashboard/tui.tsx","../src/commands/memory/dashboard/data/data-source.ts","../src/commands/memory/dashboard/app.tsx","../src/commands/memory/dashboard/hooks/use-dashboard-state.ts","../src/commands/memory/dashboard/data/formatters.ts","../src/commands/memory/dashboard/hooks/use-keybindings.ts","../src/commands/memory/dashboard/hooks/use-terminal-size.ts","../src/commands/memory/dashboard/components/keybinding-bar.tsx","../src/commands/memory/dashboard/components/header.tsx","../src/commands/memory/dashboard/components/search-bar.tsx","../src/commands/memory/dashboard/components/memory-list.tsx","../src/commands/memory/dashboard/colors.ts","../src/commands/memory/dashboard/components/memory-detail.tsx","../src/commands/memory/dashboard/data/wrap.ts","../src/commands/memory/dashboard/components/project-list.tsx","../src/commands/memory/dashboard/components/stats-bar.tsx","../src/commands/memory/dashboard/components/help-overlay.tsx","../src/commands/memory/dashboard/components/project-picker.tsx","../src/commands/memory/dashboard/components/delete-confirm.tsx","../src/commands/memory/dashboard/components/purge-confirm.tsx","../src/commands/memory/dashboard/components/expand-memory.tsx","../src/commands/memory/dashboard/components/error-boundary.tsx"],"sourcesContent":["import React from 'react';\nimport { render } from 'ink';\nimport { createDatabase, closeDatabase } from '../storage/database.js';\nimport { migrate } from '../storage/migrator.js';\nimport { MemoryRepo } from '../storage/memory-repo.js';\nimport { RelationRepo } from '../storage/relation-repo.js';\nimport { SearchRepo } from '../storage/search-repo.js';\nimport { loadConfig, resolveDataDir } from '../config.js';\nimport { DashboardDataSource } from './data/data-source.js';\nimport { App } from './app.js';\nimport { DashboardErrorBoundary } from './components/error-boundary.js';\n\nexport interface TuiOptions {\n readonly dbPath?: string;\n}\n\nexport async function startTui(options?: TuiOptions): Promise<void> {\n const config = loadConfig(\n options?.dbPath ? { dataDir: options.dbPath } : undefined,\n );\n const dataDir = resolveDataDir(config.dataDir);\n const db = createDatabase({ dataDir });\n migrate(db);\n\n const memoryRepo = new MemoryRepo(db);\n const relationRepo = new RelationRepo(db);\n const searchRepo = new SearchRepo(db);\n\n const dataSource = new DashboardDataSource(\n memoryRepo, relationRepo, searchRepo, dataDir,\n );\n\n let shuttingDown = false;\n\n const { waitUntilExit, unmount } = render(\n <DashboardErrorBoundary>\n <App dataSource={dataSource} />\n </DashboardErrorBoundary>,\n );\n\n function shutdown(): void {\n if (shuttingDown) return;\n shuttingDown = true;\n dataSource.stopWatching();\n unmount();\n closeDatabase(db);\n }\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n\n try {\n await waitUntilExit();\n } finally {\n if (!shuttingDown) {\n dataSource.stopWatching();\n closeDatabase(db);\n }\n }\n}\n","import { statSync, watchFile, unwatchFile } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { MemoryRepo } from \"../../storage/memory-repo.js\";\nimport type { RelationRepo } from \"../../storage/relation-repo.js\";\nimport type { SearchRepo } from \"../../storage/search-repo.js\";\nimport type { Memory, Relation } from \"../../types.js\";\n\n// -- Types --------------------------------------------------------------------\n\nexport interface MemoryFilter {\n readonly type?: string;\n readonly project?: string;\n readonly query?: string;\n}\n\nexport interface DashboardStats {\n readonly total: number;\n readonly byType: Record<string, number>;\n readonly byProject: Record<string, number>;\n readonly relations: number;\n readonly dbSizeBytes: number;\n readonly oldest: string | null;\n readonly newest: string | null;\n}\n\n// -- Data Source --------------------------------------------------------------\n\nexport class DashboardDataSource {\n readonly #memoryRepo: MemoryRepo;\n readonly #relationRepo: RelationRepo;\n readonly #searchRepo: SearchRepo;\n readonly #dbPath: string;\n\n #cachedMemories: readonly Memory[] = [];\n\n constructor(\n memoryRepo: MemoryRepo,\n relationRepo: RelationRepo,\n searchRepo: SearchRepo,\n dataDir: string,\n ) {\n this.#memoryRepo = memoryRepo;\n this.#relationRepo = relationRepo;\n this.#searchRepo = searchRepo;\n this.#dbPath = join(dataDir, \"memory.db\");\n }\n\n /** Re-query all memories from DB and cache them. Excludes soft-deleted (importance=0). */\n refresh(): void {\n this.#cachedMemories = this.#memoryRepo\n .getAll()\n .filter((m) => m.importance > 0);\n }\n\n /** Return cached memories, optionally filtered by type, project, or FTS query. */\n getMemories(filter?: MemoryFilter): readonly Memory[] {\n if (!filter) return this.#cachedMemories;\n\n let results: readonly Memory[] = this.#cachedMemories;\n\n if (filter.type) {\n const t = filter.type;\n results = results.filter((m) => m.type === t);\n }\n\n if (filter.project) {\n const p = filter.project;\n results = results.filter((m) => m.project === p);\n }\n\n if (filter.query) {\n const matches = this.#searchRepo.searchFts({\n query: filter.query,\n limit: 100,\n });\n const matchedIds = new Set(matches.map((m) => m.memoryId));\n results = results.filter((m) => matchedIds.has(m.id));\n }\n\n return results;\n }\n\n /** Resolve a memory id to its title for relation display (cache-only, no I/O). */\n getMemoryTitle(id: string): string | undefined {\n const m = this.#cachedMemories.find((mem) => mem.id === id);\n return m?.title ?? undefined;\n }\n\n getRelationsForMemory(id: string): readonly Relation[] {\n return this.#relationRepo.getByMemory(id);\n }\n\n /** Compute aggregate stats from cached data + DB queries. */\n getStats(): DashboardStats {\n const total = this.#memoryRepo.count();\n const byType = this.#memoryRepo.countByType();\n const relations = this.#relationRepo.count();\n const { oldest, newest } = this.#memoryRepo.dateRange();\n const dbSizeBytes = this.#getDbSize();\n const byProject = this.#computeByProject();\n\n return { total, byType, byProject, relations, dbSizeBytes, oldest, newest };\n }\n\n /** Derive unique project names from cached memories. */\n getProjects(): readonly string[] {\n const projects = new Set<string>();\n for (const m of this.#cachedMemories) {\n if (m.project) {\n projects.add(m.project);\n }\n }\n return [...projects].sort();\n }\n\n /** Watch the DB file for changes (2s polling interval). Only fires on mtime change. */\n startWatching(onChange: () => void): void {\n let lastMtime = 0;\n watchFile(this.#dbPath, { interval: 2000 }, (curr) => {\n const mtime = curr.mtimeMs;\n if (mtime === lastMtime) return;\n lastMtime = mtime;\n this.refresh();\n onChange();\n });\n }\n\n /** Hard-delete a memory by ID. Returns true if deleted. */\n deleteMemory(id: string): boolean {\n return this.#memoryRepo.hardDelete(id);\n }\n\n /** Count memories for a project (unfiltered). */\n countByProject(project: string): number {\n return this.#cachedMemories.filter((m) => m.project === project).length;\n }\n\n /** Delete all memories for a project. Returns number of deleted memories. */\n purgeProject(project: string): number {\n return this.#memoryRepo.deleteByProject(project);\n }\n\n /** Stop watching the DB file. */\n stopWatching(): void {\n unwatchFile(this.#dbPath);\n }\n\n // -- Private helpers --------------------------------------------------------\n\n #getDbSize(): number {\n try {\n return statSync(this.#dbPath).size;\n } catch {\n return 0;\n }\n }\n\n #computeByProject(): Record<string, number> {\n const counts: Record<string, number> = {};\n for (const m of this.#cachedMemories) {\n const key = m.project ?? \"(none)\";\n counts[key] = (counts[key] ?? 0) + 1;\n }\n return counts;\n }\n}\n","import React from 'react';\nimport { Box, useApp } from 'ink';\nimport type { DashboardDataSource } from './data/data-source.js';\nimport { useDashboardState } from './hooks/use-dashboard-state.js';\nimport { useKeybindings } from './hooks/use-keybindings.js';\nimport { useTerminalSize } from './hooks/use-terminal-size.js';\nimport { KeybindingBar } from './components/keybinding-bar.js';\nimport { Header } from './components/header.js';\nimport { SearchBar } from './components/search-bar.js';\nimport { MemoryList } from './components/memory-list.js';\nimport { MemoryDetail } from './components/memory-detail.js';\nimport { ProjectList } from './components/project-list.js';\nimport { StatsBar } from './components/stats-bar.js';\nimport { HelpOverlay } from './components/help-overlay.js';\nimport { ProjectPicker } from './components/project-picker.js';\nimport { DeleteConfirm } from './components/delete-confirm.js';\nimport { PurgeConfirm } from './components/purge-confirm.js';\nimport { ExpandMemory } from './components/expand-memory.js';\n\ninterface AppProps {\n readonly dataSource: DashboardDataSource;\n}\n\nexport function App({ dataSource }: AppProps): React.ReactNode {\n const { exit } = useApp();\n const { columns, rows, layout } = useTerminalSize();\n const state = useDashboardState(dataSource);\n\n useKeybindings({\n navigateUp: state.navigateUp,\n navigateDown: state.navigateDown,\n openSearch: state.openSearch,\n closeSearch: state.closeSearch,\n filterByType: state.filterByType,\n cycleLifespan: state.cycleLifespan,\n cycleProjectNext: state.cycleProjectNext,\n cycleProjectPrev: state.cycleProjectPrev,\n cycleSort: state.cycleSort,\n removeMemory: state.promptDelete,\n purgeProject: state.promptPurge,\n openProjectPicker: () => state.setShowProjectPicker((v) => !v),\n showHelp: () => state.setShowHelp((v) => !v),\n expandMemory: state.expandMemory,\n quit: exit,\n }, {\n searchActive: state.searchActive,\n pickerOpen: state.showProjectPicker,\n expandOpen: state.showExpand,\n modalOpen: state.showDeleteConfirm || state.showPurgeConfirm || state.showHelp,\n });\n\n if (state.showHelp) {\n return <HelpOverlay onClose={() => state.setShowHelp(false)} />;\n }\n\n if (state.showExpand && state.selectedMemory) {\n return (\n <ExpandMemory\n memory={state.selectedMemory}\n relations={state.relations}\n resolveTitle={(id) => dataSource.getMemoryTitle(id)}\n onClose={state.closeExpand}\n />\n );\n }\n\n if (state.showProjectPicker) {\n return (\n <ProjectPicker\n projects={[...state.projects]}\n activeProject={state.currentProject}\n onSelect={(p) => { state.setCurrentProject(p); state.setSelectedIndex(0); }}\n onClose={() => state.setShowProjectPicker(false)}\n />\n );\n }\n\n if (state.showDeleteConfirm && state.selectedMemory) {\n return (\n <DeleteConfirm\n memory={state.selectedMemory}\n onConfirm={state.confirmDelete}\n onCancel={state.cancelDelete}\n />\n );\n }\n\n if (state.showPurgeConfirm && state.currentProject) {\n return (\n <PurgeConfirm\n project={state.currentProject}\n memoryCount={dataSource.countByProject(state.currentProject)}\n onConfirm={state.confirmPurge}\n onCancel={state.cancelPurge}\n />\n );\n }\n\n const contentHeight = Math.max(4, rows - 6 - (state.searchActive ? 1 : 0));\n const isNarrow = layout === 'narrow';\n const listWidth = Math.floor(columns * 0.6);\n const rightWidth = columns - listWidth;\n // Target split: projects ≤ 1/3 of right column (capped at 12), detail takes the rest\n const projectsCount = new Set(state.filteredMemories.map((m) => m.project ?? '(none)')).size + 1;\n const projectListHeight = isNarrow\n ? 0\n : Math.min(Math.max(4, Math.floor(contentHeight / 3)), projectsCount + 3, 12);\n // Narrow layout stacks list + detail vertically — split contentHeight between them\n const listHeight = isNarrow ? Math.max(6, Math.floor(contentHeight * 0.6)) : contentHeight;\n const detailHeight = isNarrow\n ? Math.max(6, contentHeight - listHeight)\n : Math.max(6, contentHeight - projectListHeight);\n\n return (\n <Box flexDirection=\"column\">\n <KeybindingBar />\n <Header\n project={state.currentProject}\n typeFilter={state.typeFilter}\n lifespanFilter={state.lifespanFilter}\n sortMode={state.sortMode}\n searchQuery={state.searchQuery}\n layout={layout}\n />\n {state.searchActive && (\n <SearchBar\n query={state.searchQuery}\n onChange={state.setSearchQuery}\n onSubmit={state.submitSearch}\n />\n )}\n <Box flexDirection={isNarrow ? 'column' : 'row'} height={isNarrow ? undefined : contentHeight}>\n <Box width={isNarrow ? '100%' : '60%'}>\n <MemoryList\n memories={state.filteredMemories}\n selectedIndex={state.selectedIndex}\n isFocused={true}\n height={listHeight}\n />\n </Box>\n <Box flexDirection=\"column\" width={isNarrow ? '100%' : '40%'}>\n {!isNarrow && (\n <ProjectList\n memories={state.filteredMemories}\n activeProject={state.currentProject}\n isFocused={false}\n height={projectListHeight}\n />\n )}\n <MemoryDetail\n memory={state.selectedMemory}\n relations={state.relations}\n resolveTitle={(id) => dataSource.getMemoryTitle(id)}\n isFocused={false}\n height={detailHeight}\n width={rightWidth}\n />\n </Box>\n </Box>\n <StatsBar stats={state.stats} visible={state.filteredMemories} />\n </Box>\n );\n}\n","import { useState, useMemo, useEffect, useCallback } from 'react';\nimport type { DashboardDataSource } from '../data/data-source.js';\nimport type { Memory, MemoryType, Relation } from '../../types.js';\nimport type { DashboardStats } from '../data/data-source.js';\nimport { computeLifespan, type LifespanStatus } from '../data/formatters.js';\n\nexport type SortMode = 'importance' | 'age' | 'access' | 'lifespan';\n\nconst SORT_MODES: readonly SortMode[] = ['importance', 'age', 'access', 'lifespan'];\nconst LIFESPAN_FILTERS: readonly (LifespanStatus | undefined)[] = [\n undefined, 'healthy', 'fading', 'stale', 'session',\n];\n\nexport function useDashboardState(dataSource: DashboardDataSource) {\n const [revision, setRevision] = useState(0);\n const [typeFilter, setTypeFilter] = useState<MemoryType | undefined>();\n const [lifespanFilter, setLifespanFilter] = useState<LifespanStatus | undefined>();\n const [searchQuery, setSearchQuery] = useState('');\n const [searchActive, setSearchActive] = useState(false);\n const [currentProject, setCurrentProject] = useState<string | undefined>();\n const [sortMode, setSortMode] = useState<SortMode>('importance');\n const [selectedIndex, setSelectedIndex] = useState(0);\n const [showHelp, setShowHelp] = useState(false);\n const [showProjectPicker, setShowProjectPicker] = useState(false);\n const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);\n const [showPurgeConfirm, setShowPurgeConfirm] = useState(false);\n const [showExpand, setShowExpand] = useState(false);\n\n useEffect(() => {\n dataSource.refresh();\n setRevision((r) => r + 1);\n dataSource.startWatching(() => {\n dataSource.refresh();\n setRevision((r) => r + 1);\n });\n return () => dataSource.stopWatching();\n }, [dataSource]);\n\n const projects = useMemo(() => {\n void revision;\n return dataSource.getProjects();\n }, [dataSource, revision]);\n\n const filteredMemories = useMemo(() => {\n void revision;\n const raw = dataSource.getMemories({ type: typeFilter, project: currentProject });\n const withLife = lifespanFilter\n ? raw.filter((m) => computeLifespan(m).status === lifespanFilter)\n : raw;\n const withSearch = searchQuery\n ? withLife.filter((m) =>\n (m.title?.toLowerCase().includes(searchQuery.toLowerCase()) ?? false) ||\n m.content.toLowerCase().includes(searchQuery.toLowerCase()) ||\n m.tags.some((t) => t.toLowerCase().includes(searchQuery.toLowerCase()))\n )\n : withLife;\n return sortMemories(withSearch, sortMode);\n }, [dataSource, revision, typeFilter, lifespanFilter, searchQuery, currentProject, sortMode]);\n\n // Clamp: narrowing filters/search must never strand the selection past the\n // end of the list (blank detail pane until a nav key was pressed).\n const clampedIndex = Math.max(0, Math.min(selectedIndex, Math.max(0, filteredMemories.length - 1)));\n const selectedMemory = filteredMemories[clampedIndex];\n const relations = useMemo(\n () => selectedMemory ? dataSource.getRelationsForMemory(selectedMemory.id) : [],\n [dataSource, selectedMemory, revision],\n );\n const stats = useMemo(() => { void revision; return dataSource.getStats(); }, [dataSource, revision]);\n\n // Reconcile the raw index against the CURRENT list before stepping —\n // otherwise k burns presses walking a stale out-of-range index down, and\n // j on an empty list drives it negative.\n const navigateUp = useCallback(() => {\n const last = filteredMemories.length - 1;\n setSelectedIndex((i) => Math.max(0, Math.min(i, last) - 1));\n }, [filteredMemories.length]);\n const navigateDown = useCallback(() => {\n const last = filteredMemories.length - 1;\n setSelectedIndex((i) => Math.max(0, Math.min(last, Math.min(i, last) + 1)));\n }, [filteredMemories.length]);\n\n const cycleSort = useCallback(() => {\n setSortMode((m) => SORT_MODES[(SORT_MODES.indexOf(m) + 1) % SORT_MODES.length]!);\n }, []);\n const cycleLifespan = useCallback(() => {\n setLifespanFilter((f) => {\n const idx = LIFESPAN_FILTERS.findIndex((x) => x === f);\n return LIFESPAN_FILTERS[(idx + 1) % LIFESPAN_FILTERS.length];\n });\n }, []);\n const cycleProjectNext = useCallback(() => {\n setCurrentProject((curr) => {\n const idx = curr ? projects.indexOf(curr) : -1;\n return idx >= projects.length - 1 ? undefined : projects[idx + 1];\n });\n setSelectedIndex(0);\n }, [projects]);\n const cycleProjectPrev = useCallback(() => {\n setCurrentProject((curr) => {\n const idx = curr ? projects.indexOf(curr) : -1;\n return idx <= 0 ? (idx === 0 ? undefined : projects[projects.length - 1]) : projects[idx - 1];\n });\n setSelectedIndex(0);\n }, [projects]);\n const filterByType = useCallback((type: MemoryType | undefined) => {\n setTypeFilter(type);\n setSelectedIndex(0);\n }, []);\n const openSearch = useCallback(() => setSearchActive(true), []);\n // Enter: keep the filter, hand the keyboard back to the list (find-then-act).\n const submitSearch = useCallback(() => {\n setSearchActive(false);\n setSelectedIndex(0);\n }, []);\n // Esc: cancel — drop the filter entirely.\n const closeSearch = useCallback(() => {\n setSearchActive(false);\n setSearchQuery('');\n setSelectedIndex(0);\n }, []);\n const promptDelete = useCallback(() => {\n if (selectedMemory) setShowDeleteConfirm(true);\n }, [selectedMemory]);\n const confirmDelete = useCallback(() => {\n if (!selectedMemory) return;\n dataSource.deleteMemory(selectedMemory.id);\n setShowDeleteConfirm(false);\n setSelectedIndex((i) => Math.max(0, i - 1));\n dataSource.refresh();\n setRevision((r) => r + 1);\n }, [dataSource, selectedMemory]);\n const cancelDelete = useCallback(() => setShowDeleteConfirm(false), []);\n const promptPurge = useCallback(() => {\n if (currentProject) setShowPurgeConfirm(true);\n }, [currentProject]);\n const confirmPurge = useCallback(() => {\n if (!currentProject) return;\n dataSource.purgeProject(currentProject);\n setShowPurgeConfirm(false);\n setCurrentProject(undefined);\n setSelectedIndex(0);\n dataSource.refresh();\n setRevision((r) => r + 1);\n }, [dataSource, currentProject]);\n const cancelPurge = useCallback(() => setShowPurgeConfirm(false), []);\n const expandMemory = useCallback(() => {\n if (selectedMemory) setShowExpand(true);\n }, [selectedMemory]);\n const closeExpand = useCallback(() => setShowExpand(false), []);\n\n return {\n typeFilter, lifespanFilter, searchQuery, searchActive, currentProject,\n sortMode, showHelp, showProjectPicker, showDeleteConfirm, showPurgeConfirm, showExpand,\n filteredMemories, selectedMemory, relations, projects, stats,\n selectedIndex: clampedIndex,\n setSearchQuery, setCurrentProject, setSelectedIndex, setShowHelp, setShowProjectPicker,\n navigateUp, navigateDown, cycleSort, cycleLifespan,\n cycleProjectNext, cycleProjectPrev, filterByType,\n openSearch, submitSearch, closeSearch, promptDelete, confirmDelete, cancelDelete,\n promptPurge, confirmPurge, cancelPurge, expandMemory, closeExpand,\n };\n}\n\nfunction sortMemories(memories: readonly Memory[], mode: SortMode): readonly Memory[] {\n const sorted = [...memories];\n const sorters: Record<SortMode, (a: Memory, b: Memory) => number> = {\n importance: (a, b) => b.importance - a.importance,\n age: (a, b) => b.createdAt.localeCompare(a.createdAt),\n access: (a, b) => b.accessCount - a.accessCount,\n lifespan: (a, b) => computeLifespan(a).remaining - computeLifespan(b).remaining,\n };\n sorted.sort(sorters[mode]);\n return sorted;\n}\n","import type { Memory, MemoryType } from \"../../types.js\";\nimport { DEFAULT_DECAY_PARAMS } from \"../../config.js\";\n\n// -- Relative Time ------------------------------------------------------------\n\nconst MINUTE = 60_000;\nconst HOUR = 3_600_000;\nconst DAY = 86_400_000;\nconst MONTH = 30 * DAY;\nconst YEAR = 365 * DAY;\n\nexport function formatRelativeTime(isoString: string): string {\n const diff = Date.now() - new Date(isoString).getTime();\n\n if (diff < 0) return \"just now\";\n if (diff < MINUTE) return \"just now\";\n if (diff < HOUR) return `${Math.floor(diff / MINUTE)}m ago`;\n if (diff < DAY) return `${Math.floor(diff / HOUR)}h ago`;\n if (diff < MONTH) return `${Math.floor(diff / DAY)}d ago`;\n if (diff < YEAR) return `${Math.floor(diff / MONTH)}mo ago`;\n return `${Math.floor(diff / YEAR)}y ago`;\n}\n\n// -- Importance Bar -----------------------------------------------------------\n\nconst FILLED = \"\\u2588\"; // full block\nconst EMPTY = \"\\u2591\"; // light shade\n\nexport function formatImportanceBar(\n value: number,\n width: number = 8,\n): string {\n const clamped = Math.max(0, Math.min(1, value));\n const filled = Math.round(clamped * width);\n return FILLED.repeat(filled) + EMPTY.repeat(width - filled);\n}\n\n// -- Truncation ---------------------------------------------------------------\n\nexport function truncate(text: string, maxLen: number): string {\n if (text.length <= maxLen) return text;\n if (maxLen <= 1) return \"\\u2026\";\n return text.slice(0, maxLen - 1) + \"\\u2026\";\n}\n\n// -- Byte Formatting ----------------------------------------------------------\n\nconst UNITS = [\"B\", \"KB\", \"MB\", \"GB\"] as const;\n\nexport function formatBytes(bytes: number): string {\n if (bytes < 0) return \"0B\";\n let value = bytes;\n let unitIndex = 0;\n while (value >= 1024 && unitIndex < UNITS.length - 1) {\n value /= 1024;\n unitIndex++;\n }\n if (unitIndex === 0) return `${value}B`;\n return `${value.toFixed(1)}${UNITS[unitIndex]}`;\n}\n\n// -- Lifespan Helpers ---------------------------------------------------------\n\nexport type LifespanStatus = \"healthy\" | \"fading\" | \"stale\" | \"session\";\n\nexport interface LifespanInfo {\n readonly status: LifespanStatus;\n readonly tauDays: number;\n readonly ageDays: number;\n readonly remaining: number;\n}\n\nexport function tauDaysForType(type: MemoryType): number {\n return DEFAULT_DECAY_PARAMS.tauByType[type];\n}\n\nexport function computeLifespan(memory: Memory): LifespanInfo {\n const tauDays = tauDaysForType(memory.type);\n if (tauDays === 0) {\n return {\n status: \"session\",\n tauDays,\n ageDays: 0,\n remaining: 0,\n };\n }\n\n const ageDays = Math.max(\n 0,\n (Date.now() - new Date(memory.createdAt).getTime()) / DAY,\n );\n const remaining = Math.max(0, Math.min(1, 1 - ageDays / (tauDays * 2)));\n const status: LifespanStatus =\n remaining > 0.62 ? \"healthy\" : remaining > 0.32 ? \"fading\" : \"stale\";\n return { status, tauDays, ageDays, remaining };\n}\n\nexport function formatLifespanLabel(status: LifespanStatus): string {\n switch (status) {\n case \"healthy\":\n return \"HEALTHY\";\n case \"fading\":\n return \"FADING \";\n case \"stale\":\n return \"STALE \";\n case \"session\":\n return \"SESSION\";\n }\n}\n","import { useInput } from 'ink';\nimport type { MemoryType } from '../../types.js';\n\nconst TYPE_KEYS: Record<string, MemoryType> = {\n '1': 'working',\n '2': 'episodic',\n '3': 'semantic',\n '4': 'procedural',\n '5': 'pattern',\n};\n\nexport interface KeybindingActions {\n readonly navigateUp: () => void;\n readonly navigateDown: () => void;\n readonly openSearch: () => void;\n readonly closeSearch: () => void;\n readonly filterByType: (type: MemoryType | undefined) => void;\n readonly cycleLifespan: () => void;\n readonly cycleProjectNext: () => void;\n readonly cycleProjectPrev: () => void;\n readonly cycleSort: () => void;\n readonly openProjectPicker: () => void;\n readonly showHelp: () => void;\n readonly removeMemory: () => void;\n readonly purgeProject: () => void;\n readonly expandMemory: () => void;\n readonly quit: () => void;\n}\n\nexport function useKeybindings(\n actions: KeybindingActions,\n opts: { searchActive: boolean; pickerOpen: boolean; expandOpen: boolean; modalOpen: boolean },\n): void {\n useInput((input, key) => {\n // Confirm dialogs and help own the keyboard exclusively — global keys must\n // not retarget a live delete, stack confirms, or quit mid-dialog.\n if (opts.modalOpen) return;\n if (opts.expandOpen) return;\n if (opts.searchActive) {\n if (key.escape) actions.closeSearch();\n return;\n }\n if (opts.pickerOpen) {\n if (key.escape) actions.openProjectPicker(); // toggle off\n return;\n }\n\n if (input === 'j' || key.downArrow) actions.navigateDown();\n if (input === 'k' || key.upArrow) actions.navigateUp();\n if (input === '/') actions.openSearch();\n if (key.escape) actions.closeSearch();\n if (input === '0') actions.filterByType(undefined);\n if (input in TYPE_KEYS) actions.filterByType(TYPE_KEYS[input]!);\n if (input === 'l') actions.cycleLifespan();\n if (input === 's') actions.cycleSort();\n if (input === 'p') actions.openProjectPicker();\n if (input === ']' || key.rightArrow) actions.cycleProjectNext();\n if (input === '[' || key.leftArrow) actions.cycleProjectPrev();\n // d = delete the selected memory (TUI convention); X = purge the whole\n // project. The old mapping put project-nuking one key from item-delete.\n if (input === 'r' || input === 'd') actions.removeMemory();\n if (input === 'X') actions.purgeProject();\n if (input === '?') actions.showHelp();\n if (key.return) actions.expandMemory();\n if (input === 'q') actions.quit();\n });\n}\n","import { useStdout } from 'ink';\nimport { useState, useEffect } from 'react';\n\nexport interface TerminalSize {\n readonly columns: number;\n readonly rows: number;\n}\n\nexport type LayoutMode = 'wide' | 'medium' | 'narrow';\n\nexport function useTerminalSize(): TerminalSize & { layout: LayoutMode } {\n const { stdout } = useStdout();\n const [size, setSize] = useState<TerminalSize>({\n columns: stdout.columns ?? 80,\n rows: stdout.rows ?? 24,\n });\n\n useEffect(() => {\n const handler = () => setSize({ columns: stdout.columns, rows: stdout.rows });\n stdout.on('resize', handler);\n return () => { stdout.off('resize', handler); };\n }, [stdout]);\n\n const layout: LayoutMode =\n size.columns >= 120 ? 'wide' :\n size.columns >= 80 ? 'medium' : 'narrow';\n\n return { ...size, layout };\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nconst HINTS = [\n ['j/k', 'navigate'],\n ['Enter', 'expand'],\n ['/', 'search'],\n ['p', 'projects'],\n ['1-5', 'type'],\n ['l', 'life'],\n ['s', 'sort'],\n ['d', 'delete'],\n ['X', 'purge project'],\n ['?', 'help'],\n ['q', 'quit'],\n] as const;\n\nexport function KeybindingBar(): React.ReactNode {\n return (\n <Box>\n {HINTS.map(([key, label], i) => (\n <React.Fragment key={key}>\n {i > 0 && <Text dimColor> </Text>}\n <Text color=\"cyan\">{key}</Text>\n <Text dimColor> {label}</Text>\n </React.Fragment>\n ))}\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\nimport type { MemoryType } from '../../types.js';\nimport type { LifespanStatus } from '../data/formatters.js';\nimport type { SortMode } from '../hooks/use-dashboard-state.js';\nimport type { LayoutMode } from '../hooks/use-terminal-size.js';\n\ninterface HeaderProps {\n readonly project?: string;\n readonly typeFilter?: MemoryType;\n readonly lifespanFilter?: LifespanStatus;\n readonly sortMode: SortMode;\n readonly searchQuery: string;\n readonly layout: LayoutMode;\n}\n\nexport function Header({ project, typeFilter, lifespanFilter, sortMode, searchQuery, layout }: HeaderProps): React.ReactNode {\n const sep = <Text dimColor> | </Text>;\n\n return (\n <Box overflow=\"hidden\">\n <Text bold color=\"green\"> agentic-memory </Text>\n {sep}\n <Text color=\"white\">{project ?? 'all projects'}</Text>\n {layout !== 'narrow' && (\n <>\n {sep}\n <Text dimColor>{typeFilter ?? 'all types'}</Text>\n {sep}\n <Text dimColor>{lifespanFilter ?? 'all life'}</Text>\n </>\n )}\n {layout === 'wide' && (\n <>\n {sep}\n <Text dimColor>sort:{sortMode}</Text>\n </>\n )}\n {searchQuery && (\n <>\n {sep}\n <Text color=\"yellow\">/{searchQuery}</Text>\n </>\n )}\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\nimport TextInput from 'ink-text-input';\n\ninterface SearchBarProps {\n readonly query: string;\n readonly onChange: (value: string) => void;\n readonly onSubmit: () => void;\n}\n\nexport function SearchBar({ query, onChange, onSubmit }: SearchBarProps): React.ReactNode {\n return (\n <Box>\n <Text color=\"yellow\">Search: </Text>\n <TextInput value={query} onChange={onChange} onSubmit={onSubmit} />\n <Text dimColor> (Enter apply · Esc cancel)</Text>\n </Box>\n );\n}\n","import React, { useMemo } from 'react';\nimport { Box, Text } from 'ink';\nimport type { Memory } from '../../types.js';\nimport { truncate, formatRelativeTime, computeLifespan, formatLifespanLabel } from '../data/formatters.js';\nimport { TYPE_ABBREV } from '../colors.js';\n\ninterface MemoryListProps {\n readonly memories: readonly Memory[];\n readonly selectedIndex: number;\n readonly isFocused: boolean;\n readonly height: number;\n}\n\ntype LifeColor = 'green' | 'yellow' | 'red' | 'magenta';\n\nconst LIFE_COLORS: Record<string, LifeColor> = {\n healthy: 'green',\n fading: 'yellow',\n stale: 'red',\n session: 'magenta',\n};\n\nexport function MemoryList({ memories, selectedIndex, isFocused, height }: MemoryListProps): React.ReactNode {\n // Reserve 2 rows for top+bottom borders and 1 for the title — visible rows are what's left.\n const viewportHeight = Math.max(1, height - 3);\n\n const scrollOffset = useMemo(() => {\n if (selectedIndex < 0) return 0;\n if (memories.length <= viewportHeight) return 0;\n const half = Math.floor(viewportHeight / 2);\n const offset = Math.max(0, selectedIndex - half);\n return Math.min(offset, memories.length - viewportHeight);\n }, [selectedIndex, memories.length, viewportHeight]);\n\n const visible = memories.slice(scrollOffset, scrollOffset + viewportHeight);\n const label = ` Memories [${memories.length}] `;\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={isFocused ? 'cyan' : 'gray'}\n height={height}\n >\n <Text bold color={isFocused ? 'cyan' : 'gray'}>{label}</Text>\n {visible.length === 0 && <Text dimColor> No memories found</Text>}\n {visible.map((m, i) => {\n const isSelected = scrollOffset + i === selectedIndex;\n return <MemoryRow key={m.id} memory={m} isSelected={isSelected} />;\n })}\n </Box>\n );\n}\n\nfunction MemoryRow({ memory, isSelected }: { memory: Memory; isSelected: boolean }): React.ReactNode {\n const life = computeLifespan(memory);\n const title = truncate(memory.title ?? memory.content.replace(/\\n/g, ' '), 36);\n const project = truncate(memory.project ?? '', 14);\n const type = TYPE_ABBREV[memory.type] ?? memory.type;\n const lifeColor = LIFE_COLORS[life.status] ?? 'white';\n const lifeLabel = formatLifespanLabel(life.status).trim();\n const imp = `${Math.round(memory.importance * 100)}%`;\n const updated = formatRelativeTime(memory.updatedAt);\n\n return (\n <Box>\n <Text inverse={isSelected}>\n <Text bold>{isSelected ? '▸ ' : ' '}</Text>\n <Text bold>{title.padEnd(38)}</Text>\n <Text dimColor>{project.padEnd(16)}</Text>\n <Text color=\"cyan\">{type} </Text>\n <Text color={lifeColor}>{lifeLabel.padEnd(8)}</Text>\n <Text>{imp.padStart(4)} </Text>\n <Text dimColor>{updated.padEnd(8)}</Text>\n <Text color=\"blue\">acc:{memory.accessCount}</Text>\n </Text>\n </Box>\n );\n}\n","import type { MemoryType, RelationType } from \"../types.js\";\n\n// -- Type Colors (blessed-compatible color names) -----------------------------\n\nexport const TYPE_COLORS: Record<MemoryType, string> = {\n working: \"red\",\n episodic: \"yellow\",\n semantic: \"cyan\",\n procedural: \"green\",\n pattern: \"magenta\",\n};\n\n// -- Type Abbreviations (4-char max) ------------------------------------------\n\nexport const TYPE_ABBREV: Record<MemoryType, string> = {\n working: \"WORK\",\n episodic: \"EPIS\",\n semantic: \"SEMA\",\n procedural: \"PROC\",\n pattern: \"PTRN\",\n};\n\n// -- Relation Colors ----------------------------------------------------------\n\nexport const RELATION_COLORS: Record<RelationType, string> = {\n relates_to: \"white\",\n depends_on: \"blue\",\n contradicts: \"red\",\n extends: \"green\",\n implements: \"cyan\",\n derived_from: \"yellow\",\n};\n","import React from 'react';\nimport { Box, Text } from 'ink';\nimport type { Memory, Relation } from '../../types.js';\nimport {\n formatImportanceBar,\n formatRelativeTime,\n computeLifespan,\n formatLifespanLabel,\n} from '../data/formatters.js';\nimport { TYPE_COLORS, RELATION_COLORS } from '../colors.js';\nimport { wrapContent } from '../data/wrap.js';\n\nconst METADATA_ROWS = 18;\nconst BORDER_ROWS = 2;\nconst MIN_CONTENT_ROWS = 2;\n\ninterface MemoryDetailProps {\n readonly memory?: Memory;\n readonly relations: readonly Relation[];\n readonly isFocused: boolean;\n readonly height: number;\n readonly width: number;\n readonly resolveTitle?: (id: string) => string | undefined;\n}\n\nexport function MemoryDetail({ memory, relations, isFocused, height, width, resolveTitle }: MemoryDetailProps): React.ReactNode {\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={isFocused ? 'blue' : 'gray'}\n paddingX={1}\n height={height}\n >\n <Text bold color={isFocused ? 'blue' : 'gray'}> Detail </Text>\n {!memory ? (\n <Text dimColor>Select a memory to view details</Text>\n ) : (\n <DetailContent resolveTitle={resolveTitle} memory={memory} relations={relations} height={height} width={width} />\n )}\n </Box>\n );\n}\n\ninterface DetailContentProps {\n readonly memory: Memory;\n readonly relations: readonly Relation[];\n readonly height: number;\n readonly width: number;\n readonly resolveTitle?: (id: string) => string | undefined;\n}\n\nfunction DetailContent({ memory, relations, height, width, resolveTitle }: DetailContentProps): React.ReactNode {\n const life = computeLifespan(memory);\n const typeColor = TYPE_COLORS[memory.type] ?? 'white';\n const relationRows = relations.length > 0 ? relations.length + 2 : 0;\n const contentRows = Math.max(MIN_CONTENT_ROWS, height - METADATA_ROWS - BORDER_ROWS - relationRows);\n const contentWidth = Math.max(10, width - 4);\n const preview = truncateContent(memory.content, contentRows, contentWidth);\n\n return (\n <Box flexDirection=\"column\">\n <Text bold>{memory.title ?? '(untitled)'}</Text>\n <Text> </Text>\n <Text>Type: <Text color={typeColor}>{memory.type}</Text></Text>\n <Text>Lifespan: {formatLifespanLabel(life.status)} | age {Math.round(life.ageDays)}d | tau {life.tauDays}d</Text>\n <Text>Health: {formatImportanceBar(life.remaining)} {(life.remaining * 100).toFixed(0)}%</Text>\n <Text>Importance: {formatImportanceBar(memory.importance)} {memory.importance.toFixed(2)}</Text>\n <Text>Project: {memory.project ?? '(none)'}</Text>\n <Text>Tags: {memory.tags.length > 0 ? memory.tags.map((t) => `[${t}]`).join(' ') : '(none)'}</Text>\n <Text>Source: {memory.source ?? 'unknown'}</Text>\n <Text> </Text>\n <Text>Created: {formatRelativeTime(memory.createdAt)}</Text>\n <Text>Updated: {formatRelativeTime(memory.updatedAt)}</Text>\n <Text>Accessed: {memory.accessCount}x{memory.lastAccessed ? ` (last: ${formatRelativeTime(memory.lastAccessed)})` : ''}</Text>\n <Text>Injected: {memory.injectionCount}x</Text>\n <Text> </Text>\n <Text bold>Content</Text>\n <Text dimColor>{'─'.repeat(Math.min(contentWidth, 40))}</Text>\n {preview.lines.map((line, i) => (\n <Text key={`line-${i}`}>{line === '' ? ' ' : line}</Text>\n ))}\n {preview.truncated && (\n <Text dimColor>… +{preview.remainingLines} line{preview.remainingLines === 1 ? '' : 's'} · press Enter to view full</Text>\n )}\n {relations.length > 0 && <RelationsList resolveTitle={resolveTitle} relations={relations} memoryId={memory.id} />}\n </Box>\n );\n}\n\ninterface ContentPreview {\n readonly lines: readonly string[];\n readonly truncated: boolean;\n readonly remainingLines: number;\n}\n\nfunction truncateContent(content: string, maxRows: number, wrapWidth: number): ContentPreview {\n const allLines = wrapContent(content, wrapWidth);\n if (allLines.length <= maxRows) {\n return { lines: allLines, truncated: false, remainingLines: 0 };\n }\n // Reserve one row for the \"... press Enter\" hint\n const visible = Math.max(1, maxRows - 1);\n return {\n lines: allLines.slice(0, visible),\n truncated: true,\n remainingLines: allLines.length - visible,\n };\n}\n\nfunction RelationsList({ relations, memoryId, resolveTitle }: { relations: readonly Relation[]; memoryId: string; resolveTitle?: (id: string) => string | undefined }): React.ReactNode {\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n <Text bold>Relations</Text>\n <Text dimColor>{'─'.repeat(40)}</Text>\n {relations.map((r, i) => {\n const relColor = RELATION_COLORS[r.relationType] ?? 'white';\n const direction = r.sourceId === memoryId ? '→' : '←';\n const otherId = r.sourceId === memoryId ? r.targetId : r.sourceId;\n const label = resolveTitle?.(otherId) ?? otherId.slice(0, 8);\n return (\n <Text key={i}> {direction} <Text color={relColor}>{r.relationType}</Text> {label}</Text>\n );\n })}\n </Box>\n );\n}\n","/**\n * Split content into display lines, wrapping long lines at the given width.\n * Preserves empty lines.\n */\nexport function wrapContent(content: string, width: number): readonly string[] {\n if (width <= 0) return content.split('\\n');\n const out: string[] = [];\n for (const rawLine of content.split('\\n')) {\n if (rawLine.length === 0) {\n out.push('');\n continue;\n }\n for (let i = 0; i < rawLine.length; i += width) {\n out.push(rawLine.slice(i, i + width));\n }\n }\n return out;\n}\n","import React, { useMemo } from 'react';\nimport { Box, Text } from 'ink';\nimport type { Memory } from '../../types.js';\nimport { computeLifespan } from '../data/formatters.js';\n\ninterface ProjectListProps {\n readonly memories: readonly Memory[];\n readonly activeProject?: string;\n readonly isFocused: boolean;\n readonly height: number;\n}\n\ninterface ProjectRow {\n readonly project: string | undefined;\n readonly total: number;\n readonly healthPct: number;\n}\n\nexport function ProjectList({ memories, activeProject, isFocused, height }: ProjectListProps): React.ReactNode {\n const rows = useMemo(() => buildProjectRows(memories), [memories]);\n // Reserve rows for title + borders; leave one for \"+N more\" if truncated\n const visibleRows = Math.max(1, height - 3);\n const truncated = rows.length > visibleRows;\n const displayed = truncated ? rows.slice(0, visibleRows - 1) : rows;\n const hidden = rows.length - displayed.length;\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={isFocused ? 'magenta' : 'gray'}\n height={height}\n >\n <Text bold color={isFocused ? 'magenta' : 'gray'}> Projects </Text>\n {displayed.map((row) => {\n const isActive = row.project === activeProject || (row.project === undefined && !activeProject);\n const name = (row.project ?? 'All projects').padEnd(20).slice(0, 20);\n const healthColor = row.healthPct > 62 ? 'green' : row.healthPct > 32 ? 'yellow' : 'red';\n return (\n <Box key={row.project ?? '_all'}>\n <Text bold={isActive}>{isActive ? '> ' : ' '}</Text>\n <Text bold={isActive}>{name}</Text>\n <Text color=\"cyan\">{String(row.total).padStart(4)} mem</Text>\n <Text> </Text>\n <Text color={healthColor}>{String(row.healthPct).padStart(3)}%</Text>\n </Box>\n );\n })}\n {truncated && <Text dimColor> … +{hidden} more</Text>}\n </Box>\n );\n}\n\nfunction buildProjectRows(memories: readonly Memory[]): readonly ProjectRow[] {\n const byProject = new Map<string, Memory[]>();\n for (const m of memories) {\n const key = m.project ?? '(none)';\n const list = byProject.get(key) ?? [];\n list.push(m);\n byProject.set(key, list);\n }\n\n const rows: ProjectRow[] = [];\n for (const [project, mems] of byProject) {\n const avg = mems.reduce((s, m) => s + computeLifespan(m).remaining, 0) / mems.length;\n rows.push({ project, total: mems.length, healthPct: Math.round(avg * 100) });\n }\n rows.sort((a, b) => b.total - a.total);\n\n const allHealth = memories.length > 0\n ? Math.round((memories.reduce((s, m) => s + computeLifespan(m).remaining, 0) / memories.length) * 100)\n : 0;\n return [{ project: undefined, total: memories.length, healthPct: allHealth }, ...rows];\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\nimport type { DashboardStats } from '../data/data-source.js';\nimport type { Memory } from '../../types.js';\nimport { formatBytes, computeLifespan } from '../data/formatters.js';\nimport { TYPE_COLORS } from '../colors.js';\n\ninterface StatsBarProps {\n readonly stats: DashboardStats;\n readonly visible: readonly Memory[];\n}\n\nexport function StatsBar({ stats, visible }: StatsBarProps): React.ReactNode {\n const lifeCounts = { healthy: 0, fading: 0, stale: 0, session: 0 };\n for (const m of visible) {\n lifeCounts[computeLifespan(m).status]++;\n }\n\n const typeEntries = Object.entries(stats.byType).filter(([, c]) => c > 0);\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"single\" borderColor=\"gray\" paddingX={1}>\n <Box gap={2}>\n <Text><Text bold>Total:</Text> {stats.total}</Text>\n <Text><Text bold>Relations:</Text> {stats.relations}</Text>\n <Text><Text bold>Visible:</Text> {visible.length}</Text>\n <Text><Text bold>DB:</Text> {formatBytes(stats.dbSizeBytes)}</Text>\n </Box>\n <Box gap={2}>\n <Text>\n <Text color=\"green\">H:{lifeCounts.healthy}</Text>\n {' '}<Text color=\"yellow\">F:{lifeCounts.fading}</Text>\n {' '}<Text color=\"red\">S:{lifeCounts.stale}</Text>\n {' '}<Text color=\"magenta\">Sess:{lifeCounts.session}</Text>\n </Text>\n {typeEntries.map(([type, count]) => (\n <Text key={type} color={TYPE_COLORS[type as keyof typeof TYPE_COLORS] ?? 'white'}>\n {type}:{count}\n </Text>\n ))}\n </Box>\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text, useInput } from 'ink';\n\ninterface HelpOverlayProps {\n readonly onClose: () => void;\n}\n\nconst BINDINGS = [\n ['j / k / ↑↓', 'Navigate list'],\n ['Enter', 'Expand memory (full content + scroll)'],\n ['/', 'Search (live filter)'],\n ['Esc', 'Clear search'],\n ['1-5', 'Filter by type (0 = all)'],\n ['l', 'Cycle lifespan filter'],\n ['s', 'Cycle sort mode'],\n ['p', 'Open project picker'],\n ['[ / ]', 'Previous / next project'],\n ['d / r', 'Delete selected memory'],\n ['X', 'Purge all memories for current project'],\n ['?', 'Show this help'],\n ['q', 'Quit'],\n] as const;\n\nexport function HelpOverlay({ onClose }: HelpOverlayProps): React.ReactNode {\n useInput(() => onClose());\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"double\"\n borderColor=\"yellow\"\n paddingX={2}\n paddingY={1}\n >\n <Text bold color=\"yellow\">Keybindings</Text>\n <Text> </Text>\n {BINDINGS.map(([key, desc]) => (\n <Box key={key} gap={1}>\n <Text color=\"cyan\">{key.padEnd(14)}</Text>\n <Text>{desc}</Text>\n </Box>\n ))}\n <Text> </Text>\n <Text dimColor>Press any key to close</Text>\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text, useInput } from 'ink';\n\ninterface ProjectPickerProps {\n readonly projects: readonly string[];\n readonly activeProject?: string;\n readonly onSelect: (project: string | undefined) => void;\n readonly onClose: () => void;\n}\n\nexport function ProjectPicker({ projects, activeProject, onSelect, onClose }: ProjectPickerProps): React.ReactNode {\n const [selectedIdx, setSelectedIdx] = React.useState(() => {\n if (!activeProject) return 0;\n const idx = projects.indexOf(activeProject);\n return idx >= 0 ? idx + 1 : 0;\n });\n\n const options = [\n { label: 'All projects', project: undefined as string | undefined },\n ...projects.map((p) => ({ label: p, project: p as string | undefined })),\n ];\n\n useInput((input, key) => {\n if (key.escape) { onClose(); return; }\n if (input === 'j' || key.downArrow) setSelectedIdx((i) => Math.min(options.length - 1, i + 1));\n if (input === 'k' || key.upArrow) setSelectedIdx((i) => Math.max(0, i - 1));\n if (key.return) {\n onSelect(options[selectedIdx]?.project);\n onClose();\n }\n });\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"double\" borderColor=\"yellow\" paddingX={2} paddingY={1}>\n <Text bold color=\"yellow\">Project Picker</Text>\n <Text dimColor>Enter=select Esc=close</Text>\n <Text> </Text>\n {options.map((opt, i) => {\n const isSelected = i === selectedIdx;\n const isActive = opt.project === activeProject || (opt.project === undefined && !activeProject);\n return (\n <Text key={opt.label} inverse={isSelected}>\n {isActive ? '> ' : ' '}{opt.label}\n </Text>\n );\n })}\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport type { Memory } from '../../types.js';\n\ninterface DeleteConfirmProps {\n readonly memory: Memory;\n readonly onConfirm: () => void;\n readonly onCancel: () => void;\n}\n\nexport function DeleteConfirm({ memory, onConfirm, onCancel }: DeleteConfirmProps): React.ReactNode {\n useInput((input, key) => {\n if (input === 'y' || input === 'Y') onConfirm();\n if (input === 'n' || input === 'N' || key.escape) onCancel();\n });\n\n const title = memory.title ?? memory.content.slice(0, 40);\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"double\" borderColor=\"red\" paddingX={2} paddingY={1}>\n <Text bold color=\"red\">Delete memory?</Text>\n <Text> </Text>\n <Text bold>{title}</Text>\n <Text dimColor>[{memory.type}] {memory.project ?? '(no project)'}</Text>\n <Text> </Text>\n <Text>This is a permanent hard delete. The memory cannot be recovered.</Text>\n <Text> </Text>\n <Text><Text color=\"green\" bold>y</Text> confirm <Text color=\"red\" bold>n/Esc</Text> cancel</Text>\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text, useInput } from 'ink';\n\ninterface PurgeConfirmProps {\n readonly project: string;\n readonly memoryCount: number;\n readonly onConfirm: () => void;\n readonly onCancel: () => void;\n}\n\nexport function PurgeConfirm({ project, memoryCount, onConfirm, onCancel }: PurgeConfirmProps): React.ReactNode {\n useInput((input, key) => {\n if (input === 'y' || input === 'Y') onConfirm();\n if (input === 'n' || input === 'N' || key.escape) onCancel();\n });\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"double\" borderColor=\"red\" paddingX={2} paddingY={1}>\n <Text bold color=\"red\">Delete all memories for project?</Text>\n <Text> </Text>\n <Text bold>{project}</Text>\n <Text dimColor>{memoryCount} memories will be permanently deleted.</Text>\n <Text> </Text>\n <Text>This cannot be undone.</Text>\n <Text> </Text>\n <Text><Text color=\"green\" bold>y</Text> confirm <Text color=\"red\" bold>n/Esc</Text> cancel</Text>\n </Box>\n );\n}\n","import React, { useState, useEffect } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport type { Memory, Relation } from '../../types.js';\nimport { useTerminalSize } from '../hooks/use-terminal-size.js';\nimport { TYPE_COLORS, RELATION_COLORS } from '../colors.js';\nimport { formatRelativeTime } from '../data/formatters.js';\nimport { wrapContent } from '../data/wrap.js';\n\ninterface ExpandMemoryProps {\n readonly memory: Memory;\n readonly relations: readonly Relation[];\n readonly onClose: () => void;\n readonly resolveTitle?: (id: string) => string | undefined;\n}\n\nexport function ExpandMemory({ memory, relations, onClose, resolveTitle }: ExpandMemoryProps): React.ReactNode {\n const { columns, rows } = useTerminalSize();\n const [scroll, setScroll] = useState(0);\n\n const contentWidth = Math.max(20, columns - 6);\n const chromeLines = 7 + (relations.length > 0 ? relations.length + 2 : 0);\n const viewportLines = Math.max(5, rows - chromeLines);\n\n const wrappedLines = wrapContent(memory.content, contentWidth);\n const totalLines = wrappedLines.length;\n const maxScroll = Math.max(0, totalLines - viewportLines);\n\n useEffect(() => { setScroll(0); }, [memory.id]);\n\n useInput((input, key) => {\n if (key.escape || input === 'q') { onClose(); return; }\n if (input === 'j' || key.downArrow) setScroll((s) => Math.min(maxScroll, s + 1));\n if (input === 'k' || key.upArrow) setScroll((s) => Math.max(0, s - 1));\n if (key.pageDown || input === ' ') setScroll((s) => Math.min(maxScroll, s + viewportLines));\n if (key.pageUp) setScroll((s) => Math.max(0, s - viewportLines));\n if (input === 'g') setScroll(0);\n if (input === 'G') setScroll(maxScroll);\n });\n\n const typeColor = TYPE_COLORS[memory.type] ?? 'white';\n const visible = wrappedLines.slice(scroll, scroll + viewportLines);\n const scrollInfo = totalLines > viewportLines\n ? ` [${scroll + 1}-${Math.min(totalLines, scroll + viewportLines)}/${totalLines}]`\n : ` [${totalLines} lines]`;\n const divider = '─'.repeat(Math.min(contentWidth, 80));\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"double\" borderColor=\"blue\" paddingX={1}>\n <Text bold>\n <Text color={typeColor}>[{memory.type}]</Text>{' '}\n {memory.title ?? '(untitled)'}\n </Text>\n <Text dimColor>\n id: {memory.id.slice(0, 8)} | project: {memory.project ?? '(none)'} | imp: {memory.importance.toFixed(2)} | updated: {formatRelativeTime(memory.updatedAt)}\n </Text>\n <Text dimColor>{divider}</Text>\n {visible.map((line, i) => (\n <Text key={`line-${scroll + i}`}>{line === '' ? ' ' : line}</Text>\n ))}\n {Array.from({ length: Math.max(0, viewportLines - visible.length) }).map((_, i) => (\n <Text key={`pad-${i}`}> </Text>\n ))}\n <Text dimColor>{divider}</Text>\n {relations.length > 0 && (\n <Box flexDirection=\"column\">\n <Text bold>Relations</Text>\n {relations.map((r, i) => {\n const relColor = RELATION_COLORS[r.relationType] ?? 'white';\n const direction = r.sourceId === memory.id ? '→' : '←';\n const otherId = r.sourceId === memory.id ? r.targetId : r.sourceId;\n const label = resolveTitle?.(otherId) ?? otherId.slice(0, 8);\n return <Text key={i}> {direction} <Text color={relColor}>{r.relationType}</Text> {label}</Text>;\n })}\n </Box>\n )}\n <Text dimColor>\n {totalLines > viewportLines ? 'j/k scroll · space/PgDn page · g/G top/bottom · ' : ''}q/Esc close{scrollInfo}\n </Text>\n </Box>\n );\n}\n\n","import React from \"react\";\nimport { Box, Text, useApp, useInput } from \"ink\";\n\nfunction CrashScreen({\n message,\n}: {\n readonly message: string;\n}): React.ReactNode {\n const { exit } = useApp();\n useInput((input) => {\n if (input === \"q\") exit();\n });\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor=\"red\"\n padding={1}\n >\n <Text bold color=\"red\">\n Dashboard crashed\n </Text>\n <Text>{message}</Text>\n <Text dimColor>Your data is untouched. Press q to quit.</Text>\n </Box>\n );\n}\n\ninterface Props {\n readonly children: React.ReactNode;\n}\ninterface State {\n readonly error: Error | null;\n}\n\n/**\n * One bad render must not unmount Ink mid-raw-mode and strand the terminal.\n * Ink restores the terminal on clean exit; this keeps the exit clean.\n */\nexport class DashboardErrorBoundary extends React.Component<Props, State> {\n override state: State = { error: null };\n\n static getDerivedStateFromError(error: Error): State {\n return { error };\n }\n\n override render(): React.ReactNode {\n if (this.state.error) {\n return <CrashScreen message={this.state.error.message} />;\n }\n return this.props.children;\n }\n}\n"],"mappings":"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","names":["Box","useState","useEffect","Box","Text","jsx","jsxs","Box","Text","jsx","jsxs","useMemo","Box","Text","jsx","jsxs","useMemo","Box","Text","Box","Text","jsx","jsxs","Box","Text","useMemo","Box","Text","jsx","jsxs","useMemo","Box","Text","Box","Text","jsx","jsxs","Box","Text","Box","Text","useInput","jsx","jsxs","React","Box","Text","useInput","jsx","jsxs","Box","Text","useInput","jsx","jsxs","Box","Text","useInput","jsx","jsxs","useState","useEffect","Box","Text","useInput","jsx","jsxs","useState","useEffect","useInput","Box","Text","jsx","jsxs","Box","React","Box","Text","useApp","useInput","jsx","jsxs","jsx"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-launchpad",
3
- "version": "1.15.0",
3
+ "version": "1.16.0",
4
4
  "description": "Score your Claude Code config, fix the gaps with hooks and permissions, prove Claude follows your rules with eval. Includes persistent memory for Claude Code with free cross-machine sync (GitHub Gist), ranked context injection, and benchmarks that measure whether memory actually helps.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -93,6 +93,7 @@
93
93
  "@types/react": "^19.2.14",
94
94
  "@types/shell-quote": "^1.7.5",
95
95
  "better-sqlite3": "^11.10.0",
96
+ "ink-testing-library": "^4.0.0",
96
97
  "sqlite-vec": "0.1.9",
97
98
  "tsup": "^8.5.1",
98
99
  "tsx": "^4.21.0",