dsh-m 0.9.67 → 0.9.69

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.
@@ -10,7 +10,7 @@
10
10
  import { existsSync } from 'node:fs';
11
11
  import { readFile } from 'node:fs/promises';
12
12
  import { join } from 'node:path';
13
- import { dshHome, webProfileDir } from './env.js';
13
+ import { dshHome, webProfileDir, WEB_PROFILE } from './env.js';
14
14
  import { runProfileTransaction, makeNpmWarmPackument, TransactionError, } from './profile-transaction.js';
15
15
  import { listInstalledPlugins as defaultListInstalledPlugins, } from './installed.js';
16
16
  import { loaderHost } from './live-plugin.js';
@@ -18,8 +18,12 @@ import { precheckNpmCompat, IncompatibleError } from './compat-check.js';
18
18
  import { PROTECTED_MODULES, composeEnablement } from './enablement.js';
19
19
  import { readProfileOverrides } from './patch-yaml.js';
20
20
  import { loadRegistry as defaultLoadRegistry, } from './registry.js';
21
- import { COMMUNITY_CATEGORY_LABELS, fetchCommunityCatalog as defaultFetchCommunityCatalog, } from './community.js';
22
- import { adaptCommunityCatalog } from './community-adapter.js';
21
+ import { fetchCommunityCatalog as defaultFetchCommunityCatalog, } from './community.js';
22
+ // 0.9.68(ADR-0016):合并层迁入 merged-market.ts(communityOutcome/mergeRegistries/communitySummary/
23
+ // deadlineRace/matchInstalledByEntry/isCommunityEntry/COMMUNITY_CATEGORY_LABELS)——market↔community
24
+ // import 环自此断开;re-export 保既有消费方(tools.ts 的类型、profile-ops 的 matchInstalledByEntry)零改动。
25
+ import { communityOutcome, communityTimeoutSummary, withFallbackLookups, deadlineRace, isCommunityEntry, matchInstalledByEntry, mergedOutcome, } from './merged-market.js';
26
+ export { communityOutcome, matchInstalledByEntry } from './merged-market.js';
23
27
  import { normalizeSearchText, relevanceScore, tokenizeSearchText } from './search-relevance.js';
24
28
  import { GithubBudgetExhaustedError, createGithubRequestBudget, isExactVersion } from './versions.js';
25
29
  import { classifyUpgradeActivation } from './activation.js';
@@ -128,18 +132,6 @@ function timeoutRegistryState(cfg) {
128
132
  count: 0,
129
133
  };
130
134
  }
131
- function deadlineRace(task, ms) {
132
- return new Promise((resolve, reject) => {
133
- const timer = setTimeout(() => resolve('deadline'), Math.max(0, ms));
134
- task.then((value) => {
135
- clearTimeout(timer);
136
- resolve(value);
137
- }, (err) => {
138
- clearTimeout(timer);
139
- reject(err);
140
- });
141
- });
142
- }
143
135
  // ---------- latest TTL cache ----------
144
136
  // 0.9.20:纯内存 TTL 缓存(ADR-0006,推翻 0.9.14 的落盘跨重启存活——重启即失效是特性);
145
137
  // mutation 成功后的定向失效走 invalidateLatestForEntry(只失效不回写)。
@@ -194,144 +186,6 @@ function classifyLatestError(err) {
194
186
  return 'rate-limited';
195
187
  return 'network-error';
196
188
  }
197
- /** 0.9.8 导出(原模块私有):desktopUpgrade 的「已装 ↔ 收录条目」匹配与 web upgradePlugin 同语义。 */
198
- export function matchInstalledByEntry(entry, installed) {
199
- return installed.find((it) => {
200
- if (entry.npm && it.pkg === entry.npm)
201
- return true;
202
- if (entry.npm && it.name === entry.npm)
203
- return true;
204
- if (entry.github && it.source === 'github') {
205
- const m = /^github:([^#]+)/.exec(it.spec);
206
- if (m && m[1] === entry.github)
207
- return true;
208
- }
209
- return false;
210
- });
211
- }
212
- /**
213
- * 合并去重(Q41):社区条目依次与主清单的 npm 名集 / github owner-repo 集 / id 集比对,
214
- * 任一相撞即让位(每条只计一次);社区内部 npm 名重复同样让位(首条优先)。
215
- * 主清单恒优先——让位只影响社区条目,主条目原样保留。
216
- */
217
- export function mergeRegistries(primary, community) {
218
- const primaryNpm = new Set(primary.filter((e) => e.npm).map((e) => e.npm));
219
- const primaryGithub = new Set(primary.filter((e) => e.github).map((e) => e.github));
220
- const primaryIds = new Set(primary.map((e) => e.id));
221
- const displaced = [];
222
- const kept = [];
223
- const seenNpm = new Set();
224
- for (const c of community) {
225
- if (c.npm !== undefined) {
226
- if (primaryNpm.has(c.npm) || seenNpm.has(c.npm)) {
227
- displaced.push(c.id);
228
- continue;
229
- }
230
- seenNpm.add(c.npm);
231
- }
232
- if ((c.github !== undefined && primaryGithub.has(c.github)) || primaryIds.has(c.id)) {
233
- displaced.push(c.id);
234
- continue;
235
- }
236
- kept.push(c);
237
- }
238
- // Q45:主清单置顶(组内原顺序)+ 社区按 30 天下载量降序(无数据按名称)
239
- const sorted = [...kept].sort((a, b) => {
240
- const da = a.downloads ?? -1;
241
- const db = b.downloads ?? -1;
242
- if (da !== db)
243
- return db - da;
244
- return a.name.localeCompare(b.name);
245
- });
246
- const warnings = displaced.length > 0 ? [`${displaced.length} 条社区条目与主清单重复,已让位(主清单恒优先)`] : [];
247
- return { items: [...primary, ...sorted], displaced: displaced.length, warnings };
248
- }
249
- function communitySummary(state, counts, extraWarnings, categoryLabelsEn) {
250
- const unavailableLike = state.status === 'disabled' || state.status === 'unavailable';
251
- return {
252
- enabled: state.enabled,
253
- status: state.status,
254
- version: state.version,
255
- checkedAt: state.checkedAt,
256
- fetchedAt: state.fetchedAt,
257
- route: state.route,
258
- acceptedCount: unavailableLike ? 0 : (counts.acceptedCount ?? 0),
259
- upstreamCount: unavailableLike ? (state.status === 'disabled' ? null : 0) : (counts.upstreamCount ?? state.count),
260
- displaced: unavailableLike ? 0 : (counts.displaced ?? 0),
261
- skippedDirty: unavailableLike ? 0 : (counts.skippedDirty ?? 0),
262
- skippedSubpathNoNpm: unavailableLike ? 0 : (counts.skippedSubpathNoNpm ?? 0),
263
- errors: [...state.errors],
264
- warnings: [...state.warnings, ...extraWarnings],
265
- // 标签单一事实源(0.7.0 Task 4):disabled/skipped 下无社区数据语义,不携带;
266
- // EN 标签(i18n)随行携带,仅在调用方传入非空映射时出现(缺省 = 上游无 categories 数据)
267
- ...(state.status !== 'disabled' && state.status !== 'skipped'
268
- ? {
269
- categoryLabels: { ...COMMUNITY_CATEGORY_LABELS },
270
- ...(categoryLabelsEn && Object.keys(categoryLabelsEn).length > 0
271
- ? { categoryLabelsEn: { ...categoryLabelsEn } }
272
- : {}),
273
- }
274
- : {}),
275
- };
276
- }
277
- function disabledCommunitySummary() {
278
- return communitySummary({ enabled: false, status: 'disabled', version: null, checkedAt: null, fetchedAt: null, route: null, count: 0, errors: [], warnings: [] }, {}, []);
279
- }
280
- /** 查询层主动跳过(0.7.0 Task 2:source='primary'):本次未加载社区层,非配置关闭、非故障。 */
281
- function skippedCommunitySummary() {
282
- return communitySummary({ enabled: true, status: 'skipped', version: null, checkedAt: null, fetchedAt: null, route: null, count: 0, errors: [], warnings: [] }, {}, []);
283
- }
284
- function communityTimeoutSummary() {
285
- return communitySummary({ enabled: true, status: 'unavailable', version: null, checkedAt: null, fetchedAt: null, route: null, count: 0, errors: ['社区目录状态获取超时,可稍后刷新'], warnings: [] }, {}, []);
286
- }
287
- /**
288
- * 社区 loader waiter 收敛(v9/v10 waiter-scoped 契约):共享 flight 不接收调用者 deadline,
289
- * 本函数作为 waiter 用剩余 deadline race 自己的等待;到点只结束本 waiter(summary 标超时),
290
- * 共享 flight 照常继续。source='primary'/未启用 → loader 零调用(task 传 null → skipped;
291
- * 配置关闭走真任务的 disabled 分支,与跳过语义分离)。
292
- * 导出供 community.ts getCommunitySummary 复用(summary 组装单一产地)。
293
- */
294
- export async function communityOutcome(task, deadlineAt, primary) {
295
- if (!task)
296
- return { summary: skippedCommunitySummary(), merged: primary };
297
- let loaded;
298
- try {
299
- loaded = await deadlineRace(task, deadlineAt - Date.now());
300
- }
301
- finally {
302
- // race 输出后共享 promise 若仍悬挂(deadline 先到),收尾防 unhandled rejection
303
- void task.catch(() => undefined);
304
- }
305
- if (loaded === 'deadline')
306
- return { summary: communityTimeoutSummary(), merged: primary };
307
- const state = loaded.state;
308
- if (state.status === 'disabled')
309
- return { summary: disabledCommunitySummary(), merged: primary };
310
- if (state.status === 'unavailable' || !loaded.catalog) {
311
- return {
312
- summary: communitySummary(state, { acceptedCount: 0, upstreamCount: 0, displaced: 0, skippedDirty: 0, skippedSubpathNoNpm: 0 }, []),
313
- merged: primary,
314
- };
315
- }
316
- const adapted = adaptCommunityCatalog(loaded.catalog);
317
- const merge = mergeRegistries(primary, adapted.entries);
318
- // EN 分类标签(i18n):直接取上游目录 categories.en——上游新增分类自动跟进,
319
- // 缺 en 的 id 不进映射(客户端按语言取用并回退中文标签,不在此处手养第二张表)
320
- const categoryLabelsEn = Object.fromEntries(Object.entries(loaded.catalog.categories)
321
- .map(([id, c]) => [id, typeof c?.en === 'string' && c.en !== '' ? c.en : ''])
322
- .filter(([, en]) => en !== ''));
323
- const summary = communitySummary(state, {
324
- acceptedCount: adapted.entries.length,
325
- upstreamCount: loaded.catalog.plugins.length,
326
- displaced: merge.displaced,
327
- skippedDirty: adapted.skippedDirty,
328
- skippedSubpathNoNpm: adapted.skippedSubpathNoNpm,
329
- }, [...adapted.warnings, ...merge.warnings], categoryLabelsEn);
330
- return { summary, merged: merge.items };
331
- }
332
- function isCommunityEntry(entry) {
333
- return entry.descriptionEn !== undefined;
334
- }
335
189
  /** 旁路数值/日期读取(RegistryEntry 无这些键 → null/'';0.7.0 Task 2 排序用)。 */
336
190
  function dlOf(e) {
337
191
  const v = e.downloads;
@@ -469,7 +323,16 @@ export async function listMarket(cfg = {}, opts = {}, deps = {}) {
469
323
  const installedComplete = installed !== null && installed.complete === true;
470
324
  const installedItems = installed?.items ?? [];
471
325
  // 社区 waiter 收敛:主 unavailable 时 merged = 存活社区条目(Q42 出页不返空);两层皆不可用 → 空页契约
472
- const community = await communityOutcome(communityTask, deadlineAt, loaded.registry.plugins);
326
+ // 0.9.68(ADR-0016):改经物化合并市场——同身份(registry 代 + 目录 version)命中即免 adapt+merge,
327
+ // summary 仍由当次 state 现算;失败/deadline/unavailable/disabled/task=null 形态透传不落代。
328
+ const community = await mergedOutcome({
329
+ namespace,
330
+ profile: opts.profile ?? WEB_PROFILE,
331
+ cfg,
332
+ registry: loaded,
333
+ communityTask,
334
+ deadlineAt,
335
+ });
473
336
  // 分区过滤 + 全量统计 + query/category 过滤 + 分页(同步,极轻;0.7.0 Task 2):
474
337
  // categoryCounts = 分区集合(不含 query/category 过滤——chips 需要全区计数);
475
338
  // total = 分区 ∩ query ∩ category。
@@ -493,19 +356,27 @@ export async function listMarket(cfg = {}, opts = {}, deps = {}) {
493
356
  // 相关性搜索(0.7.0 Task 3):归一化分词 + 字段加权评分;0 分不返回;
494
357
  // id 整串精确匹配保证命中(收藏 stale 检测依赖)。
495
358
  const terms = tokenizeSearchText(normalizeSearchText(opts.query ?? ''));
359
+ // 0.9.68(ADR-0016 决策 7,score-once):类别不匹配先短路(不付评分成本),terms 非空时
360
+ // 单遍评分并记入 scoreByEntry——rank 阶段查表,不再对每条目二次调用 relevanceScore。
361
+ // tie-break 取 afterSort 之后的位置,与 0.9.67 语义逐点一致(评审 R1-4)。
362
+ const scoreByEntry = new Map();
496
363
  const filtered = zoned.filter((entry) => {
497
364
  const also = entry.alsoCategories ?? [];
498
365
  if (cat && entry.category !== cat && !also.includes(cat))
499
366
  return false;
500
367
  if (terms.length === 0)
501
368
  return true;
502
- return relevanceScore(entry, terms) > 0;
369
+ const score = relevanceScore(entry, terms);
370
+ if (score <= 0)
371
+ return false;
372
+ scoreByEntry.set(entry, score);
373
+ return true;
503
374
  });
504
375
  // 排序:显式 sort 先行;query 命中时相关性优先(稳定 tie-break 回到既有序——merged 现序或用户排序)
505
376
  const afterSort = opts.sort ? sortEntries(filtered, opts.sort) : filtered;
506
377
  const ranked = terms.length > 0
507
378
  ? afterSort
508
- .map((entry, idx) => ({ entry, score: relevanceScore(entry, terms), idx }))
379
+ .map((entry, idx) => ({ entry, score: scoreByEntry.get(entry), idx }))
509
380
  .sort((a, b) => b.score - a.score || a.idx - b.idx)
510
381
  .map((s) => s.entry)
511
382
  : afterSort;
@@ -590,8 +461,14 @@ export async function listMarket(cfg = {}, opts = {}, deps = {}) {
590
461
  }
591
462
  }
592
463
  // outdated 判定统一在 probe 后进行(0.9.45:cache-only 也执行——暖缓存不丢「可升级」徽标)
464
+ // 0.9.68(ADR-0016 决策 5 / 评审 R1-7):pkg→installed 查表,页内 O(1) 取代逐项 find
465
+ // first-wins:与旧 installedItems.find 逐点一致(正常枚举无重复 pkg,理论边界防御)
466
+ const instByPkg = new Map();
467
+ for (const inst of installedItems)
468
+ if (!instByPkg.has(inst.pkg))
469
+ instByPkg.set(inst.pkg, inst);
593
470
  for (const item of items) {
594
- const inst = item.installedPkg !== undefined ? installedItems.find((i) => i.pkg === item.installedPkg) : undefined;
471
+ const inst = item.installedPkg !== undefined ? instByPkg.get(item.installedPkg) : undefined;
595
472
  if (!inst)
596
473
  continue;
597
474
  if (item.latestVersion !== undefined && inst.version) {
@@ -653,7 +530,18 @@ export async function listInstalledWithMeta(cfg = {}, opts = {}, deps = {}) {
653
530
  catch {
654
531
  loaded = 'deadline';
655
532
  }
656
- const community = await communityOutcome(communityTask, deadlineAt, loaded === 'deadline' ? [] : loaded.registry.plugins);
533
+ // 0.9.68(ADR-0016):registry 正常时经物化合并市场(同身份免 adapt+merge + 匹配查表);
534
+ // registry deadline 降级路径身份残缺(primary=[]、fetchedAt 未知),走无 memo 的 communityOutcome,不进 L2。
535
+ const community = loaded === 'deadline'
536
+ ? withFallbackLookups(await communityOutcome(communityTask, deadlineAt, []))
537
+ : await mergedOutcome({
538
+ namespace,
539
+ profile: opts.profile ?? WEB_PROFILE,
540
+ cfg,
541
+ registry: loaded,
542
+ communityTask,
543
+ deadlineAt,
544
+ });
657
545
  if (loaded === 'deadline' || loaded.status === 'unavailable') {
658
546
  // registry 不可用:不做 matching/探测(原行为),但社区 summary 照常携带(CLI outdated 双源判定)
659
547
  const registryState = loaded === 'deadline' ? timeoutRegistryState(cfg) : stateOf(loaded);
@@ -661,21 +549,22 @@ export async function listInstalledWithMeta(cfg = {}, opts = {}, deps = {}) {
661
549
  return { items, others: installed.others, profileDir: installed.profileDir, registryState, community: community.summary };
662
550
  }
663
551
  const registryState = stateOf(loaded);
664
- matchInstalled(items, community.merged);
552
+ matchInstalled(items, community.merged, community.lookupInstalled);
665
553
  // 两段加载(ADR-0008):probeMode 控制探测段——缺省 'full' 行为不变;'none' 面板快列表跳过探测;
666
554
  // 'only' 面板第二段 ttlMin=0 永远新鲜(readLatestCache(key,0) 先删共享条目再重探:host ns 下浏览页/
667
555
  // 工具的 TTL 命中被刷新为更新值,预算消耗速率上升、上限不变,超限走 latestError 降级)。
668
556
  if ((opts.probeMode ?? 'full') !== 'none') {
669
557
  // 0.9.20:latest 缓存纯内存(ADR-0006)——探测段前仅一次性清扫 0.9.14 遗留磁盘信封
670
558
  await ensureLatestCacheSwept({ namespace, profile: opts.profile });
671
- await probeLatest(items, { merged: community.merged, registryAddress: loaded.configuredAddress, ttlMin: opts.probeMode === 'only' ? 0 : Math.max(0, cfg.cacheTtlMin ?? 60) }, d, { namespace, signal, githubBudget, remaining, timeoutMs: cfg.timeoutMs ?? 20_000 });
559
+ await probeLatest(items, { merged: community.merged, lookup: community.lookupInstalled, registryAddress: loaded.configuredAddress, ttlMin: opts.probeMode === 'only' ? 0 : Math.max(0, cfg.cacheTtlMin ?? 60) }, d, { namespace, signal, githubBudget, remaining, timeoutMs: cfg.timeoutMs ?? 20_000 });
672
560
  }
673
561
  return { items, others: installed.others, profileDir: installed.profileDir, registryState, community: community.summary };
674
562
  }
675
563
  /** matching(主+社区合并条目):命中主条目或社区条目都写 registryId;社区命中再标 community。 */
676
- function matchInstalled(items, merged) {
564
+ function matchInstalled(items, merged, lookup) {
677
565
  for (const item of items) {
678
- const entry = merged.find((e) => matchInstalledByEntry(e, [item]));
566
+ // 0.9.68(ADR-0016 决策 5):mergedOutcome.lookupInstalled 查表 O(I);缺省回退线性扫描保旧调用面
567
+ const entry = lookup ? lookup(item) : merged.find((e) => matchInstalledByEntry(e, [item]));
679
568
  if (!entry)
680
569
  continue;
681
570
  item.registryId = entry.id;
@@ -688,7 +577,7 @@ function matchInstalled(items, merged) {
688
577
  /** 已装页 latest 探测(Q46 已装页豁免,但 GitHub 计入 request 预算 + 宿主滚动窗口)。 */
689
578
  async function probeLatest(items, ctx, d, rt) {
690
579
  await mapWithConcurrency(items, LATEST_WORKERS, async (item) => {
691
- const entry = ctx.merged.find((e) => matchInstalledByEntry(e, [item]));
580
+ const entry = ctx.lookup ? ctx.lookup(item) : ctx.merged.find((e) => matchInstalledByEntry(e, [item]));
692
581
  // latest 探测沿用 listMarket 的 TTL cache;npm-only 条目(不在收录清单的已装包)也走
693
582
  // latestCacheKey 归一格式(0.9.14:否则首段非 host/cli 会被落盘层静默跳过)
694
583
  const cacheKey = entry
@@ -756,11 +645,31 @@ export async function resolveRegistryEntry(id, cfg = {}, opts = {}, deps) {
756
645
  if (loaded.status === 'unavailable') {
757
646
  throw new Error(`收录清单不可用,无法安装 ${id};请检查 registry 配置或网络后重试`);
758
647
  }
759
- const entry = loaded.registry.plugins.find((e) => e.id === id) ??
760
- (await findCommunityInstallEntry(id, cfg, opts, deps));
761
- if (!entry)
762
- throw new Error(`registry 中没有该条目: ${id}`);
763
- return entry;
648
+ // 主清单优先短路(今日语义原样):primary 命中不触碰社区——社区异常不阻断主清单条目安装。
649
+ const primaryEntry = loaded.registry.plugins.find((e) => e.id === id);
650
+ if (primaryEntry)
651
+ return primaryEntry;
652
+ // 0.9.68(ADR-0016 / R2-3):主清单 miss 时经物化合并市场取全量域 findById([primary..., adapt 全量...]
653
+ // 含 displaced 让位条目——id-让位条目今日可装,语义零变化);同身份命中免每装机 4,400 条重 adapt。
654
+ // communityTask reject 透传,由窄 catch 吞为 miss(与旧 findCommunityInstallEntry 同构 →「没有该条目」)。
655
+ try {
656
+ const communityTask = (deps?.fetchCommunityCatalog ?? defaultFetchCommunityCatalog)(cfg, { namespace: opts.namespace ?? 'host', signal: opts.signal, profile: opts.profile });
657
+ const outcome = await mergedOutcome({
658
+ namespace: opts.namespace ?? 'host',
659
+ profile: opts.profile ?? WEB_PROFILE,
660
+ cfg,
661
+ registry: loaded,
662
+ communityTask,
663
+ deadlineAt: Date.now() + DEFAULT_DEADLINE_MS,
664
+ });
665
+ const entry = outcome.findById(id);
666
+ if (entry)
667
+ return entry;
668
+ }
669
+ catch {
670
+ /* 社区失败/异常吞为 miss(今日语义) */
671
+ }
672
+ throw new Error(`registry 中没有该条目: ${id}`);
764
673
  }
765
674
  export async function installFromRegistry(id, cfg = {}, opts = {}, deps) {
766
675
  const entry = await resolveRegistryEntry(id, cfg, opts, deps);
@@ -1323,10 +1232,27 @@ async function upgradePluginLocked(pkg, cfg = {}, opts = {}, deps) {
1323
1232
  const target = installed.find((it) => it.pkg === pkg);
1324
1233
  if (!target)
1325
1234
  throw new Error(`web profile 未安装该插件: ${pkg}`);
1235
+ // 0.5.1:合并市场安装的社区条目同样可升级——主清单优先,miss 时查社区目录。
1236
+ // 0.9.68(ADR-0016 / R2-3):社区兜底经物化合并市场全量域 lookupInstalledAll(含 displaced 让位条目,
1237
+ // min-ord 胜者 = 今日「先主清单 find 后社区 adapt 全量 find」合成语义);reject 透传由窄 catch 吞为 miss。
1326
1238
  let entry = loaded.registry.plugins.find((e) => matchInstalledByEntry(e, [target]));
1327
- // 0.5.1:合并市场安装的社区条目同样可升级——主清单 miss 时查社区目录
1328
- if (!entry)
1329
- entry = await findCommunityUpgradeEntry(target, cfg, opts, deps);
1239
+ try {
1240
+ if (!entry) {
1241
+ const communityTask = (deps?.fetchCommunityCatalog ?? defaultFetchCommunityCatalog)(cfg, { namespace: opts.namespace ?? 'host', signal: opts.signal, profile: opts.profile });
1242
+ const outcome = await mergedOutcome({
1243
+ namespace: opts.namespace ?? 'host',
1244
+ profile: opts.profile ?? WEB_PROFILE,
1245
+ cfg,
1246
+ registry: loaded,
1247
+ communityTask,
1248
+ deadlineAt: Date.now() + DEFAULT_DEADLINE_MS,
1249
+ });
1250
+ entry = outcome.lookupInstalledAll(target);
1251
+ }
1252
+ }
1253
+ catch {
1254
+ entry = undefined;
1255
+ }
1330
1256
  if (!entry)
1331
1257
  throw new Error(`「${pkg}」不是经 dsh-m 收录的插件;直接升级请用 dsh plugin update 或先在 registry 收录它`);
1332
1258
  // 0.5.1 修复:直调 installEntryLocked——upgradePlugin 已在 mutation session 区间内,
@@ -1352,33 +1278,6 @@ async function upgradePluginLocked(pkg, cfg = {}, opts = {}, deps) {
1352
1278
  * (owner--name 等),主清单 miss 时按同一 id 查社区目录。社区清单未启用/不可用/加载
1353
1279
  * 异常/未命中 → undefined,由调用方统一报「registry 中没有该条目」。
1354
1280
  */
1355
- async function findCommunityInstallEntry(id, cfg, opts, deps) {
1356
- try {
1357
- const loaded = await (deps?.fetchCommunityCatalog ?? defaultFetchCommunityCatalog)(cfg, { namespace: opts.namespace ?? 'host', signal: opts.signal, profile: opts.profile });
1358
- if (!loaded.catalog)
1359
- return undefined;
1360
- return adaptCommunityCatalog(loaded.catalog).entries.find((e) => e.id === id);
1361
- }
1362
- catch {
1363
- return undefined;
1364
- }
1365
- }
1366
- /**
1367
- * 社区条目升级查找(0.5.1):主清单 miss 时按同一 matchInstalledByEntry 语义查社区目录。
1368
- * 社区清单未启用/不可用/加载异常/未命中 → undefined,由调用方统一报「不是经 dsh-m 收录」。
1369
- */
1370
- async function findCommunityUpgradeEntry(target, cfg, opts, deps) {
1371
- try {
1372
- const loaded = await (deps?.fetchCommunityCatalog ?? defaultFetchCommunityCatalog)(cfg, { namespace: opts.namespace ?? 'host', signal: opts.signal, profile: opts.profile });
1373
- if (!loaded.catalog)
1374
- return undefined;
1375
- const adapted = adaptCommunityCatalog(loaded.catalog);
1376
- return adapted.entries.find((e) => matchInstalledByEntry(e, [target]));
1377
- }
1378
- catch {
1379
- return undefined;
1380
- }
1381
- }
1382
1281
  /** 自升级(0.5.0 收编:host-api 直调事务的旁路封死):npmLatest + integrity fail-closed + installEntryLocked(session/守卫经 installEntry)。 */
1383
1282
  export async function selfUpgrade(pkgName, currentVersion, cfg = {}, opts = {}, deps) {
1384
1283
  return withMutationSession(async () => {