@noob-stupid/dsh-plugin-console 0.5.31 → 0.5.33

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
@@ -256,7 +256,6 @@ window.__ModuleLoader__.load({
256
256
  unloading: "卸载中",
257
257
  toggledOn: "已请求启用",
258
258
  toggledOff: "已请求停用",
259
- failed: "操作失败",
260
259
  view: "查看",
261
260
  install: "添加并启用",
262
261
  installing: "正在安装…",
@@ -527,7 +526,6 @@ window.__ModuleLoader__.load({
527
526
  sourcesUpdated: "软件源已更新",
528
527
  sourceOf: "源:",
529
528
  searchSourceTitle: "点击切换搜索源(GitHub / Gitee / 自定义)",
530
- recentFailures: "最近安装失败",
531
529
  installedAt: "已安装",
532
530
  checkUpdate: "检测更新",
533
531
  checkingUpdate: "检测中…",
@@ -810,7 +808,6 @@ window.__ModuleLoader__.load({
810
808
  unloading: "Unloading",
811
809
  toggledOn: "Enable requested",
812
810
  toggledOff: "Disable requested",
813
- failed: "Operation failed",
814
811
  view: "Inspect",
815
812
  install: "Add & enable",
816
813
  installing: "Installing…",
@@ -1077,7 +1074,6 @@ window.__ModuleLoader__.load({
1077
1074
  sourcesUpdated: "Sources updated",
1078
1075
  sourceOf: "Source: ",
1079
1076
  searchSourceTitle: "Click to switch search source (GitHub / Gitee / custom)",
1080
- recentFailures: "Recent install failures",
1081
1077
  installedAt: "Installed",
1082
1078
  checkUpdate: "Check update",
1083
1079
  checkingUpdate: "Checking…",
@@ -1229,6 +1225,18 @@ window.__ModuleLoader__.load({
1229
1225
  function phaseLabel(phase, t) {
1230
1226
  return phase === null ? t("unobserved") : t(PHASE_KEYS[phase]);
1231
1227
  }
1228
+ // 0.5.33 改错 ①-2:「已适配,立即解锁」按钮的门控判据 —— 必须与同一卡片正文用的是**同一个**判据。
1229
+ // 现症:按钮只判 pendingCompat === true,不判 entry.adoptable → 正文按 adoptable 说"不适配",
1230
+ // 按钮按 pendingCompat 说"已适配",自相矛盾;点下去 POST /adapt-unlock 必得 409(适配校验 fail),
1231
+ // 补丁与行状态零变化 ⇒ 用户观感"点了没反应"。
1232
+ // 现在只有**真的检测到已适配**(adoptable 是服务端 detectAdoptablePending 给出的对象)才出按钮;
1233
+ // 其余情况不给这个承诺,原因照旧由正文那行(pendingCompatHint + checkNote)如实展示。
1234
+ function canAdaptUnlock(entry) {
1235
+ return entry !== null && entry !== undefined
1236
+ && entry.pendingCompat === true
1237
+ && entry.adoptable !== null && entry.adoptable !== undefined
1238
+ && typeof entry.adoptable === "object";
1239
+ }
1232
1240
  async function call(path, body) {
1233
1241
  const response = await fetch(path, body === undefined
1234
1242
  ? {}
@@ -1273,7 +1281,7 @@ window.__ModuleLoader__.load({
1273
1281
  if (reload) setMessage(t("restarting"));
1274
1282
  call("/plugin-console/restart", {}).then(
1275
1283
  () => { if (reload) window.setTimeout(() => window.location.reload(), 12000); },
1276
- (error) => { setMessage(error !== null && typeof error.message === "string" && error.message !== "" ? error.message : t("failed")); },
1284
+ (error) => { setMessage(error !== null && typeof error.message === "string" && error.message !== "" ? error.message : t("safetySwitchFailed")); },
1277
1285
  );
1278
1286
  }
1279
1287
  /** 超时类错误附上可操作提示(网络黑洞期的最常见表现)。 */
@@ -1718,7 +1726,7 @@ window.__ModuleLoader__.load({
1718
1726
  setFwClearing(true);
1719
1727
  call("/plugin-console/framework-status-clear", {}).then(
1720
1728
  () => { setFrameworkStatus({ status: "idle", message: null }); setFwStatusDismissed(true); setMessage(t("fwRecordCleared")); },
1721
- (error) => { setMessage(t("failed") + ":" + friendlyGithubError(error).message); },
1729
+ (error) => { setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message); },
1722
1730
  ).finally(() => setFwClearing(false));
1723
1731
  };
1724
1732
  const fwStatusRefresh = () => {
@@ -1736,7 +1744,7 @@ window.__ModuleLoader__.load({
1736
1744
  setFwCheckBusy(true);
1737
1745
  call("/plugin-console/framework-check", refresh === true ? { refresh: true } : {}).then(
1738
1746
  (data) => { setFwCheckBusy(false); if (data && data.ok === true) setFwCheck(data); },
1739
- (error) => { setFwCheckBusy(false); setMessage(t("failed") + ":" + friendlyGithubError(error).message); },
1747
+ (error) => { setFwCheckBusy(false); setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message); },
1740
1748
  );
1741
1749
  };
1742
1750
  // 升级前契约预检:先只读预检(抓目标版本会话格式契约 + 扫本地生产方),
@@ -1753,7 +1761,7 @@ window.__ModuleLoader__.load({
1753
1761
  setFwPreflightBusy(false);
1754
1762
  setFwPreflight((prev) => (apply === true ? { report: (prev && prev.report) ?? null, patch: data } : { report: data, patch: null }));
1755
1763
  },
1756
- (error) => { setFwPreflightBusy(false); setMessage(t("failed") + ":" + friendlyGithubError(error).message); },
1764
+ (error) => { setFwPreflightBusy(false); setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message); },
1757
1765
  );
1758
1766
  };
1759
1767
  const fwShortPath = (p) => String(p ?? "").replace(/\\/gu, "/").split("/").slice(-3).join("/");
@@ -1766,7 +1774,7 @@ window.__ModuleLoader__.load({
1766
1774
  setFrameworkStatus({ status: "rollback", message: t("frameworkRollbackDone").replace("{from}", String(data?.from ?? "?")) });
1767
1775
  pollFrameworkStatus();
1768
1776
  },
1769
- (error) => { setFrameworkUpgrading(false); setMessage(t("failed") + ":" + friendlyGithubError(error).message); },
1777
+ (error) => { setFrameworkUpgrading(false); setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message); },
1770
1778
  );
1771
1779
  };
1772
1780
  // 回滚按钮可用性:已经处在「回滚目标版本」时不再提供回滚(点了等于恢复现状)。
@@ -2013,10 +2021,10 @@ window.__ModuleLoader__.load({
2013
2021
  setAiJob({ jobId: data.jobId, source, status: "running", stage: "planning" });
2014
2022
  aiPoll(data.jobId);
2015
2023
  }
2016
- else { setAiRunning(false); setMessage(t("failed") + ":" + (data?.error ?? "未知")); }
2024
+ else { setAiRunning(false); setMessage(t("safetySwitchFailed") + ":" + (data?.error ?? "未知")); }
2017
2025
  } catch (error) {
2018
2026
  setAiRunning(false);
2019
- setMessage(t("failed") + ":" + friendlyGithubError(error).message);
2027
+ setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message);
2020
2028
  }
2021
2029
  }
2022
2030
  async function aiRun() {
@@ -2035,7 +2043,7 @@ window.__ModuleLoader__.load({
2035
2043
  aiPoll(aiJob.jobId);
2036
2044
  } catch (error) {
2037
2045
  setAiRunning(false);
2038
- setMessage(t("failed") + ":" + friendlyGithubError(error).message);
2046
+ setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message);
2039
2047
  }
2040
2048
  }
2041
2049
  async function aiCancel() {
@@ -2056,7 +2064,7 @@ window.__ModuleLoader__.load({
2056
2064
  const data = await call("/plugin-console/component/" + action, { id });
2057
2065
  setMessage(t("compActionDone").replace("{action}", t(action === "start" ? "compStart" : "compStop")).replace("{name}", data?.name ?? id));
2058
2066
  } catch (error) {
2059
- setMessage(t("failed") + ":" + error.message);
2067
+ setMessage(t("safetySwitchFailed") + ":" + error.message);
2060
2068
  }
2061
2069
  setCompBusy(null);
2062
2070
  refreshComps();
@@ -2069,7 +2077,7 @@ window.__ModuleLoader__.load({
2069
2077
  setMessage(data.running ? (data.healthy ? t("compHealthy") : t("compUnhealthy")) + ":" + (data.name ?? id) : t("compStopped") + ":" + (data.name ?? id));
2070
2078
  }
2071
2079
  } catch (error) {
2072
- setMessage(t("failed") + ":" + error.message);
2080
+ setMessage(t("safetySwitchFailed") + ":" + error.message);
2073
2081
  }
2074
2082
  setCompBusy(null);
2075
2083
  refreshComps();
@@ -2088,7 +2096,7 @@ window.__ModuleLoader__.load({
2088
2096
  await call("/plugin-console/component/autostart", { id, enabled: on });
2089
2097
  setMessage((on ? "✔ 已开启自启动:" : "已关闭自启动:") + id);
2090
2098
  } catch (error) {
2091
- setMessage(t("failed") + ":" + error.message);
2099
+ setMessage(t("safetySwitchFailed") + ":" + error.message);
2092
2100
  }
2093
2101
  setCompBusy(null);
2094
2102
  refreshComps();
@@ -2500,7 +2508,7 @@ window.__ModuleLoader__.load({
2500
2508
  setRiskyConfirm({ entryId: entry.entryId, moduleName: details.moduleName ?? entry.moduleName ?? null, frameworkVersion: details.frameworkVersion ?? null, checkNote: details.checkNote ?? null });
2501
2509
  return;
2502
2510
  }
2503
- setMessage(t("failed") + ":" + friendlyGithubError(error).message);
2511
+ setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message);
2504
2512
  },
2505
2513
  ).finally(() => setBusy(null));
2506
2514
  };
@@ -2513,7 +2521,7 @@ window.__ModuleLoader__.load({
2513
2521
  : prev));
2514
2522
  setMessage(t("compatGateSaved"));
2515
2523
  },
2516
- (error) => setMessage(t("failed") + ":" + friendlyGithubError(error).message),
2524
+ (error) => setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message),
2517
2525
  );
2518
2526
  };
2519
2527
  const levenshtein = (a, b) => {
@@ -2704,7 +2712,7 @@ window.__ModuleLoader__.load({
2704
2712
  },
2705
2713
  (error) => {
2706
2714
  setLoadingMore(false);
2707
- setMessage(t("failed") + ":" + friendlyGithubError(error).message);
2715
+ setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message);
2708
2716
  },
2709
2717
  );
2710
2718
  return;
@@ -2728,7 +2736,7 @@ window.__ModuleLoader__.load({
2728
2736
  },
2729
2737
  (error) => {
2730
2738
  setLoadingMore(false);
2731
- setMessage(t("failed") + ":" + friendlyGithubError(error).message);
2739
+ setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message);
2732
2740
  },
2733
2741
  );
2734
2742
  return;
@@ -2746,7 +2754,7 @@ window.__ModuleLoader__.load({
2746
2754
  },
2747
2755
  (error) => {
2748
2756
  setLoadingMore(false);
2749
- setMessage(t("failed") + ":" + friendlyGithubError(error).message);
2757
+ setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message);
2750
2758
  },
2751
2759
  );
2752
2760
  return;
@@ -2784,7 +2792,7 @@ window.__ModuleLoader__.load({
2784
2792
  },
2785
2793
  (error) => {
2786
2794
  setLoadingMore(false);
2787
- setMessage(t("failed") + ":" + friendlyGithubError(error).message);
2795
+ setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message);
2788
2796
  },
2789
2797
  ),
2790
2798
  );
@@ -2953,7 +2961,7 @@ window.__ModuleLoader__.load({
2953
2961
  window.setTimeout(() => window.location.reload(), 2500);
2954
2962
  }
2955
2963
  } else {
2956
- setMessage(t("failed") + ":" + (data.error ?? "未知错误") + diagMessage(data));
2964
+ setMessage(t("safetySwitchFailed") + ":" + (data.error ?? "未知错误") + diagMessage(data));
2957
2965
  }
2958
2966
  setInstalling(null);
2959
2967
  setTimeout(refresh, 1500);
@@ -2966,8 +2974,8 @@ window.__ModuleLoader__.load({
2966
2974
  /** 本地 AI 兜底授权:调用模型 API 产生费用,必须用户明确同意。 */
2967
2975
  const aiConsent = (jobId, approved) => {
2968
2976
  call("/plugin-console/ai-consent", { jobId, approved }).then(
2969
- () => { if (!approved) setMessage(t("failed") + ":已取消本地 AI 兜底(不会调用模型 API)"); },
2970
- (error) => setMessage(t("failed") + ":" + friendlyGithubError(error).message),
2977
+ () => { if (!approved) setMessage(t("safetySwitchFailed") + ":已取消本地 AI 兜底(不会调用模型 API)"); },
2978
+ (error) => setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message),
2971
2979
  );
2972
2980
  };
2973
2981
  /** 安装进度文案:服务端 progress{channel,phase,index,total,name,done} → 一行人话。
@@ -3127,7 +3135,7 @@ window.__ModuleLoader__.load({
3127
3135
  // clientId 打码回显(如 abc12345…):用户未修改时原样传回服务端,服务端识别打码标记保留原配置
3128
3136
  const idValue = giteeClientId.trim();
3129
3137
  if (!idValue || !giteeClientSecret.trim()) {
3130
- setMessage(t("failed") + ":client_id / client_secret 不能为空");
3138
+ setMessage(t("safetySwitchFailed") + ":client_id / client_secret 不能为空");
3131
3139
  return;
3132
3140
  }
3133
3141
  if (idValue.endsWith("…")) {
@@ -3139,7 +3147,7 @@ window.__ModuleLoader__.load({
3139
3147
  const startGiteeOauth = () => {
3140
3148
  call("/plugin-console/gitee-oauth-url").then(
3141
3149
  (data) => { if (data && data.url) window.open(data.url, "_blank", "noopener"); },
3142
- (error) => setMessage(t("failed") + ":" + friendlyGithubError(error).message),
3150
+ (error) => setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message),
3143
3151
  );
3144
3152
  };
3145
3153
  const sourcesAction = (payload, done) => {
@@ -3151,12 +3159,12 @@ window.__ModuleLoader__.load({
3151
3159
  setMessage(t("sourcesUpdated"));
3152
3160
  if (done) done();
3153
3161
  },
3154
- (error) => setMessage(t("failed") + ":" + friendlyGithubError(error).message),
3162
+ (error) => setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message),
3155
3163
  ).finally(() => setSourcesBusy(false));
3156
3164
  };
3157
3165
  const addSource = () => {
3158
3166
  if (!isAllowedSourceUrl(sourceUrl.trim())) {
3159
- setMessage(t("failed") + ":" + t("invalidSourceUrl"));
3167
+ setMessage(t("safetySwitchFailed") + ":" + t("invalidSourceUrl"));
3160
3168
  return;
3161
3169
  }
3162
3170
  sourcesAction({ action: "add", name: sourceName.trim(), url: sourceUrl.trim() }, () => { setSourceName(""); setSourceUrl(""); });
@@ -3166,7 +3174,7 @@ window.__ModuleLoader__.load({
3166
3174
  setRegScan({ status: "scanning" });
3167
3175
  call("/plugin-console/registry-scan", {}).then(
3168
3176
  (data) => setRegScan({ status: "ready", results: Array.isArray(data.results) ? data.results : [], scannedAt: typeof data.scannedAt === "number" ? data.scannedAt : null }),
3169
- (error) => { setRegScan(null); setMessage(t("failed") + ":" + friendlyGithubError(error).message); },
3177
+ (error) => { setRegScan(null); setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message); },
3170
3178
  );
3171
3179
  };
3172
3180
  // 扫描结果派生视图:每条源的命中结果 + 可达计数 + 最新版本来自哪个源
@@ -3190,7 +3198,7 @@ window.__ModuleLoader__.load({
3190
3198
  };
3191
3199
  const addIndexSource = () => {
3192
3200
  if (!isAllowedSourceUrl(indexSourceUrl.trim())) {
3193
- setMessage(t("failed") + ":" + t("invalidSourceUrl"));
3201
+ setMessage(t("safetySwitchFailed") + ":" + t("invalidSourceUrl"));
3194
3202
  return;
3195
3203
  }
3196
3204
  sourcesAction({ action: "add-index", name: indexSourceName.trim(), url: indexSourceUrl.trim() }, () => { setIndexSourceName(""); setIndexSourceUrl(""); });
@@ -3213,11 +3221,11 @@ window.__ModuleLoader__.load({
3213
3221
  const addGitSource = () => {
3214
3222
  const tpl = gitSourceUrl.trim();
3215
3223
  if (!tpl.includes("{owner}") || !tpl.includes("{repo}")) {
3216
- setMessage(t("failed") + ":" + t("gitUrlPlaceholder"));
3224
+ setMessage(t("safetySwitchFailed") + ":" + t("gitUrlPlaceholder"));
3217
3225
  return;
3218
3226
  }
3219
3227
  if (!isAllowedSourceUrl(tpl)) {
3220
- setMessage(t("failed") + ":" + t("invalidSourceUrl"));
3228
+ setMessage(t("safetySwitchFailed") + ":" + t("invalidSourceUrl"));
3221
3229
  return;
3222
3230
  }
3223
3231
  sourcesAction({ action: "add-git", name: gitSourceName.trim(), urlTemplate: tpl }, () => { setGitSourceName(""); setGitSourceUrl(""); });
@@ -3241,7 +3249,7 @@ window.__ModuleLoader__.load({
3241
3249
  };
3242
3250
  const addSearchSource = () => {
3243
3251
  if (!isAllowedSourceUrl(searchSourceUrl.trim()) || !searchSourceUrl.includes("{q}")) {
3244
- setMessage(t("failed") + ":" + t("invalidSearchUrl"));
3252
+ setMessage(t("safetySwitchFailed") + ":" + t("invalidSearchUrl"));
3245
3253
  return;
3246
3254
  }
3247
3255
  // 解析请求头:每行 "名称: 值"
@@ -3281,7 +3289,7 @@ window.__ModuleLoader__.load({
3281
3289
  }
3282
3290
  },
3283
3291
  (error) => {
3284
- setMessage(t("failed") + ":" + friendlyGithubError(error).message);
3292
+ setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message);
3285
3293
  setInstalling(null);
3286
3294
  },
3287
3295
  );
@@ -3353,7 +3361,7 @@ window.__ModuleLoader__.load({
3353
3361
  },
3354
3362
  (error) => {
3355
3363
  setTogglingSkill(null);
3356
- setMessage(t("failed") + ":" + friendlyGithubError(error).message);
3364
+ setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message);
3357
3365
  },
3358
3366
  );
3359
3367
  };
@@ -3404,7 +3412,7 @@ window.__ModuleLoader__.load({
3404
3412
  (error) => {
3405
3413
  setFrameworkUpgrading(false);
3406
3414
  setConfirmFrameworkUpgrade(false);
3407
- setMessage(t("failed") + ":" + friendlyGithubError(error).message);
3415
+ setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message);
3408
3416
  },
3409
3417
  );
3410
3418
  };
@@ -3416,7 +3424,7 @@ window.__ModuleLoader__.load({
3416
3424
  setConfirmSkillDelete(null);
3417
3425
  setInstalledSkills((prev) => prev.filter((s) => s.name !== name));
3418
3426
  },
3419
- (error) => setMessage(t("failed") + ":" + friendlyGithubError(error).message),
3427
+ (error) => setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message),
3420
3428
  );
3421
3429
  };
3422
3430
  const installedQueryNorm = installedQuery.trim().toLowerCase();
@@ -3470,7 +3478,7 @@ window.__ModuleLoader__.load({
3470
3478
  el("p", { className: styles.status }, t("loadingDetails")));
3471
3479
  } else if (details.status === "error") {
3472
3480
  detailPanel = el("div", { className: styles.detail },
3473
- el("p", { className: styles.status, "data-error": "true" }, t("failed") + ":" + details.error.message));
3481
+ el("p", { className: styles.status, "data-error": "true" }, t("safetySwitchFailed") + ":" + details.error.message));
3474
3482
  } else {
3475
3483
  const meta = details.data.meta;
3476
3484
  const readme = details.data.readme;
@@ -3499,7 +3507,7 @@ window.__ModuleLoader__.load({
3499
3507
  title: t("aiEmpowerTitle"),
3500
3508
  onClick: () => openAiFor(String(entry.moduleName ?? entry.repo ?? "")),
3501
3509
  }, t("aiEmpowerLabel")),
3502
- entry.pendingCompat === true
3510
+ canAdaptUnlock(entry)
3503
3511
  ? el("button", {
3504
3512
  type: "button",
3505
3513
  className: styles.toggle,
@@ -3514,7 +3522,7 @@ window.__ModuleLoader__.load({
3514
3522
  setMessage(t("adaptUnlockDone"));
3515
3523
  window.setTimeout(() => window.location.reload(), 1200);
3516
3524
  },
3517
- (error) => { setAdaptUnlocking(null); setMessage(t("failed") + ":" + friendlyGithubError(error).message); },
3525
+ (error) => { setAdaptUnlocking(null); setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message); },
3518
3526
  );
3519
3527
  },
3520
3528
  }, adaptUnlocking === entry.entryId ? t("loadingPhase") : t("adaptUnlockBtn"))
@@ -3586,6 +3594,13 @@ window.__ModuleLoader__.load({
3586
3594
  phaseLabel(entry.fiberPhase, t)),
3587
3595
  el("code", null, entry.entryId),
3588
3596
  ),
3597
+ // 0.5.33 加法 ①-4:框架 peer 预检**否决**的本地复算结果(服务端 entries[].veto)。
3598
+ // 框架只在内存里禁用、原因只打 stderr —— 这里把它补出来。复用**既有行**内的
3599
+ // status 短句位(不新增常驻面板行),出路放悬浮提示(复用既有 title 位置)。
3600
+ entry.veto && entry.veto.reason
3601
+ ? el("p", { className: styles.status, "data-pending": "true", title: entry.veto.hint ?? undefined },
3602
+ entry.veto.reason)
3603
+ : null,
3589
3604
  el("div", { className: styles.rowTop, style: { justifyContent: "space-between" } },
3590
3605
  el("div", { className: styles.rowTop },
3591
3606
  el("button", {
@@ -3623,7 +3638,7 @@ window.__ModuleLoader__.load({
3623
3638
  setTimeout(refresh, 1500);
3624
3639
  }
3625
3640
  },
3626
- (error) => setMessage(t("failed") + ":" + friendlyGithubError(error).message),
3641
+ (error) => setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message),
3627
3642
  ).finally(() => setDeleteBusy(null));
3628
3643
  } else {
3629
3644
  setConfirmDeleteRowId(entry.entryId);
@@ -3679,7 +3694,7 @@ window.__ModuleLoader__.load({
3679
3694
  setFamilyCheck((prev) => ({ ...prev, [root]: { latest: d?.latest ?? null, installed } }));
3680
3695
  setMessage(t("familyUpdate") + ":" + root + " " + (d?.latest ?? "?") + (d?.migrate && d.migrate.compatible ? " → " + d.migrate.to + " v" + d.migrate.latest : "") + (d?.error ? "(" + d.error + ")" : ""));
3681
3696
  },
3682
- (e) => setMessage(t("failed") + ":" + friendlyGithubError(e).message),
3697
+ (e) => setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(e).message),
3683
3698
  );
3684
3699
  },
3685
3700
  }, t("familyCheckUpdate")),
@@ -3706,7 +3721,7 @@ window.__ModuleLoader__.load({
3706
3721
  setMessage(t("familyUnlockAllDone") + ":" + unlockedCount + " 行" + (Array.isArray(d?.kept) && d.kept.length > 0 ? ";保留 " + d.kept.length + " 行(未通过校验)" : ""));
3707
3722
  window.setTimeout(() => window.location.reload(), 1500);
3708
3723
  },
3709
- (e) => setMessage(t("failed") + ":" + friendlyGithubError(e).message),
3724
+ (e) => setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(e).message),
3710
3725
  );
3711
3726
  },
3712
3727
  }, t("familyUnlockAll")))
@@ -3765,7 +3780,7 @@ window.__ModuleLoader__.load({
3765
3780
  : t("pendingRestartNote") + ":" + (data?.packageName ?? "") + (data?.uninstallError ? "(包卸载警告:" + data.uninstallError + ")" : ""));
3766
3781
  refresh();
3767
3782
  },
3768
- (error) => setMessage(t("failed") + ":" + friendlyGithubError(error).message),
3783
+ (error) => setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message),
3769
3784
  ).finally(() => setDeleteBusy(null));
3770
3785
  } else {
3771
3786
  setConfirmDeleteRowId(job.jobId);
@@ -4388,7 +4403,7 @@ window.__ModuleLoader__.load({
4388
4403
  ? el("div", { className: styles.rowTop },
4389
4404
  el("p", { className: styles.message, style: { flex: 1, minWidth: 0, wordBreak: "break-all" } }, t("repoLandDone") + repoLandResult.path),
4390
4405
  el("button", { type: "button", className: styles.toggle, onClick: repoLandOpenFolder }, t("repoLandOpenFolder")))
4391
- : el("p", { className: styles.message, "data-error": "true" }, t("failed") + ":" + (repoLandResult.error ?? "?")))
4406
+ : el("p", { className: styles.message, "data-error": "true" }, t("safetySwitchFailed") + ":" + (repoLandResult.error ?? "?")))
4392
4407
  : null,
4393
4408
  el("strong", { className: styles.name }, t("repoLandList") + "(" + repoLanded.length + ")"),
4394
4409
  repoLanded.length === 0
@@ -4415,7 +4430,7 @@ window.__ModuleLoader__.load({
4415
4430
  onClick: () => {
4416
4431
  call("/plugin-console/framework-relaunch", {}).then(
4417
4432
  (data) => { if (data && data.ok === true) setMessage(t("relaunchDone")); },
4418
- (error) => setMessage(t("failed") + ":" + friendlyGithubError(error).message),
4433
+ (error) => setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message),
4419
4434
  );
4420
4435
  },
4421
4436
  }, t("relaunchBtn"))
@@ -4432,7 +4447,7 @@ window.__ModuleLoader__.load({
4432
4447
  const keptNote = keptCount > 0 ? ";保留在用插件 " + keptCount + " 个" : "";
4433
4448
  if (data && data.ok === true) setMessage(t("cleanResiduals") + ":" + (data.count === 0 ? "无残余" : "已清理 " + data.count + " 项") + keptNote);
4434
4449
  },
4435
- (error) => setMessage(t("failed") + ":" + friendlyGithubError(error).message),
4450
+ (error) => setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message),
4436
4451
  );
4437
4452
  },
4438
4453
  }, "🧹 " + t("cleanResiduals")),
@@ -4472,10 +4487,10 @@ window.__ModuleLoader__.load({
4472
4487
  setMessage(t("cfDone").replace("{renamed}", String(renamed)).replace("{linked}", String(relinked)).replace("{removed}", String(removed)).replace("{mb}", String(freed))
4473
4488
  + (failed > 0 ? ";" + t("cfFailed").replace("{n}", String(failed)) : ""));
4474
4489
  },
4475
- (error) => setMessage(t("failed") + ":" + friendlyGithubError(error).message),
4490
+ (error) => setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message),
4476
4491
  );
4477
4492
  },
4478
- (error) => setMessage(t("failed") + ":" + friendlyGithubError(error).message),
4493
+ (error) => setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message),
4479
4494
  );
4480
4495
  },
4481
4496
  }, "🧰 " + t("cleanFrameworkResiduals")),
@@ -4559,10 +4574,10 @@ const lockWarn = data.lockUpdated === false && typeof data.lockNote === "string"
4559
4574
  setMessage((data.note ?? "已更新") + (lockWarn === "" ? "" : "。" + lockWarn) + ",正在重启生效…");
4560
4575
  restartServiceViaServer(setMessage, { reload: false });
4561
4576
  } else {
4562
- setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
4577
+ setMessage(t("safetySwitchFailed") + ":" + (data?.reason ?? "未知"));
4563
4578
  }
4564
4579
  },
4565
- (error) => setMessage(t("failed") + ":" + friendlyGithubError(error).message),
4580
+ (error) => setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message),
4566
4581
  );
4567
4582
  }
4568
4583
  }, "⬇ " + t("hubUpdateAvailable") + " v" + selfUpdate.latest) : null,
@@ -5146,7 +5161,7 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
5146
5161
  ? el("p", { className: styles.status }, t("loading"))
5147
5162
  : sourcesData.error !== undefined
5148
5163
  ? el("div", null,
5149
- el("p", { className: styles.status }, t("failed") + ":" + sourcesData.error),
5164
+ el("p", { className: styles.status }, t("safetySwitchFailed") + ":" + sourcesData.error),
5150
5165
  el("button", { type: "button", className: styles.toggle, onClick: () => { setSourcesData(null); openSources(); } }, t("retry")))
5151
5166
  : el("div", { className: styles.accWrap },
5152
5167
  accSection("registries", t("sourcesBtn"), [
@@ -5486,7 +5501,21 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
5486
5501
  // 2026-09-27 加法:依赖锁体检结果(null = 还没体检过;不自动跑,用户点「体检」才打接口)
5487
5502
  const [lockFix, setLockFix] = react.useState(null);
5488
5503
  const load = async () => {
5489
- try { const data = await call("/plugin-console/compat-status"); if (data !== null) setStatus(data); } catch {}
5504
+ try {
5505
+ const data = await call("/plugin-console/compat-status");
5506
+ if (data !== null) {
5507
+ setStatus(data);
5508
+ // 0.5.32 加法(D1/D4/D5):**瞬时提示**,沿用既有 note 通道(自动消失、无新组件、无按钮)。
5509
+ // 文案由服务端下发(中英双语短句):「已自动切观察者」/「框架变化,已自动预检」/「已自动禁用 N 行」。
5510
+ // 语言选择复用既有 i18n:t() 在中文下取键名本身(sentinel),在英文下取字典值。
5511
+ const isEn = t("safetyUnknown") !== "safetyUnknown";
5512
+ const pick = (pair) => (pair === null || pair === undefined ? null : (isEn ? (pair.en || pair.zh) : (pair.zh || pair.en)));
5513
+ const auto = data.autoDisable && data.autoDisable.notice ? pick(data.autoDisable.notice) : null;
5514
+ if (typeof auto === "string" && auto !== "") setNote({ text: auto });
5515
+ else if (typeof data.autoPreflight?.note?.zh === "string" && data.autoPreflight.changed === true && data.autoPreflight.scheduled !== true) setNote({ text: pick(data.autoPreflight.note) });
5516
+ else if (data.modeAuto) setNote({ text: pick(data.modeAuto.note) });
5517
+ }
5518
+ } catch {}
5490
5519
  };
5491
5520
  // 依赖锁体检:**只读**接口,不打任何写操作
5492
5521
  const lockCheck = async () => {
@@ -5690,6 +5719,9 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
5690
5719
  // 仅测试用导出(tests/test-plugin-actions.mjs 的离线渲染断言:用假 React 真渲染这个组件,
5691
5720
  // 断言"有/无 suggestedAction、执行中、成功、失败、中英切换"五种情形的 DOM 结构)。
5692
5721
  exports.SuggestedActionBox = SuggestedActionBox;
5722
+ // 仅测试用导出(tests/test-adapt-unlock-gate.mjs ①-2:断言「已适配,立即解锁」按钮的门控判据,
5723
+ // 以及它必须与卡片正文用同一个判据)。
5724
+ exports.canAdaptUnlock = canAdaptUnlock;
5693
5725
  return module.exports;
5694
5726
  }
5695
5727
  });