dsh-clean-desktop-shell 0.1.11 → 0.1.13
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/CONTRIBUTORS.md +25 -19
- package/README.en.md +422 -333
- package/README.md +363 -278
- package/electron/aumid.js +17 -17
- package/electron/crashGuard.js +60 -60
- package/electron/error.html +113 -113
- package/electron/main.js +203 -187
- package/electron/outage.js +60 -0
- package/electron/preload.js +216 -49
- package/electron/progress-preload.js +11 -11
- package/electron/progress.html +79 -79
- package/electron/progress.js +56 -56
- package/electron/service.js +559 -458
- package/electron/shortcut.js +122 -122
- package/electron/tray.js +232 -232
- package/electron/window.js +603 -264
- package/lib/client.js +41 -6
- package/lib/common.js +74 -74
- package/lib/icon.js +85 -51
- package/lib/index.js +90 -15
- package/lib/runtime.js +423 -423
- package/package.json +140 -127
- package/scripts/check-syntax.mjs +54 -54
- package/scripts/selftest-recovery.mjs +140 -0
- package/scripts/selftest-runtime.mjs +90 -90
- package/src/client/client.js +41 -6
- package/src/host/common.js +74 -74
- package/src/host/icon.js +85 -51
- package/src/host/index.js +90 -15
- package/src/host/runtime.js +423 -423
- package/version.txt +1 -1
package/src/host/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import { spawn } from 'node:child_process'
|
|
|
12
12
|
import { appendFileSync } from 'node:fs'
|
|
13
13
|
import { PKG_ROOT, MAIN_JS, dshHome, runtimeRoot, launchLogPath } from './common.js'
|
|
14
14
|
import { ensureRuntime } from './runtime.js'
|
|
15
|
-
import { patchExeIcon } from './icon.js'
|
|
15
|
+
import { ensureRcedit, patchExeIcon } from './icon.js'
|
|
16
16
|
|
|
17
17
|
// cordis registers the plugin by this name — bundles without an explicit
|
|
18
18
|
// `name` export are silently skipped by the dsh loader.
|
|
@@ -21,25 +21,98 @@ export const name = 'dsh-clean-desktop-shell'
|
|
|
21
21
|
// Disable auto-launch with DSH_SHELL_AUTO_LAUNCH=0.
|
|
22
22
|
const AUTO_LAUNCH = process.env.DSH_SHELL_AUTO_LAUNCH !== '0'
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Hard budget for the taskbar-icon step. It runs before the spawn (Windows
|
|
26
|
+
* locks a running image), so it is on the launch path — but the icon is
|
|
27
|
+
* cosmetic and must never decide when the window appears. Without a budget a
|
|
28
|
+
* stalled rcedit fetch held the first launch for up to the fetchFile default
|
|
29
|
+
* of 600 s; with it, the worst case is 25 s and the usual case is ~0 (the
|
|
30
|
+
* fetch has already finished behind the Electron runtime download).
|
|
31
|
+
*/
|
|
32
|
+
const ICON_PATCH_DEADLINE_MS = 25000
|
|
33
|
+
|
|
24
34
|
let launched = false
|
|
25
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Let a best-effort step run, but never wait longer than `ms` for it. Whatever
|
|
38
|
+
* it was doing keeps running in the background.
|
|
39
|
+
*/
|
|
40
|
+
function withDeadline(ctx, promise, ms) {
|
|
41
|
+
let timer
|
|
42
|
+
const deadline = new Promise((resolve) => {
|
|
43
|
+
timer = setTimeout(() => {
|
|
44
|
+
ctx.logger.warn(`[clean-desktop-shell] icon step exceeded ${ms} ms — launching without it`)
|
|
45
|
+
resolve()
|
|
46
|
+
}, ms)
|
|
47
|
+
// Do not keep the host process alive just to fire a warning.
|
|
48
|
+
timer.unref?.()
|
|
49
|
+
})
|
|
50
|
+
const settled = promise.then(() => {}, () => {})
|
|
51
|
+
return Promise.race([settled, deadline]).finally(() => clearTimeout(timer))
|
|
52
|
+
}
|
|
53
|
+
|
|
26
54
|
export function apply(ctx) {
|
|
27
55
|
ctx.logger.info('[clean-desktop-shell] mounted (host half)')
|
|
28
56
|
if (!AUTO_LAUNCH) return
|
|
29
|
-
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
//
|
|
34
|
-
;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
57
|
+
|
|
58
|
+
// Runtime preparation is independent of authentication — start it now, but
|
|
59
|
+
// defer the Electron spawn until the launch URL is minted below.
|
|
60
|
+
let runtimeExe = null
|
|
61
|
+
// Kick the (tiny) rcedit fetch off alongside the (large) Electron runtime so
|
|
62
|
+
// the two never serialise; patchExeIcon reuses this same memoised promise.
|
|
63
|
+
void ensureRcedit(ctx)
|
|
64
|
+
const runtimeReady = ensureRuntime(ctx)
|
|
65
|
+
.then(async (exe) => {
|
|
66
|
+
runtimeExe = exe
|
|
67
|
+
await withDeadline(ctx, patchExeIcon(ctx, exe), ICON_PATCH_DEADLINE_MS)
|
|
68
|
+
})
|
|
69
|
+
.catch((err) => {
|
|
40
70
|
reportLaunchFailure(ctx, err)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
// DSH 0.1.2 BrowserAuth: the shell must not start on bare "/" (401). It
|
|
74
|
+
// needs this process's launch URL (?token=…), which the Connection service
|
|
75
|
+
// alone can mint. The service is only reachable from a deferred inject
|
|
76
|
+
// scope — reading ctx.connection in apply() throws "cannot get property
|
|
77
|
+
// without inject" — and the URL is a readiness signal: mint it only after
|
|
78
|
+
// the Loader tree settles, because the port answers 4xx before settlement.
|
|
79
|
+
// Mirror @deepseek-ai/dsh-web-app's announce pattern.
|
|
80
|
+
ctx.inject(['connection'], (connectionCtx) => {
|
|
81
|
+
const launch = () => {
|
|
82
|
+
if (launched) return
|
|
83
|
+
// Only injected services are directly reachable in this scope; the
|
|
84
|
+
// webServer sibling is read through get() (see web-app: it may declare
|
|
85
|
+
// webServer in its row inject, this host does not).
|
|
86
|
+
const webServer = connectionCtx.get('webServer')
|
|
87
|
+
if (!webServer) return
|
|
88
|
+
try {
|
|
89
|
+
const webUrl = `http://127.0.0.1:${String(webServer.port)}`
|
|
90
|
+
// dsh 0.1.2+ mints this process's launch URL through BrowserAuth.
|
|
91
|
+
// Older versions have no BrowserAuth at all — they serve the web root
|
|
92
|
+
// unauthenticated — so a missing mint must NOT stop the launch: the
|
|
93
|
+
// shell just starts with no bootstrap URL, which is exactly the
|
|
94
|
+
// pre-0.1.2 behaviour.
|
|
95
|
+
const mint = connectionCtx.connection.authenticatedUrl
|
|
96
|
+
const launchUrl = typeof mint === 'function' ? mint.call(connectionCtx.connection, webUrl) : null
|
|
97
|
+
void runtimeReady.then(() => {
|
|
98
|
+
if (runtimeExe) launchShell(runtimeExe, connectionCtx, launchUrl)
|
|
99
|
+
})
|
|
100
|
+
} catch (err) {
|
|
101
|
+
reportLaunchFailure(connectionCtx, err)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// This row's own activation can precede a sibling failure. The tree owns
|
|
105
|
+
// readiness: await the Loader, then re-check that the services still
|
|
106
|
+
// exist — an early shutdown must not spawn a shell for a dead server.
|
|
107
|
+
const settled = connectionCtx.get('loader')?.await()
|
|
108
|
+
if (settled === undefined) launch()
|
|
109
|
+
else {
|
|
110
|
+
void settled.then(() => {
|
|
111
|
+
if (connectionCtx.get('webServer') !== undefined
|
|
112
|
+
&& connectionCtx.get('connection') !== undefined) launch()
|
|
113
|
+
}, () => {})
|
|
41
114
|
}
|
|
42
|
-
})
|
|
115
|
+
})
|
|
43
116
|
}
|
|
44
117
|
|
|
45
118
|
/**
|
|
@@ -81,11 +154,13 @@ function reportLaunchFailure(ctx, err) {
|
|
|
81
154
|
}
|
|
82
155
|
}
|
|
83
156
|
|
|
84
|
-
function launchShell(exe, ctx) {
|
|
157
|
+
function launchShell(exe, ctx, launchUrl) {
|
|
85
158
|
if (launched) return
|
|
159
|
+
const env = { ...process.env, ELECTRON_RUN_AS_NODE: undefined }
|
|
160
|
+
if (launchUrl) env.DSH_WEB_LAUNCH_URL = launchUrl
|
|
86
161
|
const child = spawn(exe, [MAIN_JS], {
|
|
87
162
|
cwd: PKG_ROOT,
|
|
88
|
-
env
|
|
163
|
+
env,
|
|
89
164
|
stdio: 'ignore',
|
|
90
165
|
windowsHide: false,
|
|
91
166
|
})
|