dsh-clean-desktop-shell 0.1.0 → 0.1.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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Icather
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Icather
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.en.md CHANGED
@@ -1,91 +1,91 @@
1
- <div align="center">
2
-
3
- # dsh-clean-desktop-shell
4
-
5
- **A clean desktop shell for DeepSeek Harness, shipped as a DSH plugin**
6
-
7
- Does exactly one thing: wraps your already-configured DSH Web in a clean native desktop window — system tray, single instance, auto-launch, just like a normal app. No frosted glass, no fancy materials. **Clean.**
8
-
9
- [English](README.en.md) · [中文](README.md)
10
-
11
- [![Platform](https://img.shields.io/badge/Platform-Windows%20%7C%20macOS-0078D6?logo=windows&logoColor=white)](https://github.com/Icather/dsh-clean-desktop-shell)
12
- [![License](https://img.shields.io/badge/License-MIT-22c55e)](LICENSE)
13
- [![Release](https://img.shields.io/github/v/release/Icather/dsh-clean-desktop-shell?color=blue)](https://github.com/Icather/dsh-clean-desktop-shell/releases/latest)
14
- [![DSH](https://img.shields.io/badge/DeepSeek_Harness-rc.7-4D6BFE)](https://github.com/deepseek-ai/deepseek-harness)
15
-
16
- </div>
17
-
18
- ## What is this
19
-
20
- `dsh-clean-desktop-shell` is a **DSH-plugin-shaped clean desktop shell**: it wraps an already-running DSH Web (default `http://127.0.0.1:3080`) in a native desktop window — system tray, single instance, auto-launch, so it behaves like any normal desktop app. **No visual changes at all**: no frosted glass, no skinning — purely a window shell.
21
-
22
- Key differences from other desktop clients in the ecosystem:
23
-
24
- | | Other desktop clients (e.g. dsh-desktop family) | This plugin |
25
- |:--|:--|:--|
26
- | **Form** | Standalone Electron app with its own profile | **DSH plugin** mounted into your existing profile |
27
- | **Profile** | New `desktop` profile, plugins/config must be reinstalled | **Reuses your web profile**, zero migration |
28
- | **Visual changes** | Custom title bar / frosted glass etc. | **None** — pure window shell |
29
- | **Upstream** | Pinned version | **Tracks rc.7** |
30
-
31
- ## Architecture
32
-
33
- ```
34
- ┌─────────────────── Core (dsh web / headless service) ───────────────────┐
35
- │ Sessions · Agent · Plugins · Memory live here, decoupled from UI │
36
- └─────────────────────────────────────────────────────────────────────────┘
37
-
38
- ┌───────────────┴───────────────┐
39
- │ dsh-clean-desktop-shell │
40
- │ Electron shell (client) │
41
- │ tray · single-instance · │
42
- │ auto-launch │
43
- └────────────────────────────────┘
44
- ```
45
-
46
- - **Default**: loads the local `127.0.0.1:3080` (your configured web profile, zero migration).
47
- - **Remote-capable**: configure any remote DSH address; the shell is just a window. Phones / Linux / other devices can reach the core via browser or PWA — the shell is never bound to a local service.
48
-
49
- ### Platform matrix
50
-
51
- | Platform | Shell | Status |
52
- |:--|:--|:--|
53
- | Windows | ✅ Electron (frameless + native window buttons) | First release target |
54
- | macOS | ✅ Electron (hiddenInset) | Planned |
55
- | Linux | — (browser / PWA to the core) | Not planned |
56
- | Termux / phone / tablet | — (headless / PWA to the core) | Covered by remote core access |
57
-
58
- ## Install
59
-
60
- ```sh
61
- dsh plugin --profile web add dsh-clean-desktop-shell
62
- ```
63
-
64
- Restart `dsh web`, then launch the shell from the tray / shortcut.
65
-
66
- > The shell needs a reachable `dsh web` service (local or configured remote address). See Usage.
67
-
68
- ## Usage
69
-
70
- 1. Start `dsh web` (or configure a remote service address).
71
- 2. Launch the shell: it auto-detects local 3080; if not running it starts the service per configuration.
72
- 3. Drag the window by its top area (right side reserved for native buttons); close minimizes to tray by default.
73
-
74
- ## Development
75
-
76
- ```sh
77
- npm install
78
- npm run build # build the plugin bundle
79
- npm run dev # launch the shell (dev mode)
80
- npm run pack # package NSIS (Win) / DMG (mac)
81
- ```
82
-
83
- ## Changelog
84
-
85
- ### 0.1.0
86
- - Initial release: Electron shell skeleton, system tray / single instance / auto-launch, DSH plugin mounting.
87
-
88
- ## Credits
89
-
90
- - [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) — the core.
91
- - Architecture inspired by [Hermes Agent Desktop](https://github.com/NousResearch/hermes-agent)'s shell/core separation.
1
+ <div align="center">
2
+
3
+ # dsh-clean-desktop-shell
4
+
5
+ **A clean desktop shell for DeepSeek Harness, shipped as a DSH plugin**
6
+
7
+ Does exactly one thing: wraps your already-configured DSH Web in a clean native desktop window — system tray, single instance, auto-launch, just like a normal app. No frosted glass, no fancy materials. **Clean.**
8
+
9
+ [English](README.en.md) · [中文](README.md)
10
+
11
+ [![Platform](https://img.shields.io/badge/Platform-Windows%20%7C%20macOS-0078D6?logo=windows&logoColor=white)](https://github.com/Icather/dsh-clean-desktop-shell)
12
+ [![License](https://img.shields.io/badge/License-MIT-22c55e)](LICENSE)
13
+ [![Release](https://img.shields.io/github/v/release/Icather/dsh-clean-desktop-shell?color=blue)](https://github.com/Icather/dsh-clean-desktop-shell/releases/latest)
14
+ [![DSH](https://img.shields.io/badge/DeepSeek_Harness-rc.7-4D6BFE)](https://github.com/deepseek-ai/deepseek-harness)
15
+
16
+ </div>
17
+
18
+ ## What is this
19
+
20
+ `dsh-clean-desktop-shell` is a **DSH-plugin-shaped clean desktop shell**: it wraps an already-running DSH Web (default `http://127.0.0.1:3080`) in a native desktop window — system tray, single instance, auto-launch, so it behaves like any normal desktop app. **No visual changes at all**: no frosted glass, no skinning — purely a window shell.
21
+
22
+ Key differences from other desktop clients in the ecosystem:
23
+
24
+ | | Other desktop clients (e.g. dsh-desktop family) | This plugin |
25
+ |:--|:--|:--|
26
+ | **Form** | Standalone Electron app with its own profile | **DSH plugin** mounted into your existing profile |
27
+ | **Profile** | New `desktop` profile, plugins/config must be reinstalled | **Reuses your web profile**, zero migration |
28
+ | **Visual changes** | Custom title bar / frosted glass etc. | **None** — pure window shell |
29
+ | **Upstream** | Pinned version | **Tracks rc.7** |
30
+
31
+ ## Architecture
32
+
33
+ ```
34
+ ┌─────────────────── Core (dsh web / headless service) ───────────────────┐
35
+ │ Sessions · Agent · Plugins · Memory live here, decoupled from UI │
36
+ └─────────────────────────────────────────────────────────────────────────┘
37
+
38
+ ┌───────────────┴───────────────┐
39
+ │ dsh-clean-desktop-shell │
40
+ │ Electron shell (client) │
41
+ │ tray · single-instance · │
42
+ │ auto-launch │
43
+ └────────────────────────────────┘
44
+ ```
45
+
46
+ - **Default**: loads the local `127.0.0.1:3080` (your configured web profile, zero migration).
47
+ - **Remote-capable**: configure any remote DSH address; the shell is just a window. Phones / Linux / other devices can reach the core via browser or PWA — the shell is never bound to a local service.
48
+
49
+ ### Platform matrix
50
+
51
+ | Platform | Shell | Status |
52
+ |:--|:--|:--|
53
+ | Windows | ✅ Electron (frameless + native window buttons) | First release target |
54
+ | macOS | ✅ Electron (hiddenInset) | Planned |
55
+ | Linux | — (browser / PWA to the core) | Not planned |
56
+ | Termux / phone / tablet | — (headless / PWA to the core) | Covered by remote core access |
57
+
58
+ ## Install
59
+
60
+ ```sh
61
+ dsh plugin --profile web add dsh-clean-desktop-shell
62
+ ```
63
+
64
+ Restart `dsh web`, then launch the shell from the tray / shortcut.
65
+
66
+ > The shell needs a reachable `dsh web` service (local or configured remote address). See Usage.
67
+
68
+ ## Usage
69
+
70
+ 1. Start `dsh web` (or configure a remote service address).
71
+ 2. Launch the shell: it auto-detects local 3080; if not running it starts the service per configuration.
72
+ 3. Drag the window by its top area (right side reserved for native buttons); close minimizes to tray by default.
73
+
74
+ ## Development
75
+
76
+ ```sh
77
+ npm install
78
+ npm run build # build the plugin bundle
79
+ npm run dev # launch the shell (dev mode)
80
+ npm run pack # package NSIS (Win) / DMG (mac)
81
+ ```
82
+
83
+ ## Changelog
84
+
85
+ ### 0.1.0
86
+ - Initial release: Electron shell skeleton, system tray / single instance / auto-launch, DSH plugin mounting.
87
+
88
+ ## Credits
89
+
90
+ - [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) — the core.
91
+ - Architecture inspired by [Hermes Agent Desktop](https://github.com/NousResearch/hermes-agent)'s shell/core separation.
package/README.md CHANGED
@@ -1,90 +1,90 @@
1
- <div align="center">
2
-
3
- # dsh-clean-desktop-shell
4
-
5
- **DeepSeek Harness 的纯净桌面壳(DSH 插件形态)**
6
-
7
- 只做一件事:给已配置好的 DSH Web 加一层干净的桌面窗口——系统托盘、单实例、开机自启、像普通软件一样用。无毛玻璃、无花哨材质,**纯净**。
8
-
9
- [English](README.en.md) · [中文](README.md)
10
-
11
- [![Platform](https://img.shields.io/badge/Platform-Windows%20%7C%20macOS-0078D6?logo=windows&logoColor=white)](https://github.com/Icather/dsh-clean-desktop-shell)
12
- [![License](https://img.shields.io/badge/License-MIT-22c55e)](LICENSE)
13
- [![Release](https://img.shields.io/github/v/release/Icather/dsh-clean-desktop-shell?color=blue)](https://github.com/Icather/dsh-clean-desktop-shell/releases/latest)
14
- [![DSH](https://img.shields.io/badge/DeepSeek_Harness-rc.7-4D6BFE)](https://github.com/deepseek-ai/deepseek-harness)
15
-
16
- </div>
17
-
18
- ## 这是什么
19
-
20
- `dsh-clean-desktop-shell` 是一个 **DSH 插件形态** 的纯净桌面壳:它给已经跑起来的 DSH Web(默认 `http://127.0.0.1:3080`)套一层原生桌面窗口——系统托盘、单实例、开机自启,像普通桌面软件一样使用。**不做任何视觉改造**:不加毛玻璃、不改界面,纯粹是"窗口壳"。
21
-
22
- 与生态里其他桌面端方案的最大区别:
23
-
24
- | | 其他桌面端(如 dsh-desktop 系列) | 本插件 |
25
- |:--|:--|:--|
26
- | **形态** | 独立 Electron 应用,自带独立 profile | **DSH 插件**,挂载进现有 profile |
27
- | **Profile** | 新建 desktop profile,插件/配置要重装 | **复用现有 web profile**,零迁移 |
28
- | **视觉改造** | 自绘标题栏 / 毛玻璃等 | **零改造**,纯净窗口壳 |
29
- | **跟随上游** | 固定版本 | **跟随 rc.7** |
30
-
31
- ## 架构
32
-
33
- ```
34
- ┌──────────────────── 内核(dsh web / headless 服务) ────────────────────┐
35
- │ 会话 · Agent · 插件 · 记忆 都在这层,与界面解耦 │
36
- └─────────────────────────────────────────────────────────────────────────┘
37
-
38
- ┌───────────────┴───────────────┐
39
- │ dsh-clean-desktop-shell │
40
- │ Electron 壳(客户端) │
41
- │ 托盘 · 单实例 · 开机自启 │
42
- └────────────────────────────────┘
43
- ```
44
-
45
- - **默认**:加载本地 `127.0.0.1:3080`(已配置好的 web profile,零迁移)。
46
- - **可配远程**:在设置里填入任意远程 DSH 地址,壳只当窗口——手机 / Linux / 其他设备通过浏览器或 PWA 也能接入内核,壳本身不绑定本地服务。
47
-
48
- ### 平台矩阵
49
-
50
- | 平台 | 壳 | 状态 |
51
- |:--|:--|:--|
52
- | Windows | ✅ Electron(无边框 + 原生窗口按钮) | 首发目标 |
53
- | macOS | ✅ Electron(hiddenInset) | 规划中 |
54
- | Linux | —(浏览器 / PWA 直连内核) | 不做 |
55
- | Termux / 手机 / 平板 | —(headless / PWA 直连内核) | 由内核远程访问支持 |
56
-
57
- ## 安装
58
-
59
- ```sh
60
- dsh plugin --profile web add dsh-clean-desktop-shell
61
- ```
62
-
63
- 重启 `dsh web` 后,从系统托盘/快捷方式启动桌面壳即可。
64
-
65
- > 桌面壳需要本机有可用的 `dsh web` 服务(或配置的远程地址)。见下方「使用」。
66
-
67
- ## 使用
68
-
69
- 1. 启动 `dsh web`(或配置远程服务地址)。
70
- 2. 启动桌面壳:自动检测本地 3080;未运行时按配置拉起服务。
71
- 3. 窗口顶部(右侧留系统按钮)可拖动窗口;关闭默认缩到托盘。
72
-
73
- ## 开发
74
-
75
- ```sh
76
- npm install
77
- npm run build # 构建插件 bundle
78
- npm run dev # 启动壳(开发模式)
79
- npm run pack # 打包 NSIS (Win) / DMG (mac)
80
- ```
81
-
82
- ## 更新历史
83
-
84
- ### 0.1.0
85
- - 初始版本:Electron 壳骨架,系统托盘/单实例/开机自启,DSH 插件挂载。
86
-
87
- ## 致谢
88
-
89
- - [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) —— 内核本体。
90
- - 架构参考 [Hermes Agent Desktop](https://github.com/NousResearch/hermes-agent) 的壳/内核分离设计。
1
+ <div align="center">
2
+
3
+ # dsh-clean-desktop-shell
4
+
5
+ **DeepSeek Harness 的纯净桌面壳(DSH 插件形态)**
6
+
7
+ 只做一件事:给已配置好的 DSH Web 加一层干净的桌面窗口——系统托盘、单实例、开机自启、像普通软件一样用。无毛玻璃、无花哨材质,**纯净**。
8
+
9
+ [English](README.en.md) · [中文](README.md)
10
+
11
+ [![Platform](https://img.shields.io/badge/Platform-Windows%20%7C%20macOS-0078D6?logo=windows&logoColor=white)](https://github.com/Icather/dsh-clean-desktop-shell)
12
+ [![License](https://img.shields.io/badge/License-MIT-22c55e)](LICENSE)
13
+ [![Release](https://img.shields.io/github/v/release/Icather/dsh-clean-desktop-shell?color=blue)](https://github.com/Icather/dsh-clean-desktop-shell/releases/latest)
14
+ [![DSH](https://img.shields.io/badge/DeepSeek_Harness-rc.7-4D6BFE)](https://github.com/deepseek-ai/deepseek-harness)
15
+
16
+ </div>
17
+
18
+ ## 这是什么
19
+
20
+ `dsh-clean-desktop-shell` 是一个 **DSH 插件形态** 的纯净桌面壳:它给已经跑起来的 DSH Web(默认 `http://127.0.0.1:3080`)套一层原生桌面窗口——系统托盘、单实例、开机自启,像普通桌面软件一样使用。**不做任何视觉改造**:不加毛玻璃、不改界面,纯粹是"窗口壳"。
21
+
22
+ 与生态里其他桌面端方案的最大区别:
23
+
24
+ | | 其他桌面端(如 dsh-desktop 系列) | 本插件 |
25
+ |:--|:--|:--|
26
+ | **形态** | 独立 Electron 应用,自带独立 profile | **DSH 插件**,挂载进现有 profile |
27
+ | **Profile** | 新建 desktop profile,插件/配置要重装 | **复用现有 web profile**,零迁移 |
28
+ | **视觉改造** | 自绘标题栏 / 毛玻璃等 | **零改造**,纯净窗口壳 |
29
+ | **跟随上游** | 固定版本 | **跟随 rc.7** |
30
+
31
+ ## 架构
32
+
33
+ ```
34
+ ┌──────────────────── 内核(dsh web / headless 服务) ────────────────────┐
35
+ │ 会话 · Agent · 插件 · 记忆 都在这层,与界面解耦 │
36
+ └─────────────────────────────────────────────────────────────────────────┘
37
+
38
+ ┌───────────────┴───────────────┐
39
+ │ dsh-clean-desktop-shell │
40
+ │ Electron 壳(客户端) │
41
+ │ 托盘 · 单实例 · 开机自启 │
42
+ └────────────────────────────────┘
43
+ ```
44
+
45
+ - **默认**:加载本地 `127.0.0.1:3080`(已配置好的 web profile,零迁移)。
46
+ - **可配远程**:在设置里填入任意远程 DSH 地址,壳只当窗口——手机 / Linux / 其他设备通过浏览器或 PWA 也能接入内核,壳本身不绑定本地服务。
47
+
48
+ ### 平台矩阵
49
+
50
+ | 平台 | 壳 | 状态 |
51
+ |:--|:--|:--|
52
+ | Windows | ✅ Electron(无边框 + 原生窗口按钮) | 首发目标 |
53
+ | macOS | ✅ Electron(hiddenInset) | 规划中 |
54
+ | Linux | —(浏览器 / PWA 直连内核) | 不做 |
55
+ | Termux / 手机 / 平板 | —(headless / PWA 直连内核) | 由内核远程访问支持 |
56
+
57
+ ## 安装
58
+
59
+ ```sh
60
+ dsh plugin --profile web add dsh-clean-desktop-shell
61
+ ```
62
+
63
+ 重启 `dsh web` 后,从系统托盘/快捷方式启动桌面壳即可。
64
+
65
+ > 桌面壳需要本机有可用的 `dsh web` 服务(或配置的远程地址)。见下方「使用」。
66
+
67
+ ## 使用
68
+
69
+ 1. 启动 `dsh web`(或配置远程服务地址)。
70
+ 2. 启动桌面壳:自动检测本地 3080;未运行时按配置拉起服务。
71
+ 3. 窗口顶部(右侧留系统按钮)可拖动窗口;关闭默认缩到托盘。
72
+
73
+ ## 开发
74
+
75
+ ```sh
76
+ npm install
77
+ npm run build # 构建插件 bundle
78
+ npm run dev # 启动壳(开发模式)
79
+ npm run pack # 打包 NSIS (Win) / DMG (mac)
80
+ ```
81
+
82
+ ## 更新历史
83
+
84
+ ### 0.1.0
85
+ - 初始版本:Electron 壳骨架,系统托盘/单实例/开机自启,DSH 插件挂载。
86
+
87
+ ## 致谢
88
+
89
+ - [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) —— 内核本体。
90
+ - 架构参考 [Hermes Agent Desktop](https://github.com/NousResearch/hermes-agent) 的壳/内核分离设计。
package/cordis.patch.yml CHANGED
@@ -1,4 +1,4 @@
1
- # dsh bundle patch: inserts this plugin into a profile's layer stack.
2
- - insert:
3
- - id: clean-desktop-shell
4
- name: 'dsh-clean-desktop-shell'
1
+ # dsh bundle patch: inserts this plugin into a profile's layer stack.
2
+ - insert:
3
+ - id: clean-desktop-shell
4
+ name: 'dsh-clean-desktop-shell'
@@ -1,48 +1,48 @@
1
- /**
2
- * Shell config persistence (userData/config.json).
3
- *
4
- * Fields:
5
- * - targetUrl: default 'http://127.0.0.1:3080' — set to any remote
6
- * DSH address to run the shell as a pure window.
7
- * - autoStartService: default true — only applies to the local default URL.
8
- * - closeToTray: default true.
9
- * - windowMode: 'advanced' (mica/vibrancy) | 'compatibility'.
10
- * - autoLaunch: open at login.
11
- */
12
- import { app } from 'electron'
13
- import { readFileSync, writeFileSync, mkdirSync } from 'node:fs'
14
- import { dirname, join } from 'node:path'
15
-
16
- const DEFAULTS = {
17
- targetUrl: 'http://127.0.0.1:3080',
18
- autoStartService: true,
19
- closeToTray: true,
20
- windowMode: 'advanced',
21
- autoLaunch: false,
22
- backendPath: null,
23
- }
24
-
25
- let cached = null
26
-
27
- function configPath() {
28
- return join(app.getPath('userData'), 'config.json')
29
- }
30
-
31
- export function loadConfig() {
32
- if (cached) return cached
33
- try {
34
- const raw = readFileSync(configPath(), 'utf8')
35
- cached = { ...DEFAULTS, ...JSON.parse(raw) }
36
- } catch {
37
- cached = { ...DEFAULTS }
38
- }
39
- return cached
40
- }
41
-
42
- export function saveConfig(next) {
43
- cached = { ...DEFAULTS, ...next }
44
- const file = configPath()
45
- mkdirSync(dirname(file), { recursive: true })
46
- writeFileSync(file, JSON.stringify(cached, null, 2), 'utf8')
47
- return cached
48
- }
1
+ /**
2
+ * Shell config persistence (userData/config.json).
3
+ *
4
+ * Fields:
5
+ * - targetUrl: default 'http://127.0.0.1:3080' — set to any remote
6
+ * DSH address to run the shell as a pure window.
7
+ * - autoStartService: default true — only applies to the local default URL.
8
+ * - closeToTray: default true.
9
+ * - windowMode: 'advanced' (mica/vibrancy) | 'compatibility'.
10
+ * - autoLaunch: open at login.
11
+ */
12
+ import { app } from 'electron'
13
+ import { readFileSync, writeFileSync, mkdirSync } from 'node:fs'
14
+ import { dirname, join } from 'node:path'
15
+
16
+ const DEFAULTS = {
17
+ targetUrl: 'http://127.0.0.1:3080',
18
+ autoStartService: true,
19
+ closeToTray: true,
20
+ windowMode: 'advanced',
21
+ autoLaunch: false,
22
+ backendPath: null,
23
+ }
24
+
25
+ let cached = null
26
+
27
+ function configPath() {
28
+ return join(app.getPath('userData'), 'config.json')
29
+ }
30
+
31
+ export function loadConfig() {
32
+ if (cached) return cached
33
+ try {
34
+ const raw = readFileSync(configPath(), 'utf8')
35
+ cached = { ...DEFAULTS, ...JSON.parse(raw) }
36
+ } catch {
37
+ cached = { ...DEFAULTS }
38
+ }
39
+ return cached
40
+ }
41
+
42
+ export function saveConfig(next) {
43
+ cached = { ...DEFAULTS, ...next }
44
+ const file = configPath()
45
+ mkdirSync(dirname(file), { recursive: true })
46
+ writeFileSync(file, JSON.stringify(cached, null, 2), 'utf8')
47
+ return cached
48
+ }
@@ -0,0 +1,113 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'unsafe-inline'; script-src 'unsafe-inline'" />
6
+ <title>后端未连接</title>
7
+ <style>
8
+ html, body {
9
+ height: 100%;
10
+ margin: 0;
11
+ background: #10131A;
12
+ color: #9aa3b2;
13
+ font-family: system-ui, "Segoe UI", "Microsoft YaHei", sans-serif;
14
+ -webkit-user-select: none;
15
+ user-select: none;
16
+ }
17
+ .wrap {
18
+ height: 100%;
19
+ display: flex;
20
+ flex-direction: column;
21
+ align-items: center;
22
+ justify-content: center;
23
+ gap: 10px;
24
+ }
25
+ .whale {
26
+ width: 72px;
27
+ height: 72px;
28
+ border-radius: 18px;
29
+ background: #1b2330;
30
+ display: flex;
31
+ align-items: center;
32
+ justify-content: center;
33
+ font-size: 22px;
34
+ font-weight: 700;
35
+ letter-spacing: 0.5px;
36
+ color: #cdd3de;
37
+ filter: drop-shadow(0 8px 24px rgba(0, 0, 0, 0.45));
38
+ }
39
+ h2 {
40
+ margin: 0;
41
+ font-size: 17px;
42
+ font-weight: 600;
43
+ color: #e8eaf0;
44
+ }
45
+ p {
46
+ margin: 0;
47
+ font-size: 13px;
48
+ }
49
+ button {
50
+ padding: 9px 22px;
51
+ font-size: 13px;
52
+ color: #e8eaf0;
53
+ background: #232d3d;
54
+ border: 1px solid #33405a;
55
+ border-radius: 8px;
56
+ cursor: pointer;
57
+ }
58
+ button:hover { background: #2b3750; }
59
+ button:active { background: #202a3c; }
60
+ .actions {
61
+ display: flex;
62
+ gap: 10px;
63
+ margin-top: 4px;
64
+ }
65
+ .folder-btn {
66
+ margin-top: 2px;
67
+ padding: 4px 8px;
68
+ font-size: 12px;
69
+ color: #6b7686;
70
+ background: none;
71
+ border: none;
72
+ border-radius: 6px;
73
+ text-decoration: underline;
74
+ }
75
+ .folder-btn:hover { color: #9aa3b2; background: none; }
76
+ .hint {
77
+ font-size: 12px;
78
+ opacity: 0.55;
79
+ }
80
+ </style>
81
+ </head>
82
+ <body>
83
+ <div class="wrap">
84
+ <div class="whale">DSH</div>
85
+ <h2>后端未连接</h2>
86
+ <p>请启动 dsh 后端,或使用下方按钮</p>
87
+ <button id="retry">重新加载</button>
88
+ <div class="actions">
89
+ <button id="start">启动后端</button>
90
+ <button id="detect">自动探测后端</button>
91
+ </div>
92
+ <button id="folder" class="folder-btn">设置后端安装文件夹</button>
93
+ <p class="hint">后端启动后本窗口会自动刷新</p>
94
+ </div>
95
+ <script>
96
+ // Injected by preload (sandbox-safe). Falls back to a plain reload.
97
+ var api = window.shellAPI || {};
98
+ document.getElementById('retry').addEventListener('click', function () {
99
+ if (api.reload) api.reload();
100
+ else location.reload();
101
+ });
102
+ var startBtn = document.getElementById('start');
103
+ if (api.startBackend) startBtn.addEventListener('click', api.startBackend);
104
+ else startBtn.style.display = 'none';
105
+ var detectBtn = document.getElementById('detect');
106
+ if (api.detectBackend) detectBtn.addEventListener('click', api.detectBackend);
107
+ else detectBtn.style.display = 'none';
108
+ var folderBtn = document.getElementById('folder');
109
+ if (api.chooseBackendFolder) folderBtn.addEventListener('click', api.chooseBackendFolder);
110
+ else folderBtn.style.display = 'none';
111
+ </script>
112
+ </body>
113
+ </html>
package/electron/main.js CHANGED
@@ -9,7 +9,7 @@
9
9
  * The main window is a pure shell — all backend controls live in the tray.
10
10
  */
11
11
  import { app, BrowserWindow } from 'electron'
12
- import { createMainWindow } from './window.js'
12
+ import { createMainWindow, reloadWindow } from './window.js'
13
13
  import { createTray, refreshTrayMenu } from './tray.js'
14
14
  import { loadConfig, saveConfig } from './config.js'
15
15
  import { detect, start } from './service.js'
@@ -89,6 +89,11 @@ if (!gotLock) {
89
89
  saveConfig({ ...config, autoLaunch: enabled })
90
90
  app.setLoginItemSettings({ openAtLogin: enabled })
91
91
  },
92
+ onReload: () => {
93
+ if (mainWindow && !mainWindow.isDestroyed()) {
94
+ reloadWindow(mainWindow, loadConfig().targetUrl || 'http://127.0.0.1:3080')
95
+ }
96
+ },
92
97
  onQuit: () => {
93
98
  app.isQuitting = true
94
99
  app.quit()