@max-null/dsh-plugin-center 0.2.7 → 0.2.9

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/dist/update.d.ts CHANGED
@@ -60,6 +60,20 @@ export declare function logPnpm(profileDir: string, args: readonly string[], res
60
60
  * CreateProcess 只找 pnpm.exe(.cmd/.ps1 必须经 shell)——2026-08-17 实测
61
61
  * spawn('pnpm', shell:false) 直接 ENOENT,更新永远假成功。 */
62
62
  export declare function pnpmCandidates(): string[];
63
+ /** 归档 profile 的 node_modules 由 pnpm `<major>` 生成(SSiD 部署时把构建机
64
+ * store 元数据改写成本机路径且保留 major 后缀——shell/main.mjs rewire)。
65
+ * 若执行机全局 pnpm 是另一个 major(常见:机器装 pnpm 10,归档是 pnpm 11
66
+ * 打的),任何 pnpm 操作都报 ERR_PNPM_UNEXPECTED_STORE(不同 major 的 store
67
+ * 目录不兼容)。这里从 `.modules.yaml` 探测布局用的 major,候选命令里追
68
+ * 加 `npx --yes pnpm@<major>`(npx 拉取同 major CLI,之后走 npm 缓存),
69
+ * 保证以「与布局一致」的 pnpm 执行更新。
70
+ * @returns 布局的 pnpm major(如 11),读不到时 undefined。
71
+ */
72
+ export declare function detectStoreMajor(profileDir: string): number | undefined;
73
+ /** 完整 pnpm 命令候选序列:壳内捆绑 pnpm(SSID_PNPM,与归档 store 布局同
74
+ * major)最优先;本地 pnpm(PATH/用户级)其次;最终以 npx pnpm@<major>
75
+ * 兜底(仅当探测到布局 major)。 */
76
+ export declare function pnpmCommandCandidates(profileDir: string): string[];
63
77
  /**
64
78
  * Run pnpm in the profile directory, trying each candidate command in turn.
65
79
  * Output is captured (no named-pipe stdio — the host process is the web or
package/dist/update.js CHANGED
@@ -184,16 +184,55 @@ export function pnpmCandidates() {
184
184
  }
185
185
  return commands;
186
186
  }
187
+ /** 归档 profile 的 node_modules 由 pnpm `<major>` 生成(SSiD 部署时把构建机
188
+ * store 元数据改写成本机路径且保留 major 后缀——shell/main.mjs rewire)。
189
+ * 若执行机全局 pnpm 是另一个 major(常见:机器装 pnpm 10,归档是 pnpm 11
190
+ * 打的),任何 pnpm 操作都报 ERR_PNPM_UNEXPECTED_STORE(不同 major 的 store
191
+ * 目录不兼容)。这里从 `.modules.yaml` 探测布局用的 major,候选命令里追
192
+ * 加 `npx --yes pnpm@<major>`(npx 拉取同 major CLI,之后走 npm 缓存),
193
+ * 保证以「与布局一致」的 pnpm 执行更新。
194
+ * @returns 布局的 pnpm major(如 11),读不到时 undefined。
195
+ */
196
+ export function detectStoreMajor(profileDir) {
197
+ try {
198
+ const meta = readFileSync(join(profileDir, 'node_modules', '.modules.yaml'), 'utf8');
199
+ // JSON 转义(\\v11)与 YAML 字面(\v11)两种形态都覆盖。
200
+ const match = /storeDir[^\n]*store[\\/]+v?(\d+)/.exec(meta);
201
+ if (match === null)
202
+ return undefined;
203
+ return Number(match[1]);
204
+ }
205
+ catch {
206
+ return undefined;
207
+ }
208
+ }
209
+ /** 完整 pnpm 命令候选序列:壳内捆绑 pnpm(SSID_PNPM,与归档 store 布局同
210
+ * major)最优先;本地 pnpm(PATH/用户级)其次;最终以 npx pnpm@<major>
211
+ * 兜底(仅当探测到布局 major)。 */
212
+ export function pnpmCommandCandidates(profileDir) {
213
+ const commands = [];
214
+ const bundled = process.env.SSID_PNPM;
215
+ if (bundled !== undefined && bundled !== '')
216
+ commands.push(bundled);
217
+ commands.push(...pnpmCandidates());
218
+ const major = detectStoreMajor(profileDir);
219
+ if (major !== undefined) {
220
+ commands.push(`npx --yes pnpm@${major}`);
221
+ }
222
+ return commands;
223
+ }
187
224
  function runOne(command, args, cwd) {
188
225
  return new Promise((resolve) => {
189
226
  let child;
190
227
  try {
191
228
  // shell: true —— Windows 下 .cmd shim 必须经 shell 才能 spawn;
229
+ // command 与 args 合并为整行(command 可能是多词命令,如
230
+ // `npx --yes pnpm@11`;args 是内部生成的固定形态,无注入面)。
192
231
  // windowsHide —— GUI 宿主下不弹 cmd 窗口(2026-08-18 用户实测闪烁)。
193
232
  // stdio 走默认 pipe:捕获 pnpm 输出,失败时把尾部输出放进 detail
194
233
  // (2026-08-22 起——此前 inherit 只有 exit code,SSiD 下更新失败
195
234
  // 无法诊断;宿主进程(web/electron)非 DSH 工具沙箱,pipe 可用)。
196
- child = spawn(command, [...args], { cwd, shell: true, windowsHide: true });
235
+ child = spawn([command, ...args].join(' '), { cwd, shell: true, windowsHide: true });
197
236
  }
198
237
  catch (e) {
199
238
  resolve({ ok: false, detail: e instanceof Error ? e.message : String(e), durationMs: 0 });
@@ -231,7 +270,7 @@ function runOne(command, args, cwd) {
231
270
  */
232
271
  export async function runPnpm(args, cwd) {
233
272
  let last = { ok: false, detail: 'no pnpm candidate found', durationMs: 0 };
234
- for (const command of pnpmCandidates()) {
273
+ for (const command of pnpmCommandCandidates(cwd)) {
235
274
  last = await runOne(command, args, cwd);
236
275
  if (last.ok)
237
276
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@max-null/dsh-plugin-center",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "description": "Plugin center for DeepSeek Harness 閳?installed metadata, community market, update detection, and What\u0027s New",
5
5
  "license": "MIT",
6
6
  "publishConfig": {