@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/README.md +72 -10
- package/README.zh.md +63 -5
- package/lib/client.js +85 -53
- package/lib/server/domain/auto-disable.js +226 -0
- package/lib/server/domain/auto-preflight-run.js +184 -0
- package/lib/server/domain/auto-preflight.js +345 -0
- package/lib/server/domain/compat-state.js +57 -8
- package/lib/server/domain/compat.js +10 -60
- package/lib/server/domain/patch-yaml-check.js +151 -0
- package/lib/server/domain/peer-veto.js +103 -0
- package/lib/server/domain/safe-boot.js +520 -0
- package/lib/server/domain/settings-api-scan.js +251 -0
- package/lib/server/routes/compat.js +240 -11
- package/lib/server/routes/framework-preflight.js +14 -1
- package/lib/server/routes/index.js +4 -0
- package/lib/server/routes/plugins.js +3 -1
- package/lib/server/routes/safe-boot.js +139 -0
- package/lib/server/routes/state.js +17 -3
- package/package.json +1 -1
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
2024
|
+
else { setAiRunning(false); setMessage(t("safetySwitchFailed") + ":" + (data?.error ?? "未知")); }
|
|
2017
2025
|
} catch (error) {
|
|
2018
2026
|
setAiRunning(false);
|
|
2019
|
-
setMessage(t("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
2970
|
-
(error) => setMessage(t("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
3224
|
+
setMessage(t("safetySwitchFailed") + ":" + t("gitUrlPlaceholder"));
|
|
3217
3225
|
return;
|
|
3218
3226
|
}
|
|
3219
3227
|
if (!isAllowedSourceUrl(tpl)) {
|
|
3220
|
-
setMessage(t("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
4490
|
+
(error) => setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message),
|
|
4476
4491
|
);
|
|
4477
4492
|
},
|
|
4478
|
-
(error) => setMessage(t("
|
|
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("
|
|
4577
|
+
setMessage(t("safetySwitchFailed") + ":" + (data?.reason ?? "未知"));
|
|
4563
4578
|
}
|
|
4564
4579
|
},
|
|
4565
|
-
(error) => setMessage(t("
|
|
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("
|
|
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 {
|
|
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
|
});
|