@sparkelf/dsh-patch-wsl-native-open 0.2.0-rc.8 → 0.2.1-alpha.1
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 +3 -3
- package/patches/wsl-native-open.patch +43 -37
package/package.json
CHANGED
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
"formatVersion": 1,
|
|
5
5
|
"variants": [
|
|
6
6
|
{
|
|
7
|
-
"dsh": ">=0.
|
|
7
|
+
"dsh": ">=0.2.0-rc.2",
|
|
8
8
|
"file": "./patches/wsl-native-open.patch",
|
|
9
9
|
"id": "wsl-native-path-translation",
|
|
10
10
|
"target": {
|
|
11
|
-
"baseRevision": "
|
|
11
|
+
"baseRevision": "5badb15009ae1756c3afe0ae0cef1faafc290ccc",
|
|
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.
|
|
35
|
+
"version": "0.2.1-alpha.1"
|
|
36
36
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
diff --git a/packages/host/open-in-app/src/icons.ts b/packages/host/open-in-app/src/icons.ts
|
|
2
|
-
index
|
|
2
|
+
index 4b07441c8c..519ba1344b 100644
|
|
3
3
|
--- a/packages/host/open-in-app/src/icons.ts
|
|
4
4
|
+++ b/packages/host/open-in-app/src/icons.ts
|
|
5
|
-
@@ -
|
|
5
|
+
@@ -98,6 +98,41 @@ const EXTRACT_ICON_PS1 = [
|
|
6
6
|
'',
|
|
7
7
|
].join('\n')
|
|
8
8
|
|
|
@@ -44,7 +44,7 @@ index 6908ce7..570dc45 100644
|
|
|
44
44
|
/** Extract one Windows executable's associated icon as a 32px PNG. */
|
|
45
45
|
async function extractExecutableIconPng(
|
|
46
46
|
executablePath: string, timeoutMs: number, internals: ResolvedInternals,
|
|
47
|
-
@@ -
|
|
47
|
+
@@ -107,8 +142,12 @@ async function extractExecutableIconPng(
|
|
48
48
|
const script = join(workDir, 'extract-icon.ps1')
|
|
49
49
|
const outPng = join(workDir, 'icon.png')
|
|
50
50
|
await writeFile(script, EXTRACT_ICON_PS1, 'utf8')
|
|
@@ -58,7 +58,7 @@ index 6908ce7..570dc45 100644
|
|
|
58
58
|
], timeoutMs, internals)
|
|
59
59
|
if (ran === null) return null
|
|
60
60
|
try {
|
|
61
|
-
@@ -
|
|
61
|
+
@@ -148,6 +187,13 @@ export async function extractAppIcon(
|
|
62
62
|
): Promise<OpenInAppIcon | null> {
|
|
63
63
|
const completed = resolveInternals(internals)
|
|
64
64
|
if (completed.platform === 'linux') {
|
|
@@ -73,10 +73,10 @@ index 6908ce7..570dc45 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
|
|
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
|
-
@@ -14,10 +14,
|
|
79
|
+
@@ -14,10 +14,11 @@
|
|
80
80
|
|
|
81
81
|
import { spawn } from 'node:child_process'
|
|
82
82
|
import { readdir, readFile, stat } from 'node:fs/promises'
|
|
@@ -84,12 +84,13 @@ index 7ab964b..8ea7318 100644
|
|
|
84
84
|
+import { homedir, release as osRelease, platform as osPlatform } from 'node:os'
|
|
85
85
|
import { dirname, isAbsolute, join } from 'node:path'
|
|
86
86
|
import {
|
|
87
|
-
- canOpenNativePath, openNativePath, runNativeCommand, type NativeCommandRunner,
|
|
88
|
-
+ canOpenLinuxDesktop, canOpenNativePath, openNativePath, runNativeCommand,
|
|
87
|
+
- canOpenNativePath, openNativePath, runNativeCommand, desktopEntryFields, desktopDataDirectories, type NativeCommandRunner,
|
|
88
|
+
+ canOpenLinuxDesktop, canOpenNativePath, openNativePath, runNativeCommand,
|
|
89
|
+
+ desktopEntryFields, desktopDataDirectories, type NativeCommandRunner,
|
|
89
90
|
} from '@deepseek-ai/dsh-native-command'
|
|
90
91
|
import { scrubbedParentEnv } from '@deepseek-ai/dsh-subprocess'
|
|
91
92
|
import {
|
|
92
|
-
@@ -98,6 +
|
|
93
|
+
@@ -98,6 +99,8 @@ export const launchDetachedApp: OpenInAppLauncher = (command, args, options) =>
|
|
93
94
|
/** Injectable platform facts for deterministic tests. */
|
|
94
95
|
export interface OpenInAppInternals {
|
|
95
96
|
platform?: NodeJS.Platform
|
|
@@ -98,7 +99,7 @@ index 7ab964b..8ea7318 100644
|
|
|
98
99
|
/** SSH launch fact from the inherited process layer, independent of `.env` values. */
|
|
99
100
|
ssh?: boolean
|
|
100
101
|
/** Bundle-directory roots replacing `/Applications` and `~/Applications`. */
|
|
101
|
-
@@ -115,6 +
|
|
102
|
+
@@ -115,6 +118,7 @@ export interface OpenInAppInternals {
|
|
102
103
|
/** Platform facts after the one explicit defaulting step at each public entry. */
|
|
103
104
|
export interface ResolvedInternals {
|
|
104
105
|
platform: NodeJS.Platform
|
|
@@ -106,7 +107,7 @@ index 7ab964b..8ea7318 100644
|
|
|
106
107
|
ssh: boolean
|
|
107
108
|
applicationRoots: readonly string[]
|
|
108
109
|
env: Readonly<Record<string, string | undefined>>
|
|
109
|
-
@@ -140,6 +
|
|
110
|
+
@@ -140,6 +144,7 @@ export function resolveInternals(internals: OpenInAppInternals): ResolvedInterna
|
|
110
111
|
}
|
|
111
112
|
return {
|
|
112
113
|
platform: internals.platform ?? osPlatform(),
|
|
@@ -114,7 +115,7 @@ index 7ab964b..8ea7318 100644
|
|
|
114
115
|
ssh: internals.ssh ?? false,
|
|
115
116
|
applicationRoots: internals.applicationRoots ?? ['/Applications', join(home, 'Applications')],
|
|
116
117
|
env: internals.env ?? process.env,
|
|
117
|
-
@@ -
|
|
118
|
+
@@ -453,6 +458,14 @@ export function specFor(app: OpenInAppApp, platform: NodeJS.Platform): OpenInApp
|
|
118
119
|
: undefined
|
|
119
120
|
}
|
|
120
121
|
|
|
@@ -129,7 +130,7 @@ index 7ab964b..8ea7318 100644
|
|
|
129
130
|
/** Icon source for a resolved executable: Windows extracts from the binary itself. */
|
|
130
131
|
function executableIcon(path: string, internals: ResolvedInternals): OpenInAppIconSource | undefined {
|
|
131
132
|
return internals.platform === 'win32' ? { kind: 'executable', path } : undefined
|
|
132
|
-
@@ -
|
|
133
|
+
@@ -504,10 +517,29 @@ async function locate(
|
|
133
134
|
}
|
|
134
135
|
}
|
|
135
136
|
case 'cli': {
|
|
@@ -164,7 +165,7 @@ index 7ab964b..8ea7318 100644
|
|
|
164
165
|
return found === null
|
|
165
166
|
? null
|
|
166
167
|
diff --git a/packages/util/native-command/src/index.ts b/packages/util/native-command/src/index.ts
|
|
167
|
-
index
|
|
168
|
+
index 9ad8e0883c..3377ddcb6f 100644
|
|
168
169
|
--- a/packages/util/native-command/src/index.ts
|
|
169
170
|
+++ b/packages/util/native-command/src/index.ts
|
|
170
171
|
@@ -6,6 +6,7 @@
|
|
@@ -176,13 +177,13 @@ index a2e23a3..f1ea7c6 100644
|
|
|
176
177
|
nativeFileManager,
|
|
177
178
|
revealNativePath,
|
|
178
179
|
diff --git a/packages/util/native-command/src/path-opener.ts b/packages/util/native-command/src/path-opener.ts
|
|
179
|
-
index
|
|
180
|
+
index 67bbc35902..dd062cc003 100644
|
|
180
181
|
--- a/packages/util/native-command/src/path-opener.ts
|
|
181
182
|
+++ b/packages/util/native-command/src/path-opener.ts
|
|
182
|
-
@@ -
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
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
|
+
*/
|
|
186
187
|
+/**
|
|
187
188
|
+ * Windows PowerShell locations to try when PATH carries no Windows entry.
|
|
188
189
|
+ *
|
|
@@ -192,37 +193,42 @@ index 8f3443b..79e7ace 100644
|
|
|
192
193
|
+ * the volume the distribution mounts, and naming it there is what keeps the Windows
|
|
193
194
|
+ * desktop reachable from those processes.
|
|
194
195
|
+ */
|
|
195
|
-
+const
|
|
196
|
-
+ '/mnt/c/Windows/
|
|
197
|
-
+ '/c/Windows/
|
|
196
|
+
+const WINDOWS_EXPLORER_CANDIDATES = [
|
|
197
|
+
+ '/mnt/c/Windows/explorer.exe',
|
|
198
|
+
+ '/c/Windows/explorer.exe',
|
|
198
199
|
+] as const
|
|
199
200
|
+
|
|
200
|
-
|
|
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
|
+
+ */
|
|
201
212
|
async function openWindowsPath(path: string, signal: AbortSignal, run: PathOpenerRunner): Promise<void> {
|
|
202
|
-
- await
|
|
203
|
-
+ const
|
|
204
|
-
'-NoProfile',
|
|
205
|
-
'-Command',
|
|
206
|
-
`Invoke-Item -LiteralPath ${powershellLiteral(path)}`,
|
|
207
|
-
- ], signal)
|
|
208
|
-
+ ]
|
|
213
|
+
- await runExplorer([explorerTarget(path)], signal, run)
|
|
214
|
+
+ const target = explorerTarget(path)
|
|
209
215
|
+ try {
|
|
210
|
-
+ await
|
|
216
|
+
+ await runExplorer([target], signal, run)
|
|
211
217
|
+ return
|
|
212
218
|
+ } catch (error) {
|
|
213
|
-
+ // A missing executable is the one failure a mounted path can answer;
|
|
214
|
-
+ //
|
|
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.
|
|
215
221
|
+ if (!isMissingExecutable(error)) throw error
|
|
216
222
|
+ }
|
|
217
|
-
+ for (const candidate of
|
|
223
|
+
+ for (const candidate of WINDOWS_EXPLORER_CANDIDATES) {
|
|
218
224
|
+ try {
|
|
219
|
-
+ await run(candidate,
|
|
225
|
+
+ await run(candidate, [target], signal, 'visible')
|
|
220
226
|
+ return
|
|
221
227
|
+ } catch (error) {
|
|
222
228
|
+ if (!isMissingExecutable(error)) throw error
|
|
223
229
|
+ }
|
|
224
230
|
+ }
|
|
225
|
-
+ throw new Error('Windows
|
|
231
|
+
+ throw new Error('Windows Explorer is not reachable from this WSL mount')
|
|
226
232
|
+}
|
|
227
233
|
+
|
|
228
234
|
+/** Whether a spawn failed because the executable could not be found at all. */
|
|
@@ -231,7 +237,7 @@ index 8f3443b..79e7ace 100644
|
|
|
231
237
|
}
|
|
232
238
|
|
|
233
239
|
/** Translate a WSL path before handing it to the Windows desktop. */
|
|
234
|
-
@@ -
|
|
240
|
+
@@ -200,6 +247,25 @@ async function openNativePathWithIntent(
|
|
235
241
|
throw new Error(`native path opener is unsupported on ${platform}`)
|
|
236
242
|
}
|
|
237
243
|
|