Skip to content

fix(web): normalize workspace paths to resolve Windows session list f…#21504

Closed
chenyy9527 wants to merge 1 commit intoanomalyco:devfrom
chenyy9527:fix/21441-windows-path-normalization
Closed

fix(web): normalize workspace paths to resolve Windows session list f…#21504
chenyy9527 wants to merge 1 commit intoanomalyco:devfrom
chenyy9527:fix/21441-windows-path-normalization

Conversation

@chenyy9527
Copy link
Copy Markdown

…ailures

Closes #21441

  • Client: use workspaceKey() for all child store internal map keys (children, vcsCache, metaCache, iconCache, lifecycle, pins, disposers) to prevent duplicate stores from mixed path formats (D:/foo vs D:\foo)
  • Client: add canonicalDir map to preserve original directory for API calls that require server-side exact match (isBooting, isLoadingSessions, onDispose)
  • Client: deduplicate loadSessions requests via sessionLoads keyed by workspaceKey()
  • Client: sortedRootSessions accepts optional dir fallback for bootstrap: false
  • Server: add normalizeDirectory() (mirrors workspaceKey() logic) for Session createNext (write) and Session.list/listGlobal (query)
  • Server: fromRow normalizes directory in API response for consistency

Issue for this PR

Closes #21441

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

On Windows, the same directory can be passed with different path formats (D:/foo vs D:\foo). This caused three problems:

  1. Duplicate child storeschild-store.ts used the raw directory string as map keys, so the same physical directory created two independent stores. When total stores exceeded MAX_DIR_STORES=30, eviction disposed one store and loadSessions wrote to the disposed store — session data was lost.

  2. Duplicate API requests — On page refresh, two /session requests were sent with different path formats. The backslash request returned empty because Session.list used SQL exact match against forward-slash values in the DB.

  3. Empty session list before bootstrapsortedRootSessions only used store.path.directory for filtering. When bootstrap: false was passed, path.directory was empty and all sessions were filtered out.

Fix:

  • Client: all internal maps keyed by workspaceKey() (normalized). canonicalDir preserves original path for API calls.
  • Client: loadSessions deduplicates via sessionLoads keyed by workspaceKey().
  • Client: sortedRootSessions accepts optional dir fallback for pre-bootstrap state.
  • Server: normalizeDirectory() (identical logic to workspaceKey()) applied in Session.createNext (write), Session.list/Session.listGlobal (query), and fromRow (response).

How did you verify your code works?

  • Verified bun typecheck passes in packages/opencode and packages/app (pre-existing custom-elements.d.ts error is unrelated).
  • Traced the full data flow: page refresh → two loadSessions call paths → API requests → store writes → render, confirming the normalization unifies all paths.
  • Verified normalizeDirectory() and workspaceKey() produce identical output for all edge cases (D:/, /, D:\foo\bar\, empty string).

Screenshots / recordings

N/A

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

…ailures

Closes anomalyco#21441

- Client: use workspaceKey() for all child store internal map keys (children,
  vcsCache, metaCache, iconCache, lifecycle, pins, disposers) to prevent
  duplicate stores from mixed path formats (D:/foo vs D:\foo)
- Client: add canonicalDir map to preserve original directory for API calls
  that require server-side exact match (isBooting, isLoadingSessions, onDispose)
- Client: deduplicate loadSessions requests via sessionLoads keyed by workspaceKey()
- Client: sortedRootSessions accepts optional dir fallback for bootstrap: false
- Server: add normalizeDirectory() (mirrors workspaceKey() logic) for Session
  createNext (write) and Session.list/listGlobal (query)
- Server: fromRow normalizes directory in API response for consistency
@chenyy9527 chenyy9527 requested a review from adamdotdevin as a code owner April 8, 2026 10:20
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 8, 2026

The following comment was made by an LLM, it may be inaccurate:

The search results show PR #21504 is the current PR (as expected). I found one potentially related historical PR:

Related PR:

However, no currently open PRs appear to be duplicates of PR #21504. The search results primarily return the current PR itself, indicating this is the primary/only open PR addressing this specific Windows path normalization issue with session lists.

@chenyy9527
Copy link
Copy Markdown
Author

The following comment was made by an LLM, it may be inaccurate:

The search results show PR #21504 is the current PR (as expected). I found one potentially related historical PR:

Related PR:

However, no currently open PRs appear to be duplicates of PR #21504. The search results primarily return the current PR itself, indicating this is the primary/only open PR addressing this specific Windows path normalization issue with session lists.

PR #18709 is a low-level type system refactoring, while PR #21504 fixes a client-side session list display issue.

@chenyy9527 chenyy9527 closed this Apr 8, 2026
@chenyy9527 chenyy9527 reopened this Apr 8, 2026
@chenyy9527 chenyy9527 closed this Apr 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SortableWorkspace session list empty due to store.path.directory not bootstrapped

1 participant