authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-09-03 19:07:24-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-03 19:07:24-07:00
log617edab6539ee6573055dc9fc45fdeacdb12f673
tree22c7b05c4ff9aa081990619c467f5d23675dc81b
parent3e2c1a66f74f0a45768332c360cd3682f61129e1
signature Signed by PGP key B5690EEEBB952194

fix(server): reveal normalized paths in File Explorer (#9551)


2 files changed, 19 insertions(+), 5 deletions(-)

apps/server/src/process/externalLauncher.test.ts+10-4
......@@ -206,7 +206,9 @@ it.effect("reveals a file in File Explorer through PowerShell on Windows", () =>
206206 const launcher = yield* ExternalLauncher.ExternalLauncher;
207207 yield* launcher.launchEditor({
208208 editor: "file-manager",
209 cwd: "C:\\workspace with spaces\\media\\author's clip.mp4",
209 // Web file links normalize separators even when the server runs on
210 // Windows. Explorer's `/select` switch requires Windows separators.
211 cwd: "C:/workspace with spaces/media/author's clip.mp4",
210212 reveal: true,
211213 });
212214 return yield* launcher.resolveFileManagerRevealKind();
......@@ -261,8 +263,12 @@ it.skipIf(process.platform !== "win32")(
261263 const outputPath = NodePath.join(tempDir, "argv.txt");
262264 NodeFS.writeFileSync(recorderPath, `@echo off\r\n>"${outputPath}" echo(%*\r\n`);
263265
264 const target = "C:\\workspace with spaces\\media\\author's clip.mp4";
265 const source = ExternalLauncher.buildFileExplorerRevealPowerShellSource(recorderPath, target);
266 const target = "C:/workspace with spaces/media/author's clip.mp4";
267 const explorerTarget = target.replaceAll("/", "\\");
268 const source = ExternalLauncher.buildFileExplorerRevealPowerShellSource(
269 recorderPath,
270 explorerTarget,
271 );
266272 const powerShellPath = `${process.env.SYSTEMROOT ?? "C:\\Windows"}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;
267273 NodeChildProcess.execFileSync(
268274 powerShellPath,
......@@ -290,7 +296,7 @@ it.skipIf(process.platform !== "win32")(
290296 }
291297 await sleep(200);
292298 const recorded = NodeFS.readFileSync(outputPath, "utf8").trim();
293 assert.equal(recorded, `/select,"${target}"`);
299 assert.equal(recorded, `/select,"${explorerTarget}"`);
294300 } finally {
295301 NodeFS.rmSync(tempDir, { recursive: true, force: true });
296302 }
apps/server/src/process/externalLauncher.ts+9-1
......@@ -609,6 +609,10 @@ function fileExplorerRevealLaunch(
609609 };
610610}
611611
612function normalizeWindowsFileManagerPath(target: string): string {
613 return target.replaceAll("/", "\\");
614}
615
612616const resolveFileManagerRevealLaunch = Effect.fn("resolveFileManagerRevealLaunch")(function* (
613617 target: string,
614618 platform: NodeJS.Platform,
......@@ -626,7 +630,11 @@ const resolveFileManagerRevealLaunch = Effect.fn("resolveFileManagerRevealLaunch
626630 }
627631
628632 if (platform === "win32") {
629 return fileExplorerRevealLaunch(target, target, resolvePowerShellPath(env));
633 return fileExplorerRevealLaunch(
634 target,
635 normalizeWindowsFileManagerPath(target),
636 resolvePowerShellPath(env),
637 );
630638 }
631639
632640 if (