claude-launchpad 1.2.3 → 1.4.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.
Files changed (47) hide show
  1. package/README.md +2 -2
  2. package/dist/{chunk-UJP5PJTA.js → chunk-ADZ45KHX.js} +3 -3
  3. package/dist/{chunk-V4NXT4KB.js → chunk-DXDOVWOA.js} +64 -8
  4. package/dist/chunk-DXDOVWOA.js.map +1 -0
  5. package/dist/{chunk-N6X3E5AX.js → chunk-F6SLV2FR.js} +24 -5
  6. package/dist/chunk-F6SLV2FR.js.map +1 -0
  7. package/dist/{chunk-AR64LWGW.js → chunk-RJEPJ4JE.js} +25 -4
  8. package/dist/chunk-RJEPJ4JE.js.map +1 -0
  9. package/dist/{chunk-YXPJDIMK.js → chunk-UQOBOHKN.js} +33 -2
  10. package/dist/chunk-UQOBOHKN.js.map +1 -0
  11. package/dist/{chunk-J765H3HZ.js → chunk-WOC2PKT2.js} +2 -2
  12. package/dist/{chunk-F5PNKQKW.js → chunk-YZ53W47Z.js} +7 -2
  13. package/dist/chunk-YZ53W47Z.js.map +1 -0
  14. package/dist/cli.js +25 -14
  15. package/dist/cli.js.map +1 -1
  16. package/dist/commands/memory/server.js +12 -13
  17. package/dist/commands/memory/server.js.map +1 -1
  18. package/dist/{context-VAXF3EW3.js → context-NCV46PTY.js} +6 -6
  19. package/dist/{install-M3JWBGMK.js → install-DORMJYCU.js} +6 -6
  20. package/dist/install-DORMJYCU.js.map +1 -0
  21. package/dist/{pull-RKFE5ZXV.js → pull-UYLUGILU.js} +45 -20
  22. package/dist/pull-UYLUGILU.js.map +1 -0
  23. package/dist/{push-5ZJNWAE7.js → push-HWXJGSTL.js} +40 -17
  24. package/dist/push-HWXJGSTL.js.map +1 -0
  25. package/dist/{require-deps-QW2IU6I3.js → require-deps-RUXTMQUV.js} +3 -3
  26. package/dist/{stats-NPXPJNBO.js → stats-DFV24AJW.js} +7 -7
  27. package/dist/{sync-clean-JQLVE4WU.js → sync-clean-GFX5F55E.js} +2 -2
  28. package/dist/{sync-status-IYG7ZYC5.js → sync-status-VXMDWDRG.js} +9 -9
  29. package/dist/{tui-56GQMXXT.js → tui-ELOJ37ZA.js} +208 -40
  30. package/dist/tui-ELOJ37ZA.js.map +1 -0
  31. package/package.json +1 -1
  32. package/dist/chunk-AR64LWGW.js.map +0 -1
  33. package/dist/chunk-F5PNKQKW.js.map +0 -1
  34. package/dist/chunk-N6X3E5AX.js.map +0 -1
  35. package/dist/chunk-V4NXT4KB.js.map +0 -1
  36. package/dist/chunk-YXPJDIMK.js.map +0 -1
  37. package/dist/install-M3JWBGMK.js.map +0 -1
  38. package/dist/pull-RKFE5ZXV.js.map +0 -1
  39. package/dist/push-5ZJNWAE7.js.map +0 -1
  40. package/dist/tui-56GQMXXT.js.map +0 -1
  41. /package/dist/{chunk-UJP5PJTA.js.map → chunk-ADZ45KHX.js.map} +0 -0
  42. /package/dist/{chunk-J765H3HZ.js.map → chunk-WOC2PKT2.js.map} +0 -0
  43. /package/dist/{context-VAXF3EW3.js.map → context-NCV46PTY.js.map} +0 -0
  44. /package/dist/{require-deps-QW2IU6I3.js.map → require-deps-RUXTMQUV.js.map} +0 -0
  45. /package/dist/{stats-NPXPJNBO.js.map → stats-DFV24AJW.js.map} +0 -0
  46. /package/dist/{sync-clean-JQLVE4WU.js.map → sync-clean-GFX5F55E.js.map} +0 -0
  47. /package/dist/{sync-status-IYG7ZYC5.js.map → sync-status-VXMDWDRG.js.map} +0 -0
@@ -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"],"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';\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 <App dataSource={dataSource} />,\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 /** Get all relations for a specific memory. */\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 focusNext: state.focusNext,\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 });\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 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 onClose={() => state.setSearchQuery(state.searchQuery)}\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={state.focusedPane === 'list'}\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={state.focusedPane === 'projects'}\n height={projectListHeight}\n />\n )}\n <MemoryDetail\n memory={state.selectedMemory}\n relations={state.relations}\n isFocused={state.focusedPane === 'detail'}\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';\nexport type FocusedPane = 'list' | 'projects' | 'detail';\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 [focusedPane, setFocusedPane] = useState<FocusedPane>('list');\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 const selectedMemory = filteredMemories[selectedIndex];\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 const navigateUp = useCallback(() => {\n setSelectedIndex((i) => Math.max(0, i - 1));\n }, []);\n const navigateDown = useCallback(() => {\n setSelectedIndex((i) => Math.min(filteredMemories.length - 1, i + 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 focusNext = useCallback(() => {\n setFocusedPane((p) => p === 'list' ? 'projects' : p === 'projects' ? 'detail' : 'list');\n }, []);\n const filterByType = useCallback((type: MemoryType | undefined) => {\n setTypeFilter(type);\n setSelectedIndex(0);\n }, []);\n const openSearch = useCallback(() => setSearchActive(true), []);\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, selectedIndex, focusedPane, showHelp, showProjectPicker, showDeleteConfirm, showPurgeConfirm, showExpand,\n filteredMemories, selectedMemory, relations, projects, stats,\n setSearchQuery, setCurrentProject, setSelectedIndex, setShowHelp, setShowProjectPicker,\n navigateUp, navigateDown, cycleSort, cycleLifespan,\n cycleProjectNext, cycleProjectPrev, focusNext, filterByType,\n openSearch, 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 focusNext: () => 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 },\n): void {\n useInput((input, key) => {\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 if (key.tab) actions.focusNext();\n if (input === 'r') actions.removeMemory();\n if (input === 'd') 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 ['r', 'remove'],\n ['d', 'delete project'],\n ['Tab', 'focus'],\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 onClose: () => void;\n}\n\nexport function SearchBar({ query, onChange, onClose }: SearchBarProps): React.ReactNode {\n return (\n <Box>\n <Text color=\"yellow\">Search: </Text>\n <TextInput value={query} onChange={onChange} onSubmit={onClose} />\n <Text dimColor> (Esc to clear, Enter to keep)</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}\n\nexport function MemoryDetail({ memory, relations, isFocused, height, width }: 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 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}\n\nfunction DetailContent({ memory, relations, height, width }: 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 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 }: { relations: readonly Relation[]; memoryId: string }): 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 return (\n <Text key={i}> {direction} <Text color={relColor}>{r.relationType}</Text> {otherId}</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 ['r', 'Remove selected memory'],\n ['d', 'Delete all memories for current project'],\n ['Tab', 'Focus next pane'],\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}\n\nexport function ExpandMemory({ memory, relations, onClose }: 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 return <Text key={i}> {direction} <Text color={relColor}>{r.relationType}</Text> {otherId}</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"],"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","jsx"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-launchpad",
3
- "version": "1.2.3",
3
+ "version": "1.4.0",
4
4
  "description": "CLI toolkit for Claude Code — scaffold CLAUDE.md, diagnose config, enforce hooks, test with eval, add persistent memory",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/memory/config.ts","../src/commands/memory/storage/database.ts","../src/commands/memory/storage/migrations/001-initial.ts","../src/commands/memory/storage/migrations/002-add-project.ts","../src/commands/memory/storage/migrations/003-add-content-hash.ts","../src/commands/memory/storage/migrator.ts"],"sourcesContent":["import { z } from 'zod';\nimport { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { DecayParams } from './types.js';\n\n// ── Config Schema ─────────────────────────────────────────────\n\nconst ConfigSchema = z.object({\n dataDir: z.string().default('~/.agentic-memory'),\n injectionBudget: z.number().int().min(100).max(20000).default(3000),\n consolidationInterval: z.number().int().min(1).default(10),\n enableReranker: z.boolean().default(true),\n logLevel: z.enum(['debug', 'info', 'warn', 'error']).default('warn'),\n});\n\nexport type Config = z.infer<typeof ConfigSchema>;\n\n// ── Defaults ──────────────────────────────────────────────────\n\nexport const DEFAULT_CONFIG: Config = {\n dataDir: '~/.agentic-memory',\n injectionBudget: 3000,\n consolidationInterval: 10,\n enableReranker: true,\n logLevel: 'warn',\n};\n\nexport const DEFAULT_DECAY_PARAMS: DecayParams = {\n tauByType: {\n working: 0, // cleared each session, tau irrelevant\n episodic: 30, // fast decay (was 60, cognitive science: unrehearsed episodes fade in ~30d)\n semantic: 540, // slow decay (was 365, extracted facts are stable for years)\n procedural: 730, // near-permanent\n pattern: 180, // medium decay\n },\n accessModifiers: [\n { maxCount: 3, multiplier: 1.0 },\n { maxCount: 10, multiplier: 2.0 },\n { maxCount: Infinity, multiplier: 4.0 },\n ],\n relationModifier: {\n connectedThreshold: 3,\n connectedMultiplier: 1.8, // higher tau = slower decay for connected memories\n isolatedMultiplier: 0.8, // lower tau = slightly faster decay for isolated memories\n highlyConnectedThreshold: 6,\n highlyConnectedMultiplier: 2.5, // near-immune: ~2.5x longer effective half-life\n },\n importanceFloor: 0.05,\n pruneThreshold: 0.1,\n pruneMinAgeDays: 90,\n};\n\nexport const SCORING_WEIGHTS = {\n text: 0.35,\n importance: 0.20,\n recency: 0.20,\n access: 0.10,\n context: 0.15,\n} as const;\n\n// ── Injection Algorithm Constants ──────────────────────────────\n\nexport const INJECTION_WEIGHTS = {\n context: 0.30,\n value: 0.25,\n importance: 0.20,\n recency: 0.15,\n typeBonus: 0.05,\n noise: 0.05,\n} as const;\n\nexport const TYPE_INJECTION_BONUS: Record<string, number> = {\n procedural: 1.0,\n pattern: 0.8,\n semantic: 0.6,\n episodic: 0.3,\n working: 0.0,\n};\n\nexport const RECENCY_HALF_LIFE: Record<string, number> = {\n working: 1,\n episodic: 7,\n pattern: 14,\n semantic: 30,\n procedural: 90,\n};\n\nexport const INJECTION_MIN_SCORE = 0.25;\nexport const INJECTION_COLD_START_THRESHOLD = 5;\nexport const INJECTION_COLD_START_RAMP_END = 20;\nexport const INJECTION_HEADER_TOKENS = 50;\nexport const INJECTION_MAX_SAME_TYPE_FULL = 2;\nexport const INJECTION_PINNED_BUDGET_PCT = 0.10;\n\n// ── Config Loader ─────────────────────────────────────────────\n\nexport function resolveDataDir(dataDir: string): string {\n if (dataDir.startsWith('~')) {\n return join(homedir(), dataDir.slice(1));\n }\n return dataDir;\n}\n\nexport function loadConfig(overrides?: Partial<Config>): Config {\n const envOverrides: Record<string, unknown> = {};\n\n const envBudget = process.env['AGENTIC_MEMORY_INJECTION_BUDGET'];\n if (envBudget !== undefined) {\n envOverrides['injectionBudget'] = parseInt(envBudget, 10);\n }\n\n const envLogLevel = process.env['AGENTIC_MEMORY_LOG_LEVEL'];\n if (envLogLevel !== undefined) {\n envOverrides['logLevel'] = envLogLevel;\n }\n\n const envDataDir = process.env['AGENTIC_MEMORY_DATA_DIR'];\n if (envDataDir !== undefined) {\n envOverrides['dataDir'] = envDataDir;\n }\n\n // Try loading config.json from data dir\n let fileConfig: Record<string, unknown> = {};\n const baseDir = resolveDataDir(overrides?.dataDir ?? envOverrides['dataDir'] as string ?? DEFAULT_CONFIG.dataDir);\n try {\n const raw = readFileSync(join(baseDir, 'config.json'), 'utf-8');\n fileConfig = JSON.parse(raw) as Record<string, unknown>;\n } catch (err) {\n const isNotFound = err instanceof Error && 'code' in err && (err as NodeJS.ErrnoException).code === 'ENOENT';\n if (!isNotFound) {\n // Malformed JSON or permissions error - warn, don't silently ignore\n console.error('[agentic-memory] Failed to load config.json:', err instanceof Error ? err.message : err);\n }\n }\n\n const merged = { ...DEFAULT_CONFIG, ...fileConfig, ...envOverrides, ...overrides };\n return ConfigSchema.parse(merged);\n}\n\n// ── Token Estimation ──────────────────────────────────────────\n\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n","import type DatabaseConstructor from 'better-sqlite3';\nimport { resolveDataDir } from '../config.js';\nimport { mkdirSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { cwdRequire } from '../utils/require-deps.js';\n\nexport interface DatabaseOptions {\n readonly dbPath?: string; // full path override (e.g. ':memory:' for tests)\n readonly dataDir?: string; // resolved data dir (default ~/.agentic-memory)\n}\n\nexport function createDatabase(options: DatabaseOptions = {}): DatabaseConstructor.Database {\n const dbPath = options.dbPath ?? resolveDbPath(options.dataDir);\n\n if (dbPath !== ':memory:') {\n mkdirSync(dirname(dbPath), { recursive: true });\n }\n\n const Database = cwdRequire('better-sqlite3') as typeof DatabaseConstructor;\n const sqliteVec = cwdRequire('sqlite-vec') as { load: (db: DatabaseConstructor.Database) => void };\n\n const db = new Database(dbPath);\n\n // Load sqlite-vec extension\n sqliteVec.load(db);\n\n // Configure PRAGMAs (order matters: foreign_keys before any ops, journal_mode is persistent)\n db.pragma('journal_mode = WAL');\n db.pragma('busy_timeout = 5000');\n db.pragma('foreign_keys = ON');\n db.pragma('cache_size = -64000');\n db.pragma('mmap_size = 268435456');\n db.pragma('synchronous = NORMAL');\n db.pragma('temp_store = MEMORY');\n db.pragma('journal_size_limit = 33554432');\n\n return db;\n}\n\nexport function closeDatabase(db: DatabaseConstructor.Database): void {\n try {\n db.pragma('wal_checkpoint(TRUNCATE)');\n } catch {\n // Checkpoint may fail on :memory: - that's fine\n }\n db.close();\n}\n\nfunction resolveDbPath(dataDir?: string): string {\n const dir = resolveDataDir(dataDir ?? '~/.agentic-memory');\n return join(dir, 'memory.db');\n}\n","import type Database from 'better-sqlite3';\n\nexport const version = 1;\n\nexport function up(db: Database.Database): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS meta (\n key TEXT PRIMARY KEY,\n value TEXT\n );\n\n CREATE TABLE IF NOT EXISTS memories (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL CHECK(type IN ('episodic','semantic','procedural','working','pattern')),\n title TEXT,\n content TEXT NOT NULL,\n context TEXT,\n source TEXT CHECK(source IN ('manual','session_end','consolidation','hook','import')),\n tags TEXT NOT NULL DEFAULT '[]',\n importance REAL NOT NULL DEFAULT 0.5 CHECK(importance >= 0.0 AND importance <= 1.0),\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n updated_at TEXT NOT NULL DEFAULT (datetime('now')),\n access_count INTEGER NOT NULL DEFAULT 0 CHECK(access_count >= 0),\n last_accessed TEXT,\n injection_count INTEGER NOT NULL DEFAULT 0 CHECK(injection_count >= 0),\n embedding BLOB\n );\n\n CREATE TABLE IF NOT EXISTS relations (\n source_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,\n target_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,\n relation_type TEXT NOT NULL CHECK(relation_type IN (\n 'relates_to','depends_on','contradicts','extends','implements','derived_from'\n )),\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n PRIMARY KEY (source_id, target_id, relation_type)\n );\n\n -- FTS5 external content (no data duplication)\n CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(\n title, content, tags,\n content=memories,\n content_rowid=rowid,\n tokenize='porter unicode61'\n );\n\n -- FTS5 sync triggers\n CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN\n INSERT INTO memories_fts(rowid, title, content, tags)\n VALUES (new.rowid, new.title, new.content, new.tags);\n END;\n\n CREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN\n INSERT INTO memories_fts(memories_fts, rowid, title, content, tags)\n VALUES ('delete', old.rowid, old.title, old.content, old.tags);\n END;\n\n CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN\n INSERT INTO memories_fts(memories_fts, rowid, title, content, tags)\n VALUES ('delete', old.rowid, old.title, old.content, old.tags);\n INSERT INTO memories_fts(rowid, title, content, tags)\n VALUES (new.rowid, new.title, new.content, new.tags);\n END;\n\n -- Vector search (synced manually in application code)\n CREATE VIRTUAL TABLE IF NOT EXISTS memories_vec USING vec0(\n memory_id TEXT PRIMARY KEY,\n embedding float[384] distance_metric=cosine\n );\n\n -- Indexes\n CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(type);\n CREATE INDEX IF NOT EXISTS idx_memories_importance ON memories(importance);\n CREATE INDEX IF NOT EXISTS idx_memories_created_at ON memories(created_at);\n CREATE INDEX IF NOT EXISTS idx_relations_target ON relations(target_id);\n `);\n}\n","import type Database from 'better-sqlite3';\n\nexport const version = 2;\n\nexport function up(db: Database.Database): void {\n db.exec(`\n ALTER TABLE memories ADD COLUMN project TEXT;\n CREATE INDEX IF NOT EXISTS idx_memories_project ON memories(project);\n `);\n}\n","import { createHash } from 'node:crypto';\nimport type Database from 'better-sqlite3';\n\nexport const version = 3;\n\nexport function up(db: Database.Database): void {\n db.exec('ALTER TABLE memories ADD COLUMN content_hash TEXT');\n\n // Backfill existing rows with SHA-256 hashes\n const rows = db.prepare('SELECT id, content FROM memories ORDER BY updated_at DESC').all() as { id: string; content: string }[];\n const update = db.prepare('UPDATE memories SET content_hash = ? WHERE id = ?');\n const remove = db.prepare('DELETE FROM memories WHERE id = ?');\n\n // Track seen hashes — keep the most recently updated, remove older duplicates\n const seen = new Set<string>();\n for (const row of rows) {\n const hash = createHash('sha256').update(row.content).digest('hex');\n if (seen.has(hash)) {\n remove.run(row.id);\n } else {\n seen.add(hash);\n update.run(hash, row.id);\n }\n }\n\n db.exec('CREATE UNIQUE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash)');\n}\n","import type Database from 'better-sqlite3';\nimport * as migration001 from './migrations/001-initial.js';\nimport * as migration002 from './migrations/002-add-project.js';\nimport * as migration003 from './migrations/003-add-content-hash.js';\n\ninterface Migration {\n readonly version: number;\n readonly up: (db: Database.Database) => void;\n}\n\nconst migrations: readonly Migration[] = [\n migration001,\n migration002,\n migration003,\n];\n\nexport function getSchemaVersion(db: Database.Database): number {\n try {\n const row = db.prepare(\"SELECT value FROM meta WHERE key = 'schema_version'\").get() as\n { value: string } | undefined;\n return row ? parseInt(row.value, 10) : 0;\n } catch {\n return 0;\n }\n}\n\nexport function migrate(db: Database.Database): void {\n const current = getSchemaVersion(db);\n const pending = migrations.filter(m => m.version > current);\n\n if (pending.length === 0) return;\n\n const runMigrations = db.transaction(() => {\n for (const m of pending) {\n m.up(db);\n db.prepare(\"INSERT OR REPLACE INTO meta (key, value) VALUES ('schema_version', ?)\")\n .run(String(m.version));\n }\n });\n\n runMigrations();\n}\n"],"mappings":"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","names":["join","join","up","version","up","version"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/memory/types.ts"],"sourcesContent":["import { z } from 'zod';\n\n// ── MCP Harness Coercion ─────────────────────────────────────\n// Claude Code's MCP harness sometimes serializes arrays as JSON-encoded strings\n// (e.g. tags arrives as '[\"tag1\",\"tag2\"]' instead of [\"tag1\",\"tag2\"]).\n// This preprocess step accepts both forms.\nexport const coerceStringArray = z.preprocess((val) => {\n if (Array.isArray(val)) return val;\n if (typeof val === 'string') {\n try {\n const parsed = JSON.parse(val);\n if (Array.isArray(parsed)) return parsed;\n } catch { /* not JSON, treat as single-element array */ }\n return val.trim() ? [val] : [];\n }\n return val;\n}, z.array(z.string()));\n\n// ── Memory Types ──────────────────────────────────────────────\n\nexport const MEMORY_TYPES = ['working', 'episodic', 'semantic', 'procedural', 'pattern'] as const;\nexport type MemoryType = typeof MEMORY_TYPES[number];\n\nexport const MEMORY_SOURCES = ['manual', 'session_end', 'consolidation', 'hook', 'import'] as const;\nexport type MemorySource = typeof MEMORY_SOURCES[number];\n\nexport const RELATION_TYPES = [\n 'relates_to', 'depends_on', 'contradicts', 'extends', 'implements', 'derived_from',\n] as const;\nexport type RelationType = typeof RELATION_TYPES[number];\n\n// ── Core Entities ─────────────────────────────────────────────\n\nexport interface Memory {\n readonly id: string;\n readonly type: MemoryType;\n readonly title: string | null;\n readonly content: string;\n readonly context: string | null;\n readonly source: MemorySource | null;\n readonly project: string | null;\n readonly tags: readonly string[];\n readonly importance: number;\n readonly createdAt: string;\n readonly updatedAt: string;\n readonly accessCount: number;\n readonly lastAccessed: string | null;\n readonly injectionCount: number;\n}\n\nexport interface Relation {\n readonly sourceId: string;\n readonly targetId: string;\n readonly relationType: RelationType;\n readonly createdAt: string;\n}\n\n// ── Search Types ──────────────────────────────────────────────\n\nexport interface SearchResult {\n readonly memory: Memory;\n readonly score: number;\n readonly explanation: string;\n}\n\nexport interface FtsMatch {\n readonly rowid: number;\n readonly memoryId: string;\n readonly rank: number;\n}\n\nexport interface ScoredCandidate {\n readonly memoryId: string;\n readonly textScore: number;\n readonly importanceScore: number;\n readonly recencyScore: number;\n readonly accessScore: number;\n readonly contextScore: number;\n readonly composite: number;\n}\n\n// ── Decay Parameters ──────────────────────────────────────────\n\nexport interface DecayParams {\n readonly tauByType: Record<MemoryType, number>;\n readonly accessModifiers: readonly { readonly maxCount: number; readonly multiplier: number }[];\n readonly relationModifier: {\n readonly connectedThreshold: number;\n readonly connectedMultiplier: number;\n readonly isolatedMultiplier: number;\n readonly highlyConnectedThreshold: number;\n readonly highlyConnectedMultiplier: number;\n };\n readonly importanceFloor: number;\n readonly pruneThreshold: number;\n readonly pruneMinAgeDays: number;\n}\n\n// ── Input Schemas (for MCP tools) ─────────────────────────────\n\nexport const StoreInputSchema = z.object({\n type: z.enum(MEMORY_TYPES),\n content: z.string().min(1),\n title: z.string().max(200).optional(),\n tags: coerceStringArray.pipe(z.array(z.string()).max(20)).default([]),\n importance: z.number().min(0).max(1).default(0.5),\n context: z.string().optional(),\n source: z.enum(MEMORY_SOURCES).default('manual'),\n project: z.string().max(200).optional(),\n});\nexport type StoreInput = z.infer<typeof StoreInputSchema>;\n\nexport const SearchInputSchema = z.object({\n query: z.string().min(1).max(500),\n id: z.string().optional(),\n type: z.enum(MEMORY_TYPES).optional(),\n tags: coerceStringArray.pipe(z.array(z.string()).max(10)).optional(),\n limit: z.number().int().min(1).max(50).default(10),\n min_importance: z.number().min(0).max(1).default(0),\n project: z.string().max(200).optional(),\n});\nexport type SearchInput = z.infer<typeof SearchInputSchema>;\n\nexport const ForgetInputSchema = z.object({\n id: z.string(),\n hard_delete: z.boolean().default(false),\n});\nexport type ForgetInput = z.infer<typeof ForgetInputSchema>;\n\nexport const RelateInputSchema = z.object({\n source_id: z.string(),\n target_id: z.string(),\n relation_type: z.enum(RELATION_TYPES),\n});\nexport type RelateInput = z.infer<typeof RelateInputSchema>;\n\n// ── Sync Types ───────────────────────────────────────────────\n\nexport interface SyncPayload {\n readonly version: number;\n readonly machine_id: string;\n readonly pushed_at: string;\n readonly memories: readonly SyncMemoryRow[];\n readonly relations: readonly SyncRelationRow[];\n}\n\nexport interface SyncMemoryRow {\n readonly id: string;\n readonly type: MemoryType;\n readonly title: string | null;\n readonly content: string;\n readonly context: string | null;\n readonly source: MemorySource | null;\n readonly project: string | null;\n readonly tags: readonly string[];\n readonly importance: number;\n readonly access_count: number;\n readonly injection_count: number;\n readonly created_at: string;\n readonly updated_at: string;\n readonly last_accessed: string | null;\n}\n\nexport interface SyncRelationRow {\n readonly source_id: string;\n readonly target_id: string;\n readonly relation_type: RelationType;\n readonly created_at: string;\n}\n\nexport const SyncPayloadSchema = z.object({\n version: z.number(),\n machine_id: z.string(),\n pushed_at: z.string(),\n memories: z.array(z.object({\n id: z.string(),\n type: z.enum(MEMORY_TYPES),\n title: z.string().nullable(),\n content: z.string(),\n context: z.string().nullable(),\n source: z.enum(MEMORY_SOURCES).nullable(),\n project: z.string().nullable(),\n tags: z.array(z.string()),\n importance: z.number(),\n access_count: z.number(),\n injection_count: z.number(),\n created_at: z.string(),\n updated_at: z.string(),\n last_accessed: z.string().nullable(),\n })),\n relations: z.array(z.object({\n source_id: z.string(),\n target_id: z.string(),\n relation_type: z.enum(RELATION_TYPES),\n created_at: z.string(),\n })),\n});\n\nexport interface SyncConfig {\n readonly gistId: string;\n}\n\nexport interface MergeResult {\n readonly inserted: number;\n readonly updated: number;\n readonly relationsAdded: number;\n}\n\n// ── Stats ─────────────────────────────────────────────────────\n\nexport interface MemoryStats {\n readonly totalMemories: number;\n readonly byType: Record<MemoryType, number>;\n readonly totalRelations: number;\n readonly dbSizeBytes: number;\n readonly oldestMemory: string | null;\n readonly newestMemory: string | null;\n readonly topInjected: readonly { readonly id: string; readonly title: string | null; readonly injectionCount: number }[];\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/memory/utils/sync-merge.ts"],"sourcesContent":["import { SyncPayloadSchema } from '../types.js';\nimport type { Memory, SyncPayload, SyncMemoryRow, MergeResult, RelationType } from '../types.js';\nimport type { MemoryRepo } from '../storage/memory-repo.js';\nimport type { RelationRepo } from '../storage/relation-repo.js';\n\nfunction memoryToSyncRow(m: Memory): SyncMemoryRow {\n return {\n id: m.id,\n type: m.type,\n title: m.title,\n content: m.content,\n context: m.context,\n source: m.source,\n project: m.project,\n tags: [...m.tags],\n importance: m.importance,\n access_count: m.accessCount,\n injection_count: m.injectionCount,\n created_at: m.createdAt,\n updated_at: m.updatedAt,\n last_accessed: m.lastAccessed,\n };\n}\n\nexport { memoryToSyncRow };\n\nexport function parsePayload(raw: string | null): SyncPayload | null {\n if (!raw || raw === 'null') return null;\n try { return SyncPayloadSchema.parse(JSON.parse(raw)); }\n catch { return null; }\n}\n\nexport function mergeFromRemote(\n memoryRepo: MemoryRepo,\n relationRepo: RelationRepo,\n payload: SyncPayload,\n): MergeResult {\n let inserted = 0;\n let updated = 0;\n let relationsAdded = 0;\n\n const memories = payload.memories;\n\n for (const remote of memories) {\n const local = memoryRepo.getById(remote.id);\n if (!local) {\n memoryRepo.upsertFromSync(remote);\n inserted++;\n } else if (remote.updated_at > local.updatedAt) {\n memoryRepo.upsertFromSync(remote);\n updated++;\n }\n }\n\n const localIds = new Set(memoryRepo.getAll().map((m) => m.id));\n const relations = payload.relations.filter(\n (r) => localIds.has(r.source_id) && localIds.has(r.target_id),\n );\n\n for (const rel of relations) {\n const added = relationRepo.create(\n rel.source_id,\n rel.target_id,\n rel.relation_type as RelationType,\n );\n if (added) relationsAdded++;\n }\n\n return { inserted, updated, relationsAdded };\n}\n"],"mappings":";;;;;;AAKA,SAAS,gBAAgB,GAA0B;AACjD,SAAO;AAAA,IACL,IAAI,EAAE;AAAA,IACN,MAAM,EAAE;AAAA,IACR,OAAO,EAAE;AAAA,IACT,SAAS,EAAE;AAAA,IACX,SAAS,EAAE;AAAA,IACX,QAAQ,EAAE;AAAA,IACV,SAAS,EAAE;AAAA,IACX,MAAM,CAAC,GAAG,EAAE,IAAI;AAAA,IAChB,YAAY,EAAE;AAAA,IACd,cAAc,EAAE;AAAA,IAChB,iBAAiB,EAAE;AAAA,IACnB,YAAY,EAAE;AAAA,IACd,YAAY,EAAE;AAAA,IACd,eAAe,EAAE;AAAA,EACnB;AACF;AAIO,SAAS,aAAa,KAAwC;AACnE,MAAI,CAAC,OAAO,QAAQ,OAAQ,QAAO;AACnC,MAAI;AAAE,WAAO,kBAAkB,MAAM,KAAK,MAAM,GAAG,CAAC;AAAA,EAAG,QACjD;AAAE,WAAO;AAAA,EAAM;AACvB;AAEO,SAAS,gBACd,YACA,cACA,SACa;AACb,MAAI,WAAW;AACf,MAAI,UAAU;AACd,MAAI,iBAAiB;AAErB,QAAM,WAAW,QAAQ;AAEzB,aAAW,UAAU,UAAU;AAC7B,UAAM,QAAQ,WAAW,QAAQ,OAAO,EAAE;AAC1C,QAAI,CAAC,OAAO;AACV,iBAAW,eAAe,MAAM;AAChC;AAAA,IACF,WAAW,OAAO,aAAa,MAAM,WAAW;AAC9C,iBAAW,eAAe,MAAM;AAChC;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAW,IAAI,IAAI,WAAW,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AAC7D,QAAM,YAAY,QAAQ,UAAU;AAAA,IAClC,CAAC,MAAM,SAAS,IAAI,EAAE,SAAS,KAAK,SAAS,IAAI,EAAE,SAAS;AAAA,EAC9D;AAEA,aAAW,OAAO,WAAW;AAC3B,UAAM,QAAQ,aAAa;AAAA,MACzB,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,IACN;AACA,QAAI,MAAO;AAAA,EACb;AAEA,SAAO,EAAE,UAAU,SAAS,eAAe;AAC7C;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/memory/storage/memory-repo.ts","../src/commands/memory/storage/relation-repo.ts","../src/commands/memory/storage/search-repo.ts"],"sourcesContent":["import type Database from 'better-sqlite3';\nimport type { Memory, MemoryType, MemorySource, StoreInput, SyncMemoryRow } from '../types.js';\nimport { randomUUID, createHash } from 'node:crypto';\n\nfunction safeParseTags(raw: string): string[] {\n try {\n const parsed = JSON.parse(raw);\n return Array.isArray(parsed) ? parsed.filter(t => typeof t === 'string') : [];\n } catch {\n return [];\n }\n}\n\n// ── Row shape from SQLite ─────────────────────────────────────\n\ninterface MemoryRow {\n id: string;\n type: string;\n title: string | null;\n content: string;\n context: string | null;\n source: string | null;\n project: string | null;\n tags: string;\n importance: number;\n created_at: string;\n updated_at: string;\n access_count: number;\n last_accessed: string | null;\n injection_count: number;\n embedding: Buffer | null;\n}\n\nfunction rowToMemory(row: MemoryRow): Memory {\n return {\n id: row.id,\n type: row.type as MemoryType,\n title: row.title,\n content: row.content,\n context: row.context,\n source: row.source as MemorySource | null,\n project: row.project,\n tags: safeParseTags(row.tags),\n importance: row.importance,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n accessCount: row.access_count,\n lastAccessed: row.last_accessed,\n injectionCount: row.injection_count,\n };\n}\n\n// ── Repository ────────────────────────────────────────────────\n\nexport class MemoryRepo {\n readonly #stmts;\n readonly db: Database.Database;\n\n constructor(db: Database.Database) {\n this.db = db;\n this.#stmts = {\n insert: db.prepare(`\n INSERT OR IGNORE INTO memories (id, type, title, content, context, source, project, tags, importance, created_at, updated_at, embedding, content_hash)\n VALUES (@id, @type, @title, @content, @context, @source, @project, @tags, @importance, @createdAt, @updatedAt, @embedding, @contentHash)\n `),\n getById: db.prepare('SELECT * FROM memories WHERE id = ?'),\n getAll: db.prepare('SELECT * FROM memories ORDER BY created_at DESC'),\n getAllByProject: db.prepare('SELECT * FROM memories WHERE project = ? OR project IS NULL ORDER BY created_at DESC'),\n getByType: db.prepare('SELECT * FROM memories WHERE type = ? ORDER BY created_at DESC'),\n getByTypeAndProject: db.prepare('SELECT * FROM memories WHERE type = ? AND (project = ? OR project IS NULL) ORDER BY created_at DESC'),\n getRecent: db.prepare('SELECT * FROM memories ORDER BY created_at DESC LIMIT ?'),\n getRecentByProject: db.prepare('SELECT * FROM memories WHERE project = ? OR project IS NULL ORDER BY created_at DESC LIMIT ?'),\n getRecentByTypeAndProject: db.prepare('SELECT * FROM memories WHERE type = ? AND (project = ? OR project IS NULL) ORDER BY created_at DESC LIMIT ?'),\n update: db.prepare(`\n UPDATE memories\n SET title = @title, content = @content, context = @context, tags = @tags,\n importance = @importance, updated_at = @updatedAt, embedding = @embedding,\n content_hash = @contentHash\n WHERE id = @id\n `),\n updateImportance: db.prepare('UPDATE memories SET importance = ?, updated_at = ? WHERE id = ?'),\n updateImportanceOnly: db.prepare('UPDATE memories SET importance = ? WHERE id = ?'),\n incrementAccess: db.prepare(`\n UPDATE memories SET access_count = access_count + 1, last_accessed = ? WHERE id = ?\n `),\n incrementInjection: db.prepare(`\n UPDATE memories SET injection_count = injection_count + 1 WHERE id = ?\n `),\n softDelete: db.prepare('UPDATE memories SET importance = 0, updated_at = ? WHERE id = ?'),\n hardDelete: db.prepare('DELETE FROM memories WHERE id = ?'),\n deleteByType: db.prepare('DELETE FROM memories WHERE type = ?'),\n deleteByProject: db.prepare('DELETE FROM memories WHERE project = ?'),\n count: db.prepare('SELECT COUNT(*) as count FROM memories'),\n countByProject: db.prepare('SELECT COUNT(*) as count FROM memories WHERE project = ?'),\n countByType: db.prepare('SELECT type, COUNT(*) as count FROM memories GROUP BY type'),\n projectCounts: db.prepare('SELECT COALESCE(project, \\'_global\\') as project, COUNT(*) as count FROM memories GROUP BY project'),\n dateRange: db.prepare('SELECT MIN(created_at) as oldest, MAX(created_at) as newest FROM memories'),\n topInjected: db.prepare(`\n SELECT id, title, injection_count FROM memories\n WHERE injection_count > 0 ORDER BY injection_count DESC LIMIT ?\n `),\n insertSync: db.prepare(`\n INSERT OR IGNORE INTO memories\n (id, type, title, content, context, source, project, tags, importance,\n access_count, injection_count, created_at, updated_at, last_accessed, embedding, content_hash)\n VALUES (@id, @type, @title, @content, @context, @source, @project, @tags, @importance,\n @accessCount, @injectionCount, @createdAt, @updatedAt, @lastAccessed, NULL, @contentHash)\n `),\n updateSync: db.prepare(`\n UPDATE memories SET\n title = @title, content = @content, context = @context,\n source = @source, project = @project, tags = @tags,\n importance = @importance, access_count = @accessCount,\n injection_count = @injectionCount, updated_at = @updatedAt,\n last_accessed = @lastAccessed, content_hash = @contentHash\n WHERE id = @id\n `),\n getAllStrictProject: db.prepare(\n 'SELECT * FROM memories WHERE project = ? ORDER BY created_at DESC'\n ),\n };\n }\n\n create(input: StoreInput, _embedding: Buffer | null = null): Memory | null {\n const now = new Date().toISOString();\n const id = randomUUID();\n const contentHash = createHash('sha256').update(input.content).digest('hex');\n\n const params = {\n id,\n type: input.type,\n title: input.title ?? null,\n content: input.content,\n context: input.context ?? null,\n source: input.source,\n project: input.project ?? null,\n tags: JSON.stringify(input.tags),\n importance: input.importance,\n createdAt: now,\n updatedAt: now,\n embedding: null,\n contentHash,\n };\n\n const result = this.#stmts.insert.run(params);\n if (result.changes === 0) return null;\n\n const row: MemoryRow = {\n id,\n type: input.type,\n title: input.title ?? null,\n content: input.content,\n context: input.context ?? null,\n source: input.source,\n project: input.project ?? null,\n tags: JSON.stringify(input.tags),\n importance: input.importance,\n created_at: now,\n updated_at: now,\n access_count: 0,\n last_accessed: null,\n injection_count: 0,\n embedding: null,\n };\n\n return rowToMemory(row);\n }\n\n getById(id: string): Memory | undefined {\n const row = this.#stmts.getById.get(id) as MemoryRow | undefined;\n return row ? rowToMemory(row) : undefined;\n }\n\n getAll(project?: string): readonly Memory[] {\n if (project) {\n const rows = this.#stmts.getAllByProject.all(project) as MemoryRow[];\n return rows.map(rowToMemory);\n }\n const rows = this.#stmts.getAll.all() as MemoryRow[];\n return rows.map(rowToMemory);\n }\n\n getRecent(limit: number, project?: string, type?: MemoryType): readonly Memory[] {\n if (type && project) {\n const rows = this.#stmts.getRecentByTypeAndProject.all(type, project, limit) as MemoryRow[];\n return rows.map(rowToMemory);\n }\n if (project) {\n const rows = this.#stmts.getRecentByProject.all(project, limit) as MemoryRow[];\n return rows.map(rowToMemory);\n }\n const rows = this.#stmts.getRecent.all(limit) as MemoryRow[];\n return rows.map(rowToMemory);\n }\n\n getByType(type: MemoryType, project?: string): readonly Memory[] {\n if (project) {\n const rows = this.#stmts.getByTypeAndProject.all(type, project) as MemoryRow[];\n return rows.map(rowToMemory);\n }\n const rows = this.#stmts.getByType.all(type) as MemoryRow[];\n return rows.map(rowToMemory);\n }\n\n updateContent(id: string, updates: {\n readonly title?: string | null;\n readonly content?: string;\n readonly context?: string | null;\n readonly tags?: readonly string[];\n readonly importance?: number;\n }): boolean {\n const existing = this.getById(id);\n if (!existing) return false;\n\n const now = new Date().toISOString();\n\n const finalContent = updates.content ?? existing.content;\n const params = {\n id,\n title: updates.title !== undefined ? updates.title : existing.title,\n content: finalContent,\n context: updates.context !== undefined ? updates.context : existing.context,\n tags: JSON.stringify(updates.tags ?? existing.tags),\n importance: updates.importance ?? existing.importance,\n updatedAt: now,\n embedding: null,\n contentHash: createHash('sha256').update(finalContent).digest('hex'),\n };\n\n this.#stmts.update.run(params);\n return true;\n }\n\n updateImportance(id: string, importance: number): boolean {\n const now = new Date().toISOString();\n const result = this.#stmts.updateImportance.run(importance, now, id);\n return result.changes > 0;\n }\n\n /** Update importance without touching updated_at - used by decay to avoid resetting the clock. */\n updateImportanceOnly(id: string, importance: number): boolean {\n const result = this.#stmts.updateImportanceOnly.run(importance, id);\n return result.changes > 0;\n }\n\n incrementAccess(id: string): void {\n this.#stmts.incrementAccess.run(new Date().toISOString(), id);\n }\n\n incrementInjection(id: string): void {\n this.#stmts.incrementInjection.run(id);\n }\n\n softDelete(id: string): boolean {\n const result = this.#stmts.softDelete.run(new Date().toISOString(), id);\n return result.changes > 0;\n }\n\n hardDelete(id: string): boolean {\n const result = this.#stmts.hardDelete.run(id);\n return result.changes > 0;\n }\n\n deleteByType(type: MemoryType): number {\n const result = this.#stmts.deleteByType.run(type);\n return result.changes;\n }\n\n deleteByProject(project: string): number {\n const result = this.#stmts.deleteByProject.run(project);\n return result.changes;\n }\n\n count(project?: string): number {\n if (project) {\n const row = this.#stmts.countByProject.get(project) as { count: number };\n return row.count;\n }\n const row = this.#stmts.count.get() as { count: number };\n return row.count;\n }\n\n countByType(): Record<string, number> {\n const rows = this.#stmts.countByType.all() as { type: string; count: number }[];\n return Object.fromEntries(rows.map(r => [r.type, r.count]));\n }\n\n projectCounts(): ReadonlyMap<string, number> {\n const rows = this.#stmts.projectCounts.all() as { project: string; count: number }[];\n return new Map(rows.map(r => [r.project, r.count]));\n }\n\n dateRange(): { oldest: string | null; newest: string | null } {\n const row = this.#stmts.dateRange.get() as { oldest: string | null; newest: string | null };\n return { oldest: row.oldest, newest: row.newest };\n }\n\n topInjected(limit: number = 5): readonly { id: string; title: string | null; injectionCount: number }[] {\n const rows = this.#stmts.topInjected.all(limit) as { id: string; title: string | null; injection_count: number }[];\n return rows.map(r => ({ id: r.id, title: r.title, injectionCount: r.injection_count }));\n }\n\n upsertFromSync(row: SyncMemoryRow): void {\n const params = {\n id: row.id,\n type: row.type,\n title: row.title,\n content: row.content,\n context: row.context,\n source: row.source,\n project: row.project,\n tags: JSON.stringify(row.tags),\n importance: row.importance,\n accessCount: row.access_count,\n injectionCount: row.injection_count,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n lastAccessed: row.last_accessed,\n contentHash: createHash('sha256').update(row.content).digest('hex'),\n };\n\n const existing = this.getById(row.id);\n if (existing) {\n this.#stmts.updateSync.run(params);\n } else {\n this.#stmts.insertSync.run(params);\n }\n }\n\n getAllForSync(project?: string): readonly Memory[] {\n if (project) {\n const rows = this.#stmts.getAllStrictProject.all(project) as MemoryRow[];\n return rows.map(rowToMemory);\n }\n return this.getAll();\n }\n}\n","import type Database from 'better-sqlite3';\nimport type { Relation, RelationType } from '../types.js';\n\ninterface RelationRow {\n source_id: string;\n target_id: string;\n relation_type: string;\n created_at: string;\n}\n\nfunction rowToRelation(row: RelationRow): Relation {\n return {\n sourceId: row.source_id,\n targetId: row.target_id,\n relationType: row.relation_type as RelationType,\n createdAt: row.created_at,\n };\n}\n\nexport class RelationRepo {\n readonly #stmts;\n\n constructor(db: Database.Database) {\n this.#stmts = {\n insert: db.prepare(`\n INSERT OR IGNORE INTO relations (source_id, target_id, relation_type)\n VALUES (?, ?, ?)\n `),\n getBySource: db.prepare('SELECT * FROM relations WHERE source_id = ?'),\n getByTarget: db.prepare('SELECT * FROM relations WHERE target_id = ?'),\n getByMemory: db.prepare(`\n SELECT * FROM relations WHERE source_id = ? OR target_id = ?\n `),\n delete: db.prepare(`\n DELETE FROM relations WHERE source_id = ? AND target_id = ? AND relation_type = ?\n `),\n countByMemory: db.prepare(`\n SELECT COUNT(*) as count FROM relations WHERE source_id = ? OR target_id = ?\n `),\n count: db.prepare('SELECT COUNT(*) as count FROM relations'),\n getAll: db.prepare('SELECT * FROM relations'),\n deleteOrphaned: db.prepare(`\n DELETE FROM relations\n WHERE source_id NOT IN (SELECT id FROM memories)\n OR target_id NOT IN (SELECT id FROM memories)\n `),\n };\n }\n\n create(sourceId: string, targetId: string, relationType: RelationType): boolean {\n const result = this.#stmts.insert.run(sourceId, targetId, relationType);\n return result.changes > 0;\n }\n\n getBySource(sourceId: string): readonly Relation[] {\n const rows = this.#stmts.getBySource.all(sourceId) as RelationRow[];\n return rows.map(rowToRelation);\n }\n\n getByTarget(targetId: string): readonly Relation[] {\n const rows = this.#stmts.getByTarget.all(targetId) as RelationRow[];\n return rows.map(rowToRelation);\n }\n\n getByMemory(memoryId: string): readonly Relation[] {\n const rows = this.#stmts.getByMemory.all(memoryId, memoryId) as RelationRow[];\n return rows.map(rowToRelation);\n }\n\n delete(sourceId: string, targetId: string, relationType: RelationType): boolean {\n const result = this.#stmts.delete.run(sourceId, targetId, relationType);\n return result.changes > 0;\n }\n\n countByMemory(memoryId: string): number {\n const row = this.#stmts.countByMemory.get(memoryId, memoryId) as { count: number };\n return row.count;\n }\n\n count(): number {\n const row = this.#stmts.count.get() as { count: number };\n return row.count;\n }\n\n getAll(): readonly Relation[] {\n const rows = this.#stmts.getAll.all() as RelationRow[];\n return rows.map(rowToRelation);\n }\n\n deleteOrphaned(): number {\n const result = this.#stmts.deleteOrphaned.run();\n return result.changes;\n }\n}\n","import type Database from 'better-sqlite3';\nimport type { FtsMatch, MemoryType } from '../types.js';\n\n// ── FTS5 Search ───────────────────────────────────────────────\n\nexport interface FtsSearchOptions {\n readonly query: string;\n readonly limit: number;\n readonly type?: MemoryType;\n readonly minImportance?: number;\n readonly project?: string;\n}\n\n\nexport class SearchRepo {\n readonly #stmts;\n\n constructor(db: Database.Database) {\n // FTS5 search with BM25 ranking (weights: title=5.0, content=1.0, tags=2.0)\n this.#stmts = {\n ftsSearch: db.prepare(`\n SELECT\n m.rowid,\n m.id as memory_id,\n bm25(memories_fts, 5.0, 1.0, 2.0) as rank\n FROM memories_fts f\n JOIN memories m ON m.rowid = f.rowid\n WHERE memories_fts MATCH @query\n ORDER BY rank\n LIMIT @limit\n `),\n ftsSearchByProject: db.prepare(`\n SELECT\n m.rowid,\n m.id as memory_id,\n bm25(memories_fts, 5.0, 1.0, 2.0) as rank\n FROM memories_fts f\n JOIN memories m ON m.rowid = f.rowid\n WHERE memories_fts MATCH @query\n AND (m.project = @project OR m.project IS NULL)\n ORDER BY rank\n LIMIT @limit\n `),\n ftsSearchFiltered: db.prepare(`\n SELECT\n m.rowid,\n m.id as memory_id,\n bm25(memories_fts, 5.0, 1.0, 2.0) as rank\n FROM memories_fts f\n JOIN memories m ON m.rowid = f.rowid\n WHERE memories_fts MATCH @query\n AND m.type = @type\n AND m.importance >= @minImportance\n ORDER BY rank\n LIMIT @limit\n `),\n ftsSearchFilteredByProject: db.prepare(`\n SELECT\n m.rowid,\n m.id as memory_id,\n bm25(memories_fts, 5.0, 1.0, 2.0) as rank\n FROM memories_fts f\n JOIN memories m ON m.rowid = f.rowid\n WHERE memories_fts MATCH @query\n AND m.type = @type\n AND m.importance >= @minImportance\n AND (m.project = @project OR m.project IS NULL)\n ORDER BY rank\n LIMIT @limit\n `),\n };\n }\n\n /**\n * Full-text search using BM25 ranking.\n * Returns matches sorted by relevance (most relevant first).\n */\n searchFts(options: FtsSearchOptions): readonly FtsMatch[] {\n const ftsQuery = toFtsQuery(options.query);\n if (!ftsQuery) return [];\n\n try {\n const hasType = !!options.type;\n const hasProject = !!options.project;\n\n let rows: FtsRow[];\n if (hasType && hasProject) {\n rows = this.#stmts.ftsSearchFilteredByProject.all({\n query: ftsQuery, limit: options.limit,\n type: options.type, minImportance: options.minImportance ?? 0,\n project: options.project,\n }) as FtsRow[];\n } else if (hasType) {\n rows = this.#stmts.ftsSearchFiltered.all({\n query: ftsQuery, limit: options.limit,\n type: options.type, minImportance: options.minImportance ?? 0,\n }) as FtsRow[];\n } else if (hasProject) {\n rows = this.#stmts.ftsSearchByProject.all({\n query: ftsQuery, limit: options.limit,\n project: options.project,\n }) as FtsRow[];\n } else {\n rows = this.#stmts.ftsSearch.all({\n query: ftsQuery, limit: options.limit,\n }) as FtsRow[];\n }\n\n return rows.map(r => ({\n rowid: r.rowid,\n memoryId: r.memory_id,\n rank: r.rank,\n }));\n } catch (err) {\n // FTS5 MATCH throws on invalid query syntax - degrade gracefully\n console.error('[agentic-memory] FTS5 search error:', err instanceof Error ? err.message : err);\n return [];\n }\n }\n\n}\n\n// ── Internal helpers ──────────────────────────────────────────\n\ninterface FtsRow {\n rowid: number;\n memory_id: string;\n rank: number;\n}\n\n// Synonym expansion for common dev terms\nconst SYNONYMS: Record<string, readonly string[]> = {\n auth: ['authentication', 'login', 'oauth', 'jwt'],\n authentication: ['auth', 'login', 'oauth'],\n login: ['auth', 'authentication', 'signin'],\n db: ['database', 'sql', 'sqlite', 'postgres'],\n database: ['db', 'sql', 'sqlite', 'postgres'],\n api: ['endpoint', 'route', 'rest', 'graphql'],\n deploy: ['deployment', 'release', 'ship', 'publish'],\n test: ['testing', 'spec', 'jest', 'vitest'],\n config: ['configuration', 'settings', 'setup'],\n err: ['error', 'exception', 'crash', 'bug'],\n error: ['err', 'exception', 'crash', 'bug'],\n};\n\n/**\n * Convert a natural language query to FTS5 query syntax.\n * Expands synonyms and wraps words in quotes for safe matching.\n */\nfunction toFtsQuery(input: string): string | null {\n const words = input\n .replace(/[^\\w\\s]/g, ' ')\n .split(/\\s+/)\n .filter(w => w.length > 0);\n\n if (words.length === 0) return null;\n\n const expanded = words.flatMap((w) => {\n const lower = w.toLowerCase();\n const syns = SYNONYMS[lower];\n return syns ? [w, ...syns] : [w];\n });\n\n return [...new Set(expanded)].map(w => `\"${w}\"`).join(' OR ');\n}\n"],"mappings":"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","names":["rows","row"]}