Skip to content

feat(doctor): detect Cursor IDE UNC-mode WSL repos where hooks never fire - #2078

Open
peyton-alt wants to merge 6 commits into
mainfrom
fix/cursor-unc-mode-doctor
Open

feat(doctor): detect Cursor IDE UNC-mode WSL repos where hooks never fire#2078
peyton-alt wants to merge 6 commits into
mainfrom
fix/cursor-unc-mode-doctor

Conversation

@peyton-alt

@peyton-alt peyton-alt commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

https://entire.io/gh/entireio/cli/trails/1106

Summary

Customer report: Cursor IDE sessions on Windows + WSL2 never appear in entire session list until a manual entire session attach, while Cursor CLI in the same repo tracks fine.

Root cause, verified empirically on a Windows Server 2022 + WSL2 + Cursor 3.16.29 VM with paired sh-vs-cmd discriminator hooks: Cursor IDE executes zero hooks when a WSL repo is opened via a \\wsl$ UNC path (agent runs, transcript saves, not one hook fires, no log mention — Cursor's own dialog marks the mode "not recommended"). In WSL-remote mode ("Reopen Folder in WSL") the same repo's hooks execute inside WSL with correct CWD and Entire tracking works end-to-end. There is no CLI-side fix for UNC mode — nothing invokes us — so this PR makes the silent failure visible:

  • cursor.DetectUNCProjectDirs finds the Windows-side fingerprint from inside WSL: ~/.cursor/projects/wsl[-localhost]-<distro>-<sanitized repo path>/ dirs (both UNC spellings, case-insensitive, distro sanitized like the path — Ubuntu-22.04Ubuntu-22-04) that carry a non-empty agent-transcripts/ with activity in the last 14 days.
  • entire doctor gains a warn-only checkCursorUNCMode (gated: WSL env → worktree → cursor hooks installed → scan) telling the user to reopen in WSL. The recency window makes the warning self-clear after a user switches modes.
  • AGENT.md documents the WSL-remote vs UNC split and the macOS-verified multi-root findings.

Design decisions

  • All Windows profiles under /mnt/c/Users are scanned because the WSL username need not match the Windows one; on shared machines this can warn user A about user B's usage — accepted for a warn-only probe.
  • No ✓ OK line when healthy: this is an environment probe, not an install-state check; absence of the fingerprint isn't proof of health.
  • DetectUNCProjectDirs returns the matched paths (not a bool): the tests pin which dirs matched, which caught a real partial-match regression during review.
  • Known silent false negatives (documented in the code): Windows not on C:, remapped automount.root, drive-letter mappings of \\wsl$.

Also fixed along the way

A four-agent review pass on this branch surfaced a pre-existing production bug: sanitizePathForCursor mapped non-alphanumerics per-character while Cursor collapses runs to a single dash, so transcript resolution (GetSessionDir) — and this PR's fingerprint matching — silently missed any repo path with adjacent non-alphanumerics (e.g. anything under a .worktrees/ layout). Fixed in the shared sanitizer ([^a-zA-Z0-9]+); all pre-existing sanitizer tests pass unchanged. The same pass added a ±clock-skew tolerance to the evidence window (WSL2 lags the Windows clock after host sleep, which would have suppressed the warning for live UNC sessions).

Follow-ups (deliberate, not in this PR)

  • Surface the warning in entire status (+ --json): doctor is a command the affected user has no reason to run; status is where they look when "nothing is tracked". status.go's hooks_outdated pattern is the ready-made home.
  • Multi-root quirks (every root's hooks fire for one conversation; stop transcript_path keys to the first root) — need a design pass on session-ownership semantics.
  • Recovering already-run UNC sessions via attach/import discovery of the Windows-side transcript dirs.
  • Windows-native binary: the same broken state is detectable without fingerprinting (the repo root itself starts with \\wsl$\ / \\wsl.localhost\) — this PR's check only fires from inside WSL.

Testing

  • TestDetectUNCProjectDirs (+ versioned-distro case): both UNC spellings, case-insensitivity, browsed-only/different-repo/native-Windows negatives, empty and 30-day-stale evidence negatives, empty-distro and missing-root nil contracts.
  • Doctor: positive-path warning test via injectable users root + real hooks fixture; hooks-gate silence test against a populated root.
  • Review was mutation-verified: sanitization, recency window, evidence gate, case-folding, and both doctor gates each kill a mutant.
  • mise run fmt && mise run lint && mise run test — clean, 9368 tests.

🤖 Generated with Claude Code


Note

Cursor Bugbot is generating a summary for commit 92a6482. Configure here.

peyton-alt and others added 3 commits August 19, 2026 16:45
…WSL repo

Cursor IDE on Windows executes zero hooks when a WSL repo is opened via a
\\wsl$ UNC path (verified empirically on Windows Server 2022 + WSL2 + Cursor
3.16.29: agent session completes, transcript written, no hook runs, no log
mention), so Entire tracking silently never starts. The mode leaves a
fingerprint: a Windows-side ~/.cursor/projects/<wsl...-distro-sanitized-path>
directory, gaining agent-transcripts/ once an agent session ran there. This
scanner finds that fingerprint from inside WSL via /mnt/c/Users so doctor can
name the failure instead of leaving it to a support thread.

The distro name is sanitized like the path (Ubuntu-22.04 → Ubuntu-22-04,
matching Cursor's whole-UNC-path transform), names compare case-insensitively
(Explorer preserves the user's spelling), and evidence must be a non-empty
agent-transcripts dir with activity in the last 14 days so leftover state
stops warning after a switch to WSL mode.

UNCProjectDirNames is exported so tests and future callers share the naming
rule instead of re-deriving it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s fire)

The failure is otherwise perfectly silent: the agent works, transcripts save,
and Entire never hears about the session. Warn-only next to the other
agent-specific doctor checks; the only fix is user-side (reopen in WSL), so
the check names it. Gated on WSL_DISTRO_NAME, cursor hooks installed in this
repo, and an agent-transcripts-bearing Windows-side fingerprint dir, so every
other environment stays silent. The healthy case prints no OK line on
purpose: this is an environment probe, not an install-state check.

The users root is a package var so the warning path is testable; guidance
leads with Reopen Folder in WSL because the cursor shim in WSL only exists
after a first WSL-remote connect.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Records the empirical finding backing the doctor check: Cursor fires hooks
only in WSL-remote mode, never in \\wsl$ UNC mode.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@peyton-alt
peyton-alt requested a review from a team as a code owner August 19, 2026 23:48
Copilot AI lite review requested due to automatic review settings August 19, 2026 23:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a doctor warning to make a previously silent failure mode visible: when Cursor IDE on Windows opens a WSL repo via \\wsl$ UNC paths, Cursor runs the agent but executes no hooks, so Entire can’t track sessions. The PR introduces a WSL-side detector that fingerprints Cursor’s Windows-side project dirs and surfaces a warn-only remediation hint (“Reopen Folder in WSL”).

Changes:

  • Add a doctor check (checkCursorUNCMode) gated to WSL + repo worktree + Cursor hooks installed, warning when recent UNC-mode activity is detected.
  • Introduce cursor.DetectUNCProjectDirs to detect UNC-mode project dirs via Windows-side Cursor fingerprints + recent agent-transcripts evidence.
  • Add unit tests for both the detector and doctor integration, plus Cursor agent documentation updates for Windows+WSL behavior.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
cmd/entire/cli/doctor.go Runs the new WSL-only Cursor UNC-mode diagnostic and prints a warn-only guidance message.
cmd/entire/cli/doctor_test.go Adds tests covering the warning path and the “silent when hooks not installed” gate.
cmd/entire/cli/agent/cursor/uncmode.go Implements UNC-mode fingerprint detection by scanning Windows user profiles and checking recent transcript evidence.
cmd/entire/cli/agent/cursor/uncmode_test.go Adds unit tests for UNC spelling variants, case-insensitivity, and evidence/recency gating.
cmd/entire/cli/agent/cursor/AGENT.md Documents Cursor’s WSL-remote vs UNC behavior and how doctor detects the UNC mode.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread cmd/entire/cli/agent/cursor/uncmode.go Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 92a6482. Configure here.

Comment thread cmd/entire/cli/agent/cursor/uncmode.go
peyton-alt and others added 3 commits August 19, 2026 17:25
…itizing paths

Cursor collapses runs of non-alphanumeric characters into a single "-" when
building a project directory name; our per-character transform did not. Real
project dirs on disk contain zero "--": a path with "/.worktrees/" becomes
"...-cli-worktrees-..." on disk, while our transform produced
"...-cli--worktrees-...". Both UNC fingerprint matching and the pre-existing
GetSessionDir transcript resolution silently missed any repo path with
adjacent non-alphanumerics as a result.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Evidence mtimes come from the Windows filesystem clock via DrvFs, and WSL2's
own clock drifts behind the host after sleep. Without tolerance, a live
UNC-mode session's newest transcript entry can read as "in the future"
relative to WSL's now, and the age>=0 guard silently discarded exactly the
freshest evidence. Bounded skew (up to 24h behind) now counts; mtimes far
enough in the future to be bogus still don't.

UNCEvidenceWindow is exported so doctor.go can name the actual window in its
message instead of hardcoding "14 days".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- DetectUNCProjectDirs: match names via slices.ContainsFunc instead of
  indexing into the two-element slice; slim its doc comment to the essentials
  and defer spelling details to UNCProjectDirNames; fix the junction-skip
  comment to name the actual NTFS stubs (All Users, Default User) instead of
  a vague "profile-root junction symlinks".
- Move the C:-drive/default-automount caveat to a one-liner next to
  doctor.go's cursorWindowsUsersRoot var, which is the thing that actually
  assumes it.
- checkCursorUNCMode: point at cursor/AGENT.md's Windows + WSL section
  instead of an unverifiable "verified empirically" comment; scope the
  headline and body to what the evidence actually shows ("recent sessions
  ran over \\wsl$" / "Sessions opened this way are never tracked"), so a user
  who already switched to WSL-remote mode doesn't read an absolute "never
  tracked" about their current setup; log a debug line (count only, no
  paths) when the fingerprint matches.
- Tests: positive doctor test also asserts the "Reopen Folder in WSL" fix
  hint; folded the versioned-distro case into the main detector test as a
  second sub-fixture; folded the empty-transcripts helper into mkProjectDir
  via a withEvidence flag instead of a separate one-off helper.
- AGENT.md: point the multi-root known-quirks sentence at PR #2078.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants