dshmarket 1.2.3 → 1.3.0
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 +4 -0
- package/README.zh.md +4 -0
- package/client/client.js +270 -58
- package/client/client.js.map +1 -1
- package/data/registry-snapshot.json +4512 -975
- package/lib/dsh-cli.js +65 -5
- package/lib/index.js +4 -1
- package/lib/install.js +24 -2
- package/lib/profile.js +48 -3
- package/lib/restart.js +86 -0
- package/lib/routes.js +141 -15
- package/lib/types/dsh-cli.d.ts +7 -0
- package/lib/types/install.d.ts +6 -0
- package/lib/types/profile.d.ts +9 -1
- package/lib/types/restart.d.ts +37 -0
- package/lib/types/routes.d.ts +2 -0
- package/package.json +2 -2
- package/src/client/Market.module.css +4 -0
- package/src/client/MarketSection.tsx +157 -4
- package/src/client/locales.ts +18 -0
- package/src/dsh-cli.ts +59 -5
- package/src/index.ts +4 -1
- package/src/install.ts +22 -2
- package/src/profile.ts +45 -3
- package/src/restart.ts +96 -0
- package/src/routes.ts +147 -18
package/README.md
CHANGED
|
@@ -32,6 +32,7 @@ Restart `dsh web`, then open **Settings → Plugin Market**.
|
|
|
32
32
|
- **One-click install** — confirm the source, watch live progress; most plugins go live after a page refresh, no restart
|
|
33
33
|
- **Updates** — per-plugin update checks (npm version or pinned commit vs HEAD), one-click update, or update everything at once; the market updates itself the same way
|
|
34
34
|
- **Uninstall** — two-step confirm; plugins installed this session are removed live
|
|
35
|
+
- **Restart when needed** — changes that cannot hot-load show a one-click restart beside the pending-change banner; the action is restricted to same-origin loopback requests
|
|
35
36
|
- **Zero jargon** — if a component is missing (pnpm), the market detects it and offers a one-click automatic setup
|
|
36
37
|
- **Log export** — one click produces a sanitized plain-text log for bug reports (home paths and credential shapes are masked; nothing is ever sent anywhere)
|
|
37
38
|
|
|
@@ -45,6 +46,9 @@ Installs prefer npm tarballs over full-repo GitHub downloads whenever a plugin p
|
|
|
45
46
|
- Build scripts stay blocked by default (pnpm ≥10); allowing one is your explicit per-package choice
|
|
46
47
|
- Terminal/CLI-surface plugins are flagged before you install them into the web profile
|
|
47
48
|
- The install endpoint accepts same-origin POST only; the market never phones home
|
|
49
|
+
- The restart endpoint additionally requires a direct loopback client (forwarded requests are rejected) and relaunches the exact DSH entry, arguments, environment, and working directory
|
|
50
|
+
- One-click restart launches a detached replacement. If DSH is managed by systemd, launchd, pm2, or another supervisor, set the plugin option `allowRestart: false` and let the supervisor own restarts instead; the pending-change notice remains visible but the button is hidden
|
|
51
|
+
- For terminal-attached launches, the detached replacement keeps running after the original terminal closes
|
|
48
52
|
- Listing ≠ endorsement: plugins are third-party code, install sources you trust
|
|
49
53
|
|
|
50
54
|
## Data source
|
package/README.zh.md
CHANGED
|
@@ -32,6 +32,7 @@ dsh plugin --profile web add dshmarket
|
|
|
32
32
|
- **一键安装**——确认来源,实时进度;多数插件刷新页面即可用,无需重启
|
|
33
33
|
- **更新**——逐插件检测(npm 版本或锁定 commit 对比 HEAD),一键更新或全部更新;市场自己也走同一通道升级
|
|
34
34
|
- **卸载**——两步确认防误触;本次会话装的插件即点即卸
|
|
35
|
+
- **按需重启**——无法热加载的变更会在待重启提示旁显示一键重启;操作仅接受本机同源请求
|
|
35
36
|
- **零术语**——缺组件(pnpm)时市场自己发现、一键自动装好,全程不见命令行
|
|
36
37
|
- **导出日志**——一键生成脱敏纯文本日志方便反馈(home 路径与密钥形状已打码;任何数据都不会被上传)
|
|
37
38
|
|
|
@@ -45,6 +46,9 @@ dsh plugin --profile web add dshmarket
|
|
|
45
46
|
- 构建脚本默认禁止执行(pnpm ≥10),放行与否由你按包显式决定
|
|
46
47
|
- 终端/命令行类插件装进网页版前会被明确提醒
|
|
47
48
|
- 安装接口只接受同源 POST;市场不会向任何地方上报数据
|
|
49
|
+
- 重启接口还要求客户端直接来自环回地址(拒绝代理转发请求),并使用原入口、参数、环境和工作目录重新启动 DSH
|
|
50
|
+
- 一键重启会启动脱离终端的替代进程。若 DSH 由 systemd、launchd、pm2 等进程管理器托管,请设置插件选项 `allowRestart: false`,交由管理器负责重启;待重启提示仍会显示,但按钮会隐藏
|
|
51
|
+
- 从终端启动时,替代进程脱离原终端,关闭原终端后仍会继续运行
|
|
48
52
|
- 收录 ≠ 背书:插件是第三方代码,请只安装你信任的来源
|
|
49
53
|
|
|
50
54
|
## 数据源
|
package/client/client.js
CHANGED
|
@@ -38,6 +38,15 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
38
38
|
update: "更新",
|
|
39
39
|
updating: "更新中…",
|
|
40
40
|
updated: "✓ 已更新,重启后生效",
|
|
41
|
+
cancelOp: "取消",
|
|
42
|
+
cancelled: "已取消",
|
|
43
|
+
busyWait: "已有操作正在进行,请等它结束(同一时间只执行一个安装/更新/卸载)",
|
|
44
|
+
approveBuilds: "放行构建脚本并重试",
|
|
45
|
+
buildsSkipped: "该插件需要运行构建脚本才能工作,出于安全默认被拦下。点击下方按钮为它放行并重装:",
|
|
46
|
+
restartNow: "立即重启",
|
|
47
|
+
restarting: "正在重启…",
|
|
48
|
+
restartFail: "重启失败",
|
|
49
|
+
restartTimeout: "等待 DeepSeek Harness 启动超时",
|
|
41
50
|
updateNow: "立即更新",
|
|
42
51
|
updateFail: "更新失败",
|
|
43
52
|
upToDate: "已是最新",
|
|
@@ -97,6 +106,15 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
97
106
|
update: "Update",
|
|
98
107
|
updating: "Updating…",
|
|
99
108
|
updated: "✓ Updated — restart to apply",
|
|
109
|
+
cancelOp: "Cancel",
|
|
110
|
+
cancelled: "Cancelled",
|
|
111
|
+
busyWait: "Another operation is already running — please wait for it to finish (one install/update/uninstall at a time)",
|
|
112
|
+
approveBuilds: "Allow build scripts and retry",
|
|
113
|
+
buildsSkipped: "This plugin needs its build scripts to run; they are blocked by default for safety. Click below to allow them and reinstall:",
|
|
114
|
+
restartNow: "Restart now",
|
|
115
|
+
restarting: "Restarting…",
|
|
116
|
+
restartFail: "Restart failed",
|
|
117
|
+
restartTimeout: "Timed out waiting for DeepSeek Harness to start",
|
|
100
118
|
updateNow: "Update now",
|
|
101
119
|
updateFail: "Update failed",
|
|
102
120
|
upToDate: "Up to date",
|
|
@@ -264,7 +282,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
264
282
|
}
|
|
265
283
|
//#endregion
|
|
266
284
|
//#region \0dsh-css:/home/runner/work/dsh-market/dsh-market/src/client/Market.module.css.mjs
|
|
267
|
-
const css = ".eGUBIq_root{min-width:0;height:100%;color:var(--dsw-alias-label-primary,#1f2328);flex-direction:column;display:flex;position:relative}.eGUBIq_head{flex-direction:column;gap:12px;padding:4px 4px 12px;display:flex}.eGUBIq_title{margin:0;font-size:16px;font-weight:500;line-height:24px}.eGUBIq_sub{color:var(--dsw-alias-label-tertiary,#8b93a1);margin:0;font-size:14px;line-height:22px}.eGUBIq_searchInline{flex-shrink:0;width:200px;margin-bottom:6px}.eGUBIq_tabs{border-bottom:1px solid var(--dsw-alias-border-l2,#e5e7eb);align-items:flex-end;gap:2px;display:flex}.eGUBIq_tab{font:inherit;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-bottom:2px solid #0000;padding:7px 12px;font-size:13px}.eGUBIq_tab.eGUBIq_on{color:var(--dsw-alias-brand-primary,#4f6ef7);border-bottom-color:var(--dsw-alias-brand-primary,#4f6ef7);font-weight:600}.eGUBIq_restart{background:var(--dsw-alias-bg-layer-2,#fdf3e3);border:1px solid var(--dsw-alias-border-l2,#f3e3c3);border-radius:8px;align-items:center;gap:8px;margin:0;padding:8px 12px;font-size:12px;display:flex}.eGUBIq_body{flex:1;padding:12px 4px 24px;overflow-x:hidden;overflow-y:auto}.eGUBIq_cats{z-index:5;background:var(--dsw-alias-bg-layer-2,#f7f8fa);margin:-12px -4px 2px;padding:12px 4px 4px;position:sticky;top:-13px}.eGUBIq_catsRow{align-items:flex-start;gap:8px;display:flex;position:relative}.eGUBIq_sort{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l1,#e5e7eb);border-radius:8px;flex-shrink:0;gap:2px;padding:2px;display:flex}.eGUBIq_sort button{font:inherit;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;background:0 0;border:none;border-radius:6px;padding:3px 10px;font-size:12px}.eGUBIq_sort button.eGUBIq_on{background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-primary,#1f2328);font-weight:600;box-shadow:0 1px 3px #00000014}.eGUBIq_star{color:var(--dsw-alias-label-secondary,#9ca3af);font-size:11px}.eGUBIq_top{z-index:20;border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);width:38px;height:38px;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;border-radius:99px;font-size:16px;position:absolute;bottom:18px;right:18px;box-shadow:0 4px 14px #0000001f}.eGUBIq_top:hover{color:var(--dsw-alias-brand-primary,#4f6ef7)}.eGUBIq_tag{border:1px solid var(--dsw-alias-border-l3,#d9dde3);color:var(--dsw-alias-label-secondary,#6b7280);border-radius:4px;flex-shrink:0;padding:1px 6px;font-size:11px;line-height:16px}.eGUBIq_okState{color:var(--dsw-alias-state-success-primary,#16a34a);white-space:nowrap;font-size:12px;font-weight:600}.eGUBIq_dangerBtn.eGUBIq_dangerBtn{border-color:var(--dsw-alias-state-error-primary,#dc2626);color:var(--dsw-alias-state-error-primary,#dc2626)}.eGUBIq_dangerArmed.eGUBIq_dangerArmed{background:var(--dsw-alias-state-error-primary,#dc2626);color:#fff}.eGUBIq_warnBtn.eGUBIq_warnBtn{background:var(--dsw-alias-state-warn-primary,#ea580c);color:#fff}.eGUBIq_catsWrap{flex-wrap:wrap;flex:1;align-items:center;gap:6px;min-width:0;display:flex}.eGUBIq_catsCollapsed{max-height:62px;overflow:hidden}.eGUBIq_catsToggle.eGUBIq_catsToggle{height:26px;min-height:26px;color:var(--dsw-alias-label-secondary,#6b7280);padding:0 6px}.eGUBIq_cmdDetails{margin:0}.eGUBIq_cmdSummary{cursor:pointer;width:fit-content;color:var(--dsw-alias-label-secondary,#6b7280);border-radius:6px;align-items:center;gap:6px;margin-left:-4px;padding:2px 4px;font-size:12px;font-weight:500;line-height:18px;list-style:none;display:flex}.eGUBIq_cmdSummary::-webkit-details-marker{display:none}.eGUBIq_cmdSummary:before{content:\"\";border-bottom:1.5px solid;border-right:1.5px solid;width:5px;height:5px;transition:transform .12s;transform:rotate(-45deg)translate(-1px,-1px)}.eGUBIq_cmdDetails[open]>.eGUBIq_cmdSummary:before{transform:rotate(45deg)translate(-1px,-1px)}.eGUBIq_cmdSummary:hover{color:var(--dsw-alias-label-primary,#1f2328)}.eGUBIq_cmd{background:var(--dsw-alias-bg-layer-2,#f3f4f6);word-break:break-all;border-radius:6px;margin:8px 0 0;padding:8px 10px;font-family:ui-monospace,Menlo,monospace;font-size:11px;line-height:18px}.eGUBIq_warnLine{color:var(--dsw-alias-state-warn-primary,#b45309);margin:0;font-size:12px;font-weight:600;line-height:18px}.eGUBIq_modalNote{color:var(--dsw-alias-label-tertiary,#8b93a1);margin:12px 0 0;font-size:12px;line-height:18px}.eGUBIq_grid{grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px;display:grid}.eGUBIq_sect{color:var(--dsw-alias-label-secondary,#6b7280);margin:14px 2px 8px;font-size:12px;font-weight:600}.eGUBIq_sect:first-child{margin-top:2px}.eGUBIq_swatches{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:8px;gap:0;height:34px;display:flex;overflow:hidden}.eGUBIq_themesGrid{margin-bottom:12px}.eGUBIq_swatches i{flex:1}.eGUBIq_card{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;flex-direction:column;gap:12px;padding:12px 14px;display:flex}.eGUBIq_row1{align-items:center;gap:10px;min-width:0;display:flex}.eGUBIq_av{color:#fff;object-fit:cover;background:var(--dsw-alias-bg-layer-2,#f3f4f6);border-radius:8px;flex-shrink:0;place-items:center;width:32px;height:32px;font-size:14px;font-weight:700;display:grid}.eGUBIq_nm{text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:500;line-height:22px;overflow:hidden}.eGUBIq_owner{color:var(--dsw-alias-label-secondary,#9ca3af);font-size:11px}.eGUBIq_desc{color:var(--dsw-alias-label-tertiary,#8b93a1);min-height:36px;margin:0;font-size:12px;line-height:18px}.eGUBIq_foot{align-items:center;gap:8px;margin-top:auto;display:flex}.eGUBIq_grow{flex:1}.eGUBIq_titleRow{align-items:center;gap:10px;display:flex}.eGUBIq_descTight{min-height:0}.eGUBIq_src{color:var(--dsw-alias-label-secondary,#9ca3af);font-size:11px;text-decoration:none}.eGUBIq_src:hover{color:var(--dsw-alias-brand-primary,#4f6ef7)}.eGUBIq_dot{vertical-align:2px;margin-left:5px}.eGUBIq_loading{color:var(--dsw-alias-label-secondary,#9ca3af);flex-direction:column;align-items:center;gap:12px;padding:48px;font-size:13px;display:flex}.eGUBIq_spin{border:3px solid var(--dsw-alias-border-l1,#e5e7eb);border-top-color:var(--dsw-alias-brand-primary,#4f6ef7);border-radius:99px;width:22px;height:22px;animation:.8s linear infinite eGUBIq_sp}@keyframes eGUBIq_sp{to{transform:rotate(360deg)}}.eGUBIq_progress{background:var(--dsw-alias-bg-layer-2,#f3f4f6);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);color:var(--dsw-alias-label-secondary,#6b7280);border-radius:8px;align-items:center;gap:9px;margin:0;padding:8px 12px;font-size:12px;display:flex}.eGUBIq_irow .eGUBIq_progress{margin-top:8px}.eGUBIq_progress .eGUBIq_spin{border-width:2px;flex-shrink:0;width:14px;height:14px}.eGUBIq_progress code{text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,Menlo,monospace;font-size:11px;overflow:hidden}.eGUBIq_empty{color:var(--dsw-alias-label-secondary,#9ca3af);text-align:center;padding:32px;font-size:13px}.eGUBIq_err{color:var(--dsw-alias-state-error-primary,#dc2626);white-space:pre-wrap;word-break:break-all;margin:8px 0;font-size:12px}.eGUBIq_irow{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;align-items:center;gap:10px;margin-bottom:8px;padding:12px 14px;display:flex}.eGUBIq_irow>.eGUBIq_src,.eGUBIq_irow>.eGUBIq_owner,.eGUBIq_dangerBtn.eGUBIq_dangerBtn,.eGUBIq_warnBtn.eGUBIq_warnBtn,.eGUBIq_dangerArmed.eGUBIq_dangerArmed{white-space:nowrap;flex-shrink:0}.eGUBIq_spec{color:var(--dsw-alias-label-secondary,#9ca3af);font-family:ui-monospace,Menlo,monospace;font-size:11px}.eGUBIq_staleAction{margin-top:8px}";
|
|
285
|
+
const css = ".eGUBIq_root{min-width:0;height:100%;color:var(--dsw-alias-label-primary,#1f2328);flex-direction:column;display:flex;position:relative}.eGUBIq_head{flex-direction:column;gap:12px;padding:4px 4px 12px;display:flex}.eGUBIq_title{margin:0;font-size:16px;font-weight:500;line-height:24px}.eGUBIq_sub{color:var(--dsw-alias-label-tertiary,#8b93a1);margin:0;font-size:14px;line-height:22px}.eGUBIq_searchInline{flex-shrink:0;width:200px;margin-bottom:6px}.eGUBIq_tabs{border-bottom:1px solid var(--dsw-alias-border-l2,#e5e7eb);align-items:flex-end;gap:2px;display:flex}.eGUBIq_tab{font:inherit;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-bottom:2px solid #0000;padding:7px 12px;font-size:13px}.eGUBIq_tab.eGUBIq_on{color:var(--dsw-alias-brand-primary,#4f6ef7);border-bottom-color:var(--dsw-alias-brand-primary,#4f6ef7);font-weight:600}.eGUBIq_restart{background:var(--dsw-alias-bg-layer-2,#fdf3e3);border:1px solid var(--dsw-alias-border-l2,#f3e3c3);border-radius:8px;align-items:center;gap:8px;margin:0;padding:8px 12px;font-size:12px;display:flex}.eGUBIq_body{flex:1;padding:12px 4px 24px;overflow-x:hidden;overflow-y:auto}.eGUBIq_cats{z-index:5;background:var(--dsw-alias-bg-layer-2,#f7f8fa);margin:-12px -4px 2px;padding:12px 4px 4px;position:sticky;top:-13px}.eGUBIq_catsRow{align-items:flex-start;gap:8px;display:flex;position:relative}.eGUBIq_sort{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l1,#e5e7eb);border-radius:8px;flex-shrink:0;gap:2px;padding:2px;display:flex}.eGUBIq_sort button{font:inherit;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;background:0 0;border:none;border-radius:6px;padding:3px 10px;font-size:12px}.eGUBIq_sort button.eGUBIq_on{background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-primary,#1f2328);font-weight:600;box-shadow:0 1px 3px #00000014}.eGUBIq_star{color:var(--dsw-alias-label-secondary,#9ca3af);font-size:11px}.eGUBIq_top{z-index:20;border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);width:38px;height:38px;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;border-radius:99px;font-size:16px;position:absolute;bottom:18px;right:18px;box-shadow:0 4px 14px #0000001f}.eGUBIq_top:hover{color:var(--dsw-alias-brand-primary,#4f6ef7)}.eGUBIq_tag{border:1px solid var(--dsw-alias-border-l3,#d9dde3);color:var(--dsw-alias-label-secondary,#6b7280);border-radius:4px;flex-shrink:0;padding:1px 6px;font-size:11px;line-height:16px}.eGUBIq_okState{color:var(--dsw-alias-state-success-primary,#16a34a);white-space:nowrap;font-size:12px;font-weight:600}.eGUBIq_dangerBtn.eGUBIq_dangerBtn{border-color:var(--dsw-alias-state-error-primary,#dc2626);color:var(--dsw-alias-state-error-primary,#dc2626)}.eGUBIq_dangerArmed.eGUBIq_dangerArmed{background:var(--dsw-alias-state-error-primary,#dc2626);color:#fff}.eGUBIq_warnBtn.eGUBIq_warnBtn{background:var(--dsw-alias-state-warn-primary,#ea580c);color:#fff}.eGUBIq_catsWrap{flex-wrap:wrap;flex:1;align-items:center;gap:6px;min-width:0;display:flex}.eGUBIq_catsCollapsed{max-height:62px;overflow:hidden}.eGUBIq_catsToggle.eGUBIq_catsToggle{height:26px;min-height:26px;color:var(--dsw-alias-label-secondary,#6b7280);padding:0 6px}.eGUBIq_cmdDetails{margin:0}.eGUBIq_cmdSummary{cursor:pointer;width:fit-content;color:var(--dsw-alias-label-secondary,#6b7280);border-radius:6px;align-items:center;gap:6px;margin-left:-4px;padding:2px 4px;font-size:12px;font-weight:500;line-height:18px;list-style:none;display:flex}.eGUBIq_cmdSummary::-webkit-details-marker{display:none}.eGUBIq_cmdSummary:before{content:\"\";border-bottom:1.5px solid;border-right:1.5px solid;width:5px;height:5px;transition:transform .12s;transform:rotate(-45deg)translate(-1px,-1px)}.eGUBIq_cmdDetails[open]>.eGUBIq_cmdSummary:before{transform:rotate(45deg)translate(-1px,-1px)}.eGUBIq_cmdSummary:hover{color:var(--dsw-alias-label-primary,#1f2328)}.eGUBIq_cmd{background:var(--dsw-alias-bg-layer-2,#f3f4f6);word-break:break-all;border-radius:6px;margin:8px 0 0;padding:8px 10px;font-family:ui-monospace,Menlo,monospace;font-size:11px;line-height:18px}.eGUBIq_warnLine{color:var(--dsw-alias-state-warn-primary,#b45309);margin:0;font-size:12px;font-weight:600;line-height:18px}.eGUBIq_modalNote{color:var(--dsw-alias-label-tertiary,#8b93a1);margin:12px 0 0;font-size:12px;line-height:18px}.eGUBIq_grid{grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px;display:grid}.eGUBIq_sect{color:var(--dsw-alias-label-secondary,#6b7280);margin:14px 2px 8px;font-size:12px;font-weight:600}.eGUBIq_sect:first-child{margin-top:2px}.eGUBIq_swatches{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:8px;gap:0;height:34px;display:flex;overflow:hidden}.eGUBIq_themesGrid{margin-bottom:12px}.eGUBIq_swatches i{flex:1}.eGUBIq_card{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;flex-direction:column;gap:12px;padding:12px 14px;display:flex}.eGUBIq_row1{align-items:center;gap:10px;min-width:0;display:flex}.eGUBIq_av{color:#fff;object-fit:cover;background:var(--dsw-alias-bg-layer-2,#f3f4f6);border-radius:8px;flex-shrink:0;place-items:center;width:32px;height:32px;font-size:14px;font-weight:700;display:grid}.eGUBIq_nm{text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:500;line-height:22px;overflow:hidden}.eGUBIq_owner{color:var(--dsw-alias-label-secondary,#9ca3af);font-size:11px}.eGUBIq_desc{color:var(--dsw-alias-label-tertiary,#8b93a1);min-height:36px;margin:0;font-size:12px;line-height:18px}.eGUBIq_foot{align-items:center;gap:8px;margin-top:auto;display:flex}.eGUBIq_grow{flex:1}.eGUBIq_titleRow{align-items:center;gap:10px;display:flex}.eGUBIq_descTight{min-height:0}.eGUBIq_src{color:var(--dsw-alias-label-secondary,#9ca3af);font-size:11px;text-decoration:none}.eGUBIq_src:hover{color:var(--dsw-alias-brand-primary,#4f6ef7)}.eGUBIq_dot{vertical-align:2px;margin-left:5px}.eGUBIq_loading{color:var(--dsw-alias-label-secondary,#9ca3af);flex-direction:column;align-items:center;gap:12px;padding:48px;font-size:13px;display:flex}.eGUBIq_spin{border:3px solid var(--dsw-alias-border-l1,#e5e7eb);border-top-color:var(--dsw-alias-brand-primary,#4f6ef7);border-radius:99px;width:22px;height:22px;animation:.8s linear infinite eGUBIq_sp}@keyframes eGUBIq_sp{to{transform:rotate(360deg)}}.eGUBIq_progress{background:var(--dsw-alias-bg-layer-2,#f3f4f6);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);color:var(--dsw-alias-label-secondary,#6b7280);border-radius:8px;align-items:center;gap:9px;margin:0;padding:8px 12px;font-size:12px;display:flex}.eGUBIq_irow .eGUBIq_progress{margin-top:8px}.eGUBIq_progress .eGUBIq_spin{border-width:2px;flex-shrink:0;width:14px;height:14px}.eGUBIq_progress code{text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,Menlo,monospace;font-size:11px;overflow:hidden}.eGUBIq_empty{color:var(--dsw-alias-label-secondary,#9ca3af);text-align:center;padding:32px;font-size:13px}.eGUBIq_err{color:var(--dsw-alias-state-error-primary,#dc2626);white-space:pre-wrap;word-break:break-all;margin:8px 0;font-size:12px}.eGUBIq_irow{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;align-items:center;gap:10px;margin-bottom:8px;padding:12px 14px;display:flex}.eGUBIq_irow>.eGUBIq_src,.eGUBIq_irow>.eGUBIq_owner,.eGUBIq_dangerBtn.eGUBIq_dangerBtn,.eGUBIq_warnBtn.eGUBIq_warnBtn,.eGUBIq_dangerArmed.eGUBIq_dangerArmed{white-space:nowrap;flex-shrink:0}.eGUBIq_spec{color:var(--dsw-alias-label-secondary,#9ca3af);font-family:ui-monospace,Menlo,monospace;font-size:11px}.eGUBIq_staleAction{margin-top:8px}.eGUBIq_pct{color:var(--dsw-alias-label-secondary,#6b7280);flex-shrink:0;font-size:11px;font-weight:600}.eGUBIq_cancelBtn{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-secondary,#6b7280);font:inherit;cursor:pointer;white-space:nowrap;border-radius:6px;flex-shrink:0;padding:2px 10px;font-size:11px;line-height:16px}.eGUBIq_cancelBtn:hover{color:var(--dsw-alias-state-error-primary,#dc2626);border-color:var(--dsw-alias-state-error-primary,#dc2626)}.eGUBIq_sentinel{height:1px}";
|
|
268
286
|
const tagId = "dshmarket/Market.module.css";
|
|
269
287
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
270
288
|
const tag = document.createElement("style");
|
|
@@ -274,59 +292,62 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
274
292
|
document.head.appendChild(tag);
|
|
275
293
|
}
|
|
276
294
|
var Market_module_css_default = {
|
|
295
|
+
"dangerBtn": "eGUBIq_dangerBtn",
|
|
296
|
+
"top": "eGUBIq_top",
|
|
297
|
+
"catsWrap": "eGUBIq_catsWrap",
|
|
298
|
+
"catsToggle": "eGUBIq_catsToggle",
|
|
277
299
|
"grid": "eGUBIq_grid",
|
|
278
|
-
"
|
|
279
|
-
"
|
|
280
|
-
"
|
|
281
|
-
"empty": "eGUBIq_empty",
|
|
282
|
-
"nm": "eGUBIq_nm",
|
|
283
|
-
"on": "eGUBIq_on",
|
|
284
|
-
"loading": "eGUBIq_loading",
|
|
285
|
-
"card": "eGUBIq_card",
|
|
300
|
+
"grow": "eGUBIq_grow",
|
|
301
|
+
"titleRow": "eGUBIq_titleRow",
|
|
302
|
+
"staleAction": "eGUBIq_staleAction",
|
|
286
303
|
"modalNote": "eGUBIq_modalNote",
|
|
304
|
+
"star": "eGUBIq_star",
|
|
305
|
+
"sect": "eGUBIq_sect",
|
|
306
|
+
"row1": "eGUBIq_row1",
|
|
307
|
+
"av": "eGUBIq_av",
|
|
308
|
+
"warnBtn": "eGUBIq_warnBtn",
|
|
309
|
+
"pct": "eGUBIq_pct",
|
|
310
|
+
"loading": "eGUBIq_loading",
|
|
311
|
+
"cancelBtn": "eGUBIq_cancelBtn",
|
|
312
|
+
"spec": "eGUBIq_spec",
|
|
287
313
|
"catsRow": "eGUBIq_catsRow",
|
|
288
314
|
"cats": "eGUBIq_cats",
|
|
289
|
-
"
|
|
290
|
-
"
|
|
291
|
-
"
|
|
292
|
-
"
|
|
315
|
+
"themesGrid": "eGUBIq_themesGrid",
|
|
316
|
+
"progress": "eGUBIq_progress",
|
|
317
|
+
"descTight": "eGUBIq_descTight",
|
|
318
|
+
"irow": "eGUBIq_irow",
|
|
319
|
+
"card": "eGUBIq_card",
|
|
320
|
+
"owner": "eGUBIq_owner",
|
|
293
321
|
"warnLine": "eGUBIq_warnLine",
|
|
294
|
-
"
|
|
295
|
-
"cmdSummary": "eGUBIq_cmdSummary",
|
|
296
|
-
"restart": "eGUBIq_restart",
|
|
297
|
-
"root": "eGUBIq_root",
|
|
322
|
+
"nm": "eGUBIq_nm",
|
|
298
323
|
"dangerArmed": "eGUBIq_dangerArmed",
|
|
299
324
|
"desc": "eGUBIq_desc",
|
|
325
|
+
"empty": "eGUBIq_empty",
|
|
326
|
+
"src": "eGUBIq_src",
|
|
327
|
+
"body": "eGUBIq_body",
|
|
300
328
|
"err": "eGUBIq_err",
|
|
301
|
-
"
|
|
302
|
-
"catsToggle": "eGUBIq_catsToggle",
|
|
329
|
+
"catsCollapsed": "eGUBIq_catsCollapsed",
|
|
303
330
|
"tab": "eGUBIq_tab",
|
|
304
|
-
"
|
|
305
|
-
"dangerBtn": "eGUBIq_dangerBtn",
|
|
306
|
-
"dot": "eGUBIq_dot",
|
|
307
|
-
"irow": "eGUBIq_irow",
|
|
308
|
-
"cmd": "eGUBIq_cmd",
|
|
309
|
-
"swatches": "eGUBIq_swatches",
|
|
310
|
-
"spin": "eGUBIq_spin",
|
|
331
|
+
"on": "eGUBIq_on",
|
|
311
332
|
"sort": "eGUBIq_sort",
|
|
312
|
-
"
|
|
313
|
-
"
|
|
314
|
-
"
|
|
315
|
-
"themesGrid": "eGUBIq_themesGrid",
|
|
333
|
+
"cmd": "eGUBIq_cmd",
|
|
334
|
+
"tag": "eGUBIq_tag",
|
|
335
|
+
"head": "eGUBIq_head",
|
|
316
336
|
"okState": "eGUBIq_okState",
|
|
317
|
-
"
|
|
318
|
-
"
|
|
319
|
-
"
|
|
320
|
-
"
|
|
321
|
-
"owner": "eGUBIq_owner",
|
|
337
|
+
"root": "eGUBIq_root",
|
|
338
|
+
"tabs": "eGUBIq_tabs",
|
|
339
|
+
"dot": "eGUBIq_dot",
|
|
340
|
+
"title": "eGUBIq_title",
|
|
322
341
|
"sp": "eGUBIq_sp",
|
|
323
|
-
"
|
|
324
|
-
"
|
|
325
|
-
"
|
|
326
|
-
"
|
|
327
|
-
"
|
|
328
|
-
"
|
|
329
|
-
"
|
|
342
|
+
"sub": "eGUBIq_sub",
|
|
343
|
+
"restart": "eGUBIq_restart",
|
|
344
|
+
"swatches": "eGUBIq_swatches",
|
|
345
|
+
"cmdDetails": "eGUBIq_cmdDetails",
|
|
346
|
+
"foot": "eGUBIq_foot",
|
|
347
|
+
"spin": "eGUBIq_spin",
|
|
348
|
+
"sentinel": "eGUBIq_sentinel",
|
|
349
|
+
"cmdSummary": "eGUBIq_cmdSummary",
|
|
350
|
+
"searchInline": "eGUBIq_searchInline"
|
|
330
351
|
};
|
|
331
352
|
//#endregion
|
|
332
353
|
//#region src/client/MarketSection.tsx
|
|
@@ -354,14 +375,25 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
354
375
|
onError: () => setFailed(true)
|
|
355
376
|
});
|
|
356
377
|
}
|
|
378
|
+
/**
|
|
379
|
+
* Module-scope caches so re-entering the section renders instantly instead
|
|
380
|
+
* of refetching and rebuilding from a spinner (#30 by @StarsTom). Module
|
|
381
|
+
* state survives section switches; a background refetch keeps it current.
|
|
382
|
+
*/
|
|
383
|
+
let cachedRegistry = null;
|
|
384
|
+
let cachedInstalled = null;
|
|
357
385
|
function MarketSection(props) {
|
|
358
386
|
const t = props.t;
|
|
359
387
|
const localeSnap = (0, react.useSyncExternalStore)((cb) => props.locale.subscribe(cb), () => props.locale.getSnapshot());
|
|
360
388
|
const lang = String(localeSnap.active).toLowerCase().startsWith("zh") ? "zh" : "en";
|
|
361
389
|
const themeSnap = (0, react.useSyncExternalStore)(props.themeStore.subscribe, props.themeStore.getSnapshot);
|
|
362
|
-
const [data, setData] = (0, react.useState)(
|
|
390
|
+
const [data, setData] = (0, react.useState)(cachedRegistry);
|
|
363
391
|
const [loadError, setLoadError] = (0, react.useState)(false);
|
|
364
|
-
const [installed,
|
|
392
|
+
const [installed, setInstalledState] = (0, react.useState)(cachedInstalled ?? {});
|
|
393
|
+
const setInstalled = (0, react.useCallback)((value) => {
|
|
394
|
+
cachedInstalled = value;
|
|
395
|
+
setInstalledState(value);
|
|
396
|
+
}, []);
|
|
365
397
|
const [skins, setSkins] = (0, react.useState)([]);
|
|
366
398
|
const [tab, setTab] = (0, react.useState)(() => {
|
|
367
399
|
const saved = sessionStorage.getItem("dshm-tab");
|
|
@@ -377,6 +409,22 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
377
409
|
const [updates, setUpdates] = (0, react.useState)({});
|
|
378
410
|
const [updatingName, setUpdatingName] = (0, react.useState)(null);
|
|
379
411
|
const [staleName, setStaleName] = (0, react.useState)(null);
|
|
412
|
+
/**
|
|
413
|
+
* Cards rendered so far — the discover grid renders incrementally (60,
|
|
414
|
+
* then +120 as the sentinel scrolls into view) instead of all 400+ at
|
|
415
|
+
* once, which built a ~70k px DOM and made section switches lag (#30).
|
|
416
|
+
*/
|
|
417
|
+
const [visibleCount, setVisibleCount] = (0, react.useState)(60);
|
|
418
|
+
const sentinelRef = (0, react.useCallback)((node) => {
|
|
419
|
+
if (node === null) return;
|
|
420
|
+
new IntersectionObserver((entries) => {
|
|
421
|
+
if (entries.some((entry) => entry.isIntersecting)) setVisibleCount((count) => count + 120);
|
|
422
|
+
}, { rootMargin: "600px" }).observe(node);
|
|
423
|
+
}, []);
|
|
424
|
+
/** Determinate percent parsed from pnpm's Progress line, when available. */
|
|
425
|
+
const [progressPct, setProgressPct] = (0, react.useState)(null);
|
|
426
|
+
/** Blocked build scripts from the last install: enables approve-and-retry (#6). */
|
|
427
|
+
const [buildsSkipped, setBuildsSkipped] = (0, react.useState)(null);
|
|
380
428
|
const [updatingAll, setUpdatingAll] = (0, react.useState)(false);
|
|
381
429
|
const [updatedNames, setUpdatedNames] = (0, react.useState)([]);
|
|
382
430
|
const [hotUrls, setHotUrls] = (0, react.useState)([]);
|
|
@@ -389,6 +437,9 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
389
437
|
const [envFixing, setEnvFixing] = (0, react.useState)(false);
|
|
390
438
|
const [envFailed, setEnvFailed] = (0, react.useState)(false);
|
|
391
439
|
const [bootId, setBootId] = (0, react.useState)(null);
|
|
440
|
+
/** One-click restart (#14 by @ysyyhhh): server capability + in-flight state. */
|
|
441
|
+
const [restartEnabled, setRestartEnabled] = (0, react.useState)(false);
|
|
442
|
+
const [restarting, setRestarting] = (0, react.useState)(false);
|
|
392
443
|
const [showTop, setShowTop] = (0, react.useState)(false);
|
|
393
444
|
const bodyRef = (0, react.useRef)(null);
|
|
394
445
|
const [sort, setSort] = (0, react.useState)("hot");
|
|
@@ -406,10 +457,14 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
406
457
|
fetch("/dsh-market/registry", { cache: "no-store" }).then((res) => {
|
|
407
458
|
if (!res.ok) throw new Error("HTTP " + res.status);
|
|
408
459
|
return res.json();
|
|
409
|
-
}).then((body) =>
|
|
460
|
+
}).then((body) => {
|
|
461
|
+
cachedRegistry = body.registry;
|
|
462
|
+
setData(body.registry);
|
|
463
|
+
}).catch(() => setLoadError(true));
|
|
410
464
|
fetch("/dsh-market/status", { cache: "no-store" }).then((res) => res.json()).then((status) => {
|
|
411
465
|
setEnvReady(status.pnpm !== false);
|
|
412
466
|
if (typeof status.boot === "string") setBootId(status.boot);
|
|
467
|
+
setRestartEnabled(status.restart === true);
|
|
413
468
|
}).catch(() => {});
|
|
414
469
|
refreshInstalled();
|
|
415
470
|
}, [refreshInstalled]);
|
|
@@ -463,9 +518,16 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
463
518
|
}
|
|
464
519
|
const timer = setInterval(() => {
|
|
465
520
|
fetch("/dsh-market/status", { cache: "no-store" }).then((res) => res.json()).then((status) => {
|
|
466
|
-
if (status.active)
|
|
467
|
-
|
|
521
|
+
if (status.active) {
|
|
522
|
+
setProgressLine((status.lastLine || "…") + " (" + status.seconds + "s)");
|
|
523
|
+
const m = /resolved (\d+), reused (\d+), downloaded (\d+), added (\d+)/.exec(status.lastLine || "");
|
|
524
|
+
if (m !== null && Number(m[1]) > 0) {
|
|
525
|
+
const done = Number(m[2]) + Number(m[3]) + Number(m[4]);
|
|
526
|
+
setProgressPct(Math.max(4, Math.min(96, Math.round(done / Number(m[1]) * 100))));
|
|
527
|
+
}
|
|
528
|
+
} else {
|
|
468
529
|
setProgressLine(null);
|
|
530
|
+
setProgressPct(null);
|
|
469
531
|
setInstalled(status.installed || {});
|
|
470
532
|
if (readSession("dshm-pending") !== null && busyUrl !== null) {
|
|
471
533
|
if (data !== null && data.plugins.some((p) => p.url === busyUrl && isInstalled(p, status.installed || {}))) {
|
|
@@ -495,7 +557,15 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
495
557
|
lang,
|
|
496
558
|
sort
|
|
497
559
|
]);
|
|
560
|
+
(0, react.useEffect)(() => {
|
|
561
|
+
setVisibleCount(60);
|
|
562
|
+
}, [
|
|
563
|
+
q,
|
|
564
|
+
cat,
|
|
565
|
+
sort
|
|
566
|
+
]);
|
|
498
567
|
const doInstall = (0, react.useCallback)((plugin) => {
|
|
568
|
+
setBuildsSkipped(null);
|
|
499
569
|
setConfirming(null);
|
|
500
570
|
setInstallError(null);
|
|
501
571
|
setBusyUrl(plugin.url);
|
|
@@ -515,6 +585,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
515
585
|
location.reload();
|
|
516
586
|
return;
|
|
517
587
|
}
|
|
588
|
+
if (body.cancelled === true) {
|
|
589
|
+
refreshInstalled();
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
518
592
|
if (status === 200 && body.ok) {
|
|
519
593
|
sessionStorage.setItem("dshm-tab", "installed");
|
|
520
594
|
if (body.hot) {
|
|
@@ -523,6 +597,14 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
523
597
|
} else setDoneUrls((urls) => urls.includes(plugin.url) ? urls : urls.concat(plugin.url));
|
|
524
598
|
refreshInstalled();
|
|
525
599
|
} else {
|
|
600
|
+
if (status === 409) {
|
|
601
|
+
setInstallError(t("busyWait"));
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
if (Array.isArray(body.ignoredBuilds) && body.ignoredBuilds.length > 0) setBuildsSkipped({
|
|
605
|
+
plugin,
|
|
606
|
+
names: body.ignoredBuilds.map(String)
|
|
607
|
+
});
|
|
526
608
|
const text = (v) => typeof v === "string" ? v : v && typeof v.text === "string" ? v.text : v == null ? "" : JSON.stringify(v);
|
|
527
609
|
const detail = text(body.error) || [text(body.stderr), text(body.stdout)].filter(Boolean).join("\n").trim() || "exit " + body.exitCode;
|
|
528
610
|
setInstallError(t("installFail") + ": " + plugin.name + " — " + detail.trim().slice(-600));
|
|
@@ -532,6 +614,65 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
532
614
|
setInstallError(t("installFail") + ": " + String(error));
|
|
533
615
|
}).finally(() => setBusyUrl(null));
|
|
534
616
|
}, [refreshInstalled, t]);
|
|
617
|
+
/**
|
|
618
|
+
* Restart the host and reload once the boot id changes (#14 by @ysyyhhh).
|
|
619
|
+
* The 202 races the process's SIGTERM, so network errors on the initial
|
|
620
|
+
* request are expected and treated as "restart under way".
|
|
621
|
+
*/
|
|
622
|
+
const doRestart = (0, react.useCallback)(() => {
|
|
623
|
+
if (bootId === null || restarting) return;
|
|
624
|
+
const previousBoot = bootId;
|
|
625
|
+
setRestarting(true);
|
|
626
|
+
setInstallError(null);
|
|
627
|
+
const awaitNewBoot = () => {
|
|
628
|
+
const deadline = Date.now() + 6e4;
|
|
629
|
+
const poll = () => {
|
|
630
|
+
fetch("/dsh-market/status", { cache: "no-store" }).then((res) => res.json()).then((next) => {
|
|
631
|
+
if (typeof next.boot === "string" && next.boot !== previousBoot) {
|
|
632
|
+
location.reload();
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
retry();
|
|
636
|
+
}).catch(retry);
|
|
637
|
+
};
|
|
638
|
+
const retry = () => {
|
|
639
|
+
if (Date.now() > deadline) {
|
|
640
|
+
setRestarting(false);
|
|
641
|
+
setInstallError(t("restartTimeout"));
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
setTimeout(poll, 1500);
|
|
645
|
+
};
|
|
646
|
+
poll();
|
|
647
|
+
};
|
|
648
|
+
fetch("/dsh-market/restart", {
|
|
649
|
+
method: "POST",
|
|
650
|
+
headers: { "content-type": "application/json" },
|
|
651
|
+
body: "{}"
|
|
652
|
+
}).then((res) => res.json().then((body) => ({
|
|
653
|
+
status: res.status,
|
|
654
|
+
body
|
|
655
|
+
}))).then(({ status, body }) => {
|
|
656
|
+
if (status !== 202 || body.ok !== true) {
|
|
657
|
+
setRestarting(false);
|
|
658
|
+
setInstallError(t("restartFail") + ": " + String(body.error || "HTTP " + String(status)));
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
awaitNewBoot();
|
|
662
|
+
}).catch(awaitNewBoot);
|
|
663
|
+
}, [
|
|
664
|
+
bootId,
|
|
665
|
+
restarting,
|
|
666
|
+
t
|
|
667
|
+
]);
|
|
668
|
+
/** Cancel the running plugin command (#6 by @qichuang321). */
|
|
669
|
+
const doCancel = (0, react.useCallback)(() => {
|
|
670
|
+
fetch("/dsh-market/cancel", {
|
|
671
|
+
method: "POST",
|
|
672
|
+
headers: { "content-type": "application/json" },
|
|
673
|
+
body: "{}"
|
|
674
|
+
}).catch(() => {});
|
|
675
|
+
}, []);
|
|
535
676
|
const doUpdate = (0, react.useCallback)((name, force = false) => {
|
|
536
677
|
setInstallError(null);
|
|
537
678
|
setStaleName(null);
|
|
@@ -547,10 +688,18 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
547
688
|
status: res.status,
|
|
548
689
|
body
|
|
549
690
|
}))).then(({ status, body }) => {
|
|
691
|
+
if (body.cancelled === true) {
|
|
692
|
+
refreshInstalled();
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
550
695
|
if (status === 200 && body.ok) {
|
|
551
696
|
setUpdatedNames((names) => names.concat(name));
|
|
552
697
|
refreshInstalled();
|
|
553
698
|
} else {
|
|
699
|
+
if (status === 409) {
|
|
700
|
+
setInstallError(t("busyWait"));
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
554
703
|
if (body.stale === true) setStaleName(name);
|
|
555
704
|
const text = (v) => typeof v === "string" ? v : v && typeof v.text === "string" ? v.text : v == null ? "" : JSON.stringify(v);
|
|
556
705
|
const detail = text(body.error) || [text(body.stderr), text(body.stdout)].filter(Boolean).join("\n").trim() || "exit " + body.exitCode;
|
|
@@ -691,10 +840,23 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
691
840
|
}),
|
|
692
841
|
busy && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
693
842
|
className: Market_module_css_default.progress,
|
|
694
|
-
children: [
|
|
695
|
-
className: Market_module_css_default.
|
|
696
|
-
|
|
697
|
-
|
|
843
|
+
children: [
|
|
844
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: Market_module_css_default.spin }),
|
|
845
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
846
|
+
className: Market_module_css_default.grow,
|
|
847
|
+
children: progressLine || t("progressHint")
|
|
848
|
+
}),
|
|
849
|
+
progressPct !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
850
|
+
className: Market_module_css_default.pct,
|
|
851
|
+
children: [progressPct, "%"]
|
|
852
|
+
}),
|
|
853
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
854
|
+
type: "button",
|
|
855
|
+
className: Market_module_css_default.cancelBtn,
|
|
856
|
+
onClick: doCancel,
|
|
857
|
+
children: t("cancelOp")
|
|
858
|
+
})
|
|
859
|
+
]
|
|
698
860
|
})
|
|
699
861
|
]
|
|
700
862
|
}, p.url);
|
|
@@ -993,11 +1155,45 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
993
1155
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
994
1156
|
title: t("restartHint"),
|
|
995
1157
|
children: "ℹ️"
|
|
1158
|
+
}),
|
|
1159
|
+
restartEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1160
|
+
variant: "primary",
|
|
1161
|
+
size: "sm",
|
|
1162
|
+
disabled: restarting || busyUrl !== null || updatingName !== null || removingName !== null,
|
|
1163
|
+
onClick: doRestart,
|
|
1164
|
+
children: restarting ? t("restarting") : t("restartNow")
|
|
996
1165
|
})
|
|
997
1166
|
]
|
|
998
1167
|
})
|
|
999
1168
|
]
|
|
1000
1169
|
}),
|
|
1170
|
+
buildsSkipped !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1171
|
+
className: Market_module_css_default.restart,
|
|
1172
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1173
|
+
className: Market_module_css_default.grow,
|
|
1174
|
+
children: [
|
|
1175
|
+
t("buildsSkipped"),
|
|
1176
|
+
" ",
|
|
1177
|
+
buildsSkipped.names.join(", ")
|
|
1178
|
+
]
|
|
1179
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1180
|
+
size: "sm",
|
|
1181
|
+
disabled: busyUrl !== null,
|
|
1182
|
+
onClick: () => {
|
|
1183
|
+
const { plugin, names } = buildsSkipped;
|
|
1184
|
+
setBuildsSkipped(null);
|
|
1185
|
+
fetch("/dsh-market/approve-builds", {
|
|
1186
|
+
method: "POST",
|
|
1187
|
+
headers: { "content-type": "application/json" },
|
|
1188
|
+
body: JSON.stringify({ packages: names })
|
|
1189
|
+
}).then((res) => res.json()).then((body) => {
|
|
1190
|
+
if (body.ok) doInstall(plugin);
|
|
1191
|
+
else setInstallError(String(body.error || "approve failed"));
|
|
1192
|
+
}).catch((error) => setInstallError(String(error)));
|
|
1193
|
+
},
|
|
1194
|
+
children: t("approveBuilds")
|
|
1195
|
+
})]
|
|
1196
|
+
}),
|
|
1001
1197
|
installError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1002
1198
|
className: Market_module_css_default.err,
|
|
1003
1199
|
children: [installError, staleName !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -1064,10 +1260,13 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
1064
1260
|
}), plugins.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1065
1261
|
className: Market_module_css_default.empty,
|
|
1066
1262
|
children: t("empty")
|
|
1067
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1263
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1068
1264
|
className: Market_module_css_default.grid,
|
|
1069
|
-
children: plugins.map(pluginCard)
|
|
1070
|
-
})
|
|
1265
|
+
children: plugins.slice(0, visibleCount).map(pluginCard)
|
|
1266
|
+
}), plugins.length > visibleCount && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1267
|
+
ref: sentinelRef,
|
|
1268
|
+
className: Market_module_css_default.sentinel
|
|
1269
|
+
})] })] }) : tab === "themes" && themeSnap !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(() => {
|
|
1071
1270
|
const extra = themeSnap.themes.filter((def) => def.id !== "light" && def.id !== "dark");
|
|
1072
1271
|
return extra.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1073
1272
|
className: `${Market_module_css_default.grid} ${Market_module_css_default.themesGrid}`,
|
|
@@ -1122,10 +1321,23 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
1122
1321
|
}),
|
|
1123
1322
|
updatingName === name && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1124
1323
|
className: Market_module_css_default.progress,
|
|
1125
|
-
children: [
|
|
1126
|
-
className: Market_module_css_default.
|
|
1127
|
-
|
|
1128
|
-
|
|
1324
|
+
children: [
|
|
1325
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: Market_module_css_default.spin }),
|
|
1326
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
1327
|
+
className: Market_module_css_default.grow,
|
|
1328
|
+
children: progressLine || t("progressHint")
|
|
1329
|
+
}),
|
|
1330
|
+
progressPct !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1331
|
+
className: Market_module_css_default.pct,
|
|
1332
|
+
children: [progressPct, "%"]
|
|
1333
|
+
}),
|
|
1334
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1335
|
+
type: "button",
|
|
1336
|
+
className: Market_module_css_default.cancelBtn,
|
|
1337
|
+
onClick: doCancel,
|
|
1338
|
+
children: t("cancelOp")
|
|
1339
|
+
})
|
|
1340
|
+
]
|
|
1129
1341
|
})
|
|
1130
1342
|
]
|
|
1131
1343
|
}),
|