dshmarket 1.29.3 → 1.30.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 +64 -5
- package/client/client.js.map +1 -1
- package/lib/routes.js +34 -0
- package/package.json +1 -1
- package/src/client/MarketSection.tsx +68 -5
- package/src/client/locales.ts +2 -0
- package/src/routes.ts +34 -0
package/README.md
CHANGED
|
@@ -109,6 +109,10 @@ DSHM_REGISTRY_URL=https://your-mirror.example/plugins.json dsh web
|
|
|
109
109
|
|
|
110
110
|
[deepseek-harness-desktop](https://github.com/anywhere-labs/deepseek-harness-desktop) — an Electron desktop app for DeepSeek Harness built around the idea that everything is a plugin, including the desktop itself: profile switching, a bundled Node and pnpm, and a recoverable install path that snapshots the profile before a change. [dshdesktop.cn](https://dshdesktop.cn)
|
|
111
111
|
|
|
112
|
+
### DSH App
|
|
113
|
+
|
|
114
|
+
[dsh-app](https://github.com/RyensX/dsh-app) — a DeepSeek Harness desktop client built on Tauri 2 rather than Electron, so it ships a much smaller binary and uses the system webview. AGPL-3.0.
|
|
115
|
+
|
|
112
116
|
### DSH Get
|
|
113
117
|
|
|
114
118
|
[DSH Get](https://www.dshget.com/) — a searchable web directory for discovering DeepSeek Harness plugins: category filters, bilingual descriptions, install commands and per-plugin detail pages. Its normalized catalog snapshot is public at [bobby-sheng/dshget-data](https://github.com/bobby-sheng/dshget-data).
|
package/README.zh.md
CHANGED
|
@@ -106,6 +106,10 @@ DSHM_REGISTRY_URL=https://your-mirror.example/plugins.json dsh web
|
|
|
106
106
|
|
|
107
107
|
[deepseek-harness-desktop](https://github.com/anywhere-labs/deepseek-harness-desktop)——基于 Electron 的 DeepSeek Harness 桌面客户端,理念是「万物皆插件,桌面本身也是插件」:支持 profile 切换、内置 Node 与 pnpm,安装前会先给 profile 拍快照以便回滚。[dshdesktop.cn](https://dshdesktop.cn)
|
|
108
108
|
|
|
109
|
+
### DSH App
|
|
110
|
+
|
|
111
|
+
[dsh-app](https://github.com/RyensX/dsh-app)——基于 Tauri 2(而非 Electron)的 DeepSeek Harness 桌面客户端,因此安装包小得多,界面走系统 webview。AGPL-3.0。
|
|
112
|
+
|
|
109
113
|
### DSH Get
|
|
110
114
|
|
|
111
115
|
[DSH Get](https://www.dshget.com/)——DeepSeek Harness 插件的网页检索目录:分类筛选、中英描述、安装命令与插件详情页;其规范化的目录快照公开在 [bobby-sheng/dshget-data](https://github.com/bobby-sheng/dshget-data)。
|
package/client/client.js
CHANGED
|
@@ -267,6 +267,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
267
267
|
restorePartial: "恢复已完成,但下列插件安装失败:",
|
|
268
268
|
restoreUnportable: "依赖指向了另一台机器上的绝对路径,本机不存在,需要手动改成本机路径或重新安装",
|
|
269
269
|
restoreBootError: "恢复后仍无法启动:",
|
|
270
|
+
orphanBundle: "⚠️ 下次启动会失败:profile 声明了这些 bundle,但它们没有安装。请重新安装,或从 profile 的 package.json 的 dsh.profile.bundles 里删掉:",
|
|
270
271
|
restoreConfirm: "恢复将覆盖当前 profile 配置并重新安装插件,确定继续吗?",
|
|
271
272
|
restorePreviewDone: "备份已导入,请在「已安装」中确认后开始恢复",
|
|
272
273
|
restoreMissing: "备份中有 {0} 个插件尚未安装",
|
|
@@ -712,6 +713,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
712
713
|
restorePartial: "Restore completed, but these plugins failed to install:",
|
|
713
714
|
restoreUnportable: "points at an absolute path from another machine that does not exist here — repoint it locally or reinstall the plugin",
|
|
714
715
|
restoreBootError: "Still cannot boot after the restore:",
|
|
716
|
+
orphanBundle: "⚠️ The next start will fail: the profile declares these bundles but they are not installed. Reinstall them, or remove them from dsh.profile.bundles in the profile package.json:",
|
|
715
717
|
restoreConfirm: "Restore will overwrite this profile configuration and reinstall plugins. Continue?",
|
|
716
718
|
restorePreviewDone: "Backup imported. Review Installed, then start restore.",
|
|
717
719
|
restoreMissing: "{0} plugins from this backup are not installed",
|
|
@@ -5067,6 +5069,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
5067
5069
|
*/
|
|
5068
5070
|
const [records, setRecords] = (0, react.useState)([]);
|
|
5069
5071
|
const recordSeq = (0, react.useRef)(0);
|
|
5072
|
+
/** The synthetic install task rebuilt from dshm-pending after a remount. */
|
|
5073
|
+
const recoveredInstall = (0, react.useRef)(null);
|
|
5074
|
+
/** The synthetic task rebuilt from dshm-updating after this section remounts. */
|
|
5075
|
+
const recoveredUpdateRecordId = (0, react.useRef)(null);
|
|
5070
5076
|
/** Raised by the card marker, so "查看详情" lands on the record itself. */
|
|
5071
5077
|
const [operationsOpen, setOperationsOpen] = (0, react.useState)(false);
|
|
5072
5078
|
const openOperations = (0, react.useCallback)(() => setOperationsOpen(true), []);
|
|
@@ -5414,10 +5420,41 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
5414
5420
|
}, []);
|
|
5415
5421
|
(0, react.useEffect)(() => {
|
|
5416
5422
|
const pending = readSession("dshm-pending");
|
|
5417
|
-
if (pending !== null && typeof pending.url === "string")
|
|
5423
|
+
if (pending !== null && typeof pending.url === "string") {
|
|
5424
|
+
setBusyUrl(pending.url);
|
|
5425
|
+
recoveredInstall.current = {
|
|
5426
|
+
id: `recovered-install:${pending.url}`,
|
|
5427
|
+
url: pending.url,
|
|
5428
|
+
...typeof pending.name === "string" && pending.name !== "" ? { name: pending.name } : {}
|
|
5429
|
+
};
|
|
5430
|
+
}
|
|
5418
5431
|
const updating = readSession("dshm-updating");
|
|
5419
|
-
if (updating !== null && typeof updating.name === "string" && updating.name !== "")
|
|
5432
|
+
if (updating !== null && typeof updating.name === "string" && updating.name !== "") {
|
|
5433
|
+
setUpdatingName(updating.name);
|
|
5434
|
+
const id = `recovered-update:${updating.name}`;
|
|
5435
|
+
recoveredUpdateRecordId.current = id;
|
|
5436
|
+
setRecords((list) => list.some((record) => record.kind === "update" && record.name === updating.name && record.state === "running") ? list : enqueue(list, {
|
|
5437
|
+
id,
|
|
5438
|
+
kind: "update",
|
|
5439
|
+
name: updating.name,
|
|
5440
|
+
state: "running"
|
|
5441
|
+
}));
|
|
5442
|
+
}
|
|
5420
5443
|
}, []);
|
|
5444
|
+
(0, react.useEffect)(() => {
|
|
5445
|
+
const recovered = recoveredInstall.current;
|
|
5446
|
+
if (recovered === null) return;
|
|
5447
|
+
const name = recovered.name ?? data?.plugins.find((plugin) => plugin.url === recovered.url)?.name;
|
|
5448
|
+
if (name === void 0) return;
|
|
5449
|
+
recovered.name = name;
|
|
5450
|
+
setRecords((list) => list.some((record) => record.id === recovered.id) ? list : enqueue(list, {
|
|
5451
|
+
id: recovered.id,
|
|
5452
|
+
kind: "install",
|
|
5453
|
+
name,
|
|
5454
|
+
url: recovered.url,
|
|
5455
|
+
state: "running"
|
|
5456
|
+
}));
|
|
5457
|
+
}, [data]);
|
|
5421
5458
|
(0, react.useEffect)(() => {
|
|
5422
5459
|
if (busyUrl === null && updatingName === null) {
|
|
5423
5460
|
setProgressLine(null);
|
|
@@ -5462,11 +5499,21 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
5462
5499
|
if (data !== null && data.plugins.some((p) => p.url === busyUrl && isInstalled(p, statusInstalled, repoIdentities, data.plugins, repoHints))) {
|
|
5463
5500
|
idleStrikes.current = 0;
|
|
5464
5501
|
sessionStorage.removeItem("dshm-pending");
|
|
5502
|
+
const recovered = recoveredInstall.current;
|
|
5503
|
+
if (recovered !== null) {
|
|
5504
|
+
setRecords((list) => drop(list, recovered.id));
|
|
5505
|
+
recoveredInstall.current = null;
|
|
5506
|
+
}
|
|
5465
5507
|
setDoneUrls((urls) => urls.includes(busyUrl) ? urls : urls.concat(busyUrl));
|
|
5466
5508
|
setBusyUrl(null);
|
|
5467
5509
|
} else if (++idleStrikes.current >= 2) {
|
|
5468
5510
|
idleStrikes.current = 0;
|
|
5469
5511
|
sessionStorage.removeItem("dshm-pending");
|
|
5512
|
+
const recovered = recoveredInstall.current;
|
|
5513
|
+
if (recovered !== null) {
|
|
5514
|
+
setRecords((list) => drop(list, recovered.id));
|
|
5515
|
+
recoveredInstall.current = null;
|
|
5516
|
+
}
|
|
5470
5517
|
setBusyUrl(null);
|
|
5471
5518
|
setInstallError(t("installFail") + " — " + t("exportLog"));
|
|
5472
5519
|
}
|
|
@@ -5475,6 +5522,11 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
5475
5522
|
if (++updateIdleStrikes.current >= 2) {
|
|
5476
5523
|
updateIdleStrikes.current = 0;
|
|
5477
5524
|
sessionStorage.removeItem("dshm-updating");
|
|
5525
|
+
const recoveredId = recoveredUpdateRecordId.current;
|
|
5526
|
+
if (recoveredId !== null) {
|
|
5527
|
+
setRecords((list) => drop(list, recoveredId));
|
|
5528
|
+
recoveredUpdateRecordId.current = null;
|
|
5529
|
+
}
|
|
5478
5530
|
setUpdatingName(null);
|
|
5479
5531
|
refreshInstalled();
|
|
5480
5532
|
}
|
|
@@ -5611,7 +5663,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
5611
5663
|
url: plugin.url,
|
|
5612
5664
|
state: "running"
|
|
5613
5665
|
}));
|
|
5614
|
-
sessionStorage.setItem("dshm-pending", JSON.stringify({
|
|
5666
|
+
sessionStorage.setItem("dshm-pending", JSON.stringify({
|
|
5667
|
+
url: plugin.url,
|
|
5668
|
+
name: plugin.name
|
|
5669
|
+
}));
|
|
5615
5670
|
fetch("/dsh-market/install", {
|
|
5616
5671
|
method: "POST",
|
|
5617
5672
|
headers: { "content-type": "application/json" },
|
|
@@ -5685,7 +5740,9 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
5685
5740
|
names: blocked
|
|
5686
5741
|
});
|
|
5687
5742
|
const text = (v) => typeof v === "string" ? v : v && typeof v.text === "string" ? v.text : v == null ? "" : JSON.stringify(v);
|
|
5688
|
-
const
|
|
5743
|
+
const orphans = Array.isArray(body.orphanBundles) ? body.orphanBundles.map(String) : [];
|
|
5744
|
+
const failure = text(body.error) || humanOutput([text(body.stderr), text(body.stdout)].filter(Boolean).join("\n")) || "exit " + body.exitCode;
|
|
5745
|
+
const detail = orphans.length > 0 ? `${t("orphanBundle")} ${orphans.join(", ")}\n${failure}` : failure;
|
|
5689
5746
|
setRecords((list) => patch(list, recordId, {
|
|
5690
5747
|
state: "failed",
|
|
5691
5748
|
reason: detail.trim().slice(-600),
|
|
@@ -5903,7 +5960,9 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
5903
5960
|
restore
|
|
5904
5961
|
});
|
|
5905
5962
|
const text = (v) => typeof v === "string" ? v : v && typeof v.text === "string" ? v.text : v == null ? "" : JSON.stringify(v);
|
|
5906
|
-
const
|
|
5963
|
+
const orphans = Array.isArray(body.orphanBundles) ? body.orphanBundles.map(String) : [];
|
|
5964
|
+
const failure = text(body.error) || humanOutput([text(body.stderr), text(body.stdout)].filter(Boolean).join("\n")) || "exit " + body.exitCode;
|
|
5965
|
+
const detail = orphans.length > 0 ? `${t("orphanBundle")} ${orphans.join(", ")}\n${failure}` : failure;
|
|
5907
5966
|
setRecords((list) => patch(list, updateRecordId, {
|
|
5908
5967
|
state: "failed",
|
|
5909
5968
|
reason: detail.trim().slice(-600)
|