dshmarket 1.2.2 → 1.2.4
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 +8 -0
- package/README.zh.md +8 -0
- package/client/client.js +264 -87
- package/client/client.js.map +1 -1
- package/lib/dsh-cli.js +224 -0
- package/lib/http.js +39 -0
- package/lib/install.js +132 -0
- package/lib/pnpm-compat.js +72 -0
- package/lib/profile.js +166 -0
- package/lib/routes.js +152 -558
- package/lib/sources.js +85 -0
- package/lib/themes.js +102 -0
- package/lib/types/dsh-cli.d.ts +68 -0
- package/lib/types/http.d.ts +12 -0
- package/lib/types/install.d.ts +55 -0
- package/lib/types/pnpm-compat.d.ts +42 -0
- package/lib/types/profile.d.ts +32 -0
- package/lib/types/routes.d.ts +7 -21
- package/lib/types/sources.d.ts +42 -0
- package/lib/types/themes.d.ts +40 -0
- package/lib/types/updates.d.ts +16 -0
- package/lib/updates.js +61 -0
- package/package.json +5 -2
- package/src/client/Market.module.css +8 -1
- package/src/client/MarketSection.tsx +121 -31
- package/src/client/locales.ts +12 -0
- package/src/client/market-data.ts +60 -4
- package/src/dsh-cli.ts +248 -0
- package/src/http.ts +41 -0
- package/src/install.ts +141 -0
- package/src/pnpm-compat.ts +83 -0
- package/src/profile.ts +162 -0
- package/src/routes.ts +161 -592
- package/src/sources.ts +84 -0
- package/src/themes.ts +120 -0
- package/src/updates.ts +70 -0
package/README.md
CHANGED
|
@@ -51,6 +51,14 @@ Installs prefer npm tarballs over full-repo GitHub downloads whenever a plugin p
|
|
|
51
51
|
|
|
52
52
|
Live from [awesome-dsh-plugin.com/plugins.json](https://awesome-dsh-plugin.com/plugins.json) — curated entries, npm mapping, and star counts refreshed daily by CI — with a bundled snapshot as offline fallback.
|
|
53
53
|
|
|
54
|
+
## Related projects
|
|
55
|
+
|
|
56
|
+
### DeepSeek Harness Desktop
|
|
57
|
+
|
|
58
|
+
[DeepSeek Harness Desktop](https://github.com/anywhere-labs/deepseek-harness-desktop) is a modern desktop client for the DeepSeek Harness ecosystem — start and manage a local Harness service without installing Node.js or touching the command line. Plugin marketplace, mobile remote control, and IM Channels are on its roadmap.
|
|
59
|
+
|
|
60
|
+
[Website](https://www.dshdesktop.cn) · [GitHub](https://github.com/anywhere-labs/deepseek-harness-desktop)
|
|
61
|
+
|
|
54
62
|
## License
|
|
55
63
|
|
|
56
64
|
MIT · [dshmarket.com](https://dshmarket.com)
|
package/README.zh.md
CHANGED
|
@@ -51,6 +51,14 @@ dsh plugin --profile web add dshmarket
|
|
|
51
51
|
|
|
52
52
|
实时来自 [awesome-dsh-plugin.com/plugins.json](https://awesome-dsh-plugin.com/plugins.json)——精选条目、npm 映射、star 数由 CI 每日刷新——内置快照做离线兜底。
|
|
53
53
|
|
|
54
|
+
## 友情链接
|
|
55
|
+
|
|
56
|
+
### DeepSeek Harness Desktop
|
|
57
|
+
|
|
58
|
+
[DeepSeek Harness Desktop](https://github.com/anywhere-labs/deepseek-harness-desktop) 是一款为 DeepSeek Harness 生态打造的现代化桌面端,让用户无需配置 Node.js 或执行命令,即可启动和管理本地 Harness 服务。项目后续还将支持插件市场、移动端远程控制和 IM Channels。
|
|
59
|
+
|
|
60
|
+
[访问官网](https://www.dshdesktop.cn) · [GitHub](https://github.com/anywhere-labs/deepseek-harness-desktop)
|
|
61
|
+
|
|
54
62
|
## 许可
|
|
55
63
|
|
|
56
64
|
MIT · [dshmarket.com](https://dshmarket.com)
|
package/client/client.js
CHANGED
|
@@ -38,6 +38,12 @@ 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
|
+
updateNow: "立即更新",
|
|
41
47
|
updateFail: "更新失败",
|
|
42
48
|
upToDate: "已是最新",
|
|
43
49
|
linkedDev: "本地开发链接",
|
|
@@ -96,6 +102,12 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
96
102
|
update: "Update",
|
|
97
103
|
updating: "Updating…",
|
|
98
104
|
updated: "✓ Updated — restart to apply",
|
|
105
|
+
cancelOp: "Cancel",
|
|
106
|
+
cancelled: "Cancelled",
|
|
107
|
+
busyWait: "Another operation is already running — please wait for it to finish (one install/update/uninstall at a time)",
|
|
108
|
+
approveBuilds: "Allow build scripts and retry",
|
|
109
|
+
buildsSkipped: "This plugin needs its build scripts to run; they are blocked by default for safety. Click below to allow them and reinstall:",
|
|
110
|
+
updateNow: "Update now",
|
|
99
111
|
updateFail: "Update failed",
|
|
100
112
|
upToDate: "Up to date",
|
|
101
113
|
linkedDev: "linked (dev)",
|
|
@@ -132,10 +144,6 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
132
144
|
for (let i = 0; i < name.length; i++) hash = hash * 31 + name.charCodeAt(i) | 0;
|
|
133
145
|
return "hsl(" + (hash % 360 + 360) % 360 + " 55% 52%)";
|
|
134
146
|
}
|
|
135
|
-
function repoOf(url) {
|
|
136
|
-
const m = /^https:\/\/github\.com\/([^/]+\/[^/]+?)(?:\/tree\/.+)?\/?$/.exec(url);
|
|
137
|
-
return m ? m[1] : null;
|
|
138
|
-
}
|
|
139
147
|
function readSession(key) {
|
|
140
148
|
try {
|
|
141
149
|
return JSON.parse(sessionStorage.getItem(key) || "null");
|
|
@@ -149,6 +157,34 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
149
157
|
return /\b(tui|cli|tty|terminal)\b|终端|命令行/i.test(plugin.name + " " + desc);
|
|
150
158
|
}
|
|
151
159
|
/**
|
|
160
|
+
* The discover list: category filter, then search across name / owner /
|
|
161
|
+
* localized description, then the selected sort. Pure — the section renders
|
|
162
|
+
* exactly this.
|
|
163
|
+
*/
|
|
164
|
+
function visiblePlugins(plugins, options) {
|
|
165
|
+
const query = options.query.trim().toLowerCase();
|
|
166
|
+
const list = plugins.filter((p) => {
|
|
167
|
+
if (options.category !== "all" && p.category !== options.category) return false;
|
|
168
|
+
if (query === "") return true;
|
|
169
|
+
const desc = p.description && (p.description[options.lang] || p.description.en) || "";
|
|
170
|
+
return p.name.toLowerCase().includes(query) || p.owner.toLowerCase().includes(query) || desc.toLowerCase().includes(query);
|
|
171
|
+
});
|
|
172
|
+
if (options.sort === "hot") return [...list].sort((a, b) => (b.stars ?? -1) - (a.stars ?? -1));
|
|
173
|
+
if (options.sort === "new") return [...list].sort((a, b) => String(b.added).localeCompare(String(a.added)));
|
|
174
|
+
return list;
|
|
175
|
+
}
|
|
176
|
+
/** The themes tab listing: theme category only, most-starred first. */
|
|
177
|
+
function themePlugins(plugins) {
|
|
178
|
+
return plugins.filter((p) => p.category === "theme").sort((a, b) => (b.stars || 0) - (a.stars || 0));
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Category chip order: collapsed with an active non-'all' chip, the active
|
|
182
|
+
* one moves to the front so it stays visible inside the two-row clip.
|
|
183
|
+
*/
|
|
184
|
+
function orderedCategories(categories, active, open) {
|
|
185
|
+
return open || active === "all" ? categories : [active, ...categories.filter((id) => id !== active)];
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
152
188
|
* Unified installed-state matching (#15): both sides collapse to lowercase
|
|
153
189
|
* identity sets — the registry entry contributes its bare name, npm name and
|
|
154
190
|
* owner/repo; the dependency contributes its key and the repo inside its
|
|
@@ -158,16 +194,19 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
158
194
|
function entryIdentities(plugin) {
|
|
159
195
|
const ids = /* @__PURE__ */ new Set([plugin.name.toLowerCase()]);
|
|
160
196
|
if (plugin.npm) ids.add(plugin.npm.toLowerCase());
|
|
161
|
-
const
|
|
162
|
-
if (
|
|
197
|
+
const m = /^https:\/\/github\.com\/([^/]+\/[^/]+?)(?:\/tree\/[^/]+\/(.+?))?\/?$/.exec(plugin.url);
|
|
198
|
+
if (m !== null) ids.add(m[2] !== void 0 ? `${m[1].toLowerCase()}#path:/${m[2].toLowerCase()}` : m[1].toLowerCase());
|
|
163
199
|
return ids;
|
|
164
200
|
}
|
|
165
201
|
function depIdentities(name, spec) {
|
|
166
202
|
const ids = /* @__PURE__ */ new Set([name.toLowerCase()]);
|
|
167
203
|
const scoped = /^@([^/]+)\/(.+)$/.exec(name);
|
|
168
204
|
if (scoped !== null) ids.add(`${scoped[1].toLowerCase()}/${scoped[2].toLowerCase()}`);
|
|
169
|
-
const match = /github:([A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+)
|
|
170
|
-
if (match !== null)
|
|
205
|
+
const match = /github:([A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+)(?:#path:\/([A-Za-z0-9_./-]+))?/i.exec(spec);
|
|
206
|
+
if (match !== null) {
|
|
207
|
+
ids.add(match[1].toLowerCase());
|
|
208
|
+
if (match[2] !== void 0) ids.add(`${match[1].toLowerCase()}#path:/${match[2].toLowerCase()}`);
|
|
209
|
+
}
|
|
171
210
|
return ids;
|
|
172
211
|
}
|
|
173
212
|
/** The installed dependency name a registry entry corresponds to, or null. */
|
|
@@ -235,7 +274,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
235
274
|
}
|
|
236
275
|
//#endregion
|
|
237
276
|
//#region \0dsh-css:/home/runner/work/dsh-market/dsh-market/src/client/Market.module.css.mjs
|
|
238
|
-
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,.
|
|
277
|
+
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}";
|
|
239
278
|
const tagId = "dshmarket/Market.module.css";
|
|
240
279
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
241
280
|
const tag = document.createElement("style");
|
|
@@ -245,59 +284,62 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
245
284
|
document.head.appendChild(tag);
|
|
246
285
|
}
|
|
247
286
|
var Market_module_css_default = {
|
|
248
|
-
"tabs": "eGUBIq_tabs",
|
|
249
|
-
"swatches": "eGUBIq_swatches",
|
|
250
|
-
"star": "eGUBIq_star",
|
|
251
|
-
"okState": "eGUBIq_okState",
|
|
252
|
-
"themesGrid": "eGUBIq_themesGrid",
|
|
253
|
-
"dangerBtn": "eGUBIq_dangerBtn",
|
|
254
|
-
"modalNote": "eGUBIq_modalNote",
|
|
255
|
-
"nm": "eGUBIq_nm",
|
|
256
|
-
"btn": "eGUBIq_btn",
|
|
257
|
-
"descTight": "eGUBIq_descTight",
|
|
258
|
-
"empty": "eGUBIq_empty",
|
|
259
|
-
"cats": "eGUBIq_cats",
|
|
260
|
-
"title": "eGUBIq_title",
|
|
261
|
-
"on": "eGUBIq_on",
|
|
262
|
-
"row1": "eGUBIq_row1",
|
|
263
|
-
"body": "eGUBIq_body",
|
|
264
|
-
"top": "eGUBIq_top",
|
|
265
|
-
"searchInline": "eGUBIq_searchInline",
|
|
266
|
-
"sub": "eGUBIq_sub",
|
|
267
|
-
"catsWrap": "eGUBIq_catsWrap",
|
|
268
|
-
"head": "eGUBIq_head",
|
|
269
|
-
"av": "eGUBIq_av",
|
|
270
287
|
"warnBtn": "eGUBIq_warnBtn",
|
|
271
|
-
"
|
|
272
|
-
"
|
|
273
|
-
"
|
|
288
|
+
"grow": "eGUBIq_grow",
|
|
289
|
+
"sentinel": "eGUBIq_sentinel",
|
|
290
|
+
"body": "eGUBIq_body",
|
|
291
|
+
"titleRow": "eGUBIq_titleRow",
|
|
292
|
+
"tag": "eGUBIq_tag",
|
|
293
|
+
"sect": "eGUBIq_sect",
|
|
274
294
|
"catsRow": "eGUBIq_catsRow",
|
|
275
|
-
"
|
|
276
|
-
"
|
|
295
|
+
"dangerArmed": "eGUBIq_dangerArmed",
|
|
296
|
+
"catsCollapsed": "eGUBIq_catsCollapsed",
|
|
297
|
+
"head": "eGUBIq_head",
|
|
298
|
+
"star": "eGUBIq_star",
|
|
299
|
+
"swatches": "eGUBIq_swatches",
|
|
300
|
+
"card": "eGUBIq_card",
|
|
301
|
+
"grid": "eGUBIq_grid",
|
|
277
302
|
"root": "eGUBIq_root",
|
|
278
303
|
"tab": "eGUBIq_tab",
|
|
304
|
+
"av": "eGUBIq_av",
|
|
305
|
+
"searchInline": "eGUBIq_searchInline",
|
|
279
306
|
"desc": "eGUBIq_desc",
|
|
280
|
-
"
|
|
281
|
-
"
|
|
282
|
-
"
|
|
283
|
-
"titleRow": "eGUBIq_titleRow",
|
|
307
|
+
"foot": "eGUBIq_foot",
|
|
308
|
+
"themesGrid": "eGUBIq_themesGrid",
|
|
309
|
+
"src": "eGUBIq_src",
|
|
284
310
|
"dot": "eGUBIq_dot",
|
|
311
|
+
"spin": "eGUBIq_spin",
|
|
312
|
+
"descTight": "eGUBIq_descTight",
|
|
313
|
+
"row1": "eGUBIq_row1",
|
|
285
314
|
"progress": "eGUBIq_progress",
|
|
286
|
-
"
|
|
315
|
+
"err": "eGUBIq_err",
|
|
316
|
+
"title": "eGUBIq_title",
|
|
317
|
+
"restart": "eGUBIq_restart",
|
|
318
|
+
"cmdSummary": "eGUBIq_cmdSummary",
|
|
319
|
+
"loading": "eGUBIq_loading",
|
|
287
320
|
"sp": "eGUBIq_sp",
|
|
321
|
+
"spec": "eGUBIq_spec",
|
|
322
|
+
"staleAction": "eGUBIq_staleAction",
|
|
323
|
+
"cancelBtn": "eGUBIq_cancelBtn",
|
|
324
|
+
"tabs": "eGUBIq_tabs",
|
|
325
|
+
"on": "eGUBIq_on",
|
|
326
|
+
"top": "eGUBIq_top",
|
|
327
|
+
"sub": "eGUBIq_sub",
|
|
328
|
+
"modalNote": "eGUBIq_modalNote",
|
|
329
|
+
"cmdDetails": "eGUBIq_cmdDetails",
|
|
330
|
+
"owner": "eGUBIq_owner",
|
|
331
|
+
"okState": "eGUBIq_okState",
|
|
332
|
+
"empty": "eGUBIq_empty",
|
|
288
333
|
"cmd": "eGUBIq_cmd",
|
|
289
|
-
"
|
|
290
|
-
"
|
|
291
|
-
"catsCollapsed": "eGUBIq_catsCollapsed",
|
|
334
|
+
"pct": "eGUBIq_pct",
|
|
335
|
+
"nm": "eGUBIq_nm",
|
|
292
336
|
"sort": "eGUBIq_sort",
|
|
293
|
-
"grow": "eGUBIq_grow",
|
|
294
337
|
"warnLine": "eGUBIq_warnLine",
|
|
295
|
-
"dangerArmed": "eGUBIq_dangerArmed",
|
|
296
|
-
"loading": "eGUBIq_loading",
|
|
297
|
-
"spin": "eGUBIq_spin",
|
|
298
338
|
"irow": "eGUBIq_irow",
|
|
299
|
-
"
|
|
300
|
-
"
|
|
339
|
+
"cats": "eGUBIq_cats",
|
|
340
|
+
"catsToggle": "eGUBIq_catsToggle",
|
|
341
|
+
"dangerBtn": "eGUBIq_dangerBtn",
|
|
342
|
+
"catsWrap": "eGUBIq_catsWrap"
|
|
301
343
|
};
|
|
302
344
|
//#endregion
|
|
303
345
|
//#region src/client/MarketSection.tsx
|
|
@@ -325,14 +367,25 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
325
367
|
onError: () => setFailed(true)
|
|
326
368
|
});
|
|
327
369
|
}
|
|
370
|
+
/**
|
|
371
|
+
* Module-scope caches so re-entering the section renders instantly instead
|
|
372
|
+
* of refetching and rebuilding from a spinner (#30 by @StarsTom). Module
|
|
373
|
+
* state survives section switches; a background refetch keeps it current.
|
|
374
|
+
*/
|
|
375
|
+
let cachedRegistry = null;
|
|
376
|
+
let cachedInstalled = null;
|
|
328
377
|
function MarketSection(props) {
|
|
329
378
|
const t = props.t;
|
|
330
379
|
const localeSnap = (0, react.useSyncExternalStore)((cb) => props.locale.subscribe(cb), () => props.locale.getSnapshot());
|
|
331
380
|
const lang = String(localeSnap.active).toLowerCase().startsWith("zh") ? "zh" : "en";
|
|
332
381
|
const themeSnap = (0, react.useSyncExternalStore)(props.themeStore.subscribe, props.themeStore.getSnapshot);
|
|
333
|
-
const [data, setData] = (0, react.useState)(
|
|
382
|
+
const [data, setData] = (0, react.useState)(cachedRegistry);
|
|
334
383
|
const [loadError, setLoadError] = (0, react.useState)(false);
|
|
335
|
-
const [installed,
|
|
384
|
+
const [installed, setInstalledState] = (0, react.useState)(cachedInstalled ?? {});
|
|
385
|
+
const setInstalled = (0, react.useCallback)((value) => {
|
|
386
|
+
cachedInstalled = value;
|
|
387
|
+
setInstalledState(value);
|
|
388
|
+
}, []);
|
|
336
389
|
const [skins, setSkins] = (0, react.useState)([]);
|
|
337
390
|
const [tab, setTab] = (0, react.useState)(() => {
|
|
338
391
|
const saved = sessionStorage.getItem("dshm-tab");
|
|
@@ -347,6 +400,23 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
347
400
|
const [installError, setInstallError] = (0, react.useState)(null);
|
|
348
401
|
const [updates, setUpdates] = (0, react.useState)({});
|
|
349
402
|
const [updatingName, setUpdatingName] = (0, react.useState)(null);
|
|
403
|
+
const [staleName, setStaleName] = (0, react.useState)(null);
|
|
404
|
+
/**
|
|
405
|
+
* Cards rendered so far — the discover grid renders incrementally (60,
|
|
406
|
+
* then +120 as the sentinel scrolls into view) instead of all 400+ at
|
|
407
|
+
* once, which built a ~70k px DOM and made section switches lag (#30).
|
|
408
|
+
*/
|
|
409
|
+
const [visibleCount, setVisibleCount] = (0, react.useState)(60);
|
|
410
|
+
const sentinelRef = (0, react.useCallback)((node) => {
|
|
411
|
+
if (node === null) return;
|
|
412
|
+
new IntersectionObserver((entries) => {
|
|
413
|
+
if (entries.some((entry) => entry.isIntersecting)) setVisibleCount((count) => count + 120);
|
|
414
|
+
}, { rootMargin: "600px" }).observe(node);
|
|
415
|
+
}, []);
|
|
416
|
+
/** Determinate percent parsed from pnpm's Progress line, when available. */
|
|
417
|
+
const [progressPct, setProgressPct] = (0, react.useState)(null);
|
|
418
|
+
/** Blocked build scripts from the last install: enables approve-and-retry (#6). */
|
|
419
|
+
const [buildsSkipped, setBuildsSkipped] = (0, react.useState)(null);
|
|
350
420
|
const [updatingAll, setUpdatingAll] = (0, react.useState)(false);
|
|
351
421
|
const [updatedNames, setUpdatedNames] = (0, react.useState)([]);
|
|
352
422
|
const [hotUrls, setHotUrls] = (0, react.useState)([]);
|
|
@@ -376,7 +446,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
376
446
|
fetch("/dsh-market/registry", { cache: "no-store" }).then((res) => {
|
|
377
447
|
if (!res.ok) throw new Error("HTTP " + res.status);
|
|
378
448
|
return res.json();
|
|
379
|
-
}).then((body) =>
|
|
449
|
+
}).then((body) => {
|
|
450
|
+
cachedRegistry = body.registry;
|
|
451
|
+
setData(body.registry);
|
|
452
|
+
}).catch(() => setLoadError(true));
|
|
380
453
|
fetch("/dsh-market/status", { cache: "no-store" }).then((res) => res.json()).then((status) => {
|
|
381
454
|
setEnvReady(status.pnpm !== false);
|
|
382
455
|
if (typeof status.boot === "string") setBootId(status.boot);
|
|
@@ -433,9 +506,16 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
433
506
|
}
|
|
434
507
|
const timer = setInterval(() => {
|
|
435
508
|
fetch("/dsh-market/status", { cache: "no-store" }).then((res) => res.json()).then((status) => {
|
|
436
|
-
if (status.active)
|
|
437
|
-
|
|
509
|
+
if (status.active) {
|
|
510
|
+
setProgressLine((status.lastLine || "…") + " (" + status.seconds + "s)");
|
|
511
|
+
const m = /resolved (\d+), reused (\d+), downloaded (\d+), added (\d+)/.exec(status.lastLine || "");
|
|
512
|
+
if (m !== null && Number(m[1]) > 0) {
|
|
513
|
+
const done = Number(m[2]) + Number(m[3]) + Number(m[4]);
|
|
514
|
+
setProgressPct(Math.max(4, Math.min(96, Math.round(done / Number(m[1]) * 100))));
|
|
515
|
+
}
|
|
516
|
+
} else {
|
|
438
517
|
setProgressLine(null);
|
|
518
|
+
setProgressPct(null);
|
|
439
519
|
setInstalled(status.installed || {});
|
|
440
520
|
if (readSession("dshm-pending") !== null && busyUrl !== null) {
|
|
441
521
|
if (data !== null && data.plugins.some((p) => p.url === busyUrl && isInstalled(p, status.installed || {}))) {
|
|
@@ -453,26 +533,27 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
453
533
|
updatingName,
|
|
454
534
|
data
|
|
455
535
|
]);
|
|
456
|
-
const plugins = (0, react.useMemo)(() => {
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
const desc = p.description && (p.description[lang] || p.description.en) || "";
|
|
463
|
-
return p.name.toLowerCase().includes(query) || p.owner.toLowerCase().includes(query) || desc.toLowerCase().includes(query);
|
|
464
|
-
});
|
|
465
|
-
if (sort === "hot") return [...list].sort((a, b) => (b.stars ?? -1) - (a.stars ?? -1));
|
|
466
|
-
if (sort === "new") return [...list].sort((a, b) => String(b.added).localeCompare(String(a.added)));
|
|
467
|
-
return list;
|
|
468
|
-
}, [
|
|
536
|
+
const plugins = (0, react.useMemo)(() => data === null ? [] : visiblePlugins(data.plugins, {
|
|
537
|
+
category: cat,
|
|
538
|
+
query: q,
|
|
539
|
+
lang,
|
|
540
|
+
sort
|
|
541
|
+
}), [
|
|
469
542
|
data,
|
|
470
543
|
q,
|
|
471
544
|
cat,
|
|
472
545
|
lang,
|
|
473
546
|
sort
|
|
474
547
|
]);
|
|
548
|
+
(0, react.useEffect)(() => {
|
|
549
|
+
setVisibleCount(60);
|
|
550
|
+
}, [
|
|
551
|
+
q,
|
|
552
|
+
cat,
|
|
553
|
+
sort
|
|
554
|
+
]);
|
|
475
555
|
const doInstall = (0, react.useCallback)((plugin) => {
|
|
556
|
+
setBuildsSkipped(null);
|
|
476
557
|
setConfirming(null);
|
|
477
558
|
setInstallError(null);
|
|
478
559
|
setBusyUrl(plugin.url);
|
|
@@ -492,6 +573,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
492
573
|
location.reload();
|
|
493
574
|
return;
|
|
494
575
|
}
|
|
576
|
+
if (body.cancelled === true) {
|
|
577
|
+
refreshInstalled();
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
495
580
|
if (status === 200 && body.ok) {
|
|
496
581
|
sessionStorage.setItem("dshm-tab", "installed");
|
|
497
582
|
if (body.hot) {
|
|
@@ -500,6 +585,14 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
500
585
|
} else setDoneUrls((urls) => urls.includes(plugin.url) ? urls : urls.concat(plugin.url));
|
|
501
586
|
refreshInstalled();
|
|
502
587
|
} else {
|
|
588
|
+
if (status === 409) {
|
|
589
|
+
setInstallError(t("busyWait"));
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
if (Array.isArray(body.ignoredBuilds) && body.ignoredBuilds.length > 0) setBuildsSkipped({
|
|
593
|
+
plugin,
|
|
594
|
+
names: body.ignoredBuilds.map(String)
|
|
595
|
+
});
|
|
503
596
|
const text = (v) => typeof v === "string" ? v : v && typeof v.text === "string" ? v.text : v == null ? "" : JSON.stringify(v);
|
|
504
597
|
const detail = text(body.error) || [text(body.stderr), text(body.stdout)].filter(Boolean).join("\n").trim() || "exit " + body.exitCode;
|
|
505
598
|
setInstallError(t("installFail") + ": " + plugin.name + " — " + detail.trim().slice(-600));
|
|
@@ -509,21 +602,42 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
509
602
|
setInstallError(t("installFail") + ": " + String(error));
|
|
510
603
|
}).finally(() => setBusyUrl(null));
|
|
511
604
|
}, [refreshInstalled, t]);
|
|
512
|
-
|
|
605
|
+
/** Cancel the running plugin command (#6 by @qichuang321). */
|
|
606
|
+
const doCancel = (0, react.useCallback)(() => {
|
|
607
|
+
fetch("/dsh-market/cancel", {
|
|
608
|
+
method: "POST",
|
|
609
|
+
headers: { "content-type": "application/json" },
|
|
610
|
+
body: "{}"
|
|
611
|
+
}).catch(() => {});
|
|
612
|
+
}, []);
|
|
613
|
+
const doUpdate = (0, react.useCallback)((name, force = false) => {
|
|
513
614
|
setInstallError(null);
|
|
615
|
+
setStaleName(null);
|
|
514
616
|
setUpdatingName(name);
|
|
515
617
|
return fetch("/dsh-market/update", {
|
|
516
618
|
method: "POST",
|
|
517
619
|
headers: { "content-type": "application/json" },
|
|
518
|
-
body: JSON.stringify(
|
|
620
|
+
body: JSON.stringify(force ? {
|
|
621
|
+
name,
|
|
622
|
+
force: true
|
|
623
|
+
} : { name })
|
|
519
624
|
}).then((res) => res.json().then((body) => ({
|
|
520
625
|
status: res.status,
|
|
521
626
|
body
|
|
522
627
|
}))).then(({ status, body }) => {
|
|
628
|
+
if (body.cancelled === true) {
|
|
629
|
+
refreshInstalled();
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
523
632
|
if (status === 200 && body.ok) {
|
|
524
633
|
setUpdatedNames((names) => names.concat(name));
|
|
525
634
|
refreshInstalled();
|
|
526
635
|
} else {
|
|
636
|
+
if (status === 409) {
|
|
637
|
+
setInstallError(t("busyWait"));
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
if (body.stale === true) setStaleName(name);
|
|
527
641
|
const text = (v) => typeof v === "string" ? v : v && typeof v.text === "string" ? v.text : v == null ? "" : JSON.stringify(v);
|
|
528
642
|
const detail = text(body.error) || [text(body.stderr), text(body.stdout)].filter(Boolean).join("\n").trim() || "exit " + body.exitCode;
|
|
529
643
|
setInstallError(t("updateFail") + ": " + name + " — " + detail.trim().slice(-600));
|
|
@@ -586,7 +700,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
586
700
|
}, [updatableNames, doUpdate]);
|
|
587
701
|
const pendingRestart = doneUrls.length + updatedNames.length + removedCount;
|
|
588
702
|
const hasUpdates = Object.keys(installed).some((name) => !updatedNames.includes(name) && updates[name] && updates[name].updateAvailable);
|
|
589
|
-
const themePlugins = data === null ? [] : data.plugins
|
|
703
|
+
const themePlugins$1 = data === null ? [] : themePlugins(data.plugins);
|
|
590
704
|
const pluginCard = (p) => {
|
|
591
705
|
const desc = p.description && (p.description[lang] || p.description.en) || "";
|
|
592
706
|
const done = doneUrls.includes(p.url) || hotUrls.includes(p.url);
|
|
@@ -663,10 +777,23 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
663
777
|
}),
|
|
664
778
|
busy && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
665
779
|
className: Market_module_css_default.progress,
|
|
666
|
-
children: [
|
|
667
|
-
className: Market_module_css_default.
|
|
668
|
-
|
|
669
|
-
|
|
780
|
+
children: [
|
|
781
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: Market_module_css_default.spin }),
|
|
782
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
783
|
+
className: Market_module_css_default.grow,
|
|
784
|
+
children: progressLine || t("progressHint")
|
|
785
|
+
}),
|
|
786
|
+
progressPct !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
787
|
+
className: Market_module_css_default.pct,
|
|
788
|
+
children: [progressPct, "%"]
|
|
789
|
+
}),
|
|
790
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
791
|
+
type: "button",
|
|
792
|
+
className: Market_module_css_default.cancelBtn,
|
|
793
|
+
onClick: doCancel,
|
|
794
|
+
children: t("cancelOp")
|
|
795
|
+
})
|
|
796
|
+
]
|
|
670
797
|
})
|
|
671
798
|
]
|
|
672
799
|
}, p.url);
|
|
@@ -970,9 +1097,43 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
970
1097
|
})
|
|
971
1098
|
]
|
|
972
1099
|
}),
|
|
973
|
-
|
|
1100
|
+
buildsSkipped !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1101
|
+
className: Market_module_css_default.restart,
|
|
1102
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1103
|
+
className: Market_module_css_default.grow,
|
|
1104
|
+
children: [
|
|
1105
|
+
t("buildsSkipped"),
|
|
1106
|
+
" ",
|
|
1107
|
+
buildsSkipped.names.join(", ")
|
|
1108
|
+
]
|
|
1109
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1110
|
+
size: "sm",
|
|
1111
|
+
disabled: busyUrl !== null,
|
|
1112
|
+
onClick: () => {
|
|
1113
|
+
const { plugin, names } = buildsSkipped;
|
|
1114
|
+
setBuildsSkipped(null);
|
|
1115
|
+
fetch("/dsh-market/approve-builds", {
|
|
1116
|
+
method: "POST",
|
|
1117
|
+
headers: { "content-type": "application/json" },
|
|
1118
|
+
body: JSON.stringify({ packages: names })
|
|
1119
|
+
}).then((res) => res.json()).then((body) => {
|
|
1120
|
+
if (body.ok) doInstall(plugin);
|
|
1121
|
+
else setInstallError(String(body.error || "approve failed"));
|
|
1122
|
+
}).catch((error) => setInstallError(String(error)));
|
|
1123
|
+
},
|
|
1124
|
+
children: t("approveBuilds")
|
|
1125
|
+
})]
|
|
1126
|
+
}),
|
|
1127
|
+
installError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
974
1128
|
className: Market_module_css_default.err,
|
|
975
|
-
children: installError
|
|
1129
|
+
children: [installError, staleName !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1130
|
+
className: Market_module_css_default.staleAction,
|
|
1131
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1132
|
+
size: "sm",
|
|
1133
|
+
onClick: () => doUpdate(staleName, true),
|
|
1134
|
+
children: t("updateNow")
|
|
1135
|
+
})
|
|
1136
|
+
})]
|
|
976
1137
|
}),
|
|
977
1138
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
978
1139
|
className: Market_module_css_default.body,
|
|
@@ -992,7 +1153,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
992
1153
|
ref: catsWrapRef,
|
|
993
1154
|
className: catsOpen || visibleCats === null ? `${Market_module_css_default.catsWrap} ${Market_module_css_default.catsCollapsed}` : Market_module_css_default.catsWrap,
|
|
994
1155
|
children: (() => {
|
|
995
|
-
const ordered =
|
|
1156
|
+
const ordered = orderedCategories(categories, cat, catsOpen);
|
|
996
1157
|
const shown = catsOpen || visibleCats === null ? ordered : ordered.slice(0, Math.max(0, visibleCats - 1));
|
|
997
1158
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
998
1159
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
|
|
@@ -1029,10 +1190,13 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
1029
1190
|
}), plugins.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1030
1191
|
className: Market_module_css_default.empty,
|
|
1031
1192
|
children: t("empty")
|
|
1032
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1193
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1033
1194
|
className: Market_module_css_default.grid,
|
|
1034
|
-
children: plugins.map(pluginCard)
|
|
1035
|
-
})
|
|
1195
|
+
children: plugins.slice(0, visibleCount).map(pluginCard)
|
|
1196
|
+
}), plugins.length > visibleCount && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1197
|
+
ref: sentinelRef,
|
|
1198
|
+
className: Market_module_css_default.sentinel
|
|
1199
|
+
})] })] }) : tab === "themes" && themeSnap !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(() => {
|
|
1036
1200
|
const extra = themeSnap.themes.filter((def) => def.id !== "light" && def.id !== "dark");
|
|
1037
1201
|
return extra.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1038
1202
|
className: `${Market_module_css_default.grid} ${Market_module_css_default.themesGrid}`,
|
|
@@ -1041,12 +1205,12 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
1041
1205
|
})(), data === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1042
1206
|
className: Market_module_css_default.loading,
|
|
1043
1207
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: Market_module_css_default.spin }), t("loading")]
|
|
1044
|
-
}) : themePlugins.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1208
|
+
}) : themePlugins$1.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1045
1209
|
className: Market_module_css_default.empty,
|
|
1046
1210
|
children: t("themeEmpty")
|
|
1047
1211
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1048
1212
|
className: Market_module_css_default.grid,
|
|
1049
|
-
children: themePlugins.map(themePluginCard)
|
|
1213
|
+
children: themePlugins$1.map(themePluginCard)
|
|
1050
1214
|
})] }) : Object.keys(installed).length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1051
1215
|
className: Market_module_css_default.empty,
|
|
1052
1216
|
children: t("installedEmpty")
|
|
@@ -1087,10 +1251,23 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
1087
1251
|
}),
|
|
1088
1252
|
updatingName === name && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1089
1253
|
className: Market_module_css_default.progress,
|
|
1090
|
-
children: [
|
|
1091
|
-
className: Market_module_css_default.
|
|
1092
|
-
|
|
1093
|
-
|
|
1254
|
+
children: [
|
|
1255
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: Market_module_css_default.spin }),
|
|
1256
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
1257
|
+
className: Market_module_css_default.grow,
|
|
1258
|
+
children: progressLine || t("progressHint")
|
|
1259
|
+
}),
|
|
1260
|
+
progressPct !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1261
|
+
className: Market_module_css_default.pct,
|
|
1262
|
+
children: [progressPct, "%"]
|
|
1263
|
+
}),
|
|
1264
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1265
|
+
type: "button",
|
|
1266
|
+
className: Market_module_css_default.cancelBtn,
|
|
1267
|
+
onClick: doCancel,
|
|
1268
|
+
children: t("cancelOp")
|
|
1269
|
+
})
|
|
1270
|
+
]
|
|
1094
1271
|
})
|
|
1095
1272
|
]
|
|
1096
1273
|
}),
|