From fac0d8d877a6d85cde58edd27e13bfec953e4b32 Mon Sep 17 00:00:00 2001 From: mektpoy Date: Tue, 22 Sep 2026 17:35:54 +0800 Subject: [PATCH] docs(native-command): record the interactive-session requirement for Explorer opens --- ...2026-09-22-windows-open-through-shell-resolution.i18n.yaml | 4 ++-- .../2026-09-22-windows-open-through-shell-resolution.md | 4 +++- .../2026-09-22-windows-open-through-shell-resolution.zh.md | 4 +++- packages/util/native-command/README.i18n.yaml | 4 ++-- packages/util/native-command/README.md | 1 + packages/util/native-command/README.zh.md | 1 + 6 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.agents/notes/implemented/bug-fix/2026-09-22-windows-open-through-shell-resolution.i18n.yaml b/.agents/notes/implemented/bug-fix/2026-09-22-windows-open-through-shell-resolution.i18n.yaml index 793d1c261f..5f9cf4bdf9 100644 --- a/.agents/notes/implemented/bug-fix/2026-09-22-windows-open-through-shell-resolution.i18n.yaml +++ b/.agents/notes/implemented/bug-fix/2026-09-22-windows-open-through-shell-resolution.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-09-22-windows-open-through-shell-resolution.md -2026-09-22-windows-open-through-shell-resolution.md: 359d4163a06cc39b84f423940a22a1bf862dfbc8 -2026-09-22-windows-open-through-shell-resolution.zh.md: 755f9beacf8a635cccd63131acde5a6d072ee077 +2026-09-22-windows-open-through-shell-resolution.md: dac6b089d8d69d40a4cd7c92f4f74ee06f304329 +2026-09-22-windows-open-through-shell-resolution.zh.md: 8d2a00c6769906b568f605451d2afe339aed6dcf diff --git a/.agents/notes/implemented/bug-fix/2026-09-22-windows-open-through-shell-resolution.md b/.agents/notes/implemented/bug-fix/2026-09-22-windows-open-through-shell-resolution.md index 359d4163a0..dac6b089d8 100644 --- a/.agents/notes/implemented/bug-fix/2026-09-22-windows-open-through-shell-resolution.md +++ b/.agents/notes/implemented/bug-fix/2026-09-22-windows-open-through-shell-resolution.md @@ -34,8 +34,10 @@ The settings sheet's open gesture and the artifact and workspace opens share one The opener can no longer distinguish "the shell opened it" from "the shell declined": Explorer reports 0 or 1 for both, so the Remote still answers `{ opened: true }`, and a machine with no handler shows the shell's chooser as its only feedback. Nothing here verifies that a window appeared. +An interactive desktop session is a precondition. In a non-interactive Windows session (a service, or a scheduled task without an interactive logon) `explorer.exe` returned exit code 0 after about 30 seconds without invoking any association, where an `Invoke-Item` command opened the file in about 0.35 seconds: a Host started that way loses the capability and pays the wait, and a caller's abort signal is what bounds it. No fallback for that session is implemented. + Directories take the same path. The rejected alternative recorded in [the open-in-app note](../feature/2026-08-25-promote-open-anywhere-plugin.md) was a detached, credential-scrubbed `explorer.exe ` spawn, which is not what this handoff does: the `explorer.exe` child inherits the host environment and no detached process is created, while the application or folder window Explorer delegates to starts from the desktop session's environment rather than the host's. ## Verification -`path-opener.spec.ts` pins the encoded file URI Explorer receives for both intents, the accepted delegate exit code 1 for an open and a reveal, and the preserved failure and cancellation. `resolver.spec.ts` pins the open-in-app route's Windows command. Native desktop verification stays on Windows, per the package's test policy: on Windows 11 ARM64 build 26200 a probe association recorded the argument each handoff passed, and the opener's own commands opened the associated application for a plain file and for a file whose name contains a comma, while the same comma-bearing file handed over as a raw path opened the user's Documents folder instead — the shell split the path at the comma and reported nothing. A directory whose name contains a comma opened as a window rooted at that directory. Every one of these handoffs, successful ones included, exits 1. +`path-opener.spec.ts` pins the encoded file URI Explorer receives for both intents, the accepted delegate exit code 1 for an open and a reveal, and the preserved failure and cancellation. `resolver.spec.ts` pins the open-in-app route's Windows command. Native desktop verification stays on Windows, per the package's test policy. On Windows 11 ARM64 build 26200 an independent pass drove the module's own `openNativeAssociatedPath`, `openNativePath`, and `openNativeTextFile` from a sha256-matched copy beside an association probe that recorded every argument the shell passed: each comma-bearing target arrived complete as `%2C`, a plain file opened, and a directory named for a comma opened as a window rooted there. The negative control — the same file as a file URI whose comma is left raw — invoked no association and opened the user's Documents folder, and still exited 1. Exit 1 therefore records the delegation rather than the outcome, so accepting it cannot turn a wrong target into a success; the encoding is what keeps the path whole. Nothing here observes a window, and reveal's `/select,` highlight stays unverified. diff --git a/.agents/notes/implemented/bug-fix/2026-09-22-windows-open-through-shell-resolution.zh.md b/.agents/notes/implemented/bug-fix/2026-09-22-windows-open-through-shell-resolution.zh.md index 755f9beacf..8d2a00c676 100644 --- a/.agents/notes/implemented/bug-fix/2026-09-22-windows-open-through-shell-resolution.zh.md +++ b/.agents/notes/implemented/bug-fix/2026-09-22-windows-open-through-shell-resolution.zh.md @@ -34,8 +34,10 @@ Windows 对 HTML 与 SVG 仍然无法命名浏览器,因此 `openInBrowser` 打开器再也无法区分「shell 打开了」与「shell 拒绝了」:两种情况 Explorer 都返回 0 或 1,因此 Remote 依旧回答 `{ opened: true }`,完全没有处理程序的机器只能看到 shell 的选择框。此处不校验窗口是否真的出现。 +交互桌面会话现在是前提。在非交互 Windows 会话(服务,或没有交互登录的计划任务)中,`explorer.exe` 在约 30 秒后以退出码 0 返回且不调用任何关联,而 `Invoke-Item` 命令在同一会话里约 0.35 秒就打开了文件:这样启动的 Host 既失去能力又要付等待代价,只有调用方的 abort 信号能给这段等待封顶。该会话下的兜底尚未实现。 + 目录走同一条路径。[open-in-app 记录](../feature/2026-08-25-promote-open-anywhere-plugin.zh.md)中被否决的方案是 detached 且经过凭据清洗的 `explorer.exe ` 派生进程,那不是本交接的做法:`explorer.exe` 子进程继承宿主环境,也不创建 detached 进程;而它转交给桌面会话启动的应用或文件夹窗口,继承的是桌面会话环境而不是宿主进程环境。 ## 验证 -`path-opener.spec.ts` 固定两种意图交给 Explorer 的编码文件 URI、打开与选中都可接受的交接退出码 1,以及仍然报错的普通失败与取消。`resolver.spec.ts` 固定 open-in-app 路由在 Windows 上的命令。按该包测试策略,原生桌面验证留在 Windows:在 Windows 11 ARM64 build 26200 上,一个探针关联记录了每次交接实际收到的参数——打开器自身的命令对普通文件、以及文件名含逗号的文件都启动了关联应用;而同一个含逗号文件若以原始路径交接,则会打开用户的「文档」文件夹,shell 在逗号处分段且不作任何提示。名称含逗号的目录会以该目录为根打开窗口。上述每一次交接(包括成功的那些)退出码都是 1。 +`path-opener.spec.ts` 固定两种意图交给 Explorer 的编码文件 URI、打开与选中都可接受的交接退出码 1,以及仍然报错的普通失败与取消。`resolver.spec.ts` 固定 open-in-app 路由在 Windows 上的命令。按该包测试策略,原生桌面验证留在 Windows。在 Windows 11 ARM64 build 26200 上,一次独立验证用 sha256 与源码一致的副本直接驱动模块自身的 `openNativeAssociatedPath`、`openNativePath`、`openNativeTextFile`,旁边挂一个记录 shell 实收参数的探针关联:每个含逗号的目标都以 `%2C` 完整到达、普通文件正常打开、名为 `dir,comma` 的目录打开为根目录正确的窗口。反证——同一个文件以逗号未编码的 file URI 交给 `explorer.exe`——没有触发任何关联、打开了用户的「文档」,而且**同样返回退出码 1**。因此退出码 1 记录的是委派而非结果,接受它不会把错误目标变成成功;真正保住路径完整的是那段编码。此处不观测窗口是否出现,选中路径的 `/select,` 高亮仍未验证。 diff --git a/packages/util/native-command/README.i18n.yaml b/packages/util/native-command/README.i18n.yaml index 0e2bf74b61..d829a16ffc 100644 --- a/packages/util/native-command/README.i18n.yaml +++ b/packages/util/native-command/README.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write packages/util/native-command/README.md -README.md: b158cbf3153962af14ed99c07f7527f4bdb86f89 -README.zh.md: f02a37480934122dbf569983105b43b9962b894c +README.md: 72c9d0097975773d316e3f2fdba87da1eca4daa4 +README.zh.md: 35770a99756a9eb218b024406690b340c09bfd84 diff --git a/packages/util/native-command/README.md b/packages/util/native-command/README.md index b158cbf315..72c9d00979 100644 --- a/packages/util/native-command/README.md +++ b/packages/util/native-command/README.md @@ -109,6 +109,7 @@ Linux association discovery and explicit launching require GIO. Missing native c These limits define when this runner is not the right tool. They are current package constraints, not a task backlog. - Command output uses Node’s `execFile` buffer limit; oversized replies reject. Use the subprocess capability for streaming output. +- A Windows host needs an interactive desktop session. In a non-interactive session — a service, or a scheduled task without an interactive logon — `explorer.exe` returns exit code 0 after about 30 seconds without invoking any file association, so an open reports success having opened nothing; a caller's abort signal turns that wait into a timeout rather than a hang. An `Invoke-Item` command resolves the association in-process there in about 0.35 seconds, and its directory failure arrives as a non-zero exit code. No fallback for that session is implemented. ### Dev Note diff --git a/packages/util/native-command/README.zh.md b/packages/util/native-command/README.zh.md index f02a374809..35770a9975 100644 --- a/packages/util/native-command/README.zh.md +++ b/packages/util/native-command/README.zh.md @@ -109,6 +109,7 @@ Linux 的关联查询和指定应用启动需要 GIO。缺少原生命令时查 这些限制说明本运行器何时不是合适的工具。它们是当前包约束,不是任务积压。 - 命令输出受 Node 的 `execFile` 缓冲上限约束,超过上限时拒绝结果。流式输出由 subprocess 能力处理。 +- Windows 主机需要交互桌面会话。在非交互会话(服务,或没有交互登录的计划任务)中,`explorer.exe` 会在约 30 秒后以退出码 0 返回且不调用任何文件关联,于是「打开」会报告成功却什么都没打开;调用方的 abort 信号把这段等待变成超时而不是挂死。同一目标改用 `Invoke-Item` 命令时,该会话内约 0.35 秒即可在进程内解析关联,目录失败也会以非零退出码报出。该会话下的兜底尚未实现。 ### 开发备注