@kesike/dsh-exit 0.1.3 → 0.2.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/README.md +5 -4
- package/README.zh-CN.md +5 -4
- package/lib/client.js +144 -51
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
[](https://npmjs.com/package/@deepseek-ai/dsh)
|
|
8
8
|
[](https://www.npmjs.com/package/@kesike/dsh-exit)
|
|
9
9
|
[](https://github.com/KeS1Ke/dsh-exit)
|
|
10
|
-
[](package.json)
|
|
11
11
|
[](package.json)
|
|
12
12
|
|
|
13
13
|
[简体中文](https://github.com/KeS1Ke/dsh-exit/blob/main/README.zh-CN.md)
|
|
@@ -19,9 +19,10 @@
|
|
|
19
19
|
|
|
20
20
|
## ✨ What it does
|
|
21
21
|
|
|
22
|
-
`dsh-exit` adds a
|
|
22
|
+
`dsh-exit` adds a dedicated **Exit** section to the dsh settings panel. It uses the highest settings order so newly installed settings plugins appear above it.
|
|
23
23
|
|
|
24
24
|
- Opens a confirmation modal before doing anything destructive.
|
|
25
|
+
- Keeps the **Exit** section at the bottom of the settings navigation.
|
|
25
26
|
- Calls the typed `dshExit/exit` Remote method only after confirmation.
|
|
26
27
|
- Gives the gateway a short acknowledgement window, then ends the host process.
|
|
27
28
|
- Releases every port held by that process, including the usual `127.0.0.1:3080`.
|
|
@@ -46,7 +47,7 @@ The animation, video, and screenshot below are repository showcase assets. They
|
|
|
46
47
|
|
|
47
48
|
## 📸 Real dsh UI
|
|
48
49
|
|
|
49
|
-
The capture below comes from a running dsh Web profile with `dsh-exit` installed. The
|
|
50
|
+
The capture below comes from a running dsh Web profile with `dsh-exit` installed. The Exit control is now provided by the final section in the settings navigation.
|
|
50
51
|
|
|
51
52
|
<p align="center">
|
|
52
53
|
<img src="docs/dsh-exit-real.png" alt="Running dsh Web UI with the dsh-exit power button in the lower-right corner" width="720">
|
|
@@ -57,7 +58,7 @@ The capture below comes from a running dsh Web profile with `dsh-exit` installed
|
|
|
57
58
|
| Layer | File | Responsibility |
|
|
58
59
|
| --- | --- | --- |
|
|
59
60
|
| Host | [`lib/index.js`](lib/index.js) | Registers the `dshExit` Cordis service and the typed `exit()` Remote method. |
|
|
60
|
-
| Client | [`lib/client.js`](lib/client.js) | Self-contained browser bundle: button, CSS, modal, keyboard handling, and Remote mounting. |
|
|
61
|
+
| Client | [`lib/client.js`](lib/client.js) | Self-contained browser bundle: settings section, exit button, CSS, modal, keyboard handling, and Remote mounting. |
|
|
61
62
|
| Bundle patch | [`cordis.patch.yml`](cordis.patch.yml) | Inserts the plugin row into the dsh profile. |
|
|
62
63
|
| Package metadata | [`package.json`](package.json) | Declares the host entry, web client, and bundle patch. |
|
|
63
64
|
|
package/README.zh-CN.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
[](https://npmjs.com/package/@deepseek-ai/dsh)
|
|
8
8
|
[](https://www.npmjs.com/package/@kesike/dsh-exit)
|
|
9
9
|
[](https://github.com/KeS1Ke/dsh-exit)
|
|
10
|
-
[](package.json)
|
|
11
11
|
[](package.json)
|
|
12
12
|
|
|
13
13
|
**简体中文** | [English](https://github.com/KeS1Ke/dsh-exit/blob/main/README.md)
|
|
@@ -19,9 +19,10 @@
|
|
|
19
19
|
|
|
20
20
|
## ✨ 功能概览
|
|
21
21
|
|
|
22
|
-
`dsh-exit` 在 dsh
|
|
22
|
+
`dsh-exit` 在 dsh 设置面板中增加一个独立的**退出**栏目,并使用最高排序值,确保新安装的设置类插件仍排在它前面。
|
|
23
23
|
|
|
24
24
|
- 先弹出确认弹窗,确认前不会执行退出动作。
|
|
25
|
+
- **退出**栏目始终位于设置左侧导航的最底部。
|
|
25
26
|
- 确认后调用类型化的 `dshExit/exit` Remote 方法。
|
|
26
27
|
- 先返回调用应答,再等待短暂窗口结束宿主进程。
|
|
27
28
|
- 释放该进程占用的全部端口,包括常见的 `127.0.0.1:3080`。
|
|
@@ -46,7 +47,7 @@
|
|
|
46
47
|
|
|
47
48
|
## 📸 真实 dsh 界面
|
|
48
49
|
|
|
49
|
-
下图来自已经安装 `dsh-exit` 的真实 dsh Web profile
|
|
50
|
+
下图来自已经安装 `dsh-exit` 的真实 dsh Web profile;退出操作现在位于设置左侧导航的最后一栏。
|
|
50
51
|
|
|
51
52
|
<p align="center">
|
|
52
53
|
<img src="docs/dsh-exit-real.png" alt="运行中的 dsh Web 界面与右下角 dsh-exit 电源按钮" width="720">
|
|
@@ -57,7 +58,7 @@
|
|
|
57
58
|
| 层次 | 文件 | 职责 |
|
|
58
59
|
| --- | --- | --- |
|
|
59
60
|
| 宿主侧 | [`lib/index.js`](lib/index.js) | 注册 `dshExit` Cordis 服务和类型化 `exit()` Remote 方法。 |
|
|
60
|
-
| 客户端 | [`lib/client.js`](lib/client.js) | 自包含浏览器 bundle
|
|
61
|
+
| 客户端 | [`lib/client.js`](lib/client.js) | 自包含浏览器 bundle:设置栏目、退出按钮、样式、弹窗、键盘交互和 Remote 挂载。 |
|
|
61
62
|
| Bundle 补丁 | [`cordis.patch.yml`](cordis.patch.yml) | 向 dsh profile 插入插件行。 |
|
|
62
63
|
| 包元数据 | [`package.json`](package.json) | 声明宿主入口、Web 客户端和 Bundle 补丁。 |
|
|
63
64
|
|
package/lib/client.js
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
//#region dsh-exit 浏览器客户端 bundle
|
|
2
2
|
/**
|
|
3
3
|
* dsh-exit 客户端:
|
|
4
|
-
* -
|
|
5
|
-
* -
|
|
4
|
+
* - 在 dsh 设置菜单中注册一个始终排在最后的“退出”栏目
|
|
5
|
+
* - 栏目中的退出按钮首次点击弹确认弹窗;确认后调用 remote.dshExit.exit(),
|
|
6
6
|
* 服务端结束宿主进程并释放端口,不操作终端窗口或浏览器标签页
|
|
7
7
|
*
|
|
8
|
-
*
|
|
8
|
+
* 页面使用 dsh 已提供的 React、slots 和 locale 运行时,不引入新的运行时依赖。
|
|
9
9
|
*/
|
|
10
10
|
window.__ModuleLoader__.load({
|
|
11
11
|
// The loader key follows the resolved npm package name, including its scope.
|
|
12
12
|
id: "@kesike/dsh-exit",
|
|
13
|
-
factory: () => {
|
|
13
|
+
factory: (require) => {
|
|
14
14
|
var module = { exports: {} };
|
|
15
15
|
var exports = module.exports;
|
|
16
16
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
17
|
+
const React = require("react");
|
|
18
|
+
const h = React.createElement;
|
|
17
19
|
|
|
18
20
|
/** 与 archive-manager「删除会话」相同的错误红(设计令牌)。 */
|
|
19
21
|
const ERROR_RED = "var(--dsw-alias-state-error-primary)";
|
|
@@ -22,11 +24,23 @@ window.__ModuleLoader__.load({
|
|
|
22
24
|
const ICON_SVG = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 2v10"/><path d="M18.4 6.6a9 9 0 1 1-12.77.04"/></svg>';
|
|
23
25
|
|
|
24
26
|
const CSS_TEXT = [
|
|
25
|
-
".
|
|
26
|
-
".
|
|
27
|
-
".
|
|
28
|
-
".
|
|
29
|
-
".
|
|
27
|
+
".dshExitSettings{box-sizing:border-box;max-width:720px;padding:28px 32px 40px;color:var(--dsw-alias-label-primary)}",
|
|
28
|
+
".dshExitSettingsHeader{display:flex;align-items:flex-start;gap:14px;padding-bottom:22px;border-bottom:1px solid var(--dsw-alias-border-l2)}",
|
|
29
|
+
".dshExitSettingsIcon{box-sizing:border-box;width:38px;height:38px;display:grid;place-items:center;flex:none;border:1px solid " + ERROR_RED + ";border-radius:12px;color:" + ERROR_RED + ";background:var(--dsw-alias-button-elevated-fill)}",
|
|
30
|
+
".dshExitSettingsIcon svg{width:20px;height:20px}",
|
|
31
|
+
".dshExitSettingsTitle{margin:0;font-size:20px;line-height:28px;font-weight:650;color:var(--dsw-alias-label-primary)}",
|
|
32
|
+
".dshExitSettingsDescription{margin:6px 0 0;max-width:560px;font-size:13px;line-height:20px;color:var(--dsw-alias-label-secondary)}",
|
|
33
|
+
".dshExitSettingsCard{display:flex;align-items:center;justify-content:space-between;gap:24px;margin-top:24px;padding:20px;border:1px solid var(--dsw-alias-border-l2);border-radius:14px;background:var(--dsw-alias-bg-layer-2)}",
|
|
34
|
+
".dshExitSettingsWarning{margin:0;max-width:430px;font-size:13px;line-height:20px;color:var(--dsw-alias-label-secondary)}",
|
|
35
|
+
".dshExitSettingsButton{display:inline-flex;align-items:center;justify-content:center;gap:8px;flex:none;min-width:112px;height:36px;padding:0 16px;cursor:pointer;border:0;border-radius:10px;background:" + ERROR_RED + ";color:#fff;font-size:13px;font-weight:650;transition:filter .12s ease,opacity .12s ease}",
|
|
36
|
+
".dshExitSettingsButton svg{width:16px;height:16px}",
|
|
37
|
+
".dshExitSettingsButton:hover:not(:disabled){filter:brightness(1.08)}",
|
|
38
|
+
".dshExitSettingsButton:focus-visible{outline:2px solid " + ERROR_RED + ";outline-offset:2px}",
|
|
39
|
+
".dshExitSettingsButton:disabled{cursor:default;opacity:.6}",
|
|
40
|
+
".dshExitNavCell{color:" + ERROR_RED + " !important}",
|
|
41
|
+
".dshExitNavCell .dshExitNavLabel{color:" + ERROR_RED + " !important;font-weight:650}",
|
|
42
|
+
".dshExitNavIcon{box-sizing:border-box;width:16px;height:16px;display:grid;place-items:center;flex:none;color:" + ERROR_RED + "}",
|
|
43
|
+
".dshExitNavIcon svg{width:16px;height:16px}",
|
|
30
44
|
".dshExitOverlay{position:fixed;inset:0;z-index:2147483000;display:flex;align-items:center;justify-content:center;background:rgba(15,20,25,.45);animation:dshExitFade .12s ease-out}",
|
|
31
45
|
"@keyframes dshExitFade{from{opacity:0}}",
|
|
32
46
|
".dshExitModal{box-sizing:border-box;width:min(380px,calc(100vw - 48px));border-radius:16px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-button-elevated-fill);box-shadow:0 24px 64px rgba(0,0,0,.35);padding:24px;display:flex;flex-direction:column;gap:12px;animation:dshExitPop .14s ease-out}",
|
|
@@ -71,8 +85,37 @@ window.__ModuleLoader__.load({
|
|
|
71
85
|
]
|
|
72
86
|
};
|
|
73
87
|
|
|
88
|
+
const NS = "dsh-exit";
|
|
89
|
+
const DICT = {
|
|
90
|
+
zh: {
|
|
91
|
+
nav: "退出",
|
|
92
|
+
title: "退出 dsh",
|
|
93
|
+
description: "从这里安全结束 dsh 宿主进程,并释放它占用的端口。",
|
|
94
|
+
warning: "确认后将结束所有运行中的会话并停止后台服务,3080 端口会随之释放。",
|
|
95
|
+
button: "确认退出",
|
|
96
|
+
dialogTitle: "退出 DeepSeek Harness?",
|
|
97
|
+
dialogBody: "退出后将结束所有运行中的会话并停止后台服务,3080 端口会随之释放。",
|
|
98
|
+
cancel: "取消",
|
|
99
|
+
confirm: "确认退出",
|
|
100
|
+
exiting: "正在退出…",
|
|
101
|
+
errorPrefix: "退出失败:"
|
|
102
|
+
},
|
|
103
|
+
en: {
|
|
104
|
+
nav: "Exit",
|
|
105
|
+
title: "Exit dsh",
|
|
106
|
+
description: "Safely terminate the dsh host process and release the ports it owns.",
|
|
107
|
+
warning: "Confirming ends all running sessions and stops the background service, releasing port 3080.",
|
|
108
|
+
button: "Confirm exit",
|
|
109
|
+
dialogTitle: "Exit DeepSeek Harness?",
|
|
110
|
+
dialogBody: "This ends all running sessions and stops the background service, releasing port 3080.",
|
|
111
|
+
cancel: "Cancel",
|
|
112
|
+
confirm: "Confirm exit",
|
|
113
|
+
exiting: "Exiting…",
|
|
114
|
+
errorPrefix: "Exit failed: "
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
74
118
|
let exiting = false;
|
|
75
|
-
let exitBtnEl = null;
|
|
76
119
|
let overlayEl = null;
|
|
77
120
|
let escHandler = null;
|
|
78
121
|
|
|
@@ -84,32 +127,74 @@ window.__ModuleLoader__.load({
|
|
|
84
127
|
document.head.appendChild(tag);
|
|
85
128
|
}
|
|
86
129
|
|
|
87
|
-
function
|
|
88
|
-
|
|
89
|
-
exitBtn.className = "dshExitBtn";
|
|
90
|
-
exitBtn.type = "button";
|
|
91
|
-
exitBtn.disabled = false;
|
|
92
|
-
exitBtn.setAttribute("aria-label", "退出");
|
|
93
|
-
exitBtn.title = "退出 DeepSeek Harness";
|
|
94
|
-
exitBtn.dataset.dshExitButton = "true";
|
|
95
|
-
exitBtn.innerHTML = ICON_SVG;
|
|
96
|
-
return exitBtn;
|
|
130
|
+
function textOf(t, key) {
|
|
131
|
+
return typeof t === "function" ? t(key) : DICT.zh[key] ?? key;
|
|
97
132
|
}
|
|
98
133
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
134
|
+
/** dsh 的设置壳层为未知 section 使用齿轮图标;给本插件的导航项换成 power 图标。 */
|
|
135
|
+
function decorateExitNav(t) {
|
|
136
|
+
const labels = new Set(["退出", "Exit", textOf(t, "nav")]);
|
|
137
|
+
for (const cell of document.querySelectorAll("nav button")) {
|
|
138
|
+
const label = [...cell.querySelectorAll("span")].find((candidate) => labels.has(candidate.textContent.trim()));
|
|
139
|
+
if (label === undefined) continue;
|
|
140
|
+
cell.dataset.dshExitNav = "true";
|
|
141
|
+
cell.classList.add("dshExitNavCell");
|
|
142
|
+
label.classList.add("dshExitNavLabel");
|
|
143
|
+
if (cell.querySelector(".dshExitNavIcon") !== null) continue;
|
|
144
|
+
const originalIcon = cell.firstElementChild;
|
|
145
|
+
const icon = document.createElement("span");
|
|
146
|
+
icon.className = "dshExitNavIcon";
|
|
147
|
+
icon.innerHTML = ICON_SVG;
|
|
148
|
+
if (originalIcon !== null && originalIcon !== label) {
|
|
149
|
+
originalIcon.dataset.dshExitOriginalIcon = "true";
|
|
150
|
+
originalIcon.style.display = "none";
|
|
151
|
+
cell.insertBefore(icon, originalIcon);
|
|
152
|
+
} else {
|
|
153
|
+
cell.insertBefore(icon, label);
|
|
154
|
+
}
|
|
104
155
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function clearDecoratedExitNav() {
|
|
159
|
+
for (const cell of document.querySelectorAll("[data-dsh-exit-nav='true']")) {
|
|
160
|
+
cell.querySelector(".dshExitNavIcon")?.remove();
|
|
161
|
+
cell.querySelector("[data-dsh-exit-original-icon='true']")?.style.removeProperty("display");
|
|
162
|
+
cell.querySelector(".dshExitNavLabel")?.classList.remove("dshExitNavLabel");
|
|
163
|
+
cell.classList.remove("dshExitNavCell");
|
|
164
|
+
delete cell.dataset.dshExitNav;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function ExitSettingsSection({ ctx, t }) {
|
|
169
|
+
return h("section", {
|
|
170
|
+
className: "dshExitSettings",
|
|
171
|
+
"aria-labelledby": "dsh-exit-settings-title"
|
|
172
|
+
}, [
|
|
173
|
+
h("div", { className: "dshExitSettingsHeader", key: "header" }, [
|
|
174
|
+
h("span", {
|
|
175
|
+
className: "dshExitSettingsIcon",
|
|
176
|
+
dangerouslySetInnerHTML: { __html: ICON_SVG },
|
|
177
|
+
key: "icon"
|
|
178
|
+
}),
|
|
179
|
+
h("div", { key: "copy" }, [
|
|
180
|
+
h("h2", { className: "dshExitSettingsTitle", id: "dsh-exit-settings-title", key: "title" }, textOf(t, "title")),
|
|
181
|
+
h("p", { className: "dshExitSettingsDescription", key: "description" }, textOf(t, "description"))
|
|
182
|
+
])
|
|
183
|
+
]),
|
|
184
|
+
h("div", { className: "dshExitSettingsCard", key: "card" }, [
|
|
185
|
+
h("p", { className: "dshExitSettingsWarning", key: "warning" }, textOf(t, "warning")),
|
|
186
|
+
h("button", {
|
|
187
|
+
type: "button",
|
|
188
|
+
className: "dshExitSettingsButton",
|
|
189
|
+
"aria-label": textOf(t, "button"),
|
|
190
|
+
onClick: (event) => openModal(ctx, event.currentTarget, t),
|
|
191
|
+
key: "button"
|
|
192
|
+
}, [
|
|
193
|
+
h("span", { dangerouslySetInnerHTML: { __html: ICON_SVG }, key: "icon" }),
|
|
194
|
+
textOf(t, "button")
|
|
195
|
+
])
|
|
196
|
+
])
|
|
197
|
+
]);
|
|
113
198
|
}
|
|
114
199
|
|
|
115
200
|
function closeModal() {
|
|
@@ -123,7 +208,8 @@ window.__ModuleLoader__.load({
|
|
|
123
208
|
}
|
|
124
209
|
}
|
|
125
210
|
|
|
126
|
-
function openModal(ctx, exitBtn) {
|
|
211
|
+
function openModal(ctx, exitBtn, t) {
|
|
212
|
+
const text = (key) => textOf(t, key);
|
|
127
213
|
closeModal();
|
|
128
214
|
overlayEl = document.createElement("div");
|
|
129
215
|
overlayEl.className = "dshExitOverlay";
|
|
@@ -131,13 +217,13 @@ window.__ModuleLoader__.load({
|
|
|
131
217
|
panel.className = "dshExitModal";
|
|
132
218
|
panel.setAttribute("role", "dialog");
|
|
133
219
|
panel.setAttribute("aria-modal", "true");
|
|
134
|
-
panel.setAttribute("aria-label", "
|
|
220
|
+
panel.setAttribute("aria-label", text("dialogTitle"));
|
|
135
221
|
const title = document.createElement("h3");
|
|
136
222
|
title.className = "dshExitTitle";
|
|
137
|
-
title.textContent = "
|
|
223
|
+
title.textContent = text("dialogTitle");
|
|
138
224
|
const body = document.createElement("p");
|
|
139
225
|
body.className = "dshExitBody";
|
|
140
|
-
body.textContent = "
|
|
226
|
+
body.textContent = text("dialogBody");
|
|
141
227
|
const errorEl = document.createElement("p");
|
|
142
228
|
errorEl.className = "dshExitError";
|
|
143
229
|
const actions = document.createElement("div");
|
|
@@ -145,11 +231,11 @@ window.__ModuleLoader__.load({
|
|
|
145
231
|
const cancel = document.createElement("button");
|
|
146
232
|
cancel.type = "button";
|
|
147
233
|
cancel.className = "dshExitCancel";
|
|
148
|
-
cancel.textContent = "
|
|
234
|
+
cancel.textContent = text("cancel");
|
|
149
235
|
const confirm = document.createElement("button");
|
|
150
236
|
confirm.type = "button";
|
|
151
237
|
confirm.className = "dshExitConfirm";
|
|
152
|
-
confirm.textContent = "
|
|
238
|
+
confirm.textContent = text("confirm");
|
|
153
239
|
actions.append(cancel, confirm);
|
|
154
240
|
panel.append(title, body, errorEl, actions);
|
|
155
241
|
overlayEl.appendChild(panel);
|
|
@@ -170,7 +256,7 @@ window.__ModuleLoader__.load({
|
|
|
170
256
|
cancel.disabled = true;
|
|
171
257
|
errorEl.textContent = "";
|
|
172
258
|
exitBtn.disabled = true;
|
|
173
|
-
exitBtn.setAttribute("aria-label", "
|
|
259
|
+
exitBtn.setAttribute("aria-label", text("exiting"));
|
|
174
260
|
Promise.resolve()
|
|
175
261
|
.then(() => {
|
|
176
262
|
const service = ctx.get("remote.dshExit");
|
|
@@ -189,7 +275,7 @@ window.__ModuleLoader__.load({
|
|
|
189
275
|
cancel.disabled = false;
|
|
190
276
|
exitBtn.disabled = false;
|
|
191
277
|
exitBtn.setAttribute("aria-label", "退出");
|
|
192
|
-
errorEl.textContent = "
|
|
278
|
+
errorEl.textContent = text("errorPrefix") + (reason instanceof Error ? reason.message : String(reason));
|
|
193
279
|
});
|
|
194
280
|
});
|
|
195
281
|
document.body.appendChild(overlayEl);
|
|
@@ -197,25 +283,32 @@ window.__ModuleLoader__.load({
|
|
|
197
283
|
|
|
198
284
|
async function apply(ctx) {
|
|
199
285
|
injectCss();
|
|
200
|
-
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
286
|
+
ctx.effect(() => ctx.locale.register(NS, DICT), "dsh-exit: settings dictionaries");
|
|
287
|
+
const t = ctx.locale.bind(NS);
|
|
288
|
+
const decorate = () => decorateExitNav(t);
|
|
289
|
+
decorate();
|
|
290
|
+
const navObserver = document.body === null ? null : new MutationObserver(decorate);
|
|
291
|
+
navObserver?.observe(document.body, { childList: true, subtree: true, characterData: true });
|
|
292
|
+
const SettingsSection = (props) => h(ExitSettingsSection, { ...props, ctx });
|
|
293
|
+
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
294
|
+
name: "settings.section",
|
|
295
|
+
id: "dsh-exit",
|
|
296
|
+
order: Number.MAX_SAFE_INTEGER,
|
|
297
|
+
label: () => t("nav"),
|
|
298
|
+
locale: NS
|
|
299
|
+
}, SettingsSection));
|
|
205
300
|
let disposeRemote = () => {};
|
|
206
301
|
const remote = ctx.get("remote");
|
|
207
302
|
if (remote !== undefined) disposeRemote = await remote.$mount(EXIT_REMOTE);
|
|
208
303
|
return async () => {
|
|
209
|
-
|
|
304
|
+
navObserver?.disconnect();
|
|
305
|
+
clearDecoratedExitNav();
|
|
210
306
|
closeModal();
|
|
211
|
-
if (exitBtnEl) {
|
|
212
|
-
exitBtnEl.remove();
|
|
213
|
-
exitBtnEl = null;
|
|
214
|
-
}
|
|
215
307
|
disposeRemote();
|
|
216
308
|
};
|
|
217
309
|
}
|
|
218
310
|
|
|
311
|
+
exports.inject = ["slots", "locale"];
|
|
219
312
|
exports.apply = apply;
|
|
220
313
|
return module.exports;
|
|
221
314
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kesike/dsh-exit",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "在 dsh web 界面提供退出按钮:确认后结束宿主进程并释放端口",
|
|
6
6
|
"keywords": [
|
|
@@ -43,6 +43,11 @@
|
|
|
43
43
|
"patch": "./cordis.patch.yml"
|
|
44
44
|
},
|
|
45
45
|
"client": {
|
|
46
|
+
"inject": [
|
|
47
|
+
"@deepseek-ai/dsh-client-runtime",
|
|
48
|
+
"@deepseek-ai/dsh-client-ui-slots",
|
|
49
|
+
"@deepseek-ai/dsh-client-locale"
|
|
50
|
+
],
|
|
46
51
|
"platform": "web"
|
|
47
52
|
}
|
|
48
53
|
}
|