Repository navigation
Description
Summary
In the Terminal, Ctrl-click on a Windows-style relative path does nothing, because it isn't detected as a link. Compilers and test runners on Windows print these all the time (src\index.ts:12, .\src\index.ts:12:7, ..\lib\a.ts:3). ~/… paths also fail to expand when the working directory is a Windows home path written in lower case (c:\users\jane\…) or with forward slashes (C:/Users/Jane/…). A quoted path with spaces is cut at the first space.
T3 Code fixed the same parser in pingdotgg/t3code#21199 and #19627. BiBCode's terminal-links.ts has the same patterns they changed.
Current behavior (verified at a0ea849ef92b)
Detection (apps/web/src/terminal-links.ts)
FILE_PATH_PATTERNat:41-42:The/(?:~\/|\.{1,2}\/|\/|[A-Za-z]:[\\/]|\\\\)[^\s"'`<>]+|[A-Za-z0-9._-]+(?:\/[A-Za-z0-9._-]+)+(?::\d+){0,2}/g~,./and../prefixes and the bare relative form (dir/file) accept only/. Drive-letter paths (C:\…,C:/…) and UNC paths already work.- The file is imported by the find projection worker (file header), so it has to stay dependency-free.
- The link provider is registered in
apps/web/src/components/ThreadTerminalPanel.tsx:1715.
Resolution
resolvePathLinkTarget(:381-398) expands~/only (not~\) throughinferHomeFromCwd.inferHomeFromCwd(:142-160) matches a Windows home with/^([A-Za-z]:\\Users\\[^\\]+)/at:153. That is case-sensitive (Users) and backslash-only.- Helpers:
isWindowsAbsolutePath(:122-124),isWindowsPathStyle(:130-132),joinPath(:134-140).packages/shared/src/path.ts:28-32has a relatedisAbsoluteHostPath.
Reproduced by running the module at a0ea849ef92b under Node 24 (extractTerminalLinks and resolvePathLinkTarget):
| Input | Today | Expected |
|---|---|---|
src\index.ts:12 |
no link | src\index.ts:12 |
.\src\index.ts:12:7 |
no link | .\src\index.ts:12:7 |
..\src\index.ts:12 |
no link | ..\src\index.ts:12 |
C:\Users\Jane\p\i.ts:12 |
C:\Users\Jane\p\i.ts:12 |
same |
"C:\Users\Jane Doe\p\i.ts:12" |
C:\Users\Jane (cut at the space) |
C:\Users\Jane Doe\p\i.ts:12 |
src/index.ts:12 |
src/index.ts:12 |
same |
~/x.ts in C:\Users\Jane\proj |
C:\Users\Jane\x.ts |
same |
~/x.ts in c:\users\jane\proj |
~/x.ts (not expanded) |
c:\users\jane\x.ts |
~/x.ts in C:/Users/Jane/proj |
~/x.ts (not expanded) |
C:/Users/Jane/x.ts (separator: see Open questions) |
~\x.ts in C:\Users\Jane\proj |
C:\Users\Jane\proj\~\x.ts (wrong file) |
C:\Users\Jane\x.ts |
Existing tests – apps/web/src/terminal-links.test.ts: "finds Windows absolute paths with forward slashes" (:62), "expands home paths for macOS, Linux, and Windows cwd styles" (:292), "joins relative Windows paths and trims existing cwd separators" (:305). None of them cover backslash relative paths, ~\, a lower-case or forward-slash Windows home, or quoted paths with spaces.
Steps to reproduce
- On a Windows environment, open a Terminal in a project.
- Run
echo src\index.ts:12(or any tool that prints a relative backslash path). - Hover and Ctrl-click the path.
Expected: it's underlined and opens src\index.ts at line 12 in the editor.
Actual: it isn't a link. The same happens for .\… and ..\…. ~\… resolves under the working directory instead of the home.
Proposed change
- Accept both separators in relative forms (as T3 #21199):
/(?:~[\\/]|\.{1,2}[\\/]|\/|[A-Za-z]:[\\/]|\\\\)[^\s"'`<>]+|[A-Za-z0-9._-]+(?:[\\/][A-Za-z0-9._-]+)+(?::\d+){0,2}/g - Quoted paths with spaces. Add a quoted-path pattern that keeps the whole path between matching quotes, plus a
:line[:col]suffix inside or outside the quotes. A quoted match wins over a partial unquoted token. Keep the range correct across wrapped rows (resolveWrappedTerminalLinkRange). - Home detection, case-insensitive, both slashes (as T3 #19627):
/^([A-Za-z]:[\\/]Users[\\/][^\\/]+)/i. Expand~\as well as~/when the cwd is Windows-style. - Relative backslash paths resolve against the cwd with
joinPath, the same as/paths today..\and..\segments are kept as they are, like./and../today. - Keep the module dependency-free.
T3 Code reference (their claims, not measured by us)
- pingdotgg/t3code#21199, "recognize Windows terminal file links" (merged 2026-10-18). They report that
src\index.ts:12and.\src\index.ts:12didn't match and that"C:\Users\Jane Doe\project\index.ts:12"was cut toC:\Users\Jane. Their fix: the regex above, aQUOTED_FILE_PATH_PATTERNwith precedence over partial tokens,~\expansion, andit.eachcases (src\index.ts:12,.\src\index.ts:12:7,..\src\index.ts:12,C:\Users\Jane\project\index.ts:12, quoted paths). - pingdotgg/t3code#19627, "match Windows home paths case-insensitively in file links" (merged 2026-10-18): the home regex above, in
packages/shared/src/fileLinks.ts.
Acceptance criteria
- Table-driven unit tests in
apps/web/src/terminal-links.test.ts(it.each), run fromapps/webwithvp test run --project unit src/terminal-links.test.ts:extractTerminalLinks: every row of the table above, plus..\..\a\b.ts:1:2,src\a.ts:12:(trailing colon trimmed),(src\a.ts:12)(delimiters trimmed),'.\a b\c.ts', a backtick-quoted path, a line with a URL and a backslash path (both found, no overlap), and\\server\share\a.ts(still detected, and still refused as a network path on activation);resolvePathLinkTarget:~/and~\withC:\Users\Jane\…,c:\users\jane\…,C:/Users/Jane/…andc:/USERS/jane/…;.\src\a.ts:3andsrc\a.tsagainstC:\repoandC:\repo\; POSIX home and relative cases unchanged.- With only
terminal-links.tsreverted, the new cases fail.
- Wrapped lines: a quoted path with spaces that wraps across two rows maps back to the right buffer range (a
resolveWrappedTerminalLinkRangetest). - Existing behavior unchanged: all current
terminal-links.test.tscases, URL detection,file://handling, OSC 8 links, and the network-path refusal ("Network paths can't be opened from the terminal."). - Desktop e2e:
vp run test:ui:desktop, includingapps/desktop/e2e/specs/project-session-terminal.e2e.tsandterminal-font.e2e.ts. If the Windows native desktop job can run a terminal link check, add thesrc\index.ts:12case there; otherwise say so in the PR. - Gates:
vp check(zero warnings),vp run typecheck, Release Smoke. No Rust or contract changes are expected; if any appear,cargo fmt --all --check,cargo clippy --workspace --all-targets -- -D warnings,cargo test --workspaceandvp run check:contractstoo. - UI.md and
vercel-react-best-practicesreviews are recorded.docs/testing/runbooks are reviewed (cross-platform-validation.md:3632-3645, terminal links) and updated or stated "remain accurate". - Profiler coverage line in the delivery report. Terminal content and paths never reach profiler records or logs.
Living docs to update
docs/user/workspace-ui.md:1495-1508(Terminal links): Windows relative paths,~\, quoted paths with spaces.docs/testing/cross-platform-validation.md:3632-3645: add a Windows relative-path row to the manual check.
Not in scope
- Chat and Markdown file links (a different parser).
- Opening network paths; they stay refused.
- Normalizing
.\/..\before opening.
Related
- None found in BiBCode's open or closed issues (searched for terminal link, Windows path, backslash).
Open questions
- Should a bare
dir\filebe linked when the cwd is POSIX? It's a legal but rare filename there; T3 links it everywhere. - For a forward-slash Windows home (
C:/Users/Jane), which separator should the expanded path use?isWindowsPathStyletreatsC:/…as Windows style, sojoinPathwould produce a mixedC:/Users/Jane\x.ts. Keeping the home's own separator seems safer.
Activity
mubeda commentedon Oct 31, 2026
Triage, 2026-10-31. Not going into PR #213 (#139 MCP batch). It goes in a follow-up PR after that release. Batch 2 (quick fixes): small and independent of #213.
Planned order after the release: (1) #222 copy lint; (2) quick fixes #228, #221, #229, #231, #232; (3) MCP #220; (4) performance #225, then #223, #226, #227; (5) features #230, #224, #211, #212; (6) #210 after a Windows repro.