@max-null/dsh-plugin-center 0.1.4 → 0.1.7
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 +6 -0
- package/client.js +39 -13
- package/dist/engine.d.ts +2 -1
- package/dist/engine.js +7 -3
- package/dist/meta.d.ts +8 -0
- package/dist/meta.js +10 -0
- package/dist/rpc.js +4 -1
- package/dist/update.d.ts +9 -2
- package/dist/update.js +10 -3
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -13,6 +13,12 @@ Plugin center for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-har
|
|
|
13
13
|
- **DSH compatibility / 兼容性检查** — flags plugins whose peer range does not match the running DSH.
|
|
14
14
|
- **Skin-compatible / 皮肤兼容** — every color uses `var(--dsw-*)` tokens, so skin plugins restyle this UI too.
|
|
15
15
|
|
|
16
|
+
## Part of the SSID family / SSID 系列成员
|
|
17
|
+
|
|
18
|
+
This plugin belongs to the **`@max-null/*` family** — a set of plugins that together form the **[SSID (思灵 · Seek Soul in Darkness)](https://github.com/Max-Null/seek-soul-in-darkness)** desktop experience. SSID is the box that bundles them all: `dsh-plugin-center` · `dsh-memory` · `dsh-chinese-thinking` · `dsh-guardian` · `dsh-habit`.
|
|
19
|
+
|
|
20
|
+
本插件属于 **`@max-null/*` 插件系列**——这一系列共同构成 **[SSID(思灵 · Seek Soul in Darkness)](https://github.com/Max-Null/seek-soul-in-darkness)** 桌面体验。SSID 是整合它们的盒:`dsh-plugin-center` · `dsh-memory` · `dsh-chinese-thinking` · `dsh-guardian` · `dsh-habit`。
|
|
21
|
+
|
|
16
22
|
## Screenshots / 截图
|
|
17
23
|
|
|
18
24
|
| Installed / 已安装 | Market / 市场 | Updates / 更新 |
|
package/client.js
CHANGED
|
@@ -126,6 +126,9 @@ function closeOverlay() {
|
|
|
126
126
|
overlayOpen = false;
|
|
127
127
|
overlayListeners.forEach((l) => l());
|
|
128
128
|
}
|
|
129
|
+
function toggleOverlay() {
|
|
130
|
+
overlayOpen ? closeOverlay() : openOverlay();
|
|
131
|
+
}
|
|
129
132
|
function closeWhatsNew() {
|
|
130
133
|
whatsNewOpen = false;
|
|
131
134
|
for (const d of whatsNewDigests) readCache[d.name] = d.toVersion;
|
|
@@ -500,7 +503,7 @@ function UpdatesView({ updates, refresh, updateOne, busy }) {
|
|
|
500
503
|
u.compat === "incompatible" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-tag danger", children: t("incompat") }),
|
|
501
504
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-spacer" }),
|
|
502
505
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "pc-btn primary", disabled: busy !== null, onClick: () => {
|
|
503
|
-
updateOne(u.name);
|
|
506
|
+
updateOne(u.name, u.toVersion);
|
|
504
507
|
}, children: busy === u.name || busy === "__all__" ? t("updating") : t("update") })
|
|
505
508
|
] }),
|
|
506
509
|
u.changelog.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "pc-wn-list", children: u.changelog.slice(0, 5).map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: line }, i)) })
|
|
@@ -580,9 +583,9 @@ function CenterPanel({ variant = "section" }) {
|
|
|
580
583
|
if (timer !== null) clearTimeout(timer);
|
|
581
584
|
};
|
|
582
585
|
}, []);
|
|
583
|
-
const updateOne = (name) => {
|
|
586
|
+
const updateOne = (name, version) => {
|
|
584
587
|
setBusyUpdate(name);
|
|
585
|
-
void rpc("update", { name }).then(
|
|
588
|
+
void rpc("update", { name, version }).then(
|
|
586
589
|
(v) => {
|
|
587
590
|
if (v !== true) throw new Error(t("updateNotApplied"));
|
|
588
591
|
setBusyUpdate(null);
|
|
@@ -602,7 +605,7 @@ function CenterPanel({ variant = "section" }) {
|
|
|
602
605
|
const failures = [];
|
|
603
606
|
for (const u of updates) {
|
|
604
607
|
try {
|
|
605
|
-
const v = await rpc("update", { name: u.name });
|
|
608
|
+
const v = await rpc("update", { name: u.name, version: u.toVersion });
|
|
606
609
|
if (v !== true) throw new Error(t("updateNotApplied"));
|
|
607
610
|
okCount++;
|
|
608
611
|
okNames.push(u.name);
|
|
@@ -730,14 +733,20 @@ function OverlayPanel() {
|
|
|
730
733
|
const t = useT();
|
|
731
734
|
const open = useOverlayOpen();
|
|
732
735
|
if (!open) return null;
|
|
733
|
-
return
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
736
|
+
return (
|
|
737
|
+
// 0.1.7:点遮罩关闭——overlay 背景点击即 closeOverlay;面板内点击
|
|
738
|
+
// stopPropagation 不冒泡到遮罩(面板内部交互不受影响)。
|
|
739
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pc-overlay", role: "presentation", onClick: closeOverlay, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-panel", role: "dialog", "aria-modal": "true", "aria-label": t("title"), onClick: (e) => {
|
|
740
|
+
e.stopPropagation();
|
|
741
|
+
}, children: [
|
|
742
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-panel-head", children: [
|
|
743
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-title", children: t("title") }),
|
|
744
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-spacer" }),
|
|
745
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "pc-close", onClick: closeOverlay, "aria-label": t("close"), children: "\u2715" })
|
|
746
|
+
] }),
|
|
747
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pc-panel-body", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CenterPanel, { variant: "overlay" }) })
|
|
748
|
+
] }) })
|
|
749
|
+
);
|
|
741
750
|
}
|
|
742
751
|
function Toast() {
|
|
743
752
|
const t = useToast();
|
|
@@ -755,7 +764,7 @@ function WhatsNewDialog() {
|
|
|
755
764
|
const failures = [];
|
|
756
765
|
for (const u of whatsNewDigests) {
|
|
757
766
|
try {
|
|
758
|
-
const v = await rpc("update", { name: u.name });
|
|
767
|
+
const v = await rpc("update", { name: u.name, version: u.toVersion });
|
|
759
768
|
if (v !== true) throw new Error(t("updateNotApplied"));
|
|
760
769
|
okCount++;
|
|
761
770
|
} catch (e) {
|
|
@@ -798,8 +807,25 @@ function WhatsNewDialog() {
|
|
|
798
807
|
] }) });
|
|
799
808
|
}
|
|
800
809
|
var inject = ["slots", "connection"];
|
|
810
|
+
var GLOBAL_KEYS = ["__pluginCenterOpen", "__pluginCenterToggle", "__pluginCenterClose"];
|
|
811
|
+
function installGlobals() {
|
|
812
|
+
const w = window;
|
|
813
|
+
w.__pluginCenterOpen = openOverlay;
|
|
814
|
+
w.__pluginCenterToggle = toggleOverlay;
|
|
815
|
+
w.__pluginCenterClose = closeOverlay;
|
|
816
|
+
w.__pluginCenterGlobalsInstalled = true;
|
|
817
|
+
}
|
|
818
|
+
function cleanupGlobals() {
|
|
819
|
+
const w = window;
|
|
820
|
+
for (const key of GLOBAL_KEYS) delete w[key];
|
|
821
|
+
delete w.__pluginCenterGlobalsInstalled;
|
|
822
|
+
}
|
|
801
823
|
function apply(ctx) {
|
|
802
824
|
injectCss();
|
|
825
|
+
if (window.__pluginCenterGlobalsInstalled !== true) {
|
|
826
|
+
installGlobals();
|
|
827
|
+
window.addEventListener("unload", cleanupGlobals);
|
|
828
|
+
}
|
|
803
829
|
rpc = async (endpoint, payload = {}) => {
|
|
804
830
|
const result = await ctx.connection.rpc.call("/plugin-center", endpoint, payload);
|
|
805
831
|
if (result.ok) return result.value;
|
package/dist/engine.d.ts
CHANGED
|
@@ -69,7 +69,8 @@ export declare class PluginCenterEngine extends Service {
|
|
|
69
69
|
ok: boolean;
|
|
70
70
|
detail: string;
|
|
71
71
|
}>;
|
|
72
|
-
|
|
72
|
+
/** Update one installed plugin to the detected target version (exact — see update.ts). */
|
|
73
|
+
update(name: string, version: string): Promise<{
|
|
73
74
|
ok: boolean;
|
|
74
75
|
detail: string;
|
|
75
76
|
}>;
|
package/dist/engine.js
CHANGED
|
@@ -9,7 +9,7 @@ import { Service } from '@deepseek-ai/cordis';
|
|
|
9
9
|
import { fileURLToPath } from 'node:url';
|
|
10
10
|
import { dirname, join } from 'node:path';
|
|
11
11
|
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
12
|
-
import { buildInstalledPlugin, resolvePackage } from "./meta.js";
|
|
12
|
+
import { buildInstalledPlugin, clearPackageCache, resolvePackage } from "./meta.js";
|
|
13
13
|
import { fetchAwesomePluginsJson, fetchOhMyDshOverrides, fetchOhMyDshPlugins, mapConcurrent, mergePlugins } from "./market.js";
|
|
14
14
|
import { detectUpdate, installPlugin, updatePlugin } from "./update.js";
|
|
15
15
|
/** Runtime mirror of cordis FiberState (a cross-package const enum). */
|
|
@@ -225,8 +225,9 @@ export class PluginCenterEngine extends Service {
|
|
|
225
225
|
async install(spec) {
|
|
226
226
|
return this.enqueuePnpm(() => installPlugin(spec, this.baseUrl));
|
|
227
227
|
}
|
|
228
|
-
|
|
229
|
-
|
|
228
|
+
/** Update one installed plugin to the detected target version (exact — see update.ts). */
|
|
229
|
+
async update(name, version) {
|
|
230
|
+
return this.enqueuePnpm(() => updatePlugin(name, version, this.baseUrl));
|
|
230
231
|
}
|
|
231
232
|
/** 串行执行一次 pnpm 操作并失效缓存(无论成败都放行链条后续任务)。 */
|
|
232
233
|
enqueuePnpm(op) {
|
|
@@ -234,6 +235,9 @@ export class PluginCenterEngine extends Service {
|
|
|
234
235
|
const result = await op();
|
|
235
236
|
this.installedNamesCache = null;
|
|
236
237
|
this.updatesCache = null;
|
|
238
|
+
// pnpm rewrote node_modules on disk: drop the process-local package.json
|
|
239
|
+
// snapshot so the next listInstalled reads the new versions.
|
|
240
|
+
clearPackageCache();
|
|
237
241
|
return result;
|
|
238
242
|
});
|
|
239
243
|
this.pnpmChain = run.catch(() => { });
|
package/dist/meta.d.ts
CHANGED
|
@@ -27,6 +27,14 @@ interface PackageJson {
|
|
|
27
27
|
}
|
|
28
28
|
/** Compact a module specifier into a display name without guessing Loader id shape. */
|
|
29
29
|
export declare function displayName(specifier: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Drop every cached package.json resolution. Called after install/update:
|
|
32
|
+
* pnpm rewrites node_modules on disk, and the next `listInstalled` must see
|
|
33
|
+
* the new versions instead of the process-start snapshot (2026-08-18 — a
|
|
34
|
+
* stale cache reported the pre-update version forever, so the update looked
|
|
35
|
+
* perpetually available).
|
|
36
|
+
*/
|
|
37
|
+
export declare function clearPackageCache(): void;
|
|
30
38
|
/**
|
|
31
39
|
* Resolve one Loader entry to its package.json. `file://` specs walk upward to
|
|
32
40
|
* the nearest directory holding a package.json; `cordis:*` builtins have none.
|
package/dist/meta.js
CHANGED
|
@@ -38,6 +38,16 @@ function classifySource(specifier) {
|
|
|
38
38
|
}
|
|
39
39
|
/** Process-local cache of resolved packages — stable per run, so resolve once. */
|
|
40
40
|
const packageCache = new Map();
|
|
41
|
+
/**
|
|
42
|
+
* Drop every cached package.json resolution. Called after install/update:
|
|
43
|
+
* pnpm rewrites node_modules on disk, and the next `listInstalled` must see
|
|
44
|
+
* the new versions instead of the process-start snapshot (2026-08-18 — a
|
|
45
|
+
* stale cache reported the pre-update version forever, so the update looked
|
|
46
|
+
* perpetually available).
|
|
47
|
+
*/
|
|
48
|
+
export function clearPackageCache() {
|
|
49
|
+
packageCache.clear();
|
|
50
|
+
}
|
|
41
51
|
/**
|
|
42
52
|
* Resolve one Loader entry to its package.json. `file://` specs walk upward to
|
|
43
53
|
* the nearest directory holding a package.json; `cordis:*` builtins have none.
|
package/dist/rpc.js
CHANGED
|
@@ -35,9 +35,12 @@ export class PluginCenterRpc extends Service {
|
|
|
35
35
|
}
|
|
36
36
|
case 'update': {
|
|
37
37
|
const name = payload?.name;
|
|
38
|
+
const version = payload?.version;
|
|
38
39
|
if (typeof name !== 'string' || name === '')
|
|
39
40
|
return internal('update: name is required');
|
|
40
|
-
|
|
41
|
+
if (typeof version !== 'string' || version === '')
|
|
42
|
+
return internal('update: version is required');
|
|
43
|
+
const result = await ctx.pluginCenter.update(name, version);
|
|
41
44
|
if (!result.ok)
|
|
42
45
|
return internal(`update ${name} 失败:${result.detail}`);
|
|
43
46
|
return { ok: true, value: true };
|
package/dist/update.d.ts
CHANGED
|
@@ -34,5 +34,12 @@ export declare function pnpmCandidates(): string[];
|
|
|
34
34
|
export declare function runPnpm(args: readonly string[], cwd: string): Promise<PnpmResult>;
|
|
35
35
|
/** Install a package into the web profile, mirroring `dsh plugin add` semantics. */
|
|
36
36
|
export declare function installPlugin(packageSpec: string, profileDir: string): Promise<PnpmResult>;
|
|
37
|
-
/**
|
|
38
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Update a package to the given version, mirroring `dsh plugin add <pkg>`.
|
|
39
|
+
* The exact version is required: with a bare package name, pnpm 11's
|
|
40
|
+
* `minimumReleaseAge` supply-chain policy silently refuses a too-recent
|
|
41
|
+
* latest (exit 0, nothing installed) — a false-success update. An explicit
|
|
42
|
+
* `<name>@<version>` pins the target and pnpm records it in
|
|
43
|
+
* `minimumReleaseAgeExclude` itself (2026-08-18, reproduced in-process).
|
|
44
|
+
*/
|
|
45
|
+
export declare function updatePlugin(packageName: string, version: string, profileDir: string): Promise<PnpmResult>;
|
package/dist/update.js
CHANGED
|
@@ -118,7 +118,14 @@ export async function installPlugin(packageSpec, profileDir) {
|
|
|
118
118
|
// `-w` is required: every profile ships a pnpm-workspace.yaml.
|
|
119
119
|
return runPnpm(['add', '-w', packageSpec], profileDir);
|
|
120
120
|
}
|
|
121
|
-
/**
|
|
122
|
-
|
|
123
|
-
|
|
121
|
+
/**
|
|
122
|
+
* Update a package to the given version, mirroring `dsh plugin add <pkg>`.
|
|
123
|
+
* The exact version is required: with a bare package name, pnpm 11's
|
|
124
|
+
* `minimumReleaseAge` supply-chain policy silently refuses a too-recent
|
|
125
|
+
* latest (exit 0, nothing installed) — a false-success update. An explicit
|
|
126
|
+
* `<name>@<version>` pins the target and pnpm records it in
|
|
127
|
+
* `minimumReleaseAgeExclude` itself (2026-08-18, reproduced in-process).
|
|
128
|
+
*/
|
|
129
|
+
export async function updatePlugin(packageName, version, profileDir) {
|
|
130
|
+
return runPnpm(['add', '-w', `${packageName}@${version}`], profileDir);
|
|
124
131
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@max-null/dsh-plugin-center",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Plugin center for DeepSeek Harness
|
|
3
|
+
"version": "0.1.7",
|
|
4
|
+
"description": "Plugin center for DeepSeek Harness 鈥?installed metadata, community market, update detection, and What's New",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -83,3 +83,4 @@
|
|
|
83
83
|
"typescript": "^5.5.0"
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
|
+
|