dshmarket 1.16.3 → 1.16.5
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 +1 -1
- package/README.zh.md +1 -1
- package/client/client.js +22 -3
- package/client/client.js.map +1 -1
- package/lib/backup.js +6 -1
- package/lib/compatibility.js +20 -1
- package/lib/index.js +5 -1
- package/lib/patch.js +56 -0
- package/lib/profile.js +60 -1
- package/lib/restart.js +52 -3
- package/lib/routes.js +83 -17
- package/lib/settings.js +8 -4
- package/lib/types/compatibility.d.ts +28 -1
- package/lib/types/patch.d.ts +19 -0
- package/lib/types/profile.d.ts +20 -0
- package/lib/types/restart.d.ts +44 -2
- package/package.json +1 -1
- package/src/backup.ts +6 -1
- package/src/client/MarketSection.tsx +30 -2
- package/src/client/locales.ts +4 -0
- package/src/client/market-data.ts +6 -0
- package/src/compatibility.ts +36 -2
- package/src/index.ts +5 -1
- package/src/patch.ts +54 -0
- package/src/profile.ts +64 -1
- package/src/restart.ts +58 -3
- package/src/routes.ts +83 -18
- package/src/settings.ts +8 -4
package/README.md
CHANGED
|
@@ -62,7 +62,7 @@ Installs prefer npm tarballs over full-repo GitHub downloads whenever a plugin p
|
|
|
62
62
|
- The install endpoint accepts same-origin POST only; the market never phones home
|
|
63
63
|
- Backups can contain credentials from your profile config — the UI warns before export and upload; WebDAV sync is https-only, refuses private-network targets, and never stores your password in the browser
|
|
64
64
|
- The restart endpoint additionally requires a direct loopback client (forwarded requests are rejected) and relaunches the exact DSH entry, arguments, environment, and working directory
|
|
65
|
-
- One-click restart launches a detached replacement.
|
|
65
|
+
- One-click restart launches a detached replacement. **When this host is systemd's own service process the button is hidden automatically** — the market would otherwise kill the takeover process along with the unit's cgroup and the service would not come back. The pending-change notice stays visible and says so. Detection requires both a systemd marker AND being the unit's main process, because `INVOCATION_ID` is inherited by every descendant of a unit (an ordinary terminal included) and hiding the button for those would be the worse bug. pm2 and launchd are not detected, so those deployments need the explicit setting below. Either flip **Allow restart** off in **Settings → Plugins → Plugin configuration**, or write it into the profile patch — where it has to sit under `config:`, because the loader passes only that sub-object to a plugin and a top-level `allowRestart:` is silently ignored (#227 by @Fantasymax):
|
|
66
66
|
|
|
67
67
|
```yaml
|
|
68
68
|
- id: dsh-market
|
package/README.zh.md
CHANGED
|
@@ -59,7 +59,7 @@ dsh plugin --profile web add dshmarket
|
|
|
59
59
|
- 安装接口只接受同源 POST;市场不会向任何地方上报数据
|
|
60
60
|
- 备份可能包含 profile 配置里的密钥——导出与上传前 UI 会明确提醒;WebDAV 同步仅限 https、拒绝内网地址,且密码永不落盘浏览器
|
|
61
61
|
- 重启接口还要求客户端直接来自环回地址(拒绝代理转发请求),并使用原入口、参数、环境和工作目录重新启动 DSH
|
|
62
|
-
-
|
|
62
|
+
- 一键重启会启动脱离终端的替代进程。**当本进程就是 systemd 服务的主进程时,按钮会自动隐藏**——否则市场重启会连带杀掉 cgroup 里的接管进程,服务起不来,待重启提示会说明原因。判定要求「systemd 标记」和「本进程是该 unit 的主进程」同时成立:`INVOCATION_ID` 会被 unit 的所有后代继承(包括普通终端),只看它会误伤一大批本来能正常重启的机器。pm2 和 launchd 不做检测,这类部署需要下面的显式配置。两种做法:在**设置 → 插件 → 插件配置**里关掉「允许重启」,或者写进 profile 补丁——注意必须嵌在 `config:` 下面,因为 loader 只把这个子对象传给插件,写在顶层会静默失效(#227,感谢 @Fantasymax):
|
|
63
63
|
|
|
64
64
|
```yaml
|
|
65
65
|
- id: dsh-market
|
package/client/client.js
CHANGED
|
@@ -83,6 +83,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
83
83
|
uninstalling: "卸载中…",
|
|
84
84
|
uninstallConfirmDesc: "将从当前 profile 中移除该插件。",
|
|
85
85
|
restartHint: "重启方式:关闭当前 dsh 进程后重新运行(例如 dsh web)",
|
|
86
|
+
restartHintSupervised: "本进程是 {0} 服务的主进程,重启交给它负责——市场自己重启会连带杀掉 cgroup 里的接管进程,服务将起不来。请执行 systemctl restart <你的 unit>。确认你的配置能承受市场自行重启(如 KillMode=process),可在本插件配置里手动打开「允许重启」。",
|
|
86
87
|
confirmTitle: "安装",
|
|
87
88
|
confirmWarn: "插件是社区第三方代码。安装即表示你信任该来源;构建脚本默认被禁止执行。",
|
|
88
89
|
cancel: "取消",
|
|
@@ -103,6 +104,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
103
104
|
agentBusyUpdate: "有 agent 正在运行,请等待其完成或将其取消后再更新——更新会直接替换插件文件,运行中的 agent 可能中途报错或新旧版本混用。",
|
|
104
105
|
agentBusyInstall: "有 agent 正在运行,请等待其完成或将其取消后再安装——安装会修改插件文件,运行中的 agent 可能中途报错。",
|
|
105
106
|
compatRiskBanner: "检测到兼容性风险,建议重启前到诊断页处理,或一键回滚本次操作。",
|
|
107
|
+
shadowNameBanner: "本次操作让同一个插件名在两个层里同时存在,重启后只有一个会生效:",
|
|
106
108
|
goDiagnose: "去诊断页修复",
|
|
107
109
|
rollbackNow: "一键回滚",
|
|
108
110
|
rollingBack: "回滚中…",
|
|
@@ -439,6 +441,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
439
441
|
uninstalling: "Removing…",
|
|
440
442
|
uninstallConfirmDesc: "This removes the plugin from the current profile.",
|
|
441
443
|
restartHint: "To restart: stop the current dsh process and run it again (e.g. dsh web)",
|
|
444
|
+
restartHintSupervised: "This process is {0}'s own service process, so restarts belong to it — restarting from here would kill the takeover process along with the cgroup and the service would not come back. Use systemctl restart <your unit>. If your unit can survive a self-restart (KillMode=process), turn Allow restart on in this plugin's configuration.",
|
|
442
445
|
confirmTitle: "Install",
|
|
443
446
|
confirmWarn: "Plugins are third-party community code. Installing means you trust this source; build scripts are blocked by default.",
|
|
444
447
|
cancel: "Cancel",
|
|
@@ -459,6 +462,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
459
462
|
agentBusyUpdate: "An agent is currently working — wait for it to finish (or cancel it) before updating. Updates replace plugin files in place, so a working agent can fail or mix versions mid-turn.",
|
|
460
463
|
agentBusyInstall: "An agent is currently working — wait for it to finish (or cancel it) before installing. Installing changes plugin files, so a working agent can fail mid-turn.",
|
|
461
464
|
compatRiskBanner: "Compatibility risk detected — open Diagnostics before restarting, or roll this operation back.",
|
|
465
|
+
shadowNameBanner: "This operation left one plugin name defined in two layers; only one will load after a restart:",
|
|
462
466
|
goDiagnose: "Open Diagnostics",
|
|
463
467
|
rollbackNow: "Roll back",
|
|
464
468
|
rollingBack: "Rolling back…",
|
|
@@ -3830,6 +3834,8 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
3830
3834
|
const [bootId, setBootId] = (0, react.useState)(null);
|
|
3831
3835
|
/** One-click restart (#14 by @ysyyhhh): server capability + in-flight state. */
|
|
3832
3836
|
const [restartEnabled, setRestartEnabled] = (0, react.useState)(false);
|
|
3837
|
+
/** Supervisor the host detected around itself, when it named one (#229). */
|
|
3838
|
+
const [supervisor, setSupervisor] = (0, react.useState)(null);
|
|
3833
3839
|
const [restarting, setRestarting] = (0, react.useState)(false);
|
|
3834
3840
|
const [showTop, setShowTop] = (0, react.useState)(false);
|
|
3835
3841
|
const [backupBusy, setBackupBusy] = (0, react.useState)(false);
|
|
@@ -3948,6 +3954,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
3948
3954
|
} catch {}
|
|
3949
3955
|
}
|
|
3950
3956
|
setRestartEnabled(status.restart === true);
|
|
3957
|
+
setSupervisor(typeof status.supervisor === "string" ? status.supervisor : null);
|
|
3951
3958
|
if (typeof status.version === "string" && status.version !== "") setVersion(status.version);
|
|
3952
3959
|
}).catch(() => {});
|
|
3953
3960
|
refreshInstalled();
|
|
@@ -4176,6 +4183,13 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
4176
4183
|
const first = risks[0];
|
|
4177
4184
|
return `${first.plugin}: ${first.peer} ${first.range} vs ${first.resolved}`;
|
|
4178
4185
|
};
|
|
4186
|
+
/** Which name now resolves from two layers, and which layers those are. */
|
|
4187
|
+
const shadowSummary = (entries) => {
|
|
4188
|
+
if (entries.length === 0) return "";
|
|
4189
|
+
const first = entries[0];
|
|
4190
|
+
const rest = entries.length > 1 ? ` (+${entries.length - 1})` : "";
|
|
4191
|
+
return `${first.name} — ${first.layers.join(" / ")}${rest}`;
|
|
4192
|
+
};
|
|
4179
4193
|
const doInstall = (0, react.useCallback)((plugin) => {
|
|
4180
4194
|
setBuildsSkipped(null);
|
|
4181
4195
|
setConfirming(null);
|
|
@@ -5550,7 +5564,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
5550
5564
|
]
|
|
5551
5565
|
}),
|
|
5552
5566
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
5553
|
-
label: t("restartHint"),
|
|
5567
|
+
label: supervisor === null ? t("restartHint") : t("restartHintSupervised").replace("{0}", supervisor),
|
|
5554
5568
|
side: "bottom",
|
|
5555
5569
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5556
5570
|
className: Market_module_css_default.bannerHint,
|
|
@@ -5646,11 +5660,16 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
5646
5660
|
children: [
|
|
5647
5661
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
5648
5662
|
className: Market_module_css_default.grow,
|
|
5649
|
-
children: [
|
|
5663
|
+
children: [compatibilityNotice.risks.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
5650
5664
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: t("compatRiskBanner") }),
|
|
5651
5665
|
" ",
|
|
5652
5666
|
compatibilitySummary(compatibilityNotice.risks)
|
|
5653
|
-
]
|
|
5667
|
+
] }), compatibilityNotice.shadowedNames !== void 0 && compatibilityNotice.shadowedNames.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
5668
|
+
compatibilityNotice.risks.length > 0 && " · ",
|
|
5669
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: t("shadowNameBanner") }),
|
|
5670
|
+
" ",
|
|
5671
|
+
shadowSummary(compatibilityNotice.shadowedNames)
|
|
5672
|
+
] })]
|
|
5654
5673
|
}),
|
|
5655
5674
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
5656
5675
|
variant: "outline",
|