Replies: 1 comment
Your diagnosis is right and it is still unfixed upstream — but two of your framings need adjusting1. Your quoted code is byte-exact, and the exit-1 tolerance is deliberate, not carelessAt // Explorer parses commas itself; a file URI preserves commas and whitespace in the path.
const target = pathToFileURL(windowsPath, { windows: true }).href.replaceAll(',', '%2C')
try {
await run('explorer.exe', ['/select,', target], signal)
} catch (error) {
signal.throwIfAborted()
// Explorer can exit 1 after delegating to the existing desktop process.
if (!(error instanceof Error) || !('code' in error) || error.code !== 1) throw error
}That comment is load-bearing. It was introduced by 2. But upstream has already written down the blind spot you foundThis is the part worth quoting back at them. An in-tree note records:
and a README bullet (after a later correction) reads:
So your observation is a real, acknowledged instance of exactly that gap — which is precisely why it deserves a proper record rather than a dismissal. Your instinct to keep the two traps documented is right. 3.
|
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Summary
With the Windows ACL sandbox active (
workspace-write, the default), revealing a file in Explorerfrom the GUI ("open" → "show in file manager") reports success and does nothing visible. The
folder window is created, the target file is even correctly selected inside it, but the window is
never shown, and the process exits with code 1 — which the caller accepts as a successful handoff.
The user sees a success toast ("已请求在文件管理器中显示" / "requested to show in file manager") and
no window.
Environment
@deepseek-ai/dsh0.1.5-rc.3; re-verified on 0.1.7-rc.2 (2026-09-25),where the reveal is still broken and the same fix is still required
dsh webGUI, profileweb, file policyworkspace-writeReproduction
dsh webwith the defaultworkspace-writepolicy.added there either).
What was measured (2026-09-23)
EnumWindows+Shell.Applicationwere used to inspect the windows after the reveal. Three windowsfor the same folder existed:
VisibleSelectedItems()Shell.Application.Exploreexplorer.exe /select,(the DSH path)explorer.exe /select,(the DSH path)So the reveal is doing its job — the folder is open and the file is selected — it just leaves the
window hidden.
Correction (2026-09-25): the cause is
windowsHide, not the restricted tokenThe 2026-09-23 investigation ran its probes from a sandbox child and attributed the invisible
window to that child's restricted token. A controlled A/B under the same token the host actually
uses (a plain, unrestricted user token) shows that attribution was wrong: upstream's code produces
the invisible window there too.
Method: two separate scratch folders, two probe files, and
revealNativePathimported from theunpatched
lib/index.js.origversus the patchedlib/index.js, in one process, same token.Window state read back through
Shell.Application:Visibleindex.js.orig_reveal_aprobe.txtindex.js_reveal_bprobe.txt_reveal_b - 文件资源管理器The mechanism is in the shared runner,
runNativeCommand(
@deepseek-ai/dsh-native-command/lib/index.js):windowsHide: trueis correct for a helper that should never flash a console — butexplorer.exe /select,is not such a helper: the folder window it hands to the shell is created aspart of a process launched hidden, and it stays hidden. Explorer then exits 1, and
runExplorerdeliberately accepts exit 1 as a delegated handoff, so nothing surfaces.
That single flag explains both halves of the bug: the window is never shown, and the caller is told
the handoff succeeded.
Why the COM route is immune
Shell.Applicationis hosted by the already-runningexplorer.exe, so the window is created bythat process and our hidden-child launch flag never applies to it. That is why routing the reveal
through COM displays the window, and why the sandbox token was never the deciding variable.
(Side note, measured on 0.1.7: from inside the sandbox the COM route cannot be used — the child
runs at Low integrity,
New-Object -ComObject Shell.Applicationfails with "拒绝访问", and pipedstdio to a child fails with
spawn EPERM. This does not affect the real path: the reveal is servedby the host process — HTTP route →
dsh-client-ui-deliverables→ctx.sessionController.openWorkspacePath→revealNativePath, seedsh-api-session-controller/lib/index.js.)Root cause
@deepseek-ai/dsh-native-command,revealNativePath(). On 0.1.7-rc.2 (unchanged in substance from0.1.5-rc.3, the encoding helper around it was refined):
Two problems compound here:
runNativeCommandstarts the child withwindowsHide: true(corrected attribution; see above).explorer.exeexits 1, andrunExplorerdeliberately treats exitcode 1 as a delegated handoff. So a reveal that displayed nothing is indistinguishable from a
successful one, and the UI reports success.
Secondary observation (unrelated to the invisibility): on 0.1.5-rc.3 the
/select,target was afile://URI rather than the native path the switch documents. 0.1.7 encodes that target morecarefully (
explorerTarget()decodes non-ASCII escapes and escapes both,and=), so this ismostly addressed upstream.
Resolution (applied locally by the reporter, 2026-09-23; re-applied to 0.1.7-rc.2 on 2026-09-25)
Route the reveal through the running shell's COM object instead of spawning
explorer.exe.Shell.Applicationis hosted by the already-runningexplorer.exe, so the window it creates isdisplayed:
The helper (abridged):
Measured after the change (2026-09-25 run, host-equivalent token):
Visible = False, foreground stays on the browserVisible = True,SelectedItems() = [target file], foreground switchesto the Explorer window
confirmed in the GUI that the window now pops up and shows the file
Three behaviours worth keeping if upstream rewrites the helper:
Explore()every time piles up duplicatewindows; during this investigation three appeared.
Document.Focus()throwsdoes not contain a method named 'Focus'on this shell object while the window is visible and thefile is selected; making that fatal would report a working reveal as failed — the same class of bug
as the swallowed exit code 1.
when no window can be raised, so a future regression is visible instead of being reported as
success.
A minimal upstream alternative, if spawning PowerShell is unwanted: keep the
explorer.exehand-offbut stop hiding it (
windowsHide: false, or a per-call override for the reveal), and keep the"distinguish a real failure from exit 1" handling.
I am happy to open a PR with the helper and the small call-site change if the approach is acceptable.
All reactions