Repository navigation
Conversation
Normalize Windows absolute drive paths and tolerate valid path spaces in chat link parsing and workspace-relative resolution. Previously, toWorkspaceRel only stripped POSIX leading slashes against the workspace root, leaving Windows drive paths unstripped and causing file resolution to report missing files for valid workspace items. Additionally, FILE_TOKEN_RE and SCAN_RE rejected paths with Windows drive letters, backslashes, or spaces, leaving inline code paths inert. Fixes vastsa#1169
|
I confirmed the reported bug is real, but this PR is not yet root-complete, so I cannot merge it as-is. The new |
… resolution Complete chat link scanning for workspace-anchored paths containing spaces (both Windows drive paths and POSIX absolute roots). Previously, splitChatText fragmented anchored paths with spaces because the static SCAN_RE terminated at whitespace. Now, getScanRegex builds root prefix patterns so anchored paths with spaces are captured whole and evaluated up to the likely file path boundary. Additionally, confirmed and documented that Markdown's InlineCode component already previews file paths via resolvePreviewTarget, and added regression coverage in chat-links.test.mjs.
|
Thanks for the thorough verification and sharp catch on I've completed the implementation and addressed both points:
All tests in |
`main` is currently red, and it is not a flake:
CI vastsa#1197 166ada6 failure Typecheck Desktop
CI vastsa#1195 967f3c2 failure Typecheck Desktop
CI vastsa#1192 db16f9c failure Typecheck Desktop
CI vastsa#1189 4fedb8e success <- last green main run I can see
All three failures are the same line:
electron/main/user-login-path.ts(28,74): error TS2345: Argument of type
'string | undefined' is not assignable to parameter of type 'PathLike'.
**Root cause.** `Boolean(candidate) && existsSync(candidate)` is inside a type
predicate:
const shell = [process.env.SHELL, "/bin/zsh", "/bin/bash", "/bin/sh"].find(
(candidate): candidate is string => Boolean(candidate) && existsSync(candidate),
);
A type predicate constrains what the *caller* sees; it does not narrow the
parameter inside its own body, and `Boolean(candidate)` is not a narrowing call.
So the body still has `string | undefined` and `existsSync` rejects it.
**Fix.** Narrow with a real check, which keeps the predicate at the call site and
satisfies the body:
(candidate): candidate is string =>
typeof candidate === "string" && existsSync(candidate),
The file arrived with `574c78a9` ("fix(mcp): spawn stdio servers with the
login-shell PATH"). That commit is 1 ahead / 8 behind `4fedb8e4` — it landed on
`main` after the last green run, which is where main turns red.
**Verification** (Windows 11; `pnpm install --filter @pi-desktop/desktop...
--ignore-scripts`, `pnpm --filter "@pi-desktop/desktop^..." build`):
- Pristine file, the CI command `pnpm --filter @pi-desktop/desktop typecheck`
→ exit 2 with `user-login-path.ts(28,74): error TS2345` — the same file,
line and column as CI. With the fix → **exit 0**.
- `pnpm lint` → exit 0.
- `node scripts/check-architecture.mjs` → Architecture check passed.
- `node --test test/user-login-path.test.mjs` → 4/4 pass.
- Full `apps/desktop` suite: 2452 tests; 43 fail with the pristine file and 42
with the fix. Both failure sets are the same macOS-only group (codesign, DMG,
notarization, ssh askpass, process groups) plus a couple of load-sensitive
timeout-budget tests; I could not make those two pass on either revision, and
nothing in this change can reach them. Recording it rather than claiming the
suite is green.
Summary
Fixes #1169 by properly parsing Windows drive paths and paths containing spaces in chat messages and tool records, ensuring they resolve to interactive workspace file links.
Motivation & Root Cause
As documented in #1169:
C:\demo project\readme.md, the UI reported: "没有匹配 C:/demo project/readme.md 的文件" ("No matching file...").toWorkspaceRelinapps/desktop/src/lib/chat-links.tsonly checked for leading slashes (path.startsWith("/")). On Windows, drive-anchored paths likeC:\demo project\readme.mdfell through to the relative path branch without stripping the workspace root prefix, passingC:/demo project/readme.mdas the relative path tofsResolveRef.InlineCode) and conversational text, Windows paths or paths with spaces (e.g.C:\demo project\readme.mdor/Users/me/my project/page.md) were rendered as plain non-clickable code.FILE_TOKEN_REandSCAN_REonly allowed tokens matching[\p{L}\p{N}_@+.-], rejecting Windows drive letters (C:), backslashes, and paths with spaces.Key Changes
apps/desktop/src/lib/chat-links.ts:toWorkspaceRelto detect both POSIX absolute paths (/) and Windows drive absolute paths ([a-zA-Z]:/). Normalizes backslashes, compares roots case-insensitively for drive letters, and safely slices the workspace-relative path.FILE_TOKEN_REto allow Windows drive anchors and valid directory/file names with spaces.SCAN_REto capture Windows drive-prefixed paths whole without fragmentation.apps/desktop/test/chat-links.test.mjs:parseFileRef,toWorkspaceRel,resolvePreviewTarget, andsplitChatTextwith Windows native paths, mixed slashes, spaces, and POSIX paths with spaces.apps/desktop/test/chat-ref-resolve.test.mjs:Verification
node apps/desktop/test/chat-links.test.mjs: 26/26 passed.node apps/desktop/test/chat-ref-resolve.test.mjs: 22/22 passed.node apps/desktop/test/tool-row-file-refs.test.mjs: 8/8 passed.node apps/desktop/test/verified-chat-files.test.mjs: 7/7 passed.node apps/desktop/test/transcript-file-chips.test.mjs: 4/4 passed.pnpm lint: Checked 97 files, style tokens OK.pnpm check:pr-base: Passed against upstreammain.