@max-null/dsh-plugin-center 0.1.4 → 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 CHANGED
@@ -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)) })
@@ -580,9 +580,9 @@ function CenterPanel({ variant = "section" }) {
580
580
  if (timer !== null) clearTimeout(timer);
581
581
  };
582
582
  }, []);
583
- const updateOne = (name) => {
583
+ const updateOne = (name, version) => {
584
584
  setBusyUpdate(name);
585
- void rpc("update", { name }).then(
585
+ void rpc("update", { name, version }).then(
586
586
  (v) => {
587
587
  if (v !== true) throw new Error(t("updateNotApplied"));
588
588
  setBusyUpdate(null);
@@ -602,7 +602,7 @@ function CenterPanel({ variant = "section" }) {
602
602
  const failures = [];
603
603
  for (const u of updates) {
604
604
  try {
605
- const v = await rpc("update", { name: u.name });
605
+ const v = await rpc("update", { name: u.name, version: u.toVersion });
606
606
  if (v !== true) throw new Error(t("updateNotApplied"));
607
607
  okCount++;
608
608
  okNames.push(u.name);
@@ -755,7 +755,7 @@ function WhatsNewDialog() {
755
755
  const failures = [];
756
756
  for (const u of whatsNewDigests) {
757
757
  try {
758
- const v = await rpc("update", { name: u.name });
758
+ const v = await rpc("update", { name: u.name, version: u.toVersion });
759
759
  if (v !== true) throw new Error(t("updateNotApplied"));
760
760
  okCount++;
761
761
  } catch (e) {
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
- update(name: string): Promise<{
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
- async update(name) {
229
- return this.enqueuePnpm(() => updatePlugin(name, this.baseUrl));
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
- const result = await ctx.pluginCenter.update(name);
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
- /** Update a package to latest, mirroring `dsh plugin add <pkg>` (pnpm installs latest). */
38
- export declare function updatePlugin(packageName: string, profileDir: string): Promise<PnpmResult>;
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
- /** Update a package to latest, mirroring `dsh plugin add <pkg>` (pnpm installs latest). */
122
- export async function updatePlugin(packageName, profileDir) {
123
- return runPnpm(['add', '-w', packageName], profileDir);
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@max-null/dsh-plugin-center",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Plugin center for DeepSeek Harness — installed metadata, community market, update detection, and What's New",
5
5
  "license": "MIT",
6
6
  "publishConfig": {