Skip to content

cwd normalisation from #377 misses WSL /mnt/<drive> paths, so session/list cannot find sessions it just created #431

Description

@ycheoo

Summary

#377 made cwd comparison case-insensitive for Windows paths. The normalisation only recognises native Windows forms, so /mnt/c/... paths — what a Windows client passes when the agent runs inside WSL — still compare case-sensitively. Because Codex stores those paths lowercased in its thread index, session/list cannot find a session created moments
earlier with the very same cwd string.

Environment

  • @agentclientprotocol/codex-acp 1.6.2 (vendored @openai/codex 0.148.0, x86_64-unknown-linux-musl)
  • WSL2, Ubuntu 22.04, Node 22.23.2
  • cwd on a DrvFs mount, e.g. /mnt/c/Users/Me/Notes/MyVault

Reproduction

Over stdin, keeping stdin open for each reply:

  1. initialize
  2. session/new{"cwd": "/mnt/c/Users/Me: []} — succeeds
  3. session/list{"cwd": "/mnt/c/Users/Me/Notes/MyVault", "cursor": null}0 sessions
  4. session/list{"cwd": "/mnt/c/users/me/notes/myvault", "cursor": null}returns the session from step 2

Only the casing differs between steps 3 and

Cause

listSessions filters with arePathsEqual(thread.cwd, requestedCwd). thread.cwd comes from the Codex thread index, which stores /mnt/ paths lowercased. The same session ends up recorded twice with different casing:

Location cwd
~/.codex/sessions/.../rollout-*.jsonl, payload.cwd /mnt/c/Users/Me/Notes/MyVault
~/.codex/state_5.sqlite, threads.cwd lt`

normalizePathForComparison lowercases only when isWindowsAbsolutePath is true:

function isWindowsAbsolutePath(value) {
  const portableValue = value.replace(/\\/g, "/");
  return /^[A-Za-z]:\//.test(portableValue) || /^\/\/[^/]+\/[^/]+/.test(portableValue);
}

/mnt/c/Users/... matches neither, so it takes the POSIX branch and keeps its capitals, while the stored value has
none.

Paths under /home are unaffected, being lowercase already. WSL is not the cause: getcwd, realpath and
os.path.realpath all preserve the capitals

Suggested fix

Treat /mnt/<drive>/... as case-insensitive too — either by extending shouldComparePathCaseInsensitive with a ^/mnt/[a-z]/ test, or by lowercasing in normalizePathForComparison whenever the path resolves onto a DrvFs mount.

Downstream impact

The Obsidian Agent Client plugin passes the for its "Show current vault only" filter.Under WSL mode that filter is always empty for any vault on a Windows drive.

Note

@agentclientprotocol/claude-agent-acp 0.70.0 shows the same symptom, so the fix may be worth mirroring there.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions