@max-null/dsh-plugin-center 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client.js +23 -17
- 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 +13 -5
- package/package.json +1 -1
package/client.js
CHANGED
|
@@ -163,8 +163,8 @@ var installedCache = null;
|
|
|
163
163
|
var marketCache = {};
|
|
164
164
|
var toastState = null;
|
|
165
165
|
var toastListeners = /* @__PURE__ */ new Set();
|
|
166
|
-
function showToast(message, kind = "ok") {
|
|
167
|
-
toastState = { message, kind };
|
|
166
|
+
function showToast(message, kind = "ok", duration = 3200) {
|
|
167
|
+
toastState = { message, kind, until: Date.now() + duration };
|
|
168
168
|
toastListeners.forEach((l) => l());
|
|
169
169
|
}
|
|
170
170
|
var pendingInstall = /* @__PURE__ */ new Set();
|
|
@@ -184,7 +184,7 @@ function useToast() {
|
|
|
184
184
|
const id = setTimeout(() => {
|
|
185
185
|
toastState = null;
|
|
186
186
|
toastListeners.forEach((l) => l());
|
|
187
|
-
},
|
|
187
|
+
}, Math.max(0, t.until - Date.now()));
|
|
188
188
|
return () => clearTimeout(id);
|
|
189
189
|
}, [t]);
|
|
190
190
|
return t;
|
|
@@ -451,11 +451,11 @@ function MarketView({ category, single, source, search, onCount }) {
|
|
|
451
451
|
if (c !== void 0) c.plugins = c.plugins.map((p) => p.name === m.name ? { ...p, installed: true } : p);
|
|
452
452
|
}
|
|
453
453
|
setItems((prev) => prev.map((p) => p.name === m.name ? { ...p, installed: true } : p));
|
|
454
|
-
showToast(t("installQueued", { n: m.name }));
|
|
454
|
+
showToast(t("installQueued", { n: m.name }), "ok", 5e3);
|
|
455
455
|
},
|
|
456
456
|
(e) => {
|
|
457
457
|
setBusy(null);
|
|
458
|
-
showToast(t("installFailed", { e: e instanceof Error ? e.message : String(e) }), "error");
|
|
458
|
+
showToast(t("installFailed", { e: e instanceof Error ? e.message : String(e) }), "error", 8e3);
|
|
459
459
|
}
|
|
460
460
|
);
|
|
461
461
|
};
|
|
@@ -500,7 +500,7 @@ function UpdatesView({ updates, refresh, updateOne, busy }) {
|
|
|
500
500
|
u.compat === "incompatible" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-tag danger", children: t("incompat") }),
|
|
501
501
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-spacer" }),
|
|
502
502
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "pc-btn primary", disabled: busy !== null, onClick: () => {
|
|
503
|
-
updateOne(u.name);
|
|
503
|
+
updateOne(u.name, u.toVersion);
|
|
504
504
|
}, children: busy === u.name || busy === "__all__" ? t("updating") : t("update") })
|
|
505
505
|
] }),
|
|
506
506
|
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)) })
|
|
@@ -527,7 +527,11 @@ function CenterPanel({ variant = "section" }) {
|
|
|
527
527
|
void rpc("checkUpdates", { since: new Date(Date.now() - 30 * 864e5).toISOString() }).then(
|
|
528
528
|
(v) => {
|
|
529
529
|
const digests = v;
|
|
530
|
-
setUpdates(digests)
|
|
530
|
+
setUpdates((prev) => digests.map((d) => {
|
|
531
|
+
if (d.changelog.length > 0) return d;
|
|
532
|
+
const old = prev?.find((p) => p.name === d.name);
|
|
533
|
+
return old !== void 0 && old.changelog.length > 0 ? { ...d, changelog: old.changelog } : d;
|
|
534
|
+
}));
|
|
531
535
|
setChecking(false);
|
|
532
536
|
if (!silent) {
|
|
533
537
|
showToast(digests.length > 0 ? t("foundUpdates", { n: digests.length }) : t("allUpToDate"));
|
|
@@ -576,17 +580,17 @@ function CenterPanel({ variant = "section" }) {
|
|
|
576
580
|
if (timer !== null) clearTimeout(timer);
|
|
577
581
|
};
|
|
578
582
|
}, []);
|
|
579
|
-
const updateOne = (name) => {
|
|
583
|
+
const updateOne = (name, version) => {
|
|
580
584
|
setBusyUpdate(name);
|
|
581
|
-
void rpc("update", { name }).then(
|
|
585
|
+
void rpc("update", { name, version }).then(
|
|
582
586
|
(v) => {
|
|
583
587
|
if (v !== true) throw new Error(t("updateNotApplied"));
|
|
584
588
|
setBusyUpdate(null);
|
|
585
|
-
showToast(t("updatedOne", { n: name }));
|
|
589
|
+
showToast(t("updatedOne", { n: name }), "ok", 5e3);
|
|
586
590
|
},
|
|
587
591
|
(e) => {
|
|
588
592
|
setBusyUpdate(null);
|
|
589
|
-
showToast(t("updateFailed", { e: e instanceof Error ? e.message : String(e) }), "error");
|
|
593
|
+
showToast(t("updateFailed", { e: e instanceof Error ? e.message : String(e) }), "error", 8e3);
|
|
590
594
|
}
|
|
591
595
|
);
|
|
592
596
|
};
|
|
@@ -594,21 +598,23 @@ function CenterPanel({ variant = "section" }) {
|
|
|
594
598
|
if (updates === null || updates.length === 0) return;
|
|
595
599
|
setBusyUpdate("__all__");
|
|
596
600
|
let okCount = 0;
|
|
601
|
+
const okNames = [];
|
|
597
602
|
const failures = [];
|
|
598
603
|
for (const u of updates) {
|
|
599
604
|
try {
|
|
600
|
-
const v = await rpc("update", { name: u.name });
|
|
605
|
+
const v = await rpc("update", { name: u.name, version: u.toVersion });
|
|
601
606
|
if (v !== true) throw new Error(t("updateNotApplied"));
|
|
602
607
|
okCount++;
|
|
608
|
+
okNames.push(u.name);
|
|
603
609
|
} catch (e) {
|
|
604
610
|
failures.push(`${u.name}\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
605
611
|
}
|
|
606
612
|
}
|
|
607
613
|
setBusyUpdate(null);
|
|
608
614
|
if (failures.length === 0) {
|
|
609
|
-
showToast(t("updatedMany", { n: okCount }));
|
|
615
|
+
showToast(t("updatedMany", { n: okCount }) + `\uFF08${okNames.join("\u3001")}\uFF09`, "ok", 6e3);
|
|
610
616
|
} else {
|
|
611
|
-
showToast(t("updateSummary", { a: okCount, b: failures.length, c: failures.join("\uFF1B") }), "error");
|
|
617
|
+
showToast(t("updateSummary", { a: okCount, b: failures.length, c: failures.join("\uFF1B") }), "error", 8e3);
|
|
612
618
|
}
|
|
613
619
|
refreshUpdates();
|
|
614
620
|
};
|
|
@@ -749,7 +755,7 @@ function WhatsNewDialog() {
|
|
|
749
755
|
const failures = [];
|
|
750
756
|
for (const u of whatsNewDigests) {
|
|
751
757
|
try {
|
|
752
|
-
const v = await rpc("update", { name: u.name });
|
|
758
|
+
const v = await rpc("update", { name: u.name, version: u.toVersion });
|
|
753
759
|
if (v !== true) throw new Error(t("updateNotApplied"));
|
|
754
760
|
okCount++;
|
|
755
761
|
} catch (e) {
|
|
@@ -758,10 +764,10 @@ function WhatsNewDialog() {
|
|
|
758
764
|
}
|
|
759
765
|
setBusy(false);
|
|
760
766
|
if (failures.length === 0) {
|
|
761
|
-
showToast(t("updatedMany", { n: okCount }));
|
|
767
|
+
showToast(t("updatedMany", { n: okCount }), "ok", 6e3);
|
|
762
768
|
closeWhatsNew();
|
|
763
769
|
} else {
|
|
764
|
-
showToast(t("updateSummary", { a: okCount, b: failures.length, c: failures.join("\uFF1B") }), "error");
|
|
770
|
+
showToast(t("updateSummary", { a: okCount, b: failures.length, c: failures.join("\uFF1B") }), "error", 8e3);
|
|
765
771
|
}
|
|
766
772
|
};
|
|
767
773
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pc-overlay", role: "presentation", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-panel", style: { width: "540px" }, role: "dialog", "aria-modal": "true", "aria-label": t("whatsNewTitle"), children: [
|
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
|
@@ -87,8 +87,9 @@ function runOne(command, args, cwd) {
|
|
|
87
87
|
return new Promise((resolve) => {
|
|
88
88
|
let child;
|
|
89
89
|
try {
|
|
90
|
-
// shell: true —— Windows 下 .cmd shim 必须经 shell 才能 spawn
|
|
91
|
-
|
|
90
|
+
// shell: true —— Windows 下 .cmd shim 必须经 shell 才能 spawn;
|
|
91
|
+
// windowsHide —— GUI 宿主下不弹 cmd 窗口(2026-08-18 用户实测闪烁)。
|
|
92
|
+
child = spawn(command, [...args], { cwd, stdio: 'inherit', shell: true, windowsHide: true });
|
|
92
93
|
}
|
|
93
94
|
catch (e) {
|
|
94
95
|
resolve({ ok: false, detail: e instanceof Error ? e.message : String(e) });
|
|
@@ -117,7 +118,14 @@ export async function installPlugin(packageSpec, profileDir) {
|
|
|
117
118
|
// `-w` is required: every profile ships a pnpm-workspace.yaml.
|
|
118
119
|
return runPnpm(['add', '-w', packageSpec], profileDir);
|
|
119
120
|
}
|
|
120
|
-
/**
|
|
121
|
-
|
|
122
|
-
|
|
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);
|
|
123
131
|
}
|
package/package.json
CHANGED