@sparkelf/dsh-plus 0.2.1-rc.2.4 → 0.2.2-alpha.2.10

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.
Files changed (37) hide show
  1. package/README.md +7 -5
  2. package/README.zh.md +7 -5
  3. package/lib/apply-08huHfLG.js +665 -0
  4. package/lib/apply-DmICvIGh.js +653 -0
  5. package/lib/apply.js +1 -1
  6. package/lib/bin.js +229 -47
  7. package/lib/types/apply.d.ts +1 -1
  8. package/lib/types/apply.js +56 -117
  9. package/lib/types/patch-set.d.ts +59 -0
  10. package/lib/types/patch-set.js +132 -0
  11. package/lib/types/standalone-cli.js +93 -2
  12. package/lib/types/standalone-profile.d.ts +8 -1
  13. package/lib/types/standalone-profile.js +191 -53
  14. package/package.json +603 -175
  15. package/patches/approval-allow-policy.patch +108 -0
  16. package/patches/atomic-write-zombie-lock-holder.patch +53 -0
  17. package/patches/bootstrap-exempt-names.patch +32 -0
  18. package/patches/browser-auth-mode.patch +127 -0
  19. package/patches/composer-popover-boundaries.patch +337 -0
  20. package/patches/diagram-preview.patch +562 -0
  21. package/patches/image-offload-hoist-replay.patch +533 -0
  22. package/patches/legacy-code-preset.patch +148 -0
  23. package/patches/llm-pi-ai-transport-truncation.patch +33 -0
  24. package/patches/mobile-journal-generation.patch +76 -0
  25. package/patches/office-preview-stable-load.patch +34 -0
  26. package/patches/officecli-deliverables.patch +42 -0
  27. package/patches/ptc-mcp-schema-types.patch +156 -0
  28. package/patches/responses-reasoning-status.patch +289 -0
  29. package/patches/session-envelope-ignorable.patch +63 -0
  30. package/patches/session-export-chinese.patch +85 -0
  31. package/patches/session-format-legacy-restart.patch +35 -0
  32. package/patches/session-log-trajectory-toolbar.patch +352 -0
  33. package/patches/state-dot-brand-blue.patch +185 -0
  34. package/patches/ui-settings-compact-phone.patch +76 -0
  35. package/patches/web-runtime-compat.patch +83 -0
  36. package/patches/workspace-storage-restore.patch +186 -0
  37. package/patches/wsl-native-open.patch +265 -0
@@ -0,0 +1,265 @@
1
+ diff --git a/packages/host/open-in-app/src/icons.ts b/packages/host/open-in-app/src/icons.ts
2
+ index 4b07441c8c..519ba1344b 100644
3
+ --- a/packages/host/open-in-app/src/icons.ts
4
+ +++ b/packages/host/open-in-app/src/icons.ts
5
+ @@ -98,6 +98,41 @@ const EXTRACT_ICON_PS1 = [
6
+ '',
7
+ ].join('\n')
8
+
9
+ +/**
10
+ + * Translate POSIX paths for the Windows interpreter when this host is WSL.
11
+ + *
12
+ + * `Convert-Path` and `System.Drawing` reject a Linux path: the extension host maps
13
+ + * `/mnt/c/...` itself, but PowerShell running as a Windows process resolves
14
+ + * `\\wsl.localhost\...` and refuses to treat it as a file. `wslpath -w` produces the
15
+ + * form it accepts. A non-WSL host returns its paths unchanged.
16
+ + *
17
+ + * @param paths - absolute POSIX paths to hand to the interpreter.
18
+ + * @param timeoutMs - per-command deadline for the translation.
19
+ + * @param internals - platform and runner hooks for deterministic tests.
20
+ + * @returns the translated paths, or null when a translation failed.
21
+ + */
22
+ +async function windowsPaths(
23
+ + paths: readonly string[], timeoutMs: number, internals: ResolvedInternals,
24
+ +): Promise<string[] | null> {
25
+ + if (!isWslHost(internals)) return [...paths]
26
+ + const translated: string[] = []
27
+ + for (const path of paths) {
28
+ + const windows = await output('wslpath', ['-w', path], timeoutMs, internals)
29
+ + const trimmed = windows?.replace(/[\r\n]+$/u, '') ?? ''
30
+ + if (trimmed === '') return null
31
+ + translated.push(trimmed)
32
+ + }
33
+ + return translated
34
+ +}
35
+ +
36
+ +/** Whether this Host is a WSL distribution, whose Windows desktop takes the path. */
37
+ +function isWslHost(internals: ResolvedInternals): boolean {
38
+ + if (internals.platform !== 'linux') return false
39
+ + const env = internals.env
40
+ + if ((env.WSL_DISTRO_NAME ?? '') !== '' || (env.WSL_INTEROP ?? '') !== '') return true
41
+ + return internals.osRelease.toLowerCase().includes('microsoft')
42
+ +}
43
+ +
44
+ /** Extract one Windows executable's associated icon as a 32px PNG. */
45
+ async function extractExecutableIconPng(
46
+ executablePath: string, timeoutMs: number, internals: ResolvedInternals,
47
+ @@ -107,8 +142,12 @@ async function extractExecutableIconPng(
48
+ const script = join(workDir, 'extract-icon.ps1')
49
+ const outPng = join(workDir, 'icon.png')
50
+ await writeFile(script, EXTRACT_ICON_PS1, 'utf8')
51
+ + // Windows PowerShell reads Windows paths, so a WSL host translates all three before
52
+ + // handing them over; the unmounted caller passes them through unchanged.
53
+ + const args = await windowsPaths([script, executablePath, outPng], timeoutMs, internals)
54
+ + if (args === null) return null
55
+ const ran = await output('powershell.exe', [
56
+ - '-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-File', script, executablePath, outPng,
57
+ + '-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-File', ...args,
58
+ ], timeoutMs, internals)
59
+ if (ran === null) return null
60
+ try {
61
+ @@ -148,6 +187,13 @@ export async function extractAppIcon(
62
+ ): Promise<OpenInAppIcon | null> {
63
+ const completed = resolveInternals(internals)
64
+ if (completed.platform === 'linux') {
65
+ + // A resolved executable icon takes precedence on Linux: WSL reaches the Windows
66
+ + // shell open and its Explorer icon lives in the executable, while the desktop-entry
67
+ + // lookup below has nothing to read on a host with no Linux desktop at all.
68
+ + if (resolved.icon?.kind === 'executable') {
69
+ + const bytes = await extractExecutableIconPng(resolved.icon.path, timeoutMs, completed)
70
+ + return bytes === null ? null : { bytes, contentType: 'image/png' }
71
+ + }
72
+ const desktopId = specFor(app, completed.platform)?.desktopId
73
+ return desktopId === undefined ? null : extractLinuxIcon(desktopId, completed)
74
+ }
75
+ diff --git a/packages/host/open-in-app/src/resolver.ts b/packages/host/open-in-app/src/resolver.ts
76
+ index 970118e22a..ad8d176da4 100644
77
+ --- a/packages/host/open-in-app/src/resolver.ts
78
+ +++ b/packages/host/open-in-app/src/resolver.ts
79
+ @@ -14,10 +14,11 @@
80
+
81
+ import { spawn } from 'node:child_process'
82
+ import { readdir, readFile, stat } from 'node:fs/promises'
83
+ -import { homedir, platform as osPlatform } from 'node:os'
84
+ +import { homedir, release as osRelease, platform as osPlatform } from 'node:os'
85
+ import { dirname, isAbsolute, join } from 'node:path'
86
+ import {
87
+ - canOpenNativePath, openNativePath, runNativeCommand, desktopEntryFields, desktopDataDirectories, type NativeCommandRunner,
88
+ + canOpenLinuxDesktop, canOpenNativePath, openNativePath, runNativeCommand,
89
+ + desktopEntryFields, desktopDataDirectories, type NativeCommandRunner,
90
+ } from '@deepseek-ai/dsh-native-command'
91
+ import { scrubbedParentEnv } from '@deepseek-ai/dsh-subprocess'
92
+ import {
93
+ @@ -98,6 +99,8 @@ export const launchDetachedApp: OpenInAppLauncher = (command, args, options) =>
94
+ /** Injectable platform facts for deterministic tests. */
95
+ export interface OpenInAppInternals {
96
+ platform?: NodeJS.Platform
97
+ + /** Kernel release override; distinguishes WSL from desktop Linux without a probe. */
98
+ + osRelease?: string
99
+ /** SSH launch fact from the inherited process layer, independent of `.env` values. */
100
+ ssh?: boolean
101
+ /** Bundle-directory roots replacing `/Applications` and `~/Applications`. */
102
+ @@ -115,6 +118,7 @@ export interface OpenInAppInternals {
103
+ /** Platform facts after the one explicit defaulting step at each public entry. */
104
+ export interface ResolvedInternals {
105
+ platform: NodeJS.Platform
106
+ + osRelease: string
107
+ ssh: boolean
108
+ applicationRoots: readonly string[]
109
+ env: Readonly<Record<string, string | undefined>>
110
+ @@ -140,6 +144,7 @@ export function resolveInternals(internals: OpenInAppInternals): ResolvedInterna
111
+ }
112
+ return {
113
+ platform: internals.platform ?? osPlatform(),
114
+ + osRelease: internals.osRelease ?? osRelease(),
115
+ ssh: internals.ssh ?? false,
116
+ applicationRoots: internals.applicationRoots ?? ['/Applications', join(home, 'Applications')],
117
+ env: internals.env ?? process.env,
118
+ @@ -453,6 +458,14 @@ export function specFor(app: OpenInAppApp, platform: NodeJS.Platform): OpenInApp
119
+ : undefined
120
+ }
121
+
122
+ +/**
123
+ + * Explorer icon for the Windows shell open a WSL host resolves to.
124
+ + *
125
+ + * \`SystemRoot\` is unset inside WSL, so the mounted drive is named directly; the
126
+ + * command-line \`openWindowsPath\` reaches the same interpreter through the same mount.
127
+ + */
128
+ +const WINDOWS_EXPLORER_ICON = '/mnt/c/Windows/explorer.exe'
129
+ +
130
+ /** Icon source for a resolved executable: Windows extracts from the binary itself. */
131
+ function executableIcon(path: string, internals: ResolvedInternals): OpenInAppIconSource | undefined {
132
+ return internals.platform === 'win32' ? { kind: 'executable', path } : undefined
133
+ @@ -504,10 +517,29 @@ async function locate(
134
+ }
135
+ }
136
+ case 'cli': {
137
+ - if (locator.requiresDesktop === true && !canOpenNativePath({
138
+ - platform: internals.platform,
139
+ - env: { ...internals.env },
140
+ - })) return null
141
+ + // A desktop CLI locator names a program that draws on the host's own Linux
142
+ + // desktop. WSL has no such program, but it does have the Windows desktop, so
143
+ + // the entry stays and resolves to the Windows shell open instead of a launcher
144
+ + // this host cannot run.
145
+ + if (locator.requiresDesktop === true) {
146
+ + const facts = {
147
+ + platform: internals.platform,
148
+ + osRelease: internals.osRelease,
149
+ + env: { ...internals.env },
150
+ + }
151
+ + const linuxDesktop = canOpenLinuxDesktop(facts)
152
+ + // WSL answers no here yet can still open a path, because the Windows desktop
153
+ + // takes it. That combination is what selects the shell open below; a headless
154
+ + // Linux host answers no to both and keeps dropping the entry.
155
+ + if (!linuxDesktop && canOpenNativePath(facts)) {
156
+ + const iconPath = expandCandidate(WINDOWS_EXPLORER_ICON, internals)
157
+ + return {
158
+ + launch: { kind: 'shell-open' },
159
+ + icon: iconPath === null ? undefined : { kind: 'executable', path: iconPath },
160
+ + }
161
+ + }
162
+ + if (!linuxDesktop) return null
163
+ + }
164
+ const found = await internals.resolveExecutable(locator.name)
165
+ return found === null
166
+ ? null
167
+ diff --git a/packages/util/native-command/src/index.ts b/packages/util/native-command/src/index.ts
168
+ index 9ad8e0883c..3377ddcb6f 100644
169
+ --- a/packages/util/native-command/src/index.ts
170
+ +++ b/packages/util/native-command/src/index.ts
171
+ @@ -6,6 +6,7 @@
172
+ export { runNativeCommand } from './runner.ts'
173
+ export type { NativeCommandRunner } from './runner.ts'
174
+ export {
175
+ + canOpenLinuxDesktop,
176
+ canOpenNativePath,
177
+ nativeFileManager,
178
+ revealNativePath,
179
+ diff --git a/packages/util/native-command/src/path-opener.ts b/packages/util/native-command/src/path-opener.ts
180
+ index 67bbc35902..dd062cc003 100644
181
+ --- a/packages/util/native-command/src/path-opener.ts
182
+ +++ b/packages/util/native-command/src/path-opener.ts
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
+ */
187
+ +/**
188
+ + * Windows PowerShell locations to try when PATH carries no Windows entry.
189
+ + *
190
+ + * WSL injects its Windows directories into PATH only for the processes it starts
191
+ + * interactively, so a service, a scheduled job, or any process started after that
192
+ + * injection was lost resolves nothing by name. The interpreter is still present on
193
+ + * the volume the distribution mounts, and naming it there is what keeps the Windows
194
+ + * desktop reachable from those processes.
195
+ + */
196
+ +const WINDOWS_EXPLORER_CANDIDATES = [
197
+ + '/mnt/c/Windows/explorer.exe',
198
+ + '/c/Windows/explorer.exe',
199
+ +] as const
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
+ + */
212
+ async function openWindowsPath(path: string, signal: AbortSignal, run: PathOpenerRunner): Promise<void> {
213
+ - await runExplorer([explorerTarget(path)], signal, run)
214
+ + const target = explorerTarget(path)
215
+ + try {
216
+ + await runExplorer([target], signal, run)
217
+ + return
218
+ + } catch (error) {
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.
221
+ + if (!isMissingExecutable(error)) throw error
222
+ + }
223
+ + for (const candidate of WINDOWS_EXPLORER_CANDIDATES) {
224
+ + try {
225
+ + await run(candidate, [target], signal, 'visible')
226
+ + return
227
+ + } catch (error) {
228
+ + if (!isMissingExecutable(error)) throw error
229
+ + }
230
+ + }
231
+ + throw new Error('Windows Explorer is not reachable from this WSL mount')
232
+ +}
233
+ +
234
+ +/** Whether a spawn failed because the executable could not be found at all. */
235
+ +function isMissingExecutable(error: unknown): boolean {
236
+ + return (error as { code?: unknown } | null | undefined)?.code === 'ENOENT'
237
+ }
238
+
239
+ /** Translate a WSL path before handing it to the Windows desktop. */
240
+ @@ -200,6 +247,25 @@ async function openNativePathWithIntent(
241
+ throw new Error(`native path opener is unsupported on ${platform}`)
242
+ }
243
+
244
+ +/**
245
+ + * Whether this host can reach a Linux desktop application.
246
+ + *
247
+ + * WSL hands every path to the Windows desktop, so a Linux GUI program such as
248
+ + * `xdg-open` is not what opens anything there: a surface asking this question
249
+ + * wants to know whether a Linux display is attached, and WSL is not one even
250
+ + * though it can open a path.
251
+ + *
252
+ + * @param internals - platform and environment seam for deterministic tests.
253
+ + * @returns true when a Linux desktop application can receive the path.
254
+ + */
255
+ +export function canOpenLinuxDesktop(internals: PathOpenerInternals = {}): boolean {
256
+ + const platform = internals.platform ?? process.platform
257
+ + if (platform !== 'linux') return false
258
+ + if (isWsl(internals)) return false
259
+ + const env = internals.env ?? process.env
260
+ + return present(env.DISPLAY) || present(env.WAYLAND_DISPLAY)
261
+ +}
262
+ +
263
+ /**
264
+ * Whether {@link openNativePath} plausibly reaches a desktop on this host.
265
+ *