@sparkelf/dsh-patch-wsl-native-open 0.2.0-rc.21 → 0.2.0-rc.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -4,11 +4,11 @@
4
4
  "formatVersion": 1,
5
5
  "variants": [
6
6
  {
7
- "dsh": ">=0.1.7-alpha.2",
7
+ "dsh": ">=0.1.7-rc.1",
8
8
  "file": "./patches/wsl-native-open.patch",
9
9
  "id": "wsl-native-path-translation",
10
10
  "target": {
11
- "baseRevision": "00102833dfaee1da9f48a3a8eae9d34005a75218",
11
+ "baseRevision": "46a7f68b0922371ce7144b668b90e377d8e799f4",
12
12
  "kind": "dsh-source",
13
13
  "paths": [
14
14
  "packages/host/open-in-app/",
@@ -32,5 +32,5 @@
32
32
  "url": "git+https://github.com/SparkElf/deepseek-harness-plus.git"
33
33
  },
34
34
  "type": "module",
35
- "version": "0.2.0-rc.21"
35
+ "version": "0.2.0-rc.22"
36
36
  }
@@ -73,7 +73,7 @@ index 4b07441c8c..519ba1344b 100644
73
73
  return desktopId === undefined ? null : extractLinuxIcon(desktopId, completed)
74
74
  }
75
75
  diff --git a/packages/host/open-in-app/src/resolver.ts b/packages/host/open-in-app/src/resolver.ts
76
- index 62c6f8e4bc..1fec00b5c1 100644
76
+ index 970118e22a..ad8d176da4 100644
77
77
  --- a/packages/host/open-in-app/src/resolver.ts
78
78
  +++ b/packages/host/open-in-app/src/resolver.ts
79
79
  @@ -14,10 +14,11 @@
@@ -177,21 +177,13 @@ index 9ad8e0883c..3377ddcb6f 100644
177
177
  nativeFileManager,
178
178
  revealNativePath,
179
179
  diff --git a/packages/util/native-command/src/path-opener.ts b/packages/util/native-command/src/path-opener.ts
180
- index 618efa31b1..1356281211 100644
180
+ index 67bbc35902..dd062cc003 100644
181
181
  --- a/packages/util/native-command/src/path-opener.ts
182
182
  +++ b/packages/util/native-command/src/path-opener.ts
183
- @@ -11,7 +11,6 @@
184
-
185
- import { release as osRelease } from 'node:os'
186
- import { dirname, extname } from 'node:path'
187
- -import { pathToFileURL } from 'node:url'
188
- import { runNativeCommand, type NativeCommandRunner } from './runner.ts'
189
-
190
- /** Testable command boundary; native implementations never invoke a shell. */
191
- @@ -99,13 +98,49 @@ function isWsl(internals: PathOpenerInternals): boolean {
192
- return (internals.osRelease ?? osRelease()).toLowerCase().includes('microsoft')
193
- }
194
-
183
+ @@ -150,8 +150,55 @@ async function runExplorer(args: readonly string[], signal: AbortSignal, run: Pa
184
+ * @param signal - caller lifetime; abort terminates the command.
185
+ * @param run - shell-free command runner.
186
+ */
195
187
  +/**
196
188
  + * Windows PowerShell locations to try when PATH carries no Windows entry.
197
189
  + *
@@ -201,37 +193,42 @@ index 618efa31b1..1356281211 100644
201
193
  + * the volume the distribution mounts, and naming it there is what keeps the Windows
202
194
  + * desktop reachable from those processes.
203
195
  + */
204
- +const WINDOWS_POWERSHELL_CANDIDATES = [
205
- + '/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe',
206
- + '/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe',
196
+ +const WINDOWS_EXPLORER_CANDIDATES = [
197
+ + '/mnt/c/Windows/explorer.exe',
198
+ + '/c/Windows/explorer.exe',
207
199
  +] as const
208
200
  +
209
- /** Open one Windows-resolvable path through its registered desktop application. */
201
+ +/**
202
+ + * Open one Windows-resolvable path through its registered desktop application.
203
+ + *
204
+ + * Explorer resolves the association, but a process whose PATH lost its Windows entries
205
+ + * cannot name the shell. WSL injects those entries only for the processes it starts
206
+ + * interactively, so a service or scheduled job resolves nothing by name; naming the
207
+ + * shell on the volume the distribution mounts keeps the Windows desktop reachable.
208
+ + * @param path - Windows-resolvable path.
209
+ + * @param signal - caller lifetime; abort terminates the command.
210
+ + * @param run - shell-free command runner.
211
+ + */
210
212
  async function openWindowsPath(path: string, signal: AbortSignal, run: PathOpenerRunner): Promise<void> {
211
- - await run('powershell.exe', [
212
- + const args = [
213
- '-NoProfile',
214
- '-Command',
215
- `Invoke-Item -LiteralPath ${powershellLiteral(path)}`,
216
- - ], signal)
217
- + ]
213
+ - await runExplorer([explorerTarget(path)], signal, run)
214
+ + const target = explorerTarget(path)
218
215
  + try {
219
- + await run('powershell.exe', args, signal)
216
+ + await runExplorer([target], signal, run)
220
217
  + return
221
218
  + } catch (error) {
222
- + // A missing executable is the one failure a mounted path can answer; a non-zero
223
- + // exit from PowerShell itself is a real launch failure and must stay reported.
219
+ + // A missing executable is the one failure a mounted path can answer; any other
220
+ + // failure is Explorer's own and must stay reported.
224
221
  + if (!isMissingExecutable(error)) throw error
225
222
  + }
226
- + for (const candidate of WINDOWS_POWERSHELL_CANDIDATES) {
223
+ + for (const candidate of WINDOWS_EXPLORER_CANDIDATES) {
227
224
  + try {
228
- + await run(candidate, args, signal)
225
+ + await run(candidate, [target], signal)
229
226
  + return
230
227
  + } catch (error) {
231
228
  + if (!isMissingExecutable(error)) throw error
232
229
  + }
233
230
  + }
234
- + throw new Error('Windows PowerShell is not reachable from this WSL mount')
231
+ + throw new Error('Windows Explorer is not reachable from this WSL mount')
235
232
  +}
236
233
  +
237
234
  +/** Whether a spawn failed because the executable could not be found at all. */
@@ -240,7 +237,7 @@ index 618efa31b1..1356281211 100644
240
237
  }
241
238
 
242
239
  /** Translate a WSL path before handing it to the Windows desktop. */
243
- @@ -154,6 +189,25 @@ async function openNativePathWithIntent(
240
+ @@ -200,6 +247,25 @@ async function openNativePathWithIntent(
244
241
  throw new Error(`native path opener is unsupported on ${platform}`)
245
242
  }
246
243
 
@@ -266,20 +263,3 @@ index 618efa31b1..1356281211 100644
266
263
  /**
267
264
  * Whether {@link openNativePath} plausibly reaches a desktop on this host.
268
265
  *
269
- @@ -257,10 +311,13 @@ export async function revealNativePath(
270
- windowsPath = translated.stdout.replace(/[\r\n]+$/, '')
271
- if (windowsPath === '') throw new Error('wslpath returned no Windows path')
272
- }
273
- - // Explorer parses commas itself; a file URI preserves commas and whitespace in the path.
274
- - const target = pathToFileURL(windowsPath, { windows: true }).href.replaceAll(',', '%2C')
275
- + // Explorer takes the path itself: `wslpath -w` already produced the spelling it reads.
276
- + // A `file://` URL is not interchangeable here — a percent-encoded non-ASCII path (a CJK
277
- + // directory such as 题库) fails to resolve, and Explorer then opens its default location
278
- + // instead of selecting the file. Measured with a directory it had never opened: the native
279
- + // path selected 子目录/测试文件.txt, the URL form changed nothing.
280
- try {
281
- - await run('explorer.exe', ['/select,', target], signal)
282
- + await run('explorer.exe', ['/select,', windowsPath], signal)
283
- } catch (error) {
284
- signal.throwIfAborted()
285
- // Explorer can exit 1 after delegating to the existing desktop process.