@noob-stupid/dsh-plugin-console 0.3.26 → 0.3.28

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/lib/client.js CHANGED
@@ -104,6 +104,21 @@ window.__ModuleLoader__.load({
104
104
  pendingCompatTag: "待适配",
105
105
  pendingCompatHint: "框架升级后被强制禁用:先点「检测更新」,如有新版按钮会变为「更新并适配」,点击后更新完成自动校验通过即解锁启用",
106
106
  updateAndAdapt: "更新并适配",
107
+ familyTag: "全家桶",
108
+ familySubs: "子包",
109
+ familyUnlockAll: "一键启用已适配",
110
+ familyUnlockAllTip: "对全家桶内所有源码扫描通过(已适配)的子包批量解锁启用;未通过的保持禁用",
111
+ familyUnlockAllConfirm: "将对全家桶内所有已适配(源码扫描通过)的子包一键解锁启用?未通过的将保持禁用。",
112
+ familyUnlockAllDone: "已批量适配解锁",
113
+ familyExpand: "展开",
114
+ familyCollapse: "收起",
115
+ familyUpdate: "全家桶版本检测",
116
+ familyCheckUpdate: "批量检测更新",
117
+ adaptUnlockBtn: "已适配,立即解锁",
118
+ adaptUnlockHint: "已安装版本经源码扫描确认适配当前框架:立即移除禁用块并解锁启用",
119
+ adaptUnlockDone: "已适配解锁:刷新后该行可正常启用",
120
+ migrateTip: "项目已迁移(适配当前框架)",
121
+ migrateBtn: "迁移并适配",
107
122
  aiEmpowerFrameworkCheck: "框架适配检测",
108
123
  userForcedTag: "补丁强制启用",
109
124
  protectedTag: "受保护",
@@ -404,6 +419,21 @@ window.__ModuleLoader__.load({
404
419
  pendingCompatTag: "Pending adapt",
405
420
  pendingCompatHint: "Force-disabled after framework upgrade: click Check update first; if a newer version exists the button becomes Update & adapt - click it and it unlocks automatically after the compat check",
406
421
  updateAndAdapt: "Update & adapt",
422
+ familyTag: "Family bundle",
423
+ familySubs: "sub packages",
424
+ familyUnlockAll: "Unlock all adapted",
425
+ familyUnlockAllTip: "Batch-unlock every sub package in this family whose source scan passed; failed ones stay disabled",
426
+ familyUnlockAllConfirm: "Unlock all adapted (source-scan passed) sub packages in this family? Failed ones stay disabled.",
427
+ familyUnlockAllDone: "Family batch unlock done",
428
+ familyExpand: "Expand",
429
+ familyCollapse: "Collapse",
430
+ familyUpdate: "Family version check",
431
+ familyCheckUpdate: "Check all",
432
+ adaptUnlockBtn: "Adapted - unlock now",
433
+ adaptUnlockHint: "Installed version passed the source scan for the current framework: unlock immediately",
434
+ adaptUnlockDone: "Unlocked: refresh and the row is enabled",
435
+ migrateTip: "Project migrated (adapted to the current framework)",
436
+ migrateBtn: "Migrate & adapt",
407
437
  aiEmpowerFrameworkCheck: "Framework compat check",
408
438
  userForcedTag: "Forced on by patch",
409
439
  protectedTag: "Protected",
@@ -971,10 +1001,12 @@ window.__ModuleLoader__.load({
971
1001
  function PluginConsoleTab({ t }) {
972
1002
  const [state, setState] = react.useState({ status: "loading" });
973
1003
  const [busy, setBusy] = react.useState(null);
1004
+ const [adaptUnlocking, setAdaptUnlocking] = react.useState(null);
974
1005
  const [message, setMessage] = react.useState(null);
975
1006
  const [reloadHint, setReloadHint] = react.useState(false);
976
1007
  const [restartHint, setRestartHint] = react.useState(false);
977
1008
  const [jobs, setJobs] = react.useState({});
1009
+ const [familyCollapsed, setFamilyCollapsed] = react.useState({});
978
1010
  const [query, setQuery] = react.useState(() => {
979
1011
  try { return localStorage.getItem("pc-market-query") ?? ""; } catch { return ""; }
980
1012
  });
@@ -2239,13 +2271,31 @@ window.__ModuleLoader__.load({
2239
2271
  : ((searchSourcesList !== null ? searchSourcesList.find((s) => s.id === source)?.name : undefined) ?? source);
2240
2272
  const extraIds = new Set((state.status === "ready" ? state.data.patch?.inserts ?? [] : []));
2241
2273
  const extraCount = state.status === "ready" ? state.data.entries.filter((entry) => entry.extra === true || extraIds.has(entry.rowId)).length : 0;
2242
- const rows = state.status === "ready"
2274
+ const pkgRootOf = (m) => { const mm = String(m ?? ""); const x = mm.match(/^(@[^/]+\/[^/]+)(?:\/.*)?$/u); return x ? x[1] : mm; };
2275
+ const filteredEntries = state.status === "ready"
2243
2276
  ? state.data.entries.filter((entry) => {
2244
2277
  if (extraOnly && !(entry.extra === true || extraIds.has(entry.rowId))) return false;
2245
2278
  if (installedQueryNorm === "") return true;
2246
2279
  return [entry.moduleName, entry.entryId, entry.rowId]
2247
2280
  .some((value) => String(value ?? "").toLowerCase().includes(installedQueryNorm));
2248
- }).map((entry) => {
2281
+ })
2282
+ : [];
2283
+ // 聚合包分组:仅「同根包 + 子路径导出」(web-all 0.3.14 式,moduleName=pkg/sub)→ 全家桶组;
2284
+ // 经典多子包聚合(每子包独立名)不归组。组头与子包卡片一律置于列表【最底部】。
2285
+ const famRootOf = (entry) => {
2286
+ const m = String(entry.moduleName ?? "");
2287
+ if (m.startsWith("@deepseek-ai/")) return null;
2288
+ return pkgRootOf(m);
2289
+ };
2290
+ const familyCounts = new Map();
2291
+ for (const entry of (state.status === "ready" ? state.data.entries : [])) {
2292
+ const root = famRootOf(entry);
2293
+ if (root === null) continue;
2294
+ familyCounts.set(root, (familyCounts.get(root) ?? 0) + 1);
2295
+ }
2296
+ const familyCards = filteredEntries.map((entry) => {
2297
+ const familyRoot = String(entry.moduleName ?? "").startsWith("@deepseek-ai/") ? null : pkgRootOf(entry.moduleName);
2298
+ void familyRoot;
2249
2299
  const open = details !== null && details.entryId === entry.entryId;
2250
2300
  let detailPanel = null;
2251
2301
  if (open) {
@@ -2258,10 +2308,13 @@ window.__ModuleLoader__.load({
2258
2308
  } else {
2259
2309
  const meta = details.data.meta;
2260
2310
  const readme = details.data.readme;
2311
+ const compatInfo = state.status === "ready" && state.data.compatPending
2312
+ ? (state.data.compatPending.pending ?? []).find((p) => p.rowId === entry.rowId) ?? null
2313
+ : null;
2261
2314
  detailPanel = el("div", { className: styles.detail },
2262
2315
  meta !== null ? el("p", { className: styles.desc }, meta.description ?? t("noDetail")) : null,
2263
2316
  entry.pendingCompat === true
2264
- ? el("p", { className: styles.status, "data-pending": "true" }, t("pendingCompatHint"))
2317
+ ? el("p", { className: styles.status, "data-pending": "true" }, t("pendingCompatHint") + (compatInfo && compatInfo.checkNote ? ";已知校验:" + compatInfo.checkNote : ""))
2265
2318
  : null,
2266
2319
  meta !== null && meta.version ? el("div", { className: styles.rowTop },
2267
2320
  el("p", { className: styles.status }, t("versionLabel") + ":" + meta.version),
@@ -2276,7 +2329,38 @@ window.__ModuleLoader__.load({
2276
2329
  className: styles.toggle,
2277
2330
  title: t("aiEmpowerTitle"),
2278
2331
  onClick: () => openAiFor(String(entry.moduleName ?? entry.repo ?? "")),
2279
- }, t("aiEmpowerLabel"))) : null,
2332
+ }, t("aiEmpowerLabel")),
2333
+ entry.pendingCompat === true
2334
+ ? el("button", {
2335
+ type: "button",
2336
+ className: styles.toggle,
2337
+ "data-pending": "true",
2338
+ title: t("adaptUnlockHint"),
2339
+ disabled: installing === entry.moduleName || adaptUnlocking === entry.entryId,
2340
+ onClick: () => {
2341
+ setAdaptUnlocking(entry.entryId);
2342
+ call("/plugin-console/adapt-unlock", { rowId: entry.rowId }).then(
2343
+ () => {
2344
+ setAdaptUnlocking(null);
2345
+ setMessage(t("adaptUnlockDone"));
2346
+ window.setTimeout(() => window.location.reload(), 1200);
2347
+ },
2348
+ (error) => { setAdaptUnlocking(null); setMessage(t("failed") + ":" + friendlyGithubError(error).message); },
2349
+ );
2350
+ },
2351
+ }, adaptUnlocking === entry.entryId ? t("loadingPhase") : t("adaptUnlockBtn"))
2352
+ : null) : null,
2353
+ updateCheck !== null && updateCheck.status === "ready" && updateCheck.migrate && updateCheck.migrate.compatible
2354
+ ? el("div", null,
2355
+ el("div", { className: styles.rowTop },
2356
+ el("p", { className: styles.status }, t("migrateTip") + ":" + String(updateCheck.migrate.to ?? "") + (updateCheck.migrate.latest ? " v" + updateCheck.migrate.latest : "")),
2357
+ el("button", {
2358
+ type: "button",
2359
+ className: styles.toggle,
2360
+ disabled: installing === entry.moduleName,
2361
+ onClick: () => startJob("", updateCheck.migrate.to, "github", "plugin", false),
2362
+ }, installing === entry.moduleName ? t("installing") : t("migrateBtn"))))
2363
+ : null,
2280
2364
  updateCheck !== null && updateCheck.status === "ready"
2281
2365
  ? (updateCheck.error
2282
2366
  ? el("p", { className: styles.status, "data-error": "true" }, t("updateCheckFailed") + ":" + updateCheck.error)
@@ -2314,7 +2398,13 @@ window.__ModuleLoader__.load({
2314
2398
  }
2315
2399
  return el("li", { key: entry.entryId, className: styles.row },
2316
2400
  el("div", { className: styles.rowTop },
2317
- el("strong", { className: styles.name, title: entry.moduleName }, moduleShortName(entry.moduleName)),
2401
+ el("strong", { className: styles.name, title: entry.moduleName }, (() => {
2402
+ const famRoot = famRootOf(entry);
2403
+ const mn = String(entry.moduleName ?? "");
2404
+ return famRoot !== null && (familyCounts.get(famRoot) ?? 0) > 1 && mn.startsWith(famRoot + "/")
2405
+ ? mn.slice(famRoot.length + 1)
2406
+ : moduleShortName(entry.moduleName);
2407
+ })()),
2318
2408
  el("span", { className: styles.tag, "data-enabled": entry.enabled ? "true" : "false" },
2319
2409
  t(entry.enabled ? "enabledTag" : "disabledTag")),
2320
2410
  entry.extra === true ? el("span", { className: styles.tag, "data-user": "true" }, t("extraTag")) : null,
@@ -2360,7 +2450,7 @@ window.__ModuleLoader__.load({
2360
2450
  setMessage(t("deleteBundleNote") + ":" + (data.packageName ?? "") + (data.uninstallError ? "(包卸载警告:" + data.uninstallError + ")" : ""));
2361
2451
  setRestartHint(true);
2362
2452
  } else {
2363
- setMessage(t("deleteNote") + ":" + (data.packageName ?? "") + (data.uninstallError ? "(包卸载警告:" + data.uninstallError + ")" : ""));
2453
+ setMessage(t("deleteNote") + ":" + (data.packageName ?? "") + (data.note ? ";" + data.note : "") + (data.uninstallError ? "(包卸载警告:" + data.uninstallError + ")" : ""));
2364
2454
  setTimeout(refresh, 1500);
2365
2455
  }
2366
2456
  },
@@ -2388,8 +2478,72 @@ window.__ModuleLoader__.load({
2388
2478
  ),
2389
2479
  detailPanel,
2390
2480
  );
2391
- })
2392
- : [];
2481
+ });
2482
+ // 全家桶组头:聚合包(同根包 ≥2 行)合并展示为一个「web 包」卡片
2483
+ const familyHeaders = [];
2484
+ const familySeen = new Set();
2485
+ for (const entry of filteredEntries) {
2486
+ const root = famRootOf(entry);
2487
+ if (root === null || (familyCounts.get(root) ?? 0) <= 1 || familySeen.has(root)) continue;
2488
+ familySeen.add(root);
2489
+ familyHeaders.push(el("div", { key: "family-" + root, className: styles.detail, style: { border: "1px solid var(--dsw-alias-state-business-primary)", borderRadius: 10, padding: "8px 12px", gridColumn: "1 / -1" } },
2490
+ el("div", { className: styles.rowTop, style: { alignItems: "center" } },
2491
+ el("strong", { className: styles.name, style: { flex: "0 1 auto", minWidth: 0, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }, title: root }, root.replace(/^@[^/]+\//u, "").replace(/^dsh-/u, "")),
2492
+ el("span", { className: styles.tag, "data-user": "true" }, t("familyTag") + " · " + (familyCounts.get(root) ?? 0) + " " + t("familySubs")),
2493
+ el("button", {
2494
+ type: "button",
2495
+ className: styles.toggle,
2496
+ style: { whiteSpace: "nowrap", flexShrink: 0 },
2497
+ onClick: () => setFamilyCollapsed((prev) => ({ ...prev, [root]: prev[root] !== true })),
2498
+ }, familyCollapsed[root] === true ? "▸ " + t("familyExpand") : "▾ " + t("familyCollapse")),
2499
+ el("button", {
2500
+ type: "button",
2501
+ className: styles.toggle,
2502
+ style: { whiteSpace: "nowrap", flexShrink: 0 },
2503
+ onClick: () => {
2504
+ setMessage(t("checkingUpdate"));
2505
+ call("/plugin-console/check-update", { packageName: root }).then(
2506
+ (d) => setMessage(t("familyUpdate") + ":" + root + " " + (d?.latest ?? "?") + (d?.migrate && d.migrate.compatible ? " → " + d.migrate.to + " v" + d.migrate.latest : "") + (d?.error ? "(" + d.error + ")" : "")),
2507
+ (e) => setMessage(t("failed") + ":" + friendlyGithubError(e).message),
2508
+ );
2509
+ },
2510
+ }, t("familyCheckUpdate")),
2511
+ el("button", {
2512
+ type: "button",
2513
+ className: styles.toggle,
2514
+ style: { whiteSpace: "nowrap", flexShrink: 0 },
2515
+ title: t("familyUnlockAllTip"),
2516
+ onClick: () => {
2517
+ if (!window.confirm(t("familyUnlockAllConfirm"))) return;
2518
+ call("/plugin-console/adapt-unlock-all", { root }).then(
2519
+ (d) => {
2520
+ setMessage(t("familyUnlockAllDone") + ":" + (d.unlocked ?? []).length + " 行" + (Array.isArray(d.kept) && d.kept.length > 0 ? ";保留 " + d.kept.length + " 行(未通过校验)" : ""));
2521
+ window.setTimeout(() => window.location.reload(), 1500);
2522
+ },
2523
+ (e) => setMessage(t("failed") + ":" + friendlyGithubError(e).message),
2524
+ );
2525
+ },
2526
+ }, t("familyUnlockAll")))
2527
+ ));
2528
+ }
2529
+ // 组头放到最底部:普通条目在前,全家桶(组头+子包卡片)整体在后
2530
+ const nonFamilyCards = [];
2531
+ const familySections = new Map();
2532
+ familyCards.forEach((card, i) => {
2533
+ const e = filteredEntries[i];
2534
+ if (e === undefined) { nonFamilyCards.push(card); return; }
2535
+ const root = famRootOf(e);
2536
+ if (root === null || (familyCounts.get(root) ?? 0) <= 1) { nonFamilyCards.push(card); return; }
2537
+ if (!familySections.has(root)) familySections.set(root, { head: familyHeaders.find((h) => h && h.key === "family-" + root) ?? null, cards: [] });
2538
+ familySections.get(root).cards.push(card);
2539
+ });
2540
+ const familySectionEls = [];
2541
+ for (const [, section] of familySections) {
2542
+ if (section.head !== null) familySectionEls.push(section.head);
2543
+ const root = section.head !== null ? section.head.key.slice("family-".length) : null;
2544
+ if (root === null || familyCollapsed[root] !== true) familySectionEls.push(...section.cards);
2545
+ }
2546
+ const rows = state.status === "ready" ? [...nonFamilyCards, ...familySectionEls] : [];
2393
2547
  const marketShown = market === null || market.status !== "ready"
2394
2548
  ? []
2395
2549
  : officialOnly