@kesike/dsh-exit 0.2.0 → 0.2.2
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 +3 -3
- package/README.zh-CN.md +3 -3
- package/lib/client.js +60 -8
- package/package.json +1 -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)
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
- Keeps the **Exit** section at the bottom of the settings navigation.
|
|
26
26
|
- Calls the typed `dshExit/exit` Remote method only after confirmation.
|
|
27
27
|
- Gives the gateway a short acknowledgement window, then ends the host process.
|
|
28
|
-
- Releases every port held by that process
|
|
28
|
+
- Releases every port held by that process; the settings page displays the current dsh Web host and port.
|
|
29
29
|
- Keeps the terminal window and browser tab available for the next action.
|
|
30
30
|
- Uses the existing dsh design tokens and the Lucide `power` icon.
|
|
31
31
|
|
|
@@ -124,7 +124,7 @@ node --check lib/client.js
|
|
|
124
124
|
- **Install mode:** npm package
|
|
125
125
|
- **Surface:** lower-right floating control
|
|
126
126
|
- **Action:** terminate the dsh host process
|
|
127
|
-
- **
|
|
127
|
+
- **Runtime port:** read from the current dsh Web address in the settings page
|
|
128
128
|
- **Repository topics:** `dsh` · `deepseek-harness` · `plugin` · `javascript` · `web`
|
|
129
129
|
|
|
130
130
|
The power icon comes from [Lucide](https://lucide.dev/icons/power) and is used under its ISC license.
|
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)
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
- **退出**栏目始终位于设置左侧导航的最底部。
|
|
26
26
|
- 确认后调用类型化的 `dshExit/exit` Remote 方法。
|
|
27
27
|
- 先返回调用应答,再等待短暂窗口结束宿主进程。
|
|
28
|
-
-
|
|
28
|
+
- 释放该进程占用的全部端口;设置页会显示当前 dsh Web 的真实主机和端口。
|
|
29
29
|
- 保留宿主终端窗口和浏览器标签页,方便后续操作。
|
|
30
30
|
- 使用 dsh 现有设计令牌与 Lucide `power` 电源图标。
|
|
31
31
|
|
|
@@ -124,7 +124,7 @@ node --check lib/client.js
|
|
|
124
124
|
- **安装方式:** npm 包
|
|
125
125
|
- **界面位置:** 右下角悬浮控件
|
|
126
126
|
- **执行动作:** 结束 dsh 宿主进程
|
|
127
|
-
-
|
|
127
|
+
- **运行端口:** 从设置页当前 dsh Web 地址动态读取
|
|
128
128
|
- **仓库主题:** `dsh` · `deepseek-harness` · `plugin` · `javascript` · `web`
|
|
129
129
|
|
|
130
130
|
电源图标来自 [Lucide](https://lucide.dev/icons/power),遵循其 ISC 许可使用。
|
package/lib/client.js
CHANGED
|
@@ -37,6 +37,10 @@ window.__ModuleLoader__.load({
|
|
|
37
37
|
".dshExitSettingsButton:hover:not(:disabled){filter:brightness(1.08)}",
|
|
38
38
|
".dshExitSettingsButton:focus-visible{outline:2px solid " + ERROR_RED + ";outline-offset:2px}",
|
|
39
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}",
|
|
40
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}",
|
|
41
45
|
"@keyframes dshExitFade{from{opacity:0}}",
|
|
42
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}",
|
|
@@ -87,10 +91,10 @@ window.__ModuleLoader__.load({
|
|
|
87
91
|
nav: "退出",
|
|
88
92
|
title: "退出 dsh",
|
|
89
93
|
description: "从这里安全结束 dsh 宿主进程,并释放它占用的端口。",
|
|
90
|
-
warning: "
|
|
94
|
+
warning: "确认后将结束所有运行中的会话并停止后台服务,当前 dsh Web 端口 {endpoint} 会随之释放。",
|
|
91
95
|
button: "确认退出",
|
|
92
96
|
dialogTitle: "退出 DeepSeek Harness?",
|
|
93
|
-
dialogBody: "
|
|
97
|
+
dialogBody: "退出后将结束所有运行中的会话并停止后台服务,当前 dsh Web 端口 {endpoint} 会随之释放。",
|
|
94
98
|
cancel: "取消",
|
|
95
99
|
confirm: "确认退出",
|
|
96
100
|
exiting: "正在退出…",
|
|
@@ -100,10 +104,10 @@ window.__ModuleLoader__.load({
|
|
|
100
104
|
nav: "Exit",
|
|
101
105
|
title: "Exit dsh",
|
|
102
106
|
description: "Safely terminate the dsh host process and release the ports it owns.",
|
|
103
|
-
warning: "Confirming ends all running sessions and stops the background service, releasing port
|
|
107
|
+
warning: "Confirming ends all running sessions and stops the background service, releasing the current dsh Web port {endpoint}.",
|
|
104
108
|
button: "Confirm exit",
|
|
105
109
|
dialogTitle: "Exit DeepSeek Harness?",
|
|
106
|
-
dialogBody: "This ends all running sessions and stops the background service, releasing port
|
|
110
|
+
dialogBody: "This ends all running sessions and stops the background service, releasing the current dsh Web port {endpoint}.",
|
|
107
111
|
cancel: "Cancel",
|
|
108
112
|
confirm: "Confirm exit",
|
|
109
113
|
exiting: "Exiting…",
|
|
@@ -123,11 +127,52 @@ window.__ModuleLoader__.load({
|
|
|
123
127
|
document.head.appendChild(tag);
|
|
124
128
|
}
|
|
125
129
|
|
|
126
|
-
function textOf(t, key) {
|
|
127
|
-
|
|
130
|
+
function textOf(t, key, values = {}) {
|
|
131
|
+
const raw = typeof t === "function" ? t(key, values) : DICT.zh[key] ?? key;
|
|
132
|
+
return String(raw).replace(/\{([A-Za-z0-9_]+)\}/g, (match, name) => values[name] === undefined ? match : String(values[name]));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function currentDshEndpoint() {
|
|
136
|
+
const location = globalThis.location;
|
|
137
|
+
return location?.host || "当前 Web 端口";
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** dsh 的设置壳层为未知 section 使用齿轮图标;给本插件的导航项换成 power 图标。 */
|
|
141
|
+
function decorateExitNav(t) {
|
|
142
|
+
const labels = new Set(["退出", "Exit", textOf(t, "nav")]);
|
|
143
|
+
for (const cell of document.querySelectorAll("nav button")) {
|
|
144
|
+
const label = [...cell.querySelectorAll("span")].find((candidate) => labels.has(candidate.textContent.trim()));
|
|
145
|
+
if (label === undefined) continue;
|
|
146
|
+
cell.dataset.dshExitNav = "true";
|
|
147
|
+
cell.classList.add("dshExitNavCell");
|
|
148
|
+
label.classList.add("dshExitNavLabel");
|
|
149
|
+
if (cell.querySelector(".dshExitNavIcon") !== null) continue;
|
|
150
|
+
const originalIcon = cell.firstElementChild;
|
|
151
|
+
const icon = document.createElement("span");
|
|
152
|
+
icon.className = "dshExitNavIcon";
|
|
153
|
+
icon.innerHTML = ICON_SVG;
|
|
154
|
+
if (originalIcon !== null && originalIcon !== label) {
|
|
155
|
+
originalIcon.dataset.dshExitOriginalIcon = "true";
|
|
156
|
+
originalIcon.style.display = "none";
|
|
157
|
+
cell.insertBefore(icon, originalIcon);
|
|
158
|
+
} else {
|
|
159
|
+
cell.insertBefore(icon, label);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function clearDecoratedExitNav() {
|
|
165
|
+
for (const cell of document.querySelectorAll("[data-dsh-exit-nav='true']")) {
|
|
166
|
+
cell.querySelector(".dshExitNavIcon")?.remove();
|
|
167
|
+
cell.querySelector("[data-dsh-exit-original-icon='true']")?.style.removeProperty("display");
|
|
168
|
+
cell.querySelector(".dshExitNavLabel")?.classList.remove("dshExitNavLabel");
|
|
169
|
+
cell.classList.remove("dshExitNavCell");
|
|
170
|
+
delete cell.dataset.dshExitNav;
|
|
171
|
+
}
|
|
128
172
|
}
|
|
129
173
|
|
|
130
174
|
function ExitSettingsSection({ ctx, t }) {
|
|
175
|
+
const endpoint = currentDshEndpoint();
|
|
131
176
|
return h("section", {
|
|
132
177
|
className: "dshExitSettings",
|
|
133
178
|
"aria-labelledby": "dsh-exit-settings-title"
|
|
@@ -144,7 +189,7 @@ window.__ModuleLoader__.load({
|
|
|
144
189
|
])
|
|
145
190
|
]),
|
|
146
191
|
h("div", { className: "dshExitSettingsCard", key: "card" }, [
|
|
147
|
-
h("p", { className: "dshExitSettingsWarning", key: "warning" }, textOf(t, "warning")),
|
|
192
|
+
h("p", { className: "dshExitSettingsWarning", key: "warning" }, textOf(t, "warning", { endpoint })),
|
|
148
193
|
h("button", {
|
|
149
194
|
type: "button",
|
|
150
195
|
className: "dshExitSettingsButton",
|
|
@@ -171,7 +216,8 @@ window.__ModuleLoader__.load({
|
|
|
171
216
|
}
|
|
172
217
|
|
|
173
218
|
function openModal(ctx, exitBtn, t) {
|
|
174
|
-
const
|
|
219
|
+
const endpoint = currentDshEndpoint();
|
|
220
|
+
const text = (key) => textOf(t, key, { endpoint });
|
|
175
221
|
closeModal();
|
|
176
222
|
overlayEl = document.createElement("div");
|
|
177
223
|
overlayEl.className = "dshExitOverlay";
|
|
@@ -247,6 +293,10 @@ window.__ModuleLoader__.load({
|
|
|
247
293
|
injectCss();
|
|
248
294
|
ctx.effect(() => ctx.locale.register(NS, DICT), "dsh-exit: settings dictionaries");
|
|
249
295
|
const t = ctx.locale.bind(NS);
|
|
296
|
+
const decorate = () => decorateExitNav(t);
|
|
297
|
+
decorate();
|
|
298
|
+
const navObserver = document.body === null ? null : new MutationObserver(decorate);
|
|
299
|
+
navObserver?.observe(document.body, { childList: true, subtree: true, characterData: true });
|
|
250
300
|
const SettingsSection = (props) => h(ExitSettingsSection, { ...props, ctx });
|
|
251
301
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
252
302
|
name: "settings.section",
|
|
@@ -259,6 +309,8 @@ window.__ModuleLoader__.load({
|
|
|
259
309
|
const remote = ctx.get("remote");
|
|
260
310
|
if (remote !== undefined) disposeRemote = await remote.$mount(EXIT_REMOTE);
|
|
261
311
|
return async () => {
|
|
312
|
+
navObserver?.disconnect();
|
|
313
|
+
clearDecoratedExitNav();
|
|
262
314
|
closeModal();
|
|
263
315
|
disposeRemote();
|
|
264
316
|
};
|