fix(memory): add GlobalDir routing + tab-aware panel to fix empty memory view (#3756)#4073
fix(memory): add GlobalDir routing + tab-aware panel to fix empty memory view (#3756)#4073ashishexee wants to merge 1 commit into
Conversation
6cb0163 to
32a4d45
Compare
|
Hi @esengine / @SivanCola — regarding the CodeQL "Uncontrolled data used in path expression" alert: This is a false positiveThe var slugRe = regexp.MustCompile(`[^a-z0-9]+`)
func slug(s string) string {
return strings.Trim(slugRe.ReplaceAllString(strings.ToLower(strings.TrimSpace(s)), "-"), "-")
}After What I have triedI wrapped the path construction in a Two options going forward
I would lean toward option 1 as it is cleaner and |
1c21b29 to
f12e509
Compare
…ory view (esengine#3756) The desktop memory panel always shows empty when the Global tab (or any tab whose project-specific memory dir has no auto-memories) is active. Root cause: Store only has Dir (project-specific path), so the panel reads from the active controller's empty project dir. No shared memory directory exists for cross-project memories (user preferences, feedback). Also, the panel has no tab awareness — it always reads from the active tab's controller. Fix (two layers): Layer 1 — Backend Store: - Add GlobalDir field, populated by StoreFor() as <userDir>/memory/global - DirFor(t Type) routes TypeUser/TypeFeedback → GlobalDir, others → Dir - List(), Index() merge both dirs with dedup (global first) - Delete() removes from all dirs (handles migration duplicates) - Save() routes via DirFor(), updates only target dir's MEMORY.md - Index() reconstructs single clean index from managed lines (no dup headers) Layer 2 — Desktop App + Frontend: - Add MemoryForTab/RememberForTab/ForgetForTab/SaveDocForTab with fallback=false (no silent fallback to wrong tab on nil ctrl) - Empty tabID falls back to active tab for backward compat - Add StoreGlobalDir to MemoryView JSON payload - MemorySettingsPage gets tab selector dropdown (shown when >1 tab) - All mutations use *ForTab when a tab is selected - Unavailable screen still shows tab selector for recovery Backward compat: Store{Dir:} with empty GlobalDir works — DirFor falls back to Dir. Old Memory/Remember/Forget/SaveDoc unchanged. Tests: 9 new (65 total pass), covering routing, merge, delete-migration, index dedup, per-dir index verification, Path() GlobalDir-first lookup.
f12e509 to
c5511bb
Compare
|
CI fix note for reviewers: The Two fixes applied:
This makes the test deterministic across platforms and removes a redundant header that would have appeared in the system prompt whenever both GlobalDir and Dir contributed entries. |
Fix: Memory panel always empty on Global tab (#3756)
Problem
The desktop memory panel always shows empty when the Global tab (or any tab whose project-specific memory directory has no auto-memories) is active. The root cause is two-fold:
Store only has
Dir(project-specific path) —App.Memory()reads from the active controller'sStore.Dir, which for the Global tab points to an emptyprojects/<global-workspace-slug>/memory. There is no concept of a shared memory directory for cross-project memories (user preferences, feedback).Panel has no tab awareness — The memory panel always reads from the active tab's controller. When viewing settings from the Global tab, it gets the Global tab's empty store.
Fix (two layers)
Layer 1 — Backend
Store(internal/memory):GlobalDirfield toStore, populated byStoreFor()as<userDir>/memory/globalDirFor(t Type)routesTypeUser/TypeFeedback→GlobalDir(shared), others →Dir(project-specific); falls back toDirwhenGlobalDiris emptyList(),Index()merge both dirs with deduplication (global first)Delete()removes from all dirs (handles migration where same memory name exists in both)Save()routes viaDirFor()and updates only the target dir'sMEMORY.mdIndex()reconstructs a single clean index from managed lines across both dirs (no duplicate headers)Layer 2 — Desktop
App+ Frontend:MemoryForTab/RememberForTab/ForgetForTab/SaveDocForTabusingctrlByTabID(tabID)withfallback=false(no silent fallback to wrong tab)tabIDfalls back to active tab for backward compatibilityStoreGlobalDirtoMemoryViewJSON payloadMemorySettingsPagegets a tab selector dropdown (shown when >1 tab) so user can browse any project's memories*ForTabwhen a tab is selectedBackward Compatibility
Store{Dir: x}with emptyGlobalDir—DirFor()falls back toDir, all methods work with single directoryMemory()/Remember()/Forget()/SaveDoc()unchanged (delegate withfallback=true)Migration Safety
Dirare unaffected —List()merges both dirsList()/Index()deduplicate (GlobalDir first),Delete()cleans bothIndex()produces exactly one# Memoryheader regardless of how many dirs contribute entriesTests (9 new, 65 total pass)
TestStoreGlobalAndProject— routing + merge + delete + header dedupTestStoreForInitializesGlobalDir—StoreForsetsGlobalDirTestDirForRoutesCorrectly— type→dir routingTestDirForFallsBackWhenNoGlobalDir— emptyGlobalDir→DirTestStoreDeleteRemovesFromAllDirs— migration: both copies deletedTestStoreIndexDeduplicatesAcrossDirs— no duplicate index lines/headersTestStoreSaveVerifiesIndexDir—MEMORY.mdwritten to correct dir per typeTestStoreDeleteFlushesIndexPerDir— both dirs' indexes flushed,Index()returns""TestStorePathWithGlobalDir— GlobalDir-first lookup + Dir fallbackHi maintainers — this is my first time tackling a larger issue in this codebase. I've tried to be thorough with the implementation, test coverage, and edge cases (migration scenarios, stale tab handling, nil controller guards). That said, I'm sure there are things I could improve, and I'd genuinely appreciate any feedback on the approach, the code style, or anything I may have missed. Happy to iterate and learn. Thank you for your time reviewing this.