dsh-clean-desktop-shell 0.1.6 → 0.1.8
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 +19 -0
- package/README.en.md +108 -3
- package/README.md +80 -3
- package/electron/assets/trayTemplate.png +0 -0
- package/electron/assets/trayTemplate@2x.png +0 -0
- package/electron/tray.js +8 -2
- package/electron/update.js +43 -4
- package/lib/common.js +34 -3
- package/lib/index.js +42 -2
- package/lib/runtime.js +196 -35
- package/package.json +5 -3
- package/scripts/selftest-runtime.mjs +90 -0
- package/src/host/common.js +34 -3
- package/src/host/index.js +42 -2
- package/src/host/runtime.js +196 -35
- package/version.txt +1 -1
package/CONTRIBUTORS.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Contributors
|
|
2
|
+
|
|
3
|
+
This project welcomes contributions — especially around platforms that the
|
|
4
|
+
maintainer does not use daily.
|
|
5
|
+
|
|
6
|
+
## Author
|
|
7
|
+
|
|
8
|
+
- **Icather** — Windows side, plugin architecture, backend lifecycle, CI setup.
|
|
9
|
+
|
|
10
|
+
## Looking for help
|
|
11
|
+
|
|
12
|
+
- **macOS maintainer / co-developer**: validate the .dmg install flow,
|
|
13
|
+
test Apple Silicon + Intel builds, set up code signing + notarization,
|
|
14
|
+
and ideally add a launch-at-login menu item in the tray.
|
|
15
|
+
- **Linux maintainer**: validate the runtime provisioning and tray behavior
|
|
16
|
+
on major distributions.
|
|
17
|
+
|
|
18
|
+
If you open a PR or verified issue that moves macOS support forward, add your
|
|
19
|
+
name here.
|
package/README.en.md
CHANGED
|
@@ -11,8 +11,11 @@ Does exactly one thing: wraps your already-configured DSH Web in a clean native
|
|
|
11
11
|
[](https://github.com/Icather/dsh-clean-desktop-shell)
|
|
12
12
|
[](LICENSE)
|
|
13
13
|
[](https://github.com/Icather/dsh-clean-desktop-shell/releases/latest)
|
|
14
|
-
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
15
15
|
[](https://github.com/Icather/dsh-clean-desktop-shell/graphs/contributors)
|
|
16
|
+
[](https://www.npmjs.com/package/dsh-clean-desktop-shell)
|
|
17
|
+
[](https://github.com/Icather/dsh-clean-desktop-shell/releases)
|
|
18
|
+
[](https://github.com/Icather/dsh-clean-desktop-shell)
|
|
16
19
|
|
|
17
20
|
</div>
|
|
18
21
|
|
|
@@ -27,7 +30,25 @@ Key differences from other desktop clients in the ecosystem:
|
|
|
27
30
|
| **Form** | Standalone Electron app with its own profile | **DSH plugin** mounted into your existing profile |
|
|
28
31
|
| **Profile** | New `desktop` profile, plugins/config must be reinstalled | **Reuses your web profile**, zero migration |
|
|
29
32
|
| **Visual changes** | Custom title bar / frosted glass etc. | **None** — pure window shell |
|
|
30
|
-
| **Upstream** | Pinned version | **Tracks rc.
|
|
33
|
+
| **Upstream** | Pinned version | **Tracks 0.1.1-rc.2** |
|
|
34
|
+
|
|
35
|
+
## Highlights
|
|
36
|
+
|
|
37
|
+
**① One-click launch — like double-clicking a normal desktop app**
|
|
38
|
+
|
|
39
|
+
No terminal, no commands. **Double-click the desktop shortcut and the DSH window opens instantly**, just like launching any normal app:
|
|
40
|
+
|
|
41
|
+
- The installer creates the desktop shortcut automatically; the plugin form asks on first run, plus a one-click "create desktop shortcut" in the tray
|
|
42
|
+
- Shows immediately on double-click — never waits for the backend
|
|
43
|
+
- Single instance: a second double-click just focuses the existing window
|
|
44
|
+
|
|
45
|
+
**② Live backend monitoring · quick manual start/stop**
|
|
46
|
+
|
|
47
|
+
The tray **shows the backend state in real time** (running / starting / stopped / error) with one-click controls:
|
|
48
|
+
|
|
49
|
+
- **Live monitoring**: the window keeps probing the backend; the moment it is killed, crashes or is stopped, the window flips to the offline screen — a stale page never fakes "still alive"
|
|
50
|
+
- **Auto-reconnect**: the instant the backend recovers, the window reloads the real page by itself
|
|
51
|
+
- **Quick start/stop**: one-click start / restart / stop from the tray (with progress dialogs); "stop backend" really shuts the service down on 3080, including externally started instances
|
|
31
52
|
|
|
32
53
|
## Usage
|
|
33
54
|
|
|
@@ -48,6 +69,61 @@ Key differences from other desktop clients in the ecosystem:
|
|
|
48
69
|
- The instant the backend stops (tray stop, kill or crash) the window flips back to the offline screen — a stale page never fakes "still alive"
|
|
49
70
|
- The offline screen has self-service buttons: reload / start backend / auto-detect backend / set backend install folder
|
|
50
71
|
|
|
72
|
+
## macOS status (v0.1.7 important note)
|
|
73
|
+
|
|
74
|
+
v0.1.7 fixes the plugin-mode bug where the shell could not locate `Electron.app`
|
|
75
|
+
on macOS, which caused the window to fail silently on Mac.
|
|
76
|
+
|
|
77
|
+
However, **the maintainer does not currently have a Mac** to verify the
|
|
78
|
+
following in person:
|
|
79
|
+
|
|
80
|
+
- **The .dmg is unsigned and un-notarized**: Apple requires a yearly Developer
|
|
81
|
+
Program membership ($99/yr) for code signing + notarization. The first time you
|
|
82
|
+
open the app from the .dmg, Gatekeeper will likely say the app is "damaged"
|
|
83
|
+
or "cannot be verified".
|
|
84
|
+
- Workaround: run `xattr -cr "/Applications/DSH Clean Desktop Shell.app"`,
|
|
85
|
+
then right-click the app and choose Open.
|
|
86
|
+
- Long-term fix: a Mac co-maintainer with an Apple Developer account can help
|
|
87
|
+
set up signed + notarized builds.
|
|
88
|
+
- Post-extract executable bits and quarantine extended attributes can only be
|
|
89
|
+
confirmed on real hardware.
|
|
90
|
+
- **If the window still does not appear**: a failed launch writes diagnostics
|
|
91
|
+
to `desktop-shell-launch.log` inside your DSH home:
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
cat "${DSH_HOME:-$HOME/.dsh}/desktop-shell-launch.log"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Paste the contents into an issue — it records platform, arch, Node version,
|
|
98
|
+
DSH home, runtime directory and the exact error. With no window on screen,
|
|
99
|
+
this is the only thing that can tell us what went wrong.
|
|
100
|
+
|
|
101
|
+
If you have a Mac and want to co-maintain macOS support (test the .dmg, set up
|
|
102
|
+
signing, or add a launch-at-login tray item), PRs and verified issues are very
|
|
103
|
+
welcome. You will be added to [CONTRIBUTORS.md](./CONTRIBUTORS.md).
|
|
104
|
+
|
|
105
|
+
## Security & permissions: what it actually does
|
|
106
|
+
|
|
107
|
+
Third-party scanners (e.g. [dsh-xray](https://github.com/unStone/dsh-xray)) rate
|
|
108
|
+
this project as "high capability combined with sensitive behavior". **That rating
|
|
109
|
+
is not a false positive** — every item is real, and every item has a concrete,
|
|
110
|
+
necessary reason. You should know what runs on your machine.
|
|
111
|
+
|
|
112
|
+
| Behavior | Why it is required | Where |
|
|
113
|
+
|:--|:--|:--|
|
|
114
|
+
| Spawning system commands | The shell's core job is **starting / restarting / stopping the `dsh web` backend** and probing port 3080. There is no way to do that without system commands. | `electron/service.js` |
|
|
115
|
+
| Downloading the ~100MB Electron runtime | Needed on first launch. Two sources race with a 3s timeout: `github.com` and `npmmirror.com` — the latter is a CN mirror that is usually much faster on Chinese networks. | `src/host/runtime.js` |
|
|
116
|
+
| Calling `api.github.com` | Only for the tray's "Check for updates" action, to read the latest release metadata. | `electron/update.js` |
|
|
117
|
+
| Reading env vars | Path resolution and feature switches only: `DSH_HOME` (DSH home), `DSH_SHELL_ELECTRON_DIR` (reuse a local Electron, skip the download), `DSH_SHELL_AUTO_LAUNCH=0` (disable auto-launch), `USERPROFILE` / `APPDATA` (locate `dsh.cmd` and the shortcuts folder on Windows). | `src/host/common.js`, `src/host/index.js`, `electron/shortcut.js` |
|
|
118
|
+
| Patching the DSH runtime (`cordis.patch.yml`) | **DSH's official plugin registration mechanism** — every DSH plugin mounts this way, it is not specific to this project. | `cordis.patch.yml` |
|
|
119
|
+
|
|
120
|
+
**The line it does not cross**: no telemetry, no uploads, no reading of your
|
|
121
|
+
conversation data. The network requests above are the only two kinds that exist,
|
|
122
|
+
and both can be avoided entirely by setting `DSH_SHELL_ELECTRON_DIR`.
|
|
123
|
+
|
|
124
|
+
The unsigned-installer warnings (Windows SmartScreen, macOS Gatekeeper) come from
|
|
125
|
+
the **absence of a code-signing certificate**, not from any of the above.
|
|
126
|
+
|
|
51
127
|
## Install
|
|
52
128
|
|
|
53
129
|
**Option 1: download the installer from Releases (for a standalone desktop app)**
|
|
@@ -55,7 +131,13 @@ Key differences from other desktop clients in the ecosystem:
|
|
|
55
131
|
- Windows: `DSH-Clean-Desktop-Shell-Setup-<version>.exe`
|
|
56
132
|
- macOS: `DSH-Clean-Desktop-Shell-<version>.dmg` (Intel) or `-arm64.dmg` (Apple Silicon)
|
|
57
133
|
|
|
58
|
-
The installer **creates a desktop shortcut automatically** and provides the full desktop experience (tray).
|
|
134
|
+
The installer **creates a desktop shortcut automatically** and provides the full desktop experience (tray).
|
|
135
|
+
|
|
136
|
+
- **Windows**: the first time you run the installer you may see a SmartScreen
|
|
137
|
+
warning — **this is normal for unsigned programs, not a virus**, see
|
|
138
|
+
"Windows SmartScreen warning" below.
|
|
139
|
+
- **macOS**: the .dmg is unsigned / un-notarized and may trigger Gatekeeper.
|
|
140
|
+
See "macOS status" above.
|
|
59
141
|
|
|
60
142
|
**Option 2: install as a DSH plugin (DSH ecosystem users)**
|
|
61
143
|
|
|
@@ -149,6 +231,29 @@ npm run pack # package NSIS (Win) / DMG (mac)
|
|
|
149
231
|
|
|
150
232
|
## Changelog
|
|
151
233
|
|
|
234
|
+
### 0.1.7
|
|
235
|
+
- **Fixed a silent failure that made the window never open on macOS**: the
|
|
236
|
+
Electron macOS archive is an `Electron.app` bundle with the binary at
|
|
237
|
+
`Electron.app/Contents/MacOS/Electron`; the launcher was looking for a
|
|
238
|
+
top-level `electron` (the Linux layout) and gave up without any feedback.
|
|
239
|
+
- Extraction now tries multiple strategies (ditto / unzip / tar) and verifies
|
|
240
|
+
the payload; the executable bit is restored and the macOS quarantine
|
|
241
|
+
attribute is cleared afterwards.
|
|
242
|
+
- Launch failures no longer vanish into the log: diagnostics are written to
|
|
243
|
+
`desktop-shell-launch.log` and its full path is reported.
|
|
244
|
+
- macOS tray now uses a template image so it adapts to light/dark menu bars;
|
|
245
|
+
the Windows-only "create desktop shortcut" item is hidden elsewhere.
|
|
246
|
+
- Added `CONTRIBUTORS.md` and an open call for Mac co-maintainers (signing,
|
|
247
|
+
notarization, real-device verification).
|
|
248
|
+
|
|
249
|
+
### 0.1.6
|
|
250
|
+
- Fixed "check for updates" reporting the Electron runtime version in plugin mode.
|
|
251
|
+
|
|
252
|
+
### 0.1.5
|
|
253
|
+
- Refactored the plugin host half into focused modules.
|
|
254
|
+
- Completed package.json metadata (repository / homepage / bugs); dropped a stale auto-launch field.
|
|
255
|
+
- README: usage before install, architecture reflects the two forms, platform matrix top-level.
|
|
256
|
+
|
|
152
257
|
### 0.1.4
|
|
153
258
|
- Branch 2 (plugin-market distribution) is now live: `dsh plugin add` →
|
|
154
259
|
restart `dsh web` → the desktop shell opens automatically. The Electron
|
package/README.md
CHANGED
|
@@ -11,8 +11,11 @@
|
|
|
11
11
|
[](https://github.com/Icather/dsh-clean-desktop-shell)
|
|
12
12
|
[](LICENSE)
|
|
13
13
|
[](https://github.com/Icather/dsh-clean-desktop-shell/releases/latest)
|
|
14
|
-
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
15
15
|
[](https://github.com/Icather/dsh-clean-desktop-shell/graphs/contributors)
|
|
16
|
+
[](https://www.npmjs.com/package/dsh-clean-desktop-shell)
|
|
17
|
+
[](https://github.com/Icather/dsh-clean-desktop-shell/releases)
|
|
18
|
+
[](https://github.com/Icather/dsh-clean-desktop-shell)
|
|
16
19
|
|
|
17
20
|
</div>
|
|
18
21
|
|
|
@@ -27,7 +30,25 @@
|
|
|
27
30
|
| **形态** | 独立 Electron 应用,自带独立 profile | **DSH 插件**,挂载进现有 profile |
|
|
28
31
|
| **Profile** | 新建 desktop profile,插件/配置要重装 | **复用现有 web profile**,零迁移 |
|
|
29
32
|
| **视觉改造** | 自绘标题栏 / 毛玻璃等 | **零改造**,纯净窗口壳 |
|
|
30
|
-
| **跟随上游** | 固定版本 | **跟随 rc.
|
|
33
|
+
| **跟随上游** | 固定版本 | **跟随 0.1.1-rc.2** |
|
|
34
|
+
|
|
35
|
+
## 核心亮点
|
|
36
|
+
|
|
37
|
+
**① 像双击桌面应用一样,一键启动 DSH**
|
|
38
|
+
|
|
39
|
+
不用开终端、不用记命令。**双击桌面快捷方式,DSH 窗口立刻弹出**,和启动任何一个普通软件一样自然:
|
|
40
|
+
|
|
41
|
+
- 安装包自动创建桌面快捷方式;插件形态首次运行询问 + 托盘「创建桌面快捷方式」一键补建
|
|
42
|
+
- 双击即出窗——窗口不等后端、不做启动等待
|
|
43
|
+
- 单实例:重复双击只聚焦已有窗口,绝不重复开壳
|
|
44
|
+
|
|
45
|
+
**② 后端活性实时监测 · 快捷手动自主启停**
|
|
46
|
+
|
|
47
|
+
托盘**实时显示后端状态**(运行中 / 启动中 / 未运行 / 错误),一键启停:
|
|
48
|
+
|
|
49
|
+
- **活性监测**:窗口持续探测后端;后端一旦被杀、崩溃或手动关闭,窗口立刻切到离线页,绝不停在旧页面假装还活着
|
|
50
|
+
- **自动重连**:后端恢复的一刻,窗口自动加载回真实页面,无需手动刷新
|
|
51
|
+
- **快捷启停**:托盘右键一键启动 / 重启 / 关闭后端(带进度弹窗);「关闭后端」真正停掉 3080 端口上的服务,含外部启动的实例
|
|
31
52
|
|
|
32
53
|
## 使用
|
|
33
54
|
|
|
@@ -48,6 +69,42 @@
|
|
|
48
69
|
- 后端关闭 / 被杀的一刻,窗口立刻切回离线页——不会停在旧页面假装还活着
|
|
49
70
|
- 离线页内置快捷按钮:重新加载 / 启动后端 / 自动探测后端 / 设置后端安装文件夹
|
|
50
71
|
|
|
72
|
+
## macOS 状态(v0.1.7 重要说明)
|
|
73
|
+
|
|
74
|
+
v0.1.7 修复了插件形态在 macOS 上无法定位 `Electron.app` 路径的问题(该 bug 导致窗口在 Mac 上完全静默失败)。
|
|
75
|
+
|
|
76
|
+
但**当前开发者没有 Mac 实机**,以下事项仍然依赖 Mac 用户验证/贡献:
|
|
77
|
+
|
|
78
|
+
- **.dmg 安装包未签名、未公证**:Apple 要求年度开发者计划($99/年)才能给安装包签名+公证。首次打开 .dmg 里的应用,很可能提示「已损坏,无法打开」或「无法验证开发者」。这不是应用本身损坏,是 Gatekeeper 拦截了未签名应用。
|
|
79
|
+
- 临时解决:`xattr -cr "/Applications/DSH Clean Desktop Shell.app"`,然后右键 → 打开。
|
|
80
|
+
- 长期解决:需要一位有 Apple Developer 账号的 Mac 合作者协助签名/公证,或长期把 .dmg 安装体验写为「需要右键打开 / 执行 xattr」。
|
|
81
|
+
- **Electron.app 解压后的可执行位、quarantine 扩展属性等**只有真机能确认行为是否完全正确。
|
|
82
|
+
- **如果窗口还是没弹出来**:启动失败时会把诊断信息写到 DSH home 下的 `desktop-shell-launch.log`:
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
cat "${DSH_HOME:-$HOME/.dsh}/desktop-shell-launch.log"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
把内容贴到 Issue 即可——里面记录了平台、架构、Node 版本、DSH home、运行时目录和具体报错。没有界面时,这是唯一能回传的信息。
|
|
89
|
+
|
|
90
|
+
诚挚邀请有 Mac 环境、愿意一起打磨的同学参与:能帮忙验证安装流程、补充签名配置、或者把开机自启/登录项做进 Electron 托盘,欢迎直接提 PR 或在 Issue 里 @ 我,我会把你加入 [CONTRIBUTORS.md](./CONTRIBUTORS.md)。
|
|
91
|
+
|
|
92
|
+
## 安全与权限:它到底做了什么
|
|
93
|
+
|
|
94
|
+
第三方安全扫描器(如 [dsh-xray](https://github.com/unStone/dsh-xray))会给本项目打出「高能力 + 敏感行为」的评级。这个评级**没有误报**——列出的每一条都属实,但每一条都有明确且必要的原因。既然要装进你的机器,就该摊开讲清楚。
|
|
95
|
+
|
|
96
|
+
| 行为 | 为什么必须这么做 | 代码位置 |
|
|
97
|
+
|:--|:--|:--|
|
|
98
|
+
| 执行系统命令(spawn) | 壳的核心功能就是**启动 / 重启 / 停止 `dsh web` 后端**,以及探测 3080 端口占用。不调用系统命令无法实现。 | `electron/service.js` |
|
|
99
|
+
| 下载约 100MB 的 Electron 运行时 | 首次启动需要。两个源按网络环境自动竞速(3 秒超时):`github.com` 与 `npmmirror.com`——后者是国内镜像,CN 网络下通常更快。 | `src/host/runtime.js` |
|
|
100
|
+
| 访问 `api.github.com` | 仅用于托盘「检查更新」拉取最新 Release 信息。 | `electron/update.js` |
|
|
101
|
+
| 读取环境变量 | 只用于定位路径和功能开关:`DSH_HOME`(DSH 主目录)、`DSH_SHELL_ELECTRON_DIR`(复用本地 Electron,跳过下载)、`DSH_SHELL_AUTO_LAUNCH=0`(关闭自动弹窗)、`USERPROFILE` / `APPDATA`(Windows 下定位 `dsh.cmd` 与快捷方式目录)。 | `src/host/common.js`、`src/host/index.js`、`electron/shortcut.js` |
|
|
102
|
+
| 修改 DSH 运行时(`cordis.patch.yml`) | **DSH 官方的插件注册机制**,所有 DSH 插件都靠它挂载,并非本项目特有行为。 | `cordis.patch.yml` |
|
|
103
|
+
|
|
104
|
+
**边界**:不上传任何数据、不读取会话内容、不回传遥测。全部网络请求只有上面两类(下载运行时 / 查更新),且都可通过设置 `DSH_SHELL_ELECTRON_DIR` 完全避免。
|
|
105
|
+
|
|
106
|
+
安装包的未签名警告(Windows SmartScreen、macOS Gatekeeper)来自**缺少代码签名证书**,与上述行为无关。
|
|
107
|
+
|
|
51
108
|
## 安装
|
|
52
109
|
|
|
53
110
|
**方式一:从 Release 下载安装包(想要独立桌面应用的用户)**
|
|
@@ -55,7 +112,12 @@
|
|
|
55
112
|
- Windows:下载 `DSH-Clean-Desktop-Shell-Setup-<版本>.exe`
|
|
56
113
|
- macOS:下载 `DSH-Clean-Desktop-Shell-<版本>.dmg`(Intel)或 `-arm64.dmg`(Apple Silicon)
|
|
57
114
|
|
|
58
|
-
|
|
115
|
+
安装包会**自动创建桌面快捷方式**,并提供系统托盘等完整桌面体验。
|
|
116
|
+
|
|
117
|
+
- **Windows**:首次运行安装包可能触发 SmartScreen 警告——**这是未签名程序的正常现象,不是病毒**,见下方「Windows SmartScreen 警告说明」。
|
|
118
|
+
- **macOS**:.dmg 未签名/未公证,首次打开可能触发 Gatekeeper。见上方「macOS 状态」。
|
|
119
|
+
|
|
120
|
+
|
|
59
121
|
|
|
60
122
|
**方式二:作为 DSH 插件安装(DSH 生态用户)**
|
|
61
123
|
|
|
@@ -150,6 +212,21 @@ npm run pack # 打包 NSIS (Win) / DMG (mac)
|
|
|
150
212
|
|
|
151
213
|
## 更新历史
|
|
152
214
|
|
|
215
|
+
### 0.1.7
|
|
216
|
+
- **修复 macOS 上窗口完全打不开的静默失败**:Electron 的 macOS 包是 `Electron.app` 应用包,可执行文件位于 `Electron.app/Contents/MacOS/Electron`;此前按 Linux 布局去找顶层 `electron`,导致 Mac 上必然启动失败且无任何提示。
|
|
217
|
+
- 解压改为多策略回退(ditto / unzip / tar)并校验产物;解压后补齐可执行位,清除 macOS quarantine 扩展属性。
|
|
218
|
+
- 启动失败不再只写日志:诊断信息落盘到 `desktop-shell-launch.log`,并在提示中给出完整路径。
|
|
219
|
+
- macOS 托盘改用模板图,深浅色菜单栏自适应;非 Windows 平台隐藏「创建桌面快捷方式」。
|
|
220
|
+
- 新增 `CONTRIBUTORS.md`,公开招募 Mac 合作开发者(代码签名 / 公证 / 实机验证)。
|
|
221
|
+
|
|
222
|
+
### 0.1.6
|
|
223
|
+
- 修复插件形态下「检查更新」误报 Electron 运行时版本号的问题。
|
|
224
|
+
|
|
225
|
+
### 0.1.5
|
|
226
|
+
- 插件 host 侧重构为聚焦模块。
|
|
227
|
+
- 补全 package.json 元数据(repository / homepage / bugs),清理遗留的开机自启字段。
|
|
228
|
+
- README 调整:使用前置、架构反映两种形态、平台矩阵置顶。
|
|
229
|
+
|
|
153
230
|
### 0.1.4
|
|
154
231
|
- 分支二(插件市场分发)正式可用:`dsh plugin add` 装插件 → 重启 `dsh web` → 桌面壳自动弹出;Electron 运行时由插件自管理(本地复用 / 按网络环境自动选源下载)。
|
|
155
232
|
- 桌面快捷方式:首次启动询问创建 + 托盘「创建桌面快捷方式」一键添加(安装包与插件两种形态均支持)。
|
|
Binary file
|
|
Binary file
|
package/electron/tray.js
CHANGED
|
@@ -25,8 +25,12 @@ import { shortcutSupported, createDesktopShortcut } from './shortcut.js'
|
|
|
25
25
|
const trayIconPath = join(
|
|
26
26
|
fileURLToPath(new URL('.', import.meta.url)),
|
|
27
27
|
'assets',
|
|
28
|
-
process.platform === 'win32' ? 'tray-16.png' : '
|
|
28
|
+
process.platform === 'win32' ? 'tray-16.png' : 'trayTemplate.png',
|
|
29
29
|
)
|
|
30
|
+
// macOS: the filename must end in "Template" (e.g. trayTemplate.png) and
|
|
31
|
+
// Electron will automatically pick trayTemplate@2x.png on Retina.
|
|
32
|
+
// The image itself must be a black silhouette + alpha channel so it
|
|
33
|
+
// inverts correctly in both light and dark menu bars.
|
|
30
34
|
|
|
31
35
|
let trayInstance = null
|
|
32
36
|
let handlers = null
|
|
@@ -61,9 +65,11 @@ export function refreshTrayMenu() {
|
|
|
61
65
|
label: '刷新窗口',
|
|
62
66
|
click: onReload,
|
|
63
67
|
},
|
|
68
|
+
// Windows-only: desktop .lnk shortcut. Hidden on other platforms instead of
|
|
69
|
+
// disabled so the menu stays relevant to the OS it is running on.
|
|
64
70
|
{
|
|
65
71
|
label: '创建桌面快捷方式',
|
|
66
|
-
|
|
72
|
+
visible: shortcutSupported(),
|
|
67
73
|
click: async () => {
|
|
68
74
|
const ok = await createDesktopShortcut()
|
|
69
75
|
if (ok) {
|
package/electron/update.js
CHANGED
|
@@ -18,6 +18,8 @@ import { loadConfig } from './config.js'
|
|
|
18
18
|
|
|
19
19
|
const REPO_URL = 'https://github.com/Icather/dsh-clean-desktop-shell'
|
|
20
20
|
const RELEASES_API = 'https://api.github.com/repos/Icather/dsh-clean-desktop-shell/releases/latest'
|
|
21
|
+
// npm registry — the update source for plugin (npm-installed) mode.
|
|
22
|
+
const NPM_REGISTRY_API = 'https://registry.npmjs.org/dsh-clean-desktop-shell'
|
|
21
23
|
|
|
22
24
|
// Plugin (bare-runtime) mode has no app bundle, so app.getVersion() returns
|
|
23
25
|
// the Electron runtime version (e.g. 33.4.11). Read the plugin's own version
|
|
@@ -125,9 +127,10 @@ export async function checkForUpdatesAuto() {
|
|
|
125
127
|
return
|
|
126
128
|
}
|
|
127
129
|
|
|
128
|
-
// Manual path
|
|
129
|
-
|
|
130
|
+
// Manual path. Plugin mode is installed via npm/DSH market, so it checks the
|
|
131
|
+
// npm registry; the packaged desktop app checks GitHub Releases.
|
|
130
132
|
const isPlugin = !app.isPackaged
|
|
133
|
+
const r = isPlugin ? await checkForUpdateNpm() : await checkForUpdate()
|
|
131
134
|
if (r.hasUpdate) {
|
|
132
135
|
const choice = dialog.showMessageBoxSync({
|
|
133
136
|
type: 'info',
|
|
@@ -145,13 +148,15 @@ export async function checkForUpdatesAuto() {
|
|
|
145
148
|
dialog.showMessageBoxSync({
|
|
146
149
|
type: 'info',
|
|
147
150
|
title: '已是最新版本',
|
|
148
|
-
message: `当前版本 ${r.current}
|
|
151
|
+
message: `当前版本 ${r.current} 已是最新。`,
|
|
149
152
|
})
|
|
150
153
|
} else {
|
|
151
154
|
dialog.showMessageBoxSync({
|
|
152
155
|
type: 'warning',
|
|
153
156
|
title: '检查更新失败',
|
|
154
|
-
message:
|
|
157
|
+
message: isPlugin
|
|
158
|
+
? '无法连接 npm 检查更新,请检查网络后重试。'
|
|
159
|
+
: '无法连接 GitHub 检查更新,请检查网络后重试。',
|
|
155
160
|
})
|
|
156
161
|
}
|
|
157
162
|
}
|
|
@@ -227,3 +232,37 @@ export function openRepo() {
|
|
|
227
232
|
export function openUrl(url) {
|
|
228
233
|
shell.openExternal(url)
|
|
229
234
|
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Version check for plugin (npm-installed) mode. The plugin is updated through
|
|
238
|
+
* the npm registry / DSH market, so its "latest" must come from npm — NOT from
|
|
239
|
+
* GitHub Releases (that endpoint is only for the packaged desktop app).
|
|
240
|
+
* @returns {{ hasUpdate: boolean, latest?: string, current: string, url: string }}
|
|
241
|
+
*/
|
|
242
|
+
export async function checkForUpdateNpm() {
|
|
243
|
+
const current = currentVersion()
|
|
244
|
+
let latestStr = null
|
|
245
|
+
const url = 'https://www.npmjs.com/package/dsh-clean-desktop-shell'
|
|
246
|
+
|
|
247
|
+
try {
|
|
248
|
+
const controller = new AbortController()
|
|
249
|
+
const timer = setTimeout(() => controller.abort(), 8000)
|
|
250
|
+
const res = await fetch(NPM_REGISTRY_API, { signal: controller.signal })
|
|
251
|
+
clearTimeout(timer)
|
|
252
|
+
if (res.ok) {
|
|
253
|
+
const data = await res.json()
|
|
254
|
+
latestStr = data['dist-tags']?.latest || null
|
|
255
|
+
}
|
|
256
|
+
} catch {
|
|
257
|
+
// Network error — no update known.
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const currentV = parseVersion(current)
|
|
261
|
+
const latestV = parseVersion(latestStr)
|
|
262
|
+
return {
|
|
263
|
+
hasUpdate: isNewer(latestV, currentV),
|
|
264
|
+
latest: latestStr ? `v${latestStr}` : null,
|
|
265
|
+
current,
|
|
266
|
+
url,
|
|
267
|
+
}
|
|
268
|
+
}
|
package/lib/common.js
CHANGED
|
@@ -12,11 +12,42 @@ import { fileURLToPath } from 'node:url'
|
|
|
12
12
|
export const PKG_ROOT = dirname(dirname(fileURLToPath(import.meta.url)))
|
|
13
13
|
export const MAIN_JS = join(PKG_ROOT, 'electron', 'main.js')
|
|
14
14
|
export const isWin = process.platform === 'win32'
|
|
15
|
-
export const
|
|
15
|
+
export const isMac = process.platform === 'darwin'
|
|
16
16
|
export const ARCH = process.arch === 'arm64' ? 'arm64' : 'x64'
|
|
17
|
-
export const PLATFORM = isWin ? 'win32' :
|
|
17
|
+
export const PLATFORM = isWin ? 'win32' : isMac ? 'darwin' : 'linux'
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Electron binary path *relative to the extracted runtime dir*.
|
|
21
|
+
*
|
|
22
|
+
* The three upstream archives do not share a layout — only darwin ships an
|
|
23
|
+
* app bundle, and it is the one case with no top-level executable:
|
|
24
|
+
* win32 → electron.exe
|
|
25
|
+
* linux → electron
|
|
26
|
+
* darwin → Electron.app/Contents/MacOS/Electron
|
|
27
|
+
*
|
|
28
|
+
* Authoritative source: the `electron` package's own install.js, which writes
|
|
29
|
+
* exactly this relative path into path.txt for `require('electron')`.
|
|
30
|
+
*/
|
|
31
|
+
export const EXE_RELPATH = isWin
|
|
32
|
+
? 'electron.exe'
|
|
33
|
+
: isMac
|
|
34
|
+
? join('Electron.app', 'Contents', 'MacOS', 'Electron')
|
|
35
|
+
: 'electron'
|
|
36
|
+
|
|
37
|
+
/** First path segment of EXE_RELPATH — what a successful extract must leave behind. */
|
|
38
|
+
export const EXE_TOP = isWin ? 'electron.exe' : isMac ? 'Electron.app' : 'electron'
|
|
39
|
+
|
|
40
|
+
/** DSH home, honouring DSH_HOME the same way dsh-home-paths does. */
|
|
41
|
+
export function dshHome() {
|
|
42
|
+
return process.env.DSH_HOME || join(homedir(), '.dsh')
|
|
43
|
+
}
|
|
18
44
|
|
|
19
45
|
/** Where the self-provisioned runtimes live (shared with icon.js). */
|
|
20
46
|
export function runtimeRoot() {
|
|
21
|
-
return join(
|
|
47
|
+
return join(dshHome(), 'desktop-shell-runtime')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Launch diagnostics land here — the only thing a headless user can send us. */
|
|
51
|
+
export function launchLogPath() {
|
|
52
|
+
return join(dshHome(), 'desktop-shell-launch.log')
|
|
22
53
|
}
|
package/lib/index.js
CHANGED
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* icon.js (Windows taskbar icon).
|
|
10
10
|
*/
|
|
11
11
|
import { spawn } from 'node:child_process'
|
|
12
|
-
import {
|
|
12
|
+
import { appendFileSync } from 'node:fs'
|
|
13
|
+
import { PKG_ROOT, MAIN_JS, dshHome, runtimeRoot, launchLogPath } from './common.js'
|
|
13
14
|
import { ensureRuntime } from './runtime.js'
|
|
14
15
|
import { patchExeIcon } from './icon.js'
|
|
15
16
|
|
|
@@ -36,11 +37,50 @@ export function apply(ctx) {
|
|
|
36
37
|
await patchExeIcon(ctx, exe).catch(() => {})
|
|
37
38
|
launchShell(exe, ctx)
|
|
38
39
|
} catch (err) {
|
|
39
|
-
ctx
|
|
40
|
+
reportLaunchFailure(ctx, err)
|
|
40
41
|
}
|
|
41
42
|
})()
|
|
42
43
|
}
|
|
43
44
|
|
|
45
|
+
/**
|
|
46
|
+
* A provisioning failure used to vanish into ctx.logger — invisible to
|
|
47
|
+
* anyone who is not already tailing the DSH log. That is precisely how the
|
|
48
|
+
* macOS launch bug survived several releases: there was no window, no error
|
|
49
|
+
* dialog, and nothing on disk to send back.
|
|
50
|
+
*
|
|
51
|
+
* Write a diagnostics file next to the runtime and name it in the warning,
|
|
52
|
+
* so a user on an untested platform can hand us something actionable.
|
|
53
|
+
*/
|
|
54
|
+
function reportLaunchFailure(ctx, err) {
|
|
55
|
+
const message = err?.message ?? String(err)
|
|
56
|
+
ctx.logger.warn(`[clean-desktop-shell] shell launch failed: ${message}`)
|
|
57
|
+
|
|
58
|
+
const logPath = launchLogPath()
|
|
59
|
+
const body = [
|
|
60
|
+
`time: ${new Date().toISOString()}`,
|
|
61
|
+
`platform: ${process.platform} (${process.arch})`,
|
|
62
|
+
`node: ${process.version}`,
|
|
63
|
+
`dsh home: ${dshHome()}`,
|
|
64
|
+
`runtime: ${runtimeRoot()}`,
|
|
65
|
+
`entry: ${MAIN_JS}`,
|
|
66
|
+
`error: ${message}`,
|
|
67
|
+
'',
|
|
68
|
+
'Things worth checking:',
|
|
69
|
+
' - first launch downloads the Electron runtime; a blocked network fails here',
|
|
70
|
+
' - set DSH_SHELL_ELECTRON_DIR to an electron package to skip the download',
|
|
71
|
+
' - macOS binary: <runtime>/electron-v<ver>/Electron.app/Contents/MacOS/Electron',
|
|
72
|
+
' - macOS: unsandboxed extractors may drop the executable bit (chmod +x)',
|
|
73
|
+
'',
|
|
74
|
+
].join('\n')
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
appendFileSync(logPath, body + '\n')
|
|
78
|
+
ctx.logger.warn(`[clean-desktop-shell] diagnostics written to ${logPath}`)
|
|
79
|
+
} catch {
|
|
80
|
+
// Nothing else a headless host process can do.
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
44
84
|
function launchShell(exe, ctx) {
|
|
45
85
|
if (launched) return
|
|
46
86
|
const child = spawn(exe, [MAIN_JS], {
|