Repository navigation
fix(ai-vault): keep sessions recorded under a symlinked workspace's real path in Workspace scope - #31244
Conversation
…eal path in Workspace scope (#31139) A workspace registered through a symlink (~/work/api -> /data/src/api, or macOS /var -> /private/var) lost every session whose agent recorded the resolved cwd: scope matching compared strings, and those rows also counted against the out-of-scope depth cap. The host that owns the files (the desktop for local scans, orcad for SSH and server hosts) now resolves each scope path's real path, scans both spellings, and gives matching sessions optional matching-only cwdAliases in the registered spelling. Workspace scope, the depth cap and project attribution read cwd plus aliases; resume still uses the recorded cwd. Older hosts send no aliases and older clients strip the field. Reported, with the proposed approach, by @quzard in #31139.
…e recorded cwds Review feedback: a longer-spelled parent link could take a nested project's session, and resolving every out-of-scope cwd could stall a listing on a hung network mount or raise macOS privacy prompts.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Priority: ➖ Normal Merge Risk: ⚪ Minimal · up to
|
ELI5
If you open a workspace through a shortcut folder (a symlink, like
~/work/apipointing at/data/src/api), some agents record the real folder instead. Session History compared folder names as plain text, so those sessions vanished from the Workspace view. Now the computer that has the files works out where the shortcut really points, and those sessions count as part of the workspace.What Changed
~/work/api(a symlink to/data/src/api, or on macOS anything under/var, which is really/private/var), sessions an agent recorded under/data/src/apiwere missing from the Workspace scope. They also counted against the history depth cap for other folders, so with a small depth they could disappear from the list entirely.Mechanism:
src/main/ai-vault/session-scope-real-paths.ts(new) runs insidecached-session-list.ts, which is the single entry point for both the desktop's own scan and an Orca server'saiVault.listSessions(orcad on SSH hosts). So the real path is always resolved on the host that owns the files, never on the desktop for a remote host.realpathof each scope path (at most 64). Paths missing on that host are skipped quietly, as today; WSL network paths are skipped because Windows can't resolve a Linux link through the share.cwdAliaseswith the registered spelling (/data/src/api/pkg->~/work/api/pkg).aiVaultSessionInScope(src/shared/ai-vault-scope-cwd-match.ts), checks cwd plus aliases. Both the Workspace filter andtruncateAiVaultListResultuse it. That truncation is the depth cap used by the host cache, the desktop's per-host cache and the renderer cache.ai-vault-session-project-candidates.ts, new) also checks aliases. For aliased sessions it picks the root that leaves the shortest remaining path, so a parent folder whose link happens to have a longer name can't take a nested repo's sessions.Why
This follows @quzard's proposal in #31139: resolve on the scanning host, carry aliases next to the recorded cwd, and never change the path resume uses. Alternatives considered:
Wire compatibility:
cwdAliasesis a new optional field on a session row.Linked Issue
Part of #31139 (item 4, "Workspaces opened through a symlink"). Reported, with this approach, by @quzard. The issue stays open for the remaining items.
Visual Proof
N/A: no layout change. The affected sessions now appear in the existing Workspace list instead of being missing.
Testing
Tests that fail on main:
session-scope-real-paths.test.tsuses real symlinks (junctions on Windows): the scope gets its real path, nested cwds get aliases, and unrelated, cwd-less and WSL rows are left alone.cached-session-list.test.ts: the scan receives both spellings, the row gets its alias, and a depth-1 cache hit keeps the aliased row as in scope.ai-vault-session-filters.test.ts,ai-vault-session-depth.test.tsandsession-list-result-validation.test.ts: the alias counts for the Workspace filter and the depth cap, and malformed aliases drop only the aliases.ai-vault-session-projects.test.ts: attribution follows the alias, and a nested repo beats a longer-spelled parent link.Other checks:
Full static-analysis job run locally on this head (all steps). The only failure was
check-e2e-typecheck-ratchetontests/e2e/helpers/phone-feed-list.ts, a file this PR doesn't touch.Unit folders around the changed files:
src/main/ai-vault,src/shared/ai-vault*,right-sidebar/ai-vault*,src/main/ipc/ai-vault*,src/main/ai-vault-search.Live check on a real Linux host (omarchy), in an isolated /tmp dir: I bundled the host module plus the shared Workspace filter, then ran it against real symlinks. A scope
work-api -> data/src/apigave aliases todata/src/apianddata/src/api/pkg, and all of those rows stayed in the Workspace filter. An unrelated folder was left untouched. I did not run a full desktop + orcad session over SSH by hand.I manually tested these changes locally
Automated tests added/updated, or explained why not below
AI Disclosure
Review
Opus P3s left as follow-ups:
session-search-row-filter.ts) still matches exact paths.cwd.Agent skill upstream boundary
Notes
Ensure no issues in: Security, Cross-platoform support (Linux, Windows, Mac), Remote SSH, Mobile, general backwards compatibility, performance
The only new filesystem work is up to 64
realpathcalls on workspace paths per uncached scan. Recorded cwds are never touched.Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)