dsh-life-pack 0.2.4 → 0.2.5
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/client.js +104 -8
- package/dist/client.js.map +1 -1
- package/dist/health-view.d.ts +12 -0
- package/dist/health-view.d.ts.map +1 -1
- package/dist/health-view.js +86 -4
- package/dist/health-view.js.map +1 -1
- package/dist/nav.d.ts +1 -1
- package/dist/nav.js +1 -1
- package/dist/update-client.d.ts.map +1 -1
- package/dist/update-client.js +3 -1
- package/dist/update-client.js.map +1 -1
- package/dist/update-contract.d.ts.map +1 -1
- package/dist/update-contract.js +1 -0
- package/dist/update-contract.js.map +1 -1
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -170,6 +170,7 @@ window.__ModuleLoader__.load({
|
|
|
170
170
|
"check-expired": "上次查新版的凭证过期了:重新查一次再点安装(不要重试旧编号)。",
|
|
171
171
|
"update-busy": "同一个使用范围同时只装一个:等当前任务结束再点。",
|
|
172
172
|
"install-failed": "安装没跑成:按下面那条手工命令在终端执行一次。",
|
|
173
|
+
"manager-unreachable": "总管的电话没接上(宿主半没注册或版本对不上):重启宿主后再试;仍不行看宿主日志。",
|
|
173
174
|
"bad-request": "回执异常(请求形状不对):把宿主日志里的事件名报给作者。",
|
|
174
175
|
internal: "回执异常(总管内部错误):把宿主日志里的事件名报给作者。"
|
|
175
176
|
};
|
|
@@ -223,7 +224,7 @@ window.__ModuleLoader__.load({
|
|
|
223
224
|
payload
|
|
224
225
|
});
|
|
225
226
|
} catch (error) {
|
|
226
|
-
return failure("
|
|
227
|
+
return failure("manager-unreachable", { detail: String(error?.message ?? error) });
|
|
227
228
|
}
|
|
228
229
|
if (!result || typeof result !== "object" || typeof result.ok !== "boolean") return failure("internal", { detail: "回执信封异常(非 ok 信封)" });
|
|
229
230
|
if (result.ok) return {
|
|
@@ -770,15 +771,26 @@ window.__ModuleLoader__.load({
|
|
|
770
771
|
"aria-label": "关闭"
|
|
771
772
|
}, "×")), body, react.createElement("div", { style: PANEL_STYLE.dialogNote }, "装与更新都在宿主后台跑:关掉这块不影响正在进行的安装,再点「检查更新」可以看到最新状态。"))) : null);
|
|
772
773
|
}
|
|
773
|
-
/**
|
|
774
|
+
/** 缺席卡:**按宿主的装机读数分两态**,不让层与层的结论互相顶替。
|
|
775
|
+
*
|
|
776
|
+
* - 宿主说磁盘上没有这个包 →「未安装」+「装上」按钮(这是本票原有的能力);
|
|
777
|
+
* - 宿主说装着(`installedVersion` 非空)却没进页签槽 → 说实情、**不给「装上」**:
|
|
778
|
+
* 重装改不了产物里有没有注册代码这件事(真机实测:作息/居家/大厨/记账 的已发布 0.2.0
|
|
779
|
+
* 产物里根本没有页签槽注册,见票 #723)。给出可复制命令仅作参考。
|
|
780
|
+
*
|
|
781
|
+
* 原实现只看页签槽 ledger 就断言「未安装」——那对上面第二种情形是说假话,且点「装上」
|
|
782
|
+
* 会走进更新包的流程(它已经装着 ⇒ 没有新版 ⇒ 没有凭证)并报出误导的「查新版失败」。
|
|
783
|
+
*/
|
|
774
784
|
function AbsentCard(props) {
|
|
775
785
|
const target = props.target;
|
|
776
786
|
const row = target ? props.face.rows[target.key] : null;
|
|
777
787
|
const busy = row?.phase === "installing";
|
|
778
788
|
const manual = (target ? manualForDisplay(target, row?.failure?.manual ?? row?.outcome?.manual ?? null) : null) ?? props.fallbackCommand;
|
|
789
|
+
const installed = target ? target.installedVersion ?? target.runningVersion : null;
|
|
779
790
|
let reason = row?.failure?.message ?? null;
|
|
780
791
|
if (target && reason === null && row?.outcome && row.outcome.snapshot.blockedReason !== null) reason = verdictOf(target, row.outcome.snapshot).text;
|
|
781
|
-
|
|
792
|
+
const headline = !target ? "这个页签对应的插件还没装。" : installed === null ? "未安装[" + target.packageName + "],装上后这个页签就能用了。" : "插件已装(" + installed + "),但它这一版没把设置页接上爱生活面板:要等它发新版才对得上(重启与重装都不会变)。";
|
|
793
|
+
return react.createElement("div", { style: PANEL_STYLE.reco }, react.createElement("div", null, headline), target && installed === null ? react.createElement("button", {
|
|
782
794
|
type: "button",
|
|
783
795
|
style: busy ? {
|
|
784
796
|
...PANEL_STYLE.btn,
|
|
@@ -994,6 +1006,12 @@ window.__ModuleLoader__.load({
|
|
|
994
1006
|
yellow: "黄",
|
|
995
1007
|
green: "绿"
|
|
996
1008
|
};
|
|
1009
|
+
/** 档位的**形状**标记:颜色之外的第二条读数(灰度截图、色弱视角下也分得开谁要处理)。 */
|
|
1010
|
+
const STATUS_MARK = {
|
|
1011
|
+
red: "✕",
|
|
1012
|
+
yellow: "!",
|
|
1013
|
+
green: "✓"
|
|
1014
|
+
};
|
|
997
1015
|
/** 面板上的文字色与分隔线(与 `client.ts` 同一套别名)。 */
|
|
998
1016
|
const INK = "var(--dsw-alias-label-primary, inherit)";
|
|
999
1017
|
const INK_DIM = "var(--dsw-alias-label-secondary, #9a9a9a)";
|
|
@@ -1024,8 +1042,9 @@ window.__ModuleLoader__.load({
|
|
|
1024
1042
|
background: "transparent",
|
|
1025
1043
|
color: INK,
|
|
1026
1044
|
borderRadius: 8,
|
|
1027
|
-
padding: "
|
|
1045
|
+
padding: "6px 16px",
|
|
1028
1046
|
fontSize: 13,
|
|
1047
|
+
fontWeight: 600,
|
|
1029
1048
|
cursor: "pointer"
|
|
1030
1049
|
},
|
|
1031
1050
|
lightsRow: {
|
|
@@ -1072,6 +1091,68 @@ window.__ModuleLoader__.load({
|
|
|
1072
1091
|
const trimmed = action.trim();
|
|
1073
1092
|
return trimmed.startsWith("去哪修:") ? trimmed.slice(4).trim() : trimmed;
|
|
1074
1093
|
}
|
|
1094
|
+
/** 报文里能扫出来的每一段路径(盘符绝对路径;非 Windows 形状的退回 `/` 打头那一支)。 */
|
|
1095
|
+
function rawPathsIn(text) {
|
|
1096
|
+
return text.match(/[A-Za-z]:\/[^\s()「」,。;]+/g) ?? text.match(/\/[^\s()「」,。;]+/g) ?? [];
|
|
1097
|
+
}
|
|
1098
|
+
/** 一段落点的**根**(盘符):`C:/a/b` → `C:/`。用来把「同一个盘、但根下不同枝」的落点分开算,
|
|
1099
|
+
* 免得一个 D 盘上的旁证(比如「配了但目录不在:D:/media」)把 C 盘那几条的缩写全拖没。 */
|
|
1100
|
+
function rootOf(path) {
|
|
1101
|
+
const drive = /^[A-Za-z]:\//.exec(path);
|
|
1102
|
+
return drive === null ? "/" : drive[0];
|
|
1103
|
+
}
|
|
1104
|
+
/** 一段落点的公共目录前缀(按 `/` 切、整段比):`C:/a/b/c` + `C:/a/b/d` → `C:/a/b`。 */
|
|
1105
|
+
function commonDirOf(paths) {
|
|
1106
|
+
if (paths.length < 2) return "";
|
|
1107
|
+
const split = paths.map((path) => path.replace(/[.,。;]+$/, "").split("/"));
|
|
1108
|
+
const first = split[0];
|
|
1109
|
+
let size = 0;
|
|
1110
|
+
while (size < first.length && split.every((parts) => parts[size] === first[size])) size += 1;
|
|
1111
|
+
return size < 1 ? "" : first.slice(0, size).join("/");
|
|
1112
|
+
}
|
|
1113
|
+
/** 一份报文里**按根分开**的落点前缀(长的在前):只给「同一个根下至少两条落点」的根算前缀——
|
|
1114
|
+
* 这个根下只有一条落点时不缩(没有第二条可比,缩出来反而是瞎猜)。
|
|
1115
|
+
* 为什么要分根:一家报里常有别的盘的旁证(备忘录用 D 盘上那份媒体目录),只算一个总前缀,
|
|
1116
|
+
* 一条旁证就能把整张表的缩写全拖没(#706 出图复评:备忘录那张表整片没缩、记账那张缩了)。 */
|
|
1117
|
+
function dirPrefixesOf(report) {
|
|
1118
|
+
return dirPrefixesIn(pathsOf(report).join(" "));
|
|
1119
|
+
}
|
|
1120
|
+
/** `dirPrefixesOf` 的正文版:一段文字里(报文正文 + 表头两条混在一起)按根分组取公共目录前缀。 */
|
|
1121
|
+
function dirPrefixesIn(text) {
|
|
1122
|
+
const paths = rawPathsIn(text);
|
|
1123
|
+
const roots = [...new Set(paths.map(rootOf))];
|
|
1124
|
+
const prefixes = [];
|
|
1125
|
+
for (const root of roots) {
|
|
1126
|
+
const prefix = commonDirOf(paths.filter((path) => rootOf(path) === root));
|
|
1127
|
+
if (prefix !== "") prefixes.push(prefix);
|
|
1128
|
+
}
|
|
1129
|
+
return prefixes.sort((a, b) => b.length - a.length);
|
|
1130
|
+
}
|
|
1131
|
+
/** 那一行「配置文件 … · 数据目录 …」+ 各条报文里的长路径,都缩成「公共前缀 + 短尾巴」。 */
|
|
1132
|
+
function shorten(path, prefixes) {
|
|
1133
|
+
const hit = prefixes.find((prefix) => path.startsWith(prefix + "/"));
|
|
1134
|
+
return hit === void 0 ? path : "…/" + path.slice(hit.length + 1);
|
|
1135
|
+
}
|
|
1136
|
+
/** 一家里所有会印出来的路径。 */
|
|
1137
|
+
function pathsOf(report) {
|
|
1138
|
+
const out = [report.configPath, report.dataDir];
|
|
1139
|
+
for (const item of report.items) out.push(item.message);
|
|
1140
|
+
return out;
|
|
1141
|
+
}
|
|
1142
|
+
/** 把报文里那一长串路径按公共前缀缩短(只动打印,不动事实)。
|
|
1143
|
+
* 只按**扫得出来的那一段段落点**去缩,不做全串替换:既不误伤长路径,也不会把一段路劈成半截。 */
|
|
1144
|
+
function shortenPathsIn(text, prefixes) {
|
|
1145
|
+
const candidates = rawPathsIn(text);
|
|
1146
|
+
if (candidates.length === 0) return text;
|
|
1147
|
+
const longestFirst = [...new Set(candidates.map((path) => path.replace(/[.,。;]+$/, "")))].sort((a, b) => b.length - a.length);
|
|
1148
|
+
let out = text;
|
|
1149
|
+
for (const path of longestFirst) {
|
|
1150
|
+
const hit = prefixes.find((prefix) => path.startsWith(prefix + "/"));
|
|
1151
|
+
if (hit === void 0) continue;
|
|
1152
|
+
out = out.split(hit + "/").join("…/");
|
|
1153
|
+
}
|
|
1154
|
+
return out;
|
|
1155
|
+
}
|
|
1075
1156
|
/** 从六份报告数出那一行的灯(每家按最严重那一档上色)。 */
|
|
1076
1157
|
function lightsOf(tabs, reports) {
|
|
1077
1158
|
return tabs.map((tab) => {
|
|
@@ -1149,13 +1230,17 @@ window.__ModuleLoader__.load({
|
|
|
1149
1230
|
* **正常的**(绿)收成一行并列的小字,点得到、扫得完(票面验收第一条:正常的收成一行,有问题的才展开)。 */
|
|
1150
1231
|
function HealthTable(props) {
|
|
1151
1232
|
const { report } = props;
|
|
1233
|
+
const prefixes = report ? dirPrefixesOf(report) : [];
|
|
1152
1234
|
return react.createElement("div", {
|
|
1153
1235
|
style: HEALTH_STYLE.box,
|
|
1154
1236
|
"data-ilife-health": "table"
|
|
1155
1237
|
}, react.createElement("div", { style: HEALTH_STYLE.headRow }, react.createElement("div", { style: HEALTH_STYLE.head }, props.title + " · 体检"), report ? react.createElement("div", { style: {
|
|
1156
1238
|
color: INK_DIM,
|
|
1157
1239
|
fontSize: 12
|
|
1158
|
-
} }, countsText(countByStatus(report.items))) : null), props.phase === "idle" ? react.createElement("div", { style: HEALTH_STYLE.meta }, "还没体检:点上面那个「体检一次」。") : null, props.phase === "running" ? react.createElement("div", { style: HEALTH_STYLE.meta }, "正在体检…") : null, props.error !== null ? react.createElement("div", { style: HEALTH_STYLE.error }, props.error) : null, report ? react.createElement("div", null, react.createElement("div", {
|
|
1240
|
+
} }, countsText(countByStatus(report.items))) : null), props.phase === "idle" ? react.createElement("div", { style: HEALTH_STYLE.meta }, "还没体检:点上面那个「体检一次」。") : null, props.phase === "running" ? react.createElement("div", { style: HEALTH_STYLE.meta }, "正在体检…") : null, props.error !== null ? react.createElement("div", { style: HEALTH_STYLE.error }, props.error) : null, report ? react.createElement("div", null, react.createElement("div", {
|
|
1241
|
+
style: HEALTH_STYLE.meta,
|
|
1242
|
+
title: prefixes.join(" ")
|
|
1243
|
+
}, "配置文件 " + shorten(report.configPath, prefixes) + " · 数据目录 " + shorten(report.dataDir, prefixes)), report.items.filter(isAttentionItem).map((item) => react.createElement("div", {
|
|
1159
1244
|
key: item.id,
|
|
1160
1245
|
"data-ilife-health": "item",
|
|
1161
1246
|
"data-status": item.status,
|
|
@@ -1173,7 +1258,15 @@ window.__ModuleLoader__.load({
|
|
|
1173
1258
|
flexWrap: "wrap",
|
|
1174
1259
|
alignItems: "center",
|
|
1175
1260
|
gap: 6
|
|
1176
|
-
} }, react.createElement("span", {
|
|
1261
|
+
} }, react.createElement("span", {
|
|
1262
|
+
style: {
|
|
1263
|
+
color: STATUS_TEXT[item.status],
|
|
1264
|
+
fontWeight: 700,
|
|
1265
|
+
fontSize: 13,
|
|
1266
|
+
lineHeight: 1
|
|
1267
|
+
},
|
|
1268
|
+
"aria-hidden": "true"
|
|
1269
|
+
}, STATUS_MARK[item.status]), react.createElement("span", { style: {
|
|
1177
1270
|
width: 8,
|
|
1178
1271
|
height: 8,
|
|
1179
1272
|
borderRadius: "50%",
|
|
@@ -1185,7 +1278,10 @@ window.__ModuleLoader__.load({
|
|
|
1185
1278
|
} }, item.title), react.createElement("span", { style: {
|
|
1186
1279
|
color: STATUS_TEXT[item.status],
|
|
1187
1280
|
fontWeight: 700
|
|
1188
|
-
} }, STATUS_LABEL[item.status]), item.source ? react.createElement("span", { style: { color: INK_DIM } }, "· 来自" + item.source) : null), react.createElement("div", {
|
|
1281
|
+
} }, STATUS_LABEL[item.status]), item.source ? react.createElement("span", { style: { color: INK_DIM } }, "· 来自" + item.source) : null), react.createElement("div", {
|
|
1282
|
+
style: { color: INK },
|
|
1283
|
+
title: item.message
|
|
1284
|
+
}, shortenPathsIn(item.message, prefixes)), item.action.length > 0 ? react.createElement("div", { style: { color: INK_DIM } }, "去哪修:" + actionText(item.action)) : null)), report.items.some((item) => !isAttentionItem(item)) ? react.createElement("div", {
|
|
1189
1285
|
"data-ilife-health": "ok",
|
|
1190
1286
|
style: {
|
|
1191
1287
|
display: "flex",
|
|
@@ -1463,7 +1559,7 @@ window.__ModuleLoader__.load({
|
|
|
1463
1559
|
setActiveId(next.plugin);
|
|
1464
1560
|
tabRefs.current[nextIndex]?.focus();
|
|
1465
1561
|
}
|
|
1466
|
-
return react.createElement("div", null, react.createElement("div", { style: S.headRow }, react.createElement("div", { style: S.head }, "爱生活"), react.createElement("div", { style: S.headActions }, react.createElement(CheckUpdateButton, { face }), react.createElement(PanelActions, null))), react.createElement("div", { style: S.meta }, react.createElement("div", null, "总开关 · 开关(缺省启用,只读)"), react.createElement("div", null, "总管 dsh-life-pack · 0.2.
|
|
1562
|
+
return react.createElement("div", null, react.createElement("div", { style: S.headRow }, react.createElement("div", { style: S.head }, "爱生活"), react.createElement("div", { style: S.headActions }, react.createElement(CheckUpdateButton, { face }), react.createElement(PanelActions, null))), react.createElement("div", { style: S.meta }, react.createElement("div", null, "总开关 · 开关(缺省启用,只读)"), react.createElement("div", null, "总管 dsh-life-pack · 0.2.5")), react.createElement(UpdateResults, { face }), react.createElement(HealthOverview, {
|
|
1467
1563
|
lights: lightsOf(rows.map((row) => ({
|
|
1468
1564
|
id: row.id,
|
|
1469
1565
|
title: labelForTab(row.id)
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["IDLE","React","React","React","React"],"sources":["../src/nav.ts","../src/update-contract.ts","../src/update-client.ts","../src/update-view.ts","../src/update-panel.ts","../src/health-contract.ts","../src/health-fetch.ts","../src/health-panel.ts","../src/health-view.ts","../src/client.ts"],"sourcesContent":["/** dsh-life-pack 导航表(P10 脚手架,P3 #4 定案 order)。\n *\n * 总管只导航:6 tab 描述子仅做 openTab 路径导航,内容由各单品包自注册\n * slot 提供;总管不 import 任何单品页/单品包(见 boundaries 断言)。\n * 缺席纯条件渲染:present 缺谁就回谁的 reco(推荐安装+补装提示),不轮询。\n * 子页不占栏:卡路里 diet/exercise/goal 等 ilife:calorie:* 后缀只在单品\n * 主面板内导航,绝不在此表另起 tab 行。\n * 60 deck:map 为 matt 探针已占位,本表不动它。\n *\n * 面板外壳的两张文案表也在本文件(票 #679):右上角两个入口 PANEL_LINKS、\n * 底部「作者其他插件」卡 MORE_PLUGINS。文案与网址集中在这里,\n * 组件只负责画——改文案不碰组件(map #671 的 Q11 决议)。\n */\n\nexport interface ManagerTab {\n readonly skill: string;\n readonly slotId: string;\n readonly order: number;\n readonly title: string;\n /** 提供该 tab 的单品插件包名(仅文档级引用,不 import)。 */\n readonly plugin: string;\n}\n\nexport interface RecoTab extends ManagerTab {\n readonly kind: 'reco';\n /** 补装命令(单命令双包口径,总管必须已在位)。 */\n readonly installCmd: string;\n readonly hint: string;\n}\n\nexport const MANAGER_PLUGIN = 'dsh-life-pack' as const;\n\n/** 总管版本号(与 package.json 同步,release 时一起 bump;设置页总设置区版本行唯一来源)。 */\nexport const MANAGER_VERSION = '0.2.4' as const;\n\nexport const DUAL_ADD_PREFIX = 'dsh plugin add dsh-life-pack' as const;\n\nexport function dualInstallCmd(singlePlugin: string): string {\n return DUAL_ADD_PREFIX + ' ' + singlePlugin;\n}\n\n/** P3 定案 6 tab(order 升序即 + 号菜单顺序;已打开条不受 order 控制)。 */\nexport const MANAGER_TABS: readonly ManagerTab[] = [\n { skill: 'memo', slotId: 'ilife:memo', order: 70, title: '备忘录', plugin: 'dsh-memo-ilife' },\n { skill: 'calorie', slotId: 'ilife:calorie', order: 75, title: '卡路里', plugin: 'dsh-calorie' },\n { skill: 'schedule', slotId: 'ilife:schedule', order: 80, title: '作息', plugin: 'dsh-schedule-ilife' },\n { skill: 'home', slotId: 'ilife:home', order: 85, title: '居家', plugin: 'dsh-home-ilife' },\n { skill: 'chef', slotId: 'ilife:chef', order: 90, title: '大厨', plugin: 'dsh-chef' },\n { skill: 'bill', slotId: 'ilife:cookie', order: 95, title: '记账', plugin: 'dsh-bill-ilife' },\n];\n\nexport function recoFor(tab: ManagerTab): RecoTab {\n const installCmd = dualInstallCmd(tab.plugin);\n return {\n ...tab,\n kind: 'reco',\n installCmd,\n hint: '未安装[' + tab.plugin + '],请补装后使用:' + installCmd,\n };\n}\n\nexport type Presence = ReadonlySet<string>;\n\nexport function tabsForPresence(present: Presence): readonly (ManagerTab | RecoTab)[] {\n return MANAGER_TABS.map((t) => (present.has(t.slotId) ? t : recoFor(t)));\n}\n\nexport interface OpenPort {\n openTab(seed: { readonly type: string; readonly path: string }, scope?: { readonly sessionId?: string }): void;\n}\n\nexport interface HasTabsPort extends OpenPort {\n hasTabs(): boolean;\n}\n\n/** 总管导航:只做 openTab 路径导航(内容型打开),缺席由调用方渲染 reco。 */\nexport function openManagerTab(port: HasTabsPort, slotId: string, sessionId?: string): void {\n if (!port.hasTabs()) return;\n port.openTab({ type: slotId, path: slotId }, sessionId ? { sessionId } : undefined);\n}\n\n/** 面板右上角一个入口:图标 + 悬停说明 + 目标网址。 */\nexport interface PanelLinkRow {\n readonly key: 'star' | 'feedback';\n /** 图标字形(照参照实现 dsh-mattpocock-skills-deck,星星只留 ⭐、反馈只留 💬)。 */\n readonly glyph: string;\n /** 鼠标悬停给出的说明文字。 */\n readonly tip: string;\n readonly url: string;\n}\n\n/** 面板右上角两个入口:星(去本仓点 star)+ 气泡(去本仓开 issue)。\n *\n * 两处都指本仓 FeatherHunter/ilife——这是 map #671 裁定过的(「星与气泡指向哪个仓」\n * 一问:反馈要落在本仓的需求池,「引流到作者其他技能」是底部那张卡的事)。\n * 三件并排里的第三件「检查更新」住隔壁票(#678),本表不管它。\n */\nexport const PANEL_LINKS: readonly PanelLinkRow[] = [\n { key: 'star', glyph: '⭐', tip: '去 GitHub 点 Star', url: 'https://github.com/FeatherHunter/ilife' },\n { key: 'feedback', glyph: '💬', tip: '反馈问题', url: 'https://github.com/FeatherHunter/ilife/issues/new' },\n];\n\n/** 底部「作者其他插件」卡里的一行:包名 + 一句说明 + 行尾外链图标指向的仓库。 */\nexport interface MorePluginRow {\n readonly pkg: string;\n readonly desc: string;\n readonly url: string;\n}\n\n/** 「作者其他插件」四行:包名 + 一句说明 + 仓库地址。\n *\n * 文案口径(用户 2026-09-18 拍板):**不写数字**——数字会过期(用户截图里的「34 款」实测已到 38 款),\n * 写错最伤推荐位的可信度;第一行也不用 deck 自己面板里的自指「本面板自己」,改成不自指的说法。\n * 只收真实存在的仓库,网址已逐个验真。第一行的说明描述的是 deck 那个包(工程技能面板),不是爱生活面板。\n */\nexport const MORE_PLUGINS: readonly MorePluginRow[] = [\n {\n pkg: 'dsh-mattpocock-skills-deck',\n desc: '工程技能面板:装好就能在右侧直接用',\n url: 'https://github.com/FeatherHunter/dsh-mattpocock-skills-deck',\n },\n {\n pkg: 'dsh-opencode-palette',\n desc: '多款长时间编程护眼配色,一键换上',\n url: 'https://github.com/FeatherHunter/dsh-opencode-palette',\n },\n {\n pkg: 'dsh-prompt',\n desc: '常用提示模板随手点,不用来回复制粘贴',\n url: 'https://github.com/FeatherHunter/dsh-prompt',\n },\n {\n pkg: 'dsh-im-companion',\n desc: '聊天机器人的伴侣插件:扫码或填凭据就把飞书、微信等聊天接进来',\n url: 'https://github.com/FeatherHunter/dsh-im-companion',\n },\n];\n","/** 总管与面板之间的定案形状:载体、电话名、原因人话表、手工兜底命令。\n *\n * 分工:本文件只管「两侧都认的常量与文案」;宿主半见 `update-host.ts`,面板见 `client.ts`。\n * 电话名分两类:\n * - 七个**更新电话组**(每组三个 `updateStatus` / `updateCheck` / `updateInstall`)由更新包\n * 自己拼(`update.phoneNames`),面板侧取值见构建期派生的 `update-phones.ts`;\n * - 两个**总管自有电话**(装上缺席包、取版本行数据)是本包定义的,见 `MANAGER_ACTIONS`。\n *\n * 原因码的人话文案逐条抄更新包 README 第 8 节「用户该做什么」列与第 12 节排错表;\n * 手工命令形状抄第 9 节(`commands.ts:104-122` 的 `manualCommand`)。\n */\nimport type { BlockedReason } from 'dsh-plugin-update';\n\n/** 载体:宿主注册 `connection.fetch.register` 的路径 / 面板 `connection.rpc.call` 的两段参数。 */\nexport const MANAGER_RPC = {\n /** 载体基段(`connection.rpc.call` 的**第一段**参数)。传错第一段就是 404:真机上踩过一次。 */\n base: '/api',\n /** 单段通道名,须 match `/^\\/[A-Za-z0-9._~-]+$/`(cookbook §6)。 */\n channel: '/ilife-manager',\n /** 面板侧第二段参数(等于通道名去掉前导斜杠那一段)。 */\n endpoint: 'ilife-manager',\n /** 宿主侧注册的完整路径(= `base` + `channel`)。 */\n path: '/api/ilife-manager',\n} as const;\n\n/** 总管自有电话名:更新包的三个动作名是冻结集合(`config.ts:14`),这里另起名字不撞车。 */\nexport const MANAGER_ACTIONS = {\n /** 装上缺席的目标包:入参 `{packageName, version}`,回包 `{packageName, version}`。 */\n install: 'ilife-manager.install',\n /** 七个更新目标的表:入参 `{}`,回包 `{targets: [{key, title, packageName, phones, runningVersion, installedVersion, skill}]}`。\n *\n * 电话名为什么由宿主转交而不是面板侧写死:更新包的三个电话名只有它自己知道\n * (`update.phoneNames`,`host.ts:335`);面板侧既不能 import 更新包(浏览器产物纯度门)\n * 也不该把名字再写一份(写两份必然走散)。宿主把名字表连同版本行一起交出去,\n * 面板一行字面量都不留。 */\n targets: 'ilife-manager.targets',\n} as const;\n\n/** 更新包默认官方源(`config.ts:20`,总管侧拼手工命令时用同一个值)。 */\nexport const DEFAULT_REGISTRY = 'https://registry.npmjs.org/' as const;\n\n/** 装不了 / 装不成的人话原因表:八种 `blockedReason` + 过程错误码(更新包 README 第 8、12 节)。 */\nconst REASON_TEXT: Record<string, string> = {\n 'unknown-profile': '使用范围认不出(名字非法或目录不存在):先检查使用范围名与目录,这种情形不给手工命令。',\n 'source-install': '当前是从源码装的,不是按版本号装的:想走更新,先按版本号重装一次。',\n 'invalid-installation': '已装的包不完整(名字对不上、版本非法、入口文件缺失):重装当前版本,修好已装目录再查。',\n 'installation-changed': '安装位置在使用中途变了:重新打开宿主再查一次;还出现就重装。',\n 'pending-restart': '新版已装到磁盘,正在跑的还是旧版:重启宿主后生效。',\n 'registry-conflict': '本地声明的版本与磁盘实际版本互相矛盾:打开使用范围的清单,把目标包名那行改成版本号再试。',\n 'incompatible-node': '新版要求的 Node 与当前运行的 Node 对不上:先把 Node 升到 22 或更高,再查。',\n 'recovery-required': '上次安装被打断,留下一个半截任务:重新点一次安装;一直出现就查宿主日志。',\n 'check-failed': '查新版失败(联网不通或官方源不可达):检查网络与官方源地址,再查一次。',\n 'invalid-release': '远端发行信息不合规(名字对不上、版本非法、包地址或完整性校验不过):换个版本再查。',\n 'check-expired': '上次查新版的凭证过期了:重新查一次再点安装(不要重试旧编号)。',\n 'update-busy': '同一个使用范围同时只装一个:等当前任务结束再点。',\n 'install-failed': '安装没跑成:按下面那条手工命令在终端执行一次。',\n 'bad-request': '回执异常(请求形状不对):把宿主日志里的事件名报给作者。',\n internal: '回执异常(总管内部错误):把宿主日志里的事件名报给作者。',\n};\n\n/** 原因码 → 人话(认不出的码不猜、原样回码并说明这是未知原因)。 */\nexport function reasonText(code: string): string {\n return REASON_TEXT[code] ?? '未知原因(' + code + '):把宿主日志里的事件名报给作者。';\n}\n\n/** 手工兜底命令(更新包 README 第 9 节形状):使用范围名含特殊字符时加引号。 */\nexport function manualInstallCommand(input: {\n profileName: string | null;\n packageName: string;\n version: string;\n registryUrl?: string;\n}): string | null {\n const name = typeof input.profileName === 'string' ? input.profileName.trim() : '';\n if (!name || name.length > 255 || name.startsWith('-') || ['.', '..', 'node_modules'].includes(name)) return null;\n const version = typeof input.version === 'string' && /^\\d+\\.\\d+\\.\\d+$/.test(input.version) ? input.version : '';\n if (!version) return null;\n const registry = input.registryUrl ?? DEFAULT_REGISTRY;\n const profileArg = /^[A-Za-z0-9_.-]+$/.test(name) ? name : JSON.stringify(name);\n return 'dsh plugin --profile ' + profileArg + ' add --save-exact ' + input.packageName + '@' + version + ' --registry=' + registry;\n}\n\n/** 八种装不了原因码(给门禁与测试对表用;值就是 `BlockedReason` 全集)。 */\nexport const BLOCKED_REASONS: readonly BlockedReason[] = [\n 'unknown-profile',\n 'source-install',\n 'invalid-installation',\n 'installation-changed',\n 'pending-restart',\n 'registry-conflict',\n 'incompatible-node',\n 'recovery-required',\n];\n","/** 面板到宿主的三条流程(纯异步函数:无 DOM、无 react;传输口由调用方注入,便于单测)。\n *\n * 三条流程与更新包 README 的对应关系:\n * - 检查更新:`updateCheck`(第 3 节第 3 步的 `host.call(UPD_CHECK, {})`);\n * - 装上更新:`updateCheck` 拿凭证 → `updateInstall` 提交 → **按间隔轮询 `updateStatus`**\n * 直到任务离开 `installing`/`verifying`(第 3 节第 3 步与第 9 节:安装是后台跑,\n * 调用方不干等;凭证过期 `check-expired` 是正常错误码,重查一次再提交,见第 11 节);\n * - 装上缺席的包:走总管自有的 `ilife-manager.install`(更新包的三个电话只管已装的包)。\n */\nimport { MANAGER_ACTIONS, MANAGER_RPC, reasonText } from './update-contract.js';\nimport type { CheckOutcome, TargetInfo } from './update-view.js';\n\n/** 传输口(DSH 载体 `connection.rpc.call` 的形状,cookbook §6)。 */\nexport type CallFace = (\n channel: string,\n endpoint: string,\n payload: unknown,\n signal?: AbortSignal,\n) => Promise<\n | { readonly ok: true; readonly value: unknown }\n | { readonly ok: false; readonly error: { readonly code: string; readonly message: string; readonly details: Record<string, unknown> } }\n>;\n\nexport interface CallFailure {\n readonly ok: false;\n readonly code: string;\n readonly message: string;\n readonly details: Record<string, unknown>;\n /** 能给的话给一条可复制的手工命令(更新包每次回包都带,见其 README 第 9 节)。 */\n readonly manual: string | null;\n}\n\nexport type CallOutcome<T> = { readonly ok: true; readonly value: T } | CallFailure;\n\n/** 轮询上限:1 秒一次、最多 900 次(覆盖更新包 15 分钟的安装时限)。 */\nconst MAX_POLL_TRIES = 900;\n/** 轮询默认间隔(只有在宿主没给 `pollMs` 时才用;正常取值由宿主转交更新包的 panelPollMs)。 */\nconst FALLBACK_POLL_MS = 1000;\nlet requestSeq = 0;\n\nfunction failure(code: string, details: Record<string, unknown> = {}, manual: string | null = null): CallFailure {\n return { ok: false, code, message: reasonText(code), details, manual };\n}\n\n/** 取数间隔:settle 即清 timer。定时器有界重试的例外依据(p10 静态门三件套):\n * 这里有清理(clearTimeout)、有次数上限(MAX_POLL_TRIES)、间隔取自宿主转交的更新包\n * `panelPollMs`(不写死);用途是更新包 README 第 3 节要求的状态轮询(安装是后台跑,\n * 面板每秒问一次进度),不是无界重试。 */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n const timer = setTimeout(() => {\n clearTimeout(timer);\n resolve();\n }, ms);\n });\n}\n\nasync function callManager<T>(call: CallFace | null, method: string, payload: Record<string, unknown>): Promise<CallOutcome<T>> {\n if (typeof call !== 'function') return failure('internal', { detail: '宿主连接缺席:connection.rpc.call 不可用' });\n let result: Awaited<ReturnType<CallFace>>;\n try {\n // 第一段是**载体基段**(`/api`)、第二段才是本包端点;传错就是打到一个不存在的路由(真机踩过)。\n result = await call(MANAGER_RPC.base, MANAGER_RPC.endpoint, { method, payload });\n } catch (error) {\n return failure('check-failed', { detail: String((error as Error)?.message ?? error) });\n }\n if (!result || typeof result !== 'object' || typeof (result as { ok?: unknown }).ok !== 'boolean') {\n return failure('internal', { detail: '回执信封异常(非 ok 信封)' });\n }\n if (result.ok) return { ok: true, value: result.value as T };\n const error = (result as { error?: { code?: unknown; details?: unknown } }).error;\n const code = typeof error?.code === 'string' ? error.code : 'internal';\n const details = error && typeof error.details === 'object' && error.details !== null ? (error.details as Record<string, unknown>) : {};\n return failure(code, details);\n}\n\n/** 取七个更新目标的表(宿主转交更新包的三个电话名与版本行,面板不写死任何电话名)。 */\nexport async function loadTargets(call: CallFace | null): Promise<CallOutcome<{ targets: TargetInfo[]; pollMs: number }>> {\n const out = await callManager<{ targets?: TargetInfo[]; pollMs?: number }>(call, MANAGER_ACTIONS.targets, {});\n if (!out.ok) return out;\n const targets = Array.isArray(out.value?.targets) ? out.value.targets : [];\n const pollMs = typeof out.value?.pollMs === 'number' && out.value.pollMs > 0 ? out.value.pollMs : FALLBACK_POLL_MS;\n return { ok: true, value: { targets, pollMs } };\n}\n\n/** 查一家:默认查新版(`updateCheck`,顺带回最新版本与凭证);给 `phoneName` 时查那个电话。 */\nexport async function checkTarget(\n call: CallFace | null,\n target: TargetInfo,\n phoneName?: string,\n): Promise<CallOutcome<CheckOutcome>> {\n const name = phoneName ?? target.phones?.check;\n if (!target.phones || !name) return failure('bad-request', { target: target.key });\n return callManager<CheckOutcome>(call, name, {});\n}\n\n/** 装上缺席的包:版本取自查新版拿到的「最新版本」(宿主用更新包的执行器真装)。 */\nexport async function installAbsent(\n call: CallFace | null,\n target: TargetInfo,\n version: string,\n): Promise<CallOutcome<{ packageName: string; version: string }>> {\n return callManager(call, MANAGER_ACTIONS.install, { packageName: target.packageName, version });\n}\n\n/** 装上更新:查新版 → 提交安装 → 有界轮询查状态到任务收尾;凭证过期重查一次再提交。 */\nexport async function updateInstalled(\n call: CallFace | null,\n target: TargetInfo,\n pollMs: number,\n): Promise<CallOutcome<CheckOutcome>> {\n if (!target.phones) return failure('bad-request', { target: target.key });\n const first = await checkTarget(call, target);\n if (!first.ok) return first;\n let checked = first.value;\n if (!checked.receipt) {\n const code = checked.snapshot.blockedReason ?? 'check-failed';\n return failure(code, { target: target.key }, checked.manual);\n }\n requestSeq += 1;\n const requestId = 'ilife-manager-' + Date.now().toString(36) + '-' + String(requestSeq);\n let submitted = await callManager<CheckOutcome>(call, target.phones.install, {\n checkId: checked.receipt.checkId,\n requestId,\n });\n if (!submitted.ok && submitted.code === 'check-expired') {\n const again = await checkTarget(call, target);\n if (!again.ok) return again;\n checked = again.value;\n if (!checked.receipt) {\n return failure(checked.snapshot.blockedReason ?? 'check-failed', { target: target.key }, checked.manual);\n }\n submitted = await callManager<CheckOutcome>(call, target.phones.install, {\n checkId: checked.receipt.checkId,\n requestId: requestId + 'r',\n });\n }\n if (!submitted.ok) return { ...submitted, manual: submitted.manual ?? checked.manual };\n // 安装是后台跑(`service.ts:434-436`:落盘后后台跑,调用方不干等),故按间隔轮询到任务收尾。\n let latest = submitted.value;\n const interval = pollMs > 0 ? pollMs : FALLBACK_POLL_MS;\n for (let tries = 0; ; tries += 1) {\n const job = latest.snapshot.job;\n if (job === null || (job.state !== 'installing' && job.state !== 'verifying')) break;\n if (tries >= MAX_POLL_TRIES) break;\n await sleep(interval);\n const status = await checkTarget(call, target, target.phones.status);\n if (!status.ok) return status;\n latest = status.value;\n }\n return { ok: true, value: latest };\n}\n","/** 面板的视图逻辑(纯函数:无 DOM、无 node、无 react),客户端与单测共用同一份。\n *\n * 判定「有没有新版」不自己算版本号大小:更新核心已经在快照里给了结论\n * (`canInstall` 为真即有新版可装,`blockedReason` 非空即为什么装不了,见更新包 README 第 8 节),\n * 本文件只把结论翻成三种状态与一句话,不另起一套版本比较。\n */\nimport type { CheckReceipt, BlockedReason, UpdateSnapshot } from 'dsh-plugin-update';\nimport { dualInstallCmd } from './nav.js';\nimport { reasonText } from './update-contract.js';\n\n/** 一个更新目标的面板数据(宿主 `ilife-manager.targets` 的每行)。 */\nexport interface TargetInfo {\n readonly key: string;\n readonly title: string;\n readonly packageName: string;\n readonly phones: { readonly status: string; readonly check: string; readonly install: string } | null;\n /** 宿主启动那一刻磁盘上的版本;null = 启动时这个包还没装。 */\n readonly runningVersion: string | null;\n readonly installedVersion: string | null;\n /** 技能包随插件的那条精确 pin(插件包 manifest 里的 `skill-*` 依赖)。 */\n readonly skill: { readonly packageName: string; readonly version: string } | null;\n}\n\n/** 更新电话查到的结果(`updateCheck` / `updateStatus` 回包体)。 */\nexport interface CheckOutcome {\n readonly snapshot: UpdateSnapshot;\n readonly manual: string | null;\n readonly receipt: CheckReceipt | null;\n}\n\n/** 缺席:宿主启动时没装、现在磁盘上也没有(`runningVersion`/`installedVersion` 都是 null)。 */\nexport function isAbsent(target: TargetInfo): boolean {\n return target.runningVersion === null && target.installedVersion === null;\n}\n\nexport type VerdictKind = 'unknown' | 'up-to-date' | 'update-available' | 'blocked';\n\nexport interface Verdict {\n readonly kind: VerdictKind;\n /** 一句话结论(面板那行正文)。 */\n readonly text: string;\n /** 这一行给不给按钮:缺席给「装上」,有新版给「装上更新」,其余不给。 */\n readonly action: 'install' | 'update' | null;\n}\n\n/** 把快照翻成一行结论:还没查 / 已是最新 / 有新版 / 装不了(附人话原因)。 */\nexport function verdictOf(target: TargetInfo, snapshot: UpdateSnapshot): Verdict {\n const absent = isAbsent(target);\n const latest = snapshot.latestVersion;\n if (absent && latest === null) {\n return { kind: 'unknown', text: '未安装;点「检查更新」查最新版本后装上。', action: null };\n }\n if (absent) {\n return { kind: 'update-available', text: '未安装;最新版本 ' + String(latest) + '。', action: 'install' };\n }\n if (snapshot.blockedReason !== null) {\n const blocked = snapshot.blockedReason as BlockedReason;\n if (blocked === 'pending-restart') {\n return { kind: 'blocked', text: reasonText(blocked), action: null };\n }\n return { kind: 'blocked', text: reasonText(blocked), action: null };\n }\n if (latest === null) {\n return { kind: 'unknown', text: '还没查过最新版本;点「检查更新」。', action: null };\n }\n if (snapshot.canInstall) {\n return { kind: 'update-available', text: '有新版:' + String(latest) + ',点「装上更新」。', action: 'update' };\n }\n return { kind: 'up-to-date', text: '已是最新(' + String(latest) + ')。', action: null };\n}\n\n/** 待重启横幅文案(更新包 README 第 10 节:说清新版号与「重启后才生效」两件事)。 */\nexport function pendingRestartText(target: TargetInfo, snapshot: UpdateSnapshot): string | null {\n if (snapshot.blockedReason !== 'pending-restart') return null;\n const installed = snapshot.installedVersion ?? snapshot.job?.targetVersion ?? null;\n const running = snapshot.runningVersion;\n if (installed === null) return '⚠️ 新版已装好,重启宿主后生效。';\n if (installed === running) return '⚠️ 新版 ' + installed + ' 已装好,重启宿主后生效。';\n return '⚠️ 新版 ' + installed + ' 已装好,正在跑的还是 ' + running + ',重启宿主后生效。';\n}\n\n/** 面板展示的那条可复制命令(用户会照着敲的那一条)。\n *\n * 缺席包给人人都会用的**单命令双包**口径(#674 冻结的装入口径:不带版本号、不带任何开关);\n * 已装包给更新包回包里那条(`--save-exact ... --registry=` 是它 README 第 9 节的冻结合同,\n * 本仓不动它——要改只能提上游)。规范词见 docs/plugins/plugin-manager/t678-缺席即装与检查更新.md。 */\nexport function manualForDisplay(target: TargetInfo, manual: string | null): string | null {\n if (isAbsent(target)) return dualInstallCmd(target.packageName);\n return manual;\n}\n\n/** 版本行两行文字:插件包(本家) + 技能包(随插件,不单独查更新)。 */\nexport function versionLines(target: TargetInfo, snapshot: UpdateSnapshot | null): readonly string[] {\n const running = snapshot?.runningVersion ?? target.runningVersion ?? 'unknown';\n const installed = snapshot?.installedVersion ?? target.installedVersion;\n const lines = [target.packageName + ' ' + running + (installed && installed !== running ? '(磁盘已装 ' + installed + ')' : '')];\n if (target.skill) lines.push(target.skill.packageName + ' ' + target.skill.version + '(随插件,不单独查更新)');\n else lines.push('技能包随插件(不单独查更新)');\n return lines;\n}\n","/** 爱生活面板的更新界面:检查更新按钮、七家结果行、待重启横幅、缺席卡的「装上」。\n *\n * 面板侧纪律(沿 `client.ts` 既有口径):React.createElement 手写(禁 JSX)、内联 style、\n * 颜色走 DSH 主题别名(深浅主题自适应,写死值只做回退)、只用 `dsh-ctx` 镜像内的上下文成员、\n * 不 import 更新包(电话名与轮询间隔由宿主转交,见 `update-contract.ts` 的 `MANAGER_ACTIONS.targets`)。\n *\n * 视觉对照(用户给的第二张截图,参照实现 `dsh-mattpocock-skills-deck/src/client/views/SettingsPage.js:152-168`):\n * 标题右侧并排若干件——本文件出「检查更新」一件,隔壁票(爱生活面板头部与底部)在同一个\n * `actions` 容器里补星与气泡两件,故这里把容器单独留出来。\n */\nimport * as React from 'react';\nimport { checkTarget, installAbsent, loadTargets, updateInstalled } from './update-client.js';\nimport type { CallFace, CallFailure } from './update-client.js';\nimport { isAbsent, manualForDisplay, pendingRestartText, verdictOf, versionLines } from './update-view.js';\nimport type { CheckOutcome, TargetInfo } from './update-view.js';\n\n/** 面板视觉(沿用总管既有语言:内联 style,主题别名带回退)。 */\nexport const PANEL_STYLE = {\n head: { fontSize: 15, fontWeight: 700, margin: '2px 0 8px', color: 'var(--dsw-alias-label-primary, inherit)' } as React.CSSProperties,\n headRow: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8, flexWrap: 'wrap' } as React.CSSProperties,\n actions: { display: 'inline-flex', alignItems: 'center', gap: 6 } as React.CSSProperties,\n meta: { color: 'var(--dsw-alias-label-secondary, #9a9a9a)', fontSize: 12, lineHeight: 1.7, marginBottom: 10 } as React.CSSProperties,\n tablist: { display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 10 } as React.CSSProperties,\n tab: {\n border: '1px solid var(--dsw-alias-border, rgba(128,128,128,.35))',\n background: 'transparent',\n color: 'var(--dsw-alias-label-primary, inherit)',\n borderRadius: 999,\n padding: '4px 12px',\n fontSize: 13,\n cursor: 'pointer',\n } as React.CSSProperties,\n tabActive: {\n background: 'var(--dsw-alias-brand-primary, #0a84ff)',\n borderColor: 'transparent',\n color: '#fff',\n fontWeight: 700,\n } as React.CSSProperties,\n reco: {\n padding: '12px 14px',\n borderRadius: 10,\n border: '1px dashed var(--dsw-alias-border, rgba(128,128,128,.45))',\n color: 'var(--dsw-alias-label-secondary, #9a9a9a)',\n fontSize: 13,\n lineHeight: 1.7,\n } as React.CSSProperties,\n cmd: {\n display: 'block',\n marginTop: 8,\n padding: '8px 10px',\n borderRadius: 8,\n background: 'var(--dsw-alias-bg-base, rgba(128,128,128,.12))',\n color: 'var(--dsw-alias-label-primary, inherit)',\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n fontSize: 12,\n userSelect: 'all',\n } as React.CSSProperties,\n btn: {\n border: '1px solid var(--dsw-alias-border, rgba(128,128,128,.35))',\n background: 'transparent',\n color: 'var(--dsw-alias-label-primary, inherit)',\n borderRadius: 8,\n padding: '4px 12px',\n fontSize: 13,\n cursor: 'pointer',\n } as React.CSSProperties,\n banner: {\n padding: '10px 12px',\n marginBottom: 10,\n borderRadius: 8,\n border: '1px solid var(--dsw-alias-state-warning-primary, #d8a300)',\n background: 'var(--dsw-alias-bg-base, rgba(216,163,0,.12))',\n color: 'var(--dsw-alias-label-primary, inherit)',\n fontSize: 13,\n lineHeight: 1.7,\n } as React.CSSProperties,\n row: {\n padding: '10px 12px',\n marginBottom: 8,\n borderRadius: 10,\n border: '1px solid var(--dsw-alias-border, rgba(128,128,128,.3))',\n fontSize: 13,\n lineHeight: 1.7,\n } as React.CSSProperties,\n rowHead: { fontWeight: 700, marginBottom: 2 } as React.CSSProperties,\n rowMeta: { color: 'var(--dsw-alias-label-secondary, #9a9a9a)', fontSize: 12 } as React.CSSProperties,\n reason: { color: 'var(--dsw-alias-state-error-primary, #ff6b6b)', fontSize: 12, marginTop: 4 } as React.CSSProperties,\n skill: { color: 'var(--dsw-alias-label-tertiary, #8a8a8a)', fontSize: 12, marginTop: 4 } as React.CSSProperties,\n overlay: {\n position: 'fixed',\n inset: 0,\n zIndex: 40,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n padding: 16,\n background: 'rgba(0,0,0,.45)',\n } as React.CSSProperties,\n dialog: {\n width: '100%',\n maxWidth: 560,\n maxHeight: '80vh',\n overflow: 'auto',\n padding: '12px 14px',\n borderRadius: 12,\n border: '1px solid var(--dsw-alias-border, rgba(128,128,128,.4))',\n background: 'var(--dsw-alias-bg-elevated, var(--dsw-alias-bg-base, #222))',\n color: 'var(--dsw-alias-label-primary, inherit)',\n boxShadow: '0 12px 32px rgba(0,0,0,.35)',\n } as React.CSSProperties,\n dialogHead: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 8,\n marginBottom: 8,\n } as React.CSSProperties,\n dialogTitle: { fontSize: 14, fontWeight: 700 } as React.CSSProperties,\n close: {\n border: '1px solid var(--dsw-alias-border, rgba(128,128,128,.35))',\n background: 'transparent',\n color: 'var(--dsw-alias-label-primary, inherit)',\n borderRadius: 8,\n width: 26,\n height: 26,\n lineHeight: 1,\n fontSize: 14,\n cursor: 'pointer',\n } as React.CSSProperties,\n dialogNote: { color: 'var(--dsw-alias-label-tertiary, #8a8a8a)', fontSize: 12, marginTop: 4 } as React.CSSProperties,\n};\n\n/** 一行的运行时状态:还没查 / 查着 / 有结果 / 装着 / 出错。 */\nexport interface UpdateRowState {\n readonly phase: 'idle' | 'checking' | 'ready' | 'installing' | 'failed';\n readonly outcome: CheckOutcome | null;\n readonly failure: CallFailure | null;\n}\n\nexport interface UpdateRowsFace {\n readonly targets: readonly TargetInfo[];\n readonly rows: Readonly<Record<string, UpdateRowState>>;\n readonly pollMs: number;\n readonly loadError: string | null;\n readonly checking: boolean;\n /** 结果浮层是否打开(点「检查更新」开,关法三种:×、点遮罩、Esc)。 */\n readonly open: boolean;\n close(): void;\n checkAll(): void;\n act(target: TargetInfo): void;\n}\n\nconst IDLE: UpdateRowState = { phase: 'idle', outcome: null, failure: null };\n\n/** 面板的更新状态源:挂载时取七个目标的表,之后按需查/装(组件与按钮共用一个 face)。 */\nexport function useUpdateRows(getCall: () => CallFace | null): UpdateRowsFace {\n const [targets, setTargets] = React.useState<readonly TargetInfo[]>([]);\n const [rows, setRows] = React.useState<Record<string, UpdateRowState>>({});\n const [pollMs, setPollMs] = React.useState(1000);\n const [loadError, setLoadError] = React.useState<string | null>(null);\n const [checking, setChecking] = React.useState(false);\n const [open, setOpen] = React.useState(false);\n React.useEffect(() => {\n let alive = true;\n void (async () => {\n const loaded = await loadTargets(getCall());\n if (!alive) return;\n if (loaded.ok) {\n setTargets(loaded.value.targets);\n setPollMs(loaded.value.pollMs);\n } else {\n setLoadError(loaded.message);\n }\n })();\n return () => {\n alive = false;\n };\n }, [getCall]);\n const patch = React.useCallback((key: string, next: UpdateRowState) => {\n setRows((previous) => ({ ...previous, [key]: next }));\n }, []);\n const checkAll = React.useCallback(() => {\n setChecking(true);\n setOpen(true);\n const list = targets;\n for (const target of list) patch(target.key, { phase: 'checking', outcome: rows[target.key]?.outcome ?? null, failure: null });\n void Promise.all(\n list.map(async (target) => {\n const result = await checkTarget(getCall(), target);\n patch(target.key, result.ok ? { phase: 'ready', outcome: result.value, failure: null } : { phase: 'failed', outcome: null, failure: result });\n }),\n ).finally(() => setChecking(false));\n }, [getCall, patch, rows, targets]);\n const act = React.useCallback(\n (target: TargetInfo) => {\n const current = rows[target.key] ?? IDLE;\n patch(target.key, { ...current, phase: 'installing', failure: null });\n void (async () => {\n const absent = isAbsent(target);\n let version = current.outcome?.snapshot.latestVersion ?? null;\n if (absent && version === null) {\n const checked = await checkTarget(getCall(), target);\n if (!checked.ok) {\n patch(target.key, { phase: 'failed', outcome: null, failure: checked });\n return;\n }\n patch(target.key, { phase: 'installing', outcome: checked.value, failure: null });\n version = checked.value.snapshot.latestVersion;\n }\n const result = absent\n ? await installAbsent(getCall(), target, version ?? '')\n : await updateInstalled(getCall(), target, pollMs);\n if (result.ok) {\n // 装完不自己编快照:向宿主问一次真实状态(装到磁盘但宿主还跑着旧版 ⇒ 待重启)。\n const refreshed = await checkTarget(getCall(), target, target.phones?.status);\n patch(target.key, refreshed.ok ? { phase: 'ready', outcome: refreshed.value, failure: null } : { phase: 'failed', outcome: null, failure: refreshed });\n return;\n }\n patch(target.key, {\n phase: 'failed',\n outcome: current.outcome,\n failure: { ...result, manual: result.manual ?? current.outcome?.manual ?? null },\n });\n })();\n },\n [getCall, patch, pollMs, rows],\n );\n return { targets, rows, pollMs, loadError, checking, open, close: () => setOpen(false), checkAll, act };\n}\n\n/** 标题右侧的「检查更新」:一个按钮一次查七家(吃 `useUpdateRows` 的表)。 */\nexport function CheckUpdateButton(props: { readonly face: UpdateRowsFace }): React.ReactElement {\n const { checking, checkAll, targets } = props.face;\n const disabled = checking || targets.length === 0;\n return React.createElement(\n 'button',\n {\n type: 'button',\n style: disabled ? { ...PANEL_STYLE.btn, opacity: 0.55, cursor: 'default' } : PANEL_STYLE.btn,\n disabled,\n onClick: checkAll,\n title: '一次查七家(总管自己 + 六个单品)的插件包版本',\n },\n checking ? '检查中…' : '检查更新',\n );\n}\n\n/** 待重启横幅:任何一家成 `pending-restart` 就常驻显示,重启宿主后自动消失(更新包 README 第 10 节)。 */\nfunction RestartBanners(props: { readonly face: UpdateRowsFace }): React.ReactElement | null {\n const lines: string[] = [];\n for (const target of props.face.targets) {\n const outcome = props.face.rows[target.key]?.outcome;\n if (!outcome) continue;\n const text = pendingRestartText(target, outcome.snapshot);\n if (text) lines.push(text);\n }\n if (lines.length === 0) return null;\n return React.createElement(\n 'div',\n { style: PANEL_STYLE.banner },\n lines.map((line, index) => React.createElement('div', { key: String(index) }, line)),\n );\n}\n\n/** 七家结果:装不了的与待重启的常驻(横幅),详细结果放**居中浮层**(点「检查更新」开)。\n *\n * 为什么是浮层:内联展开会把面板本体撑长、且它自身没有关闭控件(真机第一次做成内联后用户反馈\n * 「打开就无法收回了」)。参照实现也是浮层:`dsh-mattpocock-skills-deck/src/client/views/SettingsPage.js`\n * 的 `upd.dialog`。关法三种:右上角 ×、点遮罩、Esc(Esc 靠浮层自己拿焦点后收 keydown,\n * 不摸 window——客户端纪律禁直写 DOM 全局)。\n * 手工命令只在「装不了」或「装失败」的行显示:正常用户用不到,摊在每行上既吵又误导。\n */\nexport function UpdateResults(props: { readonly face: UpdateRowsFace }): React.ReactElement | null {\n const { targets, rows, loadError, checking, open, close } = props.face;\n const dialogRef = React.useRef<HTMLDivElement | null>(null);\n React.useEffect(() => {\n if (open) dialogRef.current?.focus();\n }, [open]);\n const shown = targets.filter((target) => rows[target.key] && rows[target.key].phase !== 'idle');\n if (loadError) return React.createElement('div', { style: PANEL_STYLE.reason }, '更新能力没接上:' + loadError);\n if (targets.length === 0) return null;\n if (shown.length === 0 && !open) return null;\n const body = shown.map((target) => {\n const row = rows[target.key];\n const snapshot = row.outcome?.snapshot ?? null;\n const verdict = snapshot ? verdictOf(target, snapshot) : null;\n const manual = manualForDisplay(target, row.failure?.manual ?? row.outcome?.manual ?? null);\n const busy = row.phase === 'installing';\n const showManual = manual !== null && (row.phase === 'failed' || verdict?.kind === 'blocked');\n return React.createElement(\n 'div',\n { key: target.key, style: PANEL_STYLE.row },\n React.createElement('div', { style: PANEL_STYLE.rowHead }, target.title + ' · ' + target.packageName),\n React.createElement(\n 'div',\n { style: PANEL_STYLE.rowMeta },\n '当前 ' +\n String(snapshot?.runningVersion ?? target.runningVersion ?? '未安装') +\n ' · 最新 ' +\n String(snapshot?.latestVersion ?? '未查'),\n ),\n React.createElement('div', null, busy ? '正在装,请稍候…' : (verdict?.text ?? (checking ? '检查中…' : ''))),\n verdict?.action\n ? React.createElement(\n 'button',\n {\n type: 'button',\n style: busy ? { ...PANEL_STYLE.btn, opacity: 0.55 } : { ...PANEL_STYLE.btn, marginTop: 6 },\n disabled: busy,\n onClick: () => props.face.act(target),\n },\n verdict.action === 'install' ? '装上' : '装上更新',\n )\n : null,\n row.failure ? React.createElement('div', { style: PANEL_STYLE.reason }, '装不上:' + row.failure.message) : null,\n versionLines(target, snapshot).map((line, index) =>\n React.createElement('div', { key: String(index), style: PANEL_STYLE.skill }, line),\n ),\n showManual ? React.createElement('code', { style: PANEL_STYLE.cmd }, manual) : null,\n );\n });\n return React.createElement(\n 'div',\n null,\n React.createElement(RestartBanners, { face: props.face }),\n open\n ? React.createElement(\n 'div',\n {\n style: PANEL_STYLE.overlay,\n role: 'presentation',\n onClick: () => close(),\n },\n React.createElement(\n 'div',\n {\n ref: dialogRef,\n tabIndex: -1,\n role: 'dialog',\n 'aria-label': '检查更新结果',\n style: PANEL_STYLE.dialog,\n onClick: (event: React.MouseEvent) => event.stopPropagation(),\n onKeyDown: (event: React.KeyboardEvent) => {\n if (event.key === 'Escape') close();\n },\n },\n React.createElement(\n 'div',\n { style: PANEL_STYLE.dialogHead },\n React.createElement('div', { style: PANEL_STYLE.dialogTitle }, '检查更新(七家)'),\n React.createElement(\n 'button',\n { type: 'button', style: PANEL_STYLE.close, onClick: () => close(), title: '关闭', 'aria-label': '关闭' },\n '×',\n ),\n ),\n body,\n React.createElement(\n 'div',\n { style: PANEL_STYLE.dialogNote },\n '装与更新都在宿主后台跑:关掉这块不影响正在进行的安装,再点「检查更新」可以看到最新状态。',\n ),\n ),\n )\n : null,\n );\n}\n\n/** 缺席卡:一句人话 +「装上」按钮(复制命令降为辅助展示);总管缺席时不显示此卡(面板也看不到)。 */\nexport function AbsentCard(props: {\n readonly target: TargetInfo | null;\n readonly fallbackCommand: string;\n readonly face: UpdateRowsFace;\n}): React.ReactElement {\n const target = props.target;\n const row = target ? props.face.rows[target.key] : null;\n const busy = row?.phase === 'installing';\n const manual = (target ? manualForDisplay(target, row?.failure?.manual ?? row?.outcome?.manual ?? null) : null) ?? props.fallbackCommand;\n let reason: string | null = row?.failure?.message ?? null;\n if (target && reason === null && row?.outcome && row.outcome.snapshot.blockedReason !== null) {\n reason = verdictOf(target, row.outcome.snapshot).text;\n }\n return React.createElement(\n 'div',\n { style: PANEL_STYLE.reco },\n React.createElement('div', null, target ? '未安装[' + target.packageName + '],装上后这个页签就能用了。' : '这个页签对应的插件还没装。'),\n target\n ? React.createElement(\n 'button',\n {\n type: 'button',\n style: busy ? { ...PANEL_STYLE.btn, marginTop: 8, opacity: 0.55 } : { ...PANEL_STYLE.btn, marginTop: 8 },\n disabled: busy,\n onClick: () => props.face.act(target),\n },\n busy ? '正在装,请稍候…' : '装上',\n )\n : null,\n reason ? React.createElement('div', { style: PANEL_STYLE.reason }, reason) : null,\n React.createElement('code', { style: PANEL_STYLE.cmd }, manual),\n );\n}\n","/** 配置体检:各家技能回给面板的那份报告的形状(唯一真相在技能侧,本件只是面板侧镜像)。\n *\n * 为什么形状这样定(票 #706「开工前的形状裁定」第一条):**判据住技能侧**。\n * 每条检查项的有效值只有技能源码算得出来(例:`resolveDbDir()` 里「空串=按默认落点」),\n * 插件包对技能的全部能力是 spawn `cmd_read` 与读 stdout 信封,看不到那些算式。所以:\n *\n * 技能侧出**判据**(每条给红/黄/绿 + 一句话 + 去哪修);\n * 插件包出**透传**(把技能回执原样交回,不重写一个字);\n * 总管出**总览与渲染**(零特例:不认任何一家,只认下面这个形状)。\n *\n * 于是「同一份数据、不许两处各算一遍」是结构上的性质:面板一次取数拿到六份报告,\n * 总览一行与各家那张表都从同一个快照读(见 `health-panel.ts` 的单一状态源)。\n *\n * 三档判据的语义(照检查表 `docs/research/check-table-671-life-panel-20260917.html`):\n * · `red`=现在用不了,必须去修;\n * · `yellow`=现在这状态能用,但有人真去用那个功能时会撞上(例:照片目录没配);\n * · `green`=正常。\n */\n\n/** 三档判据。 */\nexport type HealthStatus = 'red' | 'yellow' | 'green';\n\n/** 一条检查项的回执。 */\nexport interface HealthItem {\n /** 稳定标识:配置项就是它在配置文件里的键路径(`db.dir`),非配置项用点式名(`xunji.cli`)。 */\n readonly id: string;\n /** 页面上那一行的中文标题(技能侧定,面板不重写)。 */\n readonly title: string;\n readonly status: HealthStatus;\n /** 一句话:现在是什么状态,带上路径或门槛这类实证。 */\n readonly message: string;\n /** 去哪修。`green` 时可为空。 */\n readonly action: string;\n /** 这个值从哪来(只陈述,不判好坏):`配置文件`/`默认值`/`环境`。非取值类检查项可省。 */\n readonly source?: string;\n}\n\n/** 一家的体检报告。 */\nexport interface HealthReport {\n /** 技能名(`calorie`/`bill`/…),等于该家配置文件的主体名。 */\n readonly skill: string;\n /** 实际生效的那份配置文件路径。 */\n readonly configPath: string;\n /** 实际生效的数据目录。 */\n readonly dataDir: string;\n readonly items: readonly HealthItem[];\n}\n\n/** 体检出口:技能侧在**进分派层之前**拦下的那一类只读命令名(照三个配置命令的先例)。\n *\n * 载荷:入参 `{}`;回包 `{report}`(技能侧 envelope 的 `data`)。**只报不改**:\n * 不建目录、不写文件、不落默认配置——凡是要建目录才算得出的结论,一律当「不在」报。 */\nexport const HEALTH_CHECK_KEY = 'config.check' as const;\n\n/** 面板第二段参数(与各家的端点名同值,和各家的 `RPC_CHANNEL` 配成一次调用)。 */\nexport const HEALTH_ENDPOINT = 'config.check' as const;\n\n/** 三档排序:数字大的更严重(总览一行取**最严重**那档当那一家的灯)。 */\nconst RANK: Readonly<Record<HealthStatus, number>> = { green: 0, yellow: 1, red: 2 };\n\n/** 一家的总判据:全部项里最严重的那一档;一条都没有时回 `null`(不冒充绿)。 */\nexport function worstStatus(items: readonly HealthItem[]): HealthStatus | null {\n let worst: HealthStatus | null = null;\n for (const item of items) {\n if (worst === null || RANK[item.status] > RANK[worst]) worst = item.status;\n }\n return worst;\n}\n\n/** 三档计数(面板那一行「红 N 黄 N」用的就是它)。 */\nexport function countByStatus(items: readonly HealthItem[]): Readonly<Record<HealthStatus, number>> {\n const out = { red: 0, yellow: 0, green: 0 };\n for (const item of items) out[item.status] += 1;\n return out;\n}\n\n/** 回执校验:面板只渲染自己认得的形状,认不出即报「回执异常」,不猜、不返空冒充正常。 */\nexport function isHealthReport(raw: unknown): raw is HealthReport {\n if (typeof raw !== 'object' || raw === null) return false;\n const report = raw as Partial<HealthReport>;\n if (typeof report.skill !== 'string' || report.skill.length === 0) return false;\n if (typeof report.configPath !== 'string' || typeof report.dataDir !== 'string') return false;\n if (!Array.isArray(report.items)) return false;\n return report.items.every((item: unknown) => {\n if (typeof item !== 'object' || item === null) return false;\n const row = item as Partial<HealthItem>;\n return typeof row.id === 'string' && typeof row.title === 'string'\n && (row.status === 'red' || row.status === 'yellow' || row.status === 'green')\n && typeof row.message === 'string' && typeof row.action === 'string';\n });\n}\n","/** 面板到各家的配置体检:一次取数、六份报告(纯异步函数:无 DOM、无 react;传输口注入,便于单测)。\n *\n * 三条纪律:\n * · **只走各家自己的通道**(`rpc.call(channel, HEALTH_ENDPOINT, …)`)——总管不认任何一家、也不加\n * 任何单品的依赖;通道名从「爱生活页签槽」的账本条目带出来(各家注册时写进 options)。\n * · **一次取数,六份报告**:总览那行与各家那张表读的是同一份结果(见 `health-panel.ts` 的单一状态源),\n * 不许两处各算一遍。\n * · 有界超时:一家不回不该拖死整屏(技能侧 spawn 上限 20 s,这里给 25 s)。\n */\nimport { HEALTH_ENDPOINT, isHealthReport } from './health-contract.js';\nimport type { HealthReport } from './health-contract.js';\n\n/** 传输口(DSH 载体 `connection.rpc.call` 的形状,cookbook §6)。 */\nexport type HealthCallFace = (\n channel: string,\n endpoint: string,\n payload: unknown,\n signal?: AbortSignal,\n) => Promise<\n | { readonly ok: true; readonly value: unknown }\n | { readonly ok: false; readonly error: { readonly code: string; readonly message: string; readonly details: Record<string, unknown> } }\n>;\n\n/** 一次取数的时限(毫秒):技能侧 spawn 上限 20 s,这里留一点余量。 */\nexport const HEALTH_TIMEOUT_MS = 25_000 as const;\n\n/** 一家的一行:报告取到了就是 `report`,取不到就是 `error`(缺席的包不进这张表)。 */\nexport interface HealthFetchRow {\n /** 该家插件包名(=爱生活页签槽 id,也是缺席判定的那个 join 键)。 */\n readonly id: string;\n readonly report: HealthReport | null;\n readonly error: string | null;\n}\n\n/** 一次取数的结果:每家一行(顺序照页签顺序)。 */\nexport interface HealthFetchResult {\n readonly rows: readonly HealthFetchRow[];\n /** 取数过程本身的错(通道缺席之类),不是某一家的问题。 */\n readonly error: string | null;\n}\n\n/** 账本条目里本票要用的那一段(页签槽注册时写进 options)。 */\nexport interface HealthTabRow {\n readonly id: string;\n readonly channel: string;\n}\n\nfunction timeoutText(): string {\n return '体检超时(' + String(Math.round(HEALTH_TIMEOUT_MS / 1000)) + 's):技能没在时限内回话。';\n}\n\nasync function fetchOne(call: HealthCallFace, row: HealthTabRow): Promise<{ readonly report: HealthReport | null; readonly error: string | null }> {\n try {\n const result = await call(row.channel, HEALTH_ENDPOINT, {}, AbortSignal.timeout(HEALTH_TIMEOUT_MS));\n if (!result || typeof result !== 'object' || typeof (result as { ok?: unknown }).ok !== 'boolean') {\n return { report: null, error: '回执信封异常(非 ok 信封)。' };\n }\n if (!result.ok) {\n const error = (result as { error?: { code?: unknown; message?: unknown } }).error;\n const message = typeof error?.message === 'string' && error.message.length > 0 ? error.message : '体检没跑起来。';\n return { report: null, error: message };\n }\n const value = (result as { value?: unknown }).value;\n if (!isHealthReport(value)) return { report: null, error: '体检报告形状认不出(技能包与总管版本对不上?)。' };\n return { report: value, error: null };\n } catch (error) {\n if (error instanceof Error && (error.name === 'AbortError' || error.name === 'TimeoutError')) {\n return { report: null, error: timeoutText() };\n }\n return { report: null, error: '体检没跑起来:' + (error instanceof Error ? error.message : String(error)) };\n }\n}\n\n/** 取六家的体检报告(缺席的包不在此列,由调用方按账本判断)。 */\nexport async function loadHealthReports(call: HealthCallFace | null, tabs: readonly HealthTabRow[]): Promise<HealthFetchResult> {\n if (typeof call !== 'function') return { rows: [], error: '宿主连接缺席:connection.rpc.call 不可用' };\n const rows = await Promise.all(tabs.map(async (tab): Promise<HealthFetchRow> => {\n const one = await fetchOne(call, tab);\n return { id: tab.id, report: one.report, error: one.error };\n }));\n return { rows, error: null };\n}\n","/** 配置体检的状态源:**一份快照**喂两处(面板顶部那行总览 + 各家页签那张表)。\n *\n * 为什么是一个 hook 而不是两处各取一次(票 #706 验收第三条「同一份数据,不许两处各算一遍」):\n * 这一处取数、这一处存状态,总览与各家表都从它读 —— 那条验收因此是**结构上的性质**,不是靠自觉。\n *\n * 取数是**按需**的(点「体检一次」才跑):没有轮询、没有定时器(静态门那条「无数据轮询」照旧)。\n */\nimport * as React from 'react';\nimport { loadHealthReports } from './health-fetch.js';\nimport type { HealthCallFace, HealthTabRow } from './health-fetch.js';\nimport { worstStatus } from './health-contract.js';\nimport type { HealthReport, HealthStatus } from './health-contract.js';\n\n/** 一家的状态:没跑过/正在跑/有报告/这一家出错。 */\nexport type HealthPhase = 'idle' | 'running' | 'ready' | 'failed';\n\nexport interface HealthPanelFace {\n /** 一次取数的结果:包名 → 该家的状态(缺席的包不在表里)。 */\n readonly rows: Readonly<Record<string, { readonly phase: HealthPhase; readonly report: HealthReport | null; readonly error: string | null }>>;\n /** 取数过程本身的错(通道缺席之类)。 */\n readonly error: string | null;\n /** 正在跑。 */\n readonly running: boolean;\n /** 跑一次(六家一起)。 */\n run(): void;\n}\n\nconst IDLE = { phase: 'idle' as HealthPhase, report: null, error: null };\n\n/** 一家的灯:没报告=`null`(不冒充绿)。 */\nexport function lightOf(row: { readonly report: HealthReport | null } | undefined): HealthStatus | null {\n return row?.report ? worstStatus(row.report.items) : null;\n}\n\n/** 体检状态源:挂载时不自动跑(体检要读盘、要起子进程,按需跑),点一次跑六家。 */\nexport function useHealthPanel(getCall: () => HealthCallFace | null, tabs: readonly HealthTabRow[]): HealthPanelFace {\n const [rows, setRows] = React.useState<HealthPanelFace['rows']>({});\n const [error, setError] = React.useState<string | null>(null);\n const [running, setRunning] = React.useState(false);\n const run = React.useCallback(() => {\n const diag = (globalThis as { __T706_RUN__?: string[] }).__T706_RUN__;\n if (Array.isArray(diag)) diag.push('run:tabs=' + String(tabs.length));\n setRunning(true);\n setError(null);\n const targets = tabs;\n setRows(Object.fromEntries(targets.map((tab) => [tab.id, { ...IDLE, phase: 'running' as HealthPhase }])));\n void (async () => {\n const loaded = await loadHealthReports(getCall(), targets);\n // 渲染台的调试图(浏览器里没人写它,写入失败无所谓):只记条数与第一条的错。\n try {\n const diag = (globalThis as { __T706_RUN__?: string[] }).__T706_RUN__;\n if (Array.isArray(diag)) diag.push('rows=' + String(loaded.rows.length) + ' err=' + String(loaded.error) + ' first=' + String(loaded.rows[0]?.error ?? 'null'));\n } catch {\n /* 调试图写不进去不影响正经事 */\n }\n const next: Record<string, { phase: HealthPhase; report: HealthReport | null; error: string | null }> = {};\n for (const row of loaded.rows) {\n next[row.id] = { phase: row.report ? 'ready' : 'failed', report: row.report, error: row.error };\n }\n setRows(next);\n setError(loaded.error);\n setRunning(false);\n })();\n }, [getCall, tabs]);\n const face: HealthPanelFace = { rows, error, running, run };\n // 出图页的取数口(渲染台的 hooks 替身没有真事件环,页内点按钮那条路不落定取数)。\n // 只在有人预先挂了 `__T706_FACE_SINK__` 时写一次,浏览器里没人挂它,等于没有这一行。\n const sink = (globalThis as { __T706_FACE_SINK__?: (value: HealthPanelFace) => void }).__T706_FACE_SINK__;\n if (typeof sink === 'function') {\n try {\n sink(face);\n } catch {\n /* 出图口的错不影响正经渲染 */\n }\n }\n return face;\n}\n","/** 配置体检的两个画法:面板顶部那行总览(六家一盏灯)+ 各家那张表。\n *\n * 面板侧纪律(沿 `client.ts`/`update-panel.ts` 既有口径):`createElement` 手写(禁 JSX)、内联 style、\n * 颜色走 DSH 主题别名(深浅主题自适应,写死值只做回退)、不 import 任何单品包、不 import 技能实现。\n *\n * 判据与文案**全部来自各家技能的报告**,本件一个字都不重写——只按三档上色、按状态挑文案。\n */\nimport * as React from 'react';\nimport { countByStatus, worstStatus } from './health-contract.js';\nimport type { HealthItem, HealthReport, HealthStatus } from './health-contract.js';\n\n/** 三档的配色(绿走主题别名;红黄用实色,理由见下)。\n *\n * 红与黄为什么必须落在**不同明度带**上:这两档要一起出现在同一行灯里,用户扫一眼要能分开\n * 「红了(用不了)」与「黄了(能用但要撞上)」。评审连着两轮点「黄灯偏暗与红相近」,所以:\n * · 红=深红(暗、重);\n * · 黄=高饱和的琥珀(亮、跳)——它在白底上的对比度仍然够(`#b45309` 对白 ≈ 4.9:1)。\n * 绿不给底色:它是「正常」,不该和要处理的那两档抢注意力。 */\nconst STATUS_COLOR: Readonly<Record<HealthStatus, string>> = {\n red: '#c0392b',\n yellow: '#e08a00',\n green: 'var(--dsw-alias-state-success-primary, #4ec9a0)',\n};\n\n/** 整行底色的浅一档:饱和降一档,免得红黄行「刺眼」压过正文(评审第二轮的扣分点)。 */\nconst STATUS_TINT: Readonly<Record<HealthStatus, string>> = {\n red: 'rgba(192, 57, 43, 0.06)',\n yellow: 'rgba(224, 138, 0, 0.10)',\n green: 'transparent',\n};\n\n/** 档位词(灯里那几个字)用的色:红黄要**够深**才读得清,故另取一枚比灯更深的值。 */\nconst STATUS_TEXT: Readonly<Record<HealthStatus, string>> = {\n red: '#a5281b',\n yellow: '#8a5200',\n green: 'var(--dsw-alias-state-success-primary, #4ec9a0)',\n};\n\nconst STATUS_LABEL: Readonly<Record<HealthStatus, string>> = { red: '红', yellow: '黄', green: '绿' };\n\n/** 面板上的文字色与分隔线(与 `client.ts` 同一套别名)。 */\nconst INK = 'var(--dsw-alias-label-primary, inherit)';\nconst INK_DIM = 'var(--dsw-alias-label-secondary, #9a9a9a)';\nconst BORDER = 'var(--dsw-alias-border, rgba(128,128,128,.35))';\n\nexport const HEALTH_STYLE = {\n box: {\n padding: '10px 12px',\n marginBottom: 10,\n borderRadius: 10,\n border: '1px solid ' + BORDER,\n } as React.CSSProperties,\n headRow: { display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 8, marginBottom: 4 } as React.CSSProperties,\n head: { fontSize: 13, fontWeight: 700, color: INK } as React.CSSProperties,\n /** 「体检一次」不挤在标题右端:它单独占一行、与标题同一起始边(视觉复评两轮点「孤立在右上缺层次」)。 */\n runRow: { margin: '8px 0 10px' } as React.CSSProperties,\n btn: {\n border: '1px solid ' + BORDER,\n background: 'transparent',\n color: INK,\n borderRadius: 8,\n padding: '4px 12px',\n fontSize: 13,\n cursor: 'pointer',\n } as React.CSSProperties,\n lightsRow: { display: 'flex', flexWrap: 'wrap', gap: 8 } as React.CSSProperties,\n light: {\n display: 'inline-flex',\n alignItems: 'center',\n gap: 4,\n background: 'transparent',\n border: '1px solid ' + BORDER,\n borderRadius: 999,\n padding: '3px 10px',\n fontSize: 12.5,\n color: INK,\n cursor: 'pointer',\n } as React.CSSProperties,\n lightIdle: { cursor: 'default', color: INK_DIM } as React.CSSProperties,\n meta: { color: INK_DIM, fontSize: 12, lineHeight: 1.7, marginTop: 12 } as React.CSSProperties,\n error: { color: STATUS_COLOR.red, fontSize: 12, lineHeight: 1.7, marginTop: 6 } as React.CSSProperties,\n} as const;\n\n/** 值得一眼看见的那两档(档位名与整行文字都上色;绿行保持淡)。 */\nfunction isAttention(status: HealthStatus): boolean {\n return status === 'red' || status === 'yellow';\n}\n\n/** 「去哪修」那一行的正文:各家交回来的 action 里若已自带「去哪修:」,这里剥掉一层——\n * 面板已经带了这个前缀,两边都写就会印成「去哪修:去哪修:…」。只剥开头那一次,别的一字不动。 */\nexport function actionText(action: string): string {\n const trimmed = action.trim();\n return trimmed.startsWith('去哪修:') ? trimmed.slice(4).trim() : trimmed;\n}\n\n/** 一盏灯:一家一名一档(数到几个红黄绿)。点一下把面板切到那家的页签。 */\nexport interface HealthLightRow {\n readonly id: string;\n readonly title: string;\n readonly status: HealthStatus | null;\n readonly counts: Readonly<Record<HealthStatus, number>>;\n}\n\n/** 从六份报告数出那一行的灯(每家按最严重那一档上色)。 */\nexport function lightsOf(\n tabs: readonly { readonly id: string; readonly title: string }[],\n reports: Readonly<Record<string, HealthReport | undefined>>,\n): readonly HealthLightRow[] {\n return tabs.map((tab) => {\n const report = reports[tab.id];\n return {\n id: tab.id,\n title: tab.title,\n status: report ? worstStatus(report.items) : null,\n counts: countByStatus(report?.items ?? []),\n };\n });\n}\n\n/** 一家的一句话读数:「红 1 黄 2」,全绿就是「绿」。 */\nfunction countsText(counts: Readonly<Record<HealthStatus, number>>): string {\n const parts: string[] = [];\n if (counts.red > 0) parts.push('红 ' + String(counts.red));\n if (counts.yellow > 0) parts.push('黄 ' + String(counts.yellow));\n if (parts.length === 0) return '绿';\n return parts.join(' · ');\n}\n\n/** 顶部那行总览:六家一盏灯 + 一个「体检一次」按钮。 */\nexport function HealthOverview(props: {\n readonly lights: readonly HealthLightRow[];\n readonly running: boolean;\n readonly error: string | null;\n readonly onRun: () => void;\n readonly onJump: (id: string) => void;\n}): React.ReactElement {\n return React.createElement(\n 'div',\n { style: HEALTH_STYLE.box, 'data-ilife-health': 'overview' },\n React.createElement(\n 'div',\n { style: HEALTH_STYLE.headRow },\n React.createElement('div', { style: HEALTH_STYLE.head }, '配置体检'),\n ),\n React.createElement(\n 'div',\n { style: HEALTH_STYLE.runRow },\n React.createElement(\n 'button',\n {\n type: 'button',\n style: props.running ? { ...HEALTH_STYLE.btn, opacity: 0.55, cursor: 'default' } : HEALTH_STYLE.btn,\n disabled: props.running,\n onClick: props.onRun,\n title: '对六家各跑一次配置体检(只看不改:不建目录、不改配置)',\n },\n props.running ? '体检中…' : '体检一次',\n ),\n ),\n React.createElement(\n 'div',\n { style: HEALTH_STYLE.lightsRow, 'data-ilife-health': 'lights' },\n props.lights.map((light) =>\n React.createElement(\n 'button',\n {\n key: light.id,\n type: 'button',\n 'data-ilife-health': 'light',\n 'data-skill': light.id,\n // 档位落到按钮自身的边框与底色上:一眼扫过去先看到颜色,再读家名(票面验收:一屏看红黄)。\n style: light.status === null\n ? { ...HEALTH_STYLE.light, ...HEALTH_STYLE.lightIdle }\n : {\n ...HEALTH_STYLE.light,\n borderColor: STATUS_COLOR[light.status],\n borderWidth: 1.5,\n background: STATUS_TINT[light.status],\n },\n disabled: light.status === null,\n onClick: () => props.onJump(light.id),\n title: light.status === null\n ? '还没体检(或这一家没装)'\n : light.title + ':' + countsText(light.counts),\n },\n React.createElement('span', {\n style: {\n width: 10,\n height: 10,\n borderRadius: '50%',\n background: light.status === null ? INK_DIM : STATUS_COLOR[light.status],\n display: 'inline-block',\n },\n }),\n React.createElement('span', { style: { color: INK, fontWeight: 650 } }, light.title),\n React.createElement(\n 'span',\n { style: { color: light.status === null ? INK_DIM : STATUS_TEXT[light.status], fontWeight: 700 } },\n light.status === null ? '—' : countsText(light.counts),\n ),\n ),\n ),\n ),\n React.createElement(\n 'div',\n { style: HEALTH_STYLE.meta },\n props.error !== null ? props.error : '只看不改 · 灯=那一家最严重的一档 · 点一下跳到那家配置页',\n ),\n );\n}\n\n/** 正正常常的那些:绿条只留「名字」,一句话与「去哪修」都不印(票面验收第一条:正常的收成一行)。 */\nfunction isAttentionItem(item: HealthItem): boolean {\n return isAttention(item.status);\n}\n\n/** 一家那张表:**要处理的**(红黄)一条一块、整行上底带一句话与「去哪修」;\n * **正常的**(绿)收成一行并列的小字,点得到、扫得完(票面验收第一条:正常的收成一行,有问题的才展开)。 */\nexport function HealthTable(props: {\n readonly title: string;\n readonly phase: 'idle' | 'running' | 'ready' | 'failed';\n readonly report: HealthReport | null;\n readonly error: string | null;\n}): React.ReactElement {\n const { report } = props;\n return React.createElement(\n 'div',\n { style: HEALTH_STYLE.box, 'data-ilife-health': 'table' },\n React.createElement(\n 'div',\n { style: HEALTH_STYLE.headRow },\n React.createElement('div', { style: HEALTH_STYLE.head }, props.title + ' · 体检'),\n report ? React.createElement('div', { style: { color: INK_DIM, fontSize: 12 } }, countsText(countByStatus(report.items))) : null,\n ),\n props.phase === 'idle'\n ? React.createElement('div', { style: HEALTH_STYLE.meta }, '还没体检:点上面那个「体检一次」。')\n : null,\n props.phase === 'running' ? React.createElement('div', { style: HEALTH_STYLE.meta }, '正在体检…') : null,\n props.error !== null ? React.createElement('div', { style: HEALTH_STYLE.error }, props.error) : null,\n report\n ? React.createElement(\n 'div',\n null,\n React.createElement('div', { style: HEALTH_STYLE.meta }, '配置文件 ' + report.configPath + ' · 数据目录 ' + report.dataDir),\n report.items.filter(isAttentionItem).map((item) =>\n React.createElement(\n 'div',\n {\n key: item.id,\n 'data-ilife-health': 'item',\n 'data-status': item.status,\n // 红黄两档整行上底:扫一眼先看见「要处理的」。\n style: {\n padding: '7px 8px',\n margin: '2px 0',\n borderTop: '1px solid ' + BORDER,\n borderRadius: 6,\n fontSize: 13,\n lineHeight: 1.75,\n background: STATUS_TINT[item.status],\n },\n },\n React.createElement(\n 'div',\n { style: { display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 6 } },\n React.createElement('span', {\n style: {\n width: 8, height: 8, borderRadius: '50%', display: 'inline-block', background: STATUS_COLOR[item.status],\n },\n }),\n React.createElement('span', { style: { fontWeight: 650, color: INK } }, item.title),\n React.createElement('span', {\n style: { color: STATUS_TEXT[item.status], fontWeight: 700 },\n }, STATUS_LABEL[item.status]),\n item.source ? React.createElement('span', { style: { color: INK_DIM } }, '· 来自' + item.source) : null,\n ),\n React.createElement('div', { style: { color: INK } }, item.message),\n item.action.length > 0\n ? React.createElement('div', { style: { color: INK_DIM } }, '去哪修:' + actionText(item.action))\n : null,\n ),\n ),\n // 正常的那一档:一条都不用点开,名字排成一行(`data-ilife-health=\"ok\"` 供判据核对「一条不少」)。\n report.items.some((item) => !isAttentionItem(item))\n ? React.createElement(\n 'div',\n {\n 'data-ilife-health': 'ok',\n style: {\n display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: '2px 10px',\n marginTop: 8, paddingTop: 6, borderTop: '1px solid ' + BORDER,\n fontSize: 12, lineHeight: 1.6, color: INK_DIM,\n },\n },\n React.createElement('span', { style: { fontWeight: 650, color: INK } }, '正常 ' + String(countByStatus(report.items).green) + ' 条'),\n report.items.filter((item) => !isAttentionItem(item)).map((item) =>\n React.createElement('span', { key: item.id, 'data-ilife-health': 'ok-item' }, '· ' + item.title),\n ),\n )\n : null,\n )\n : null,\n );\n}\n","/** dsh-life-pack client 适配器(六边形:browser 侧;爱生活单卡方案)。\n *\n * 真实 DSH 契约(出处见 docs/agents/dsh-client-contract.md §5/§11):\n * - 本文件经 tsdown 打成 loader 工厂包(browser/CJS + 注册包裹),classic 执行\n * 只注册,副作用全在 factory 内;传递闭包禁 node 内建与 ESM 语法(回路\n * test/client-bundle-48.test.mjs 看门)。\n * - inject 短名 ['slots','connection']:本包现在有 RPC(装与更新的能力由宿主半提供,\n * 电话名与轮询间隔由宿主转交,面板不写死),读了 ctx.connection 就必须声明 'connection'(#48 血例)。\n * - 爱生活页签条走 slot 驱动(settings-plugins 先例,禁纯 useState 手画 tab):\n * section 声明 children 爱生活页签槽,各技能往里注册自家技能设置页;\n * tab 行从 ledger 投影(entries+getVersion+subscribe),面板用 props.renderSlot\n * 按 `{only}` 投影(一次只挂载一个)+ visited 缓存;ledger 无某技能=缺席,\n * 显示推荐安装只读文本(不返空冒充)。\n * - 组件 React.createElement 手写(禁 JSX),无数据轮询、无 document/window/process。\n * - 面板外壳两处(票 #679):标题行右上角两个入口(星/气泡,悬停出说明文字,\n * 窄窗口折到标题下方);页签面板之后是底部「作者其他插件」引流卡(四行,点开新窗口)。\n * 文案与网址都取自 nav.ts 的两张静态表,本文件只画不算。\n */\n\nimport * as React from 'react';\nimport { MANAGER_TABS, MANAGER_VERSION, MORE_PLUGINS, PANEL_LINKS, recoFor } from './nav.js';\nimport type { ManagerTab } from './nav.js';\nimport { AbsentCard, CheckUpdateButton, UpdateResults, useUpdateRows } from './update-panel.js';\nimport type { CallFace } from './update-client.js';\nimport { useHealthPanel } from './health-panel.js';\nimport { HealthOverview, HealthTable, lightsOf } from './health-view.js';\nimport { HEALTH_ENDPOINT } from './health-contract.js';\nimport type {\n ClientCtx,\n ConfigTabRow,\n LifePackSectionProps,\n SlotLedgerEntry,\n} from './dsh-ctx.js';\n\nexport const inject = ['slots', 'connection'];\n\n/** 爱生活页签槽(总管声明的 children,技能设置页注册进来;单段名,避开官方 settings.* 前缀)。 */\nexport const CONFIG_TAB_SLOT = 'ilife.config-tab' as const;\n\n/** 总管视觉(内联 style;颜色走 DSH 主题别名,深浅主题自适应,写死值只做回退;与技能面板同语言)。 */\nconst S = {\n headRow: {\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: 8,\n margin: '2px 0 8px',\n } as React.CSSProperties,\n head: { fontSize: 15, fontWeight: 700, flex: '0 0 auto', color: 'var(--dsw-alias-label-primary, inherit)' } as React.CSSProperties,\n headActions: {\n display: 'inline-flex',\n alignItems: 'center',\n gap: 2,\n marginLeft: 'auto',\n flex: '0 0 auto',\n } as React.CSSProperties,\n iconLink: {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: 26,\n height: 26,\n borderRadius: 6,\n border: '1px solid transparent',\n color: 'var(--dsw-alias-label-primary, inherit)',\n textDecoration: 'none',\n fontSize: 14,\n lineHeight: 1,\n } as React.CSSProperties,\n meta: { color: 'var(--dsw-alias-label-secondary, #9a9a9a)', fontSize: 12, lineHeight: 1.7, marginBottom: 10 } as React.CSSProperties,\n tablist: { display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 10 } as React.CSSProperties,\n tab: {\n border: '1px solid var(--dsw-alias-border, rgba(128,128,128,.35))',\n background: 'transparent',\n color: 'var(--dsw-alias-label-primary, inherit)',\n borderRadius: 999,\n padding: '4px 12px',\n fontSize: 13,\n cursor: 'pointer',\n } as React.CSSProperties,\n tabActive: {\n background: 'var(--dsw-alias-brand-primary, #0a84ff)',\n borderColor: 'transparent',\n color: '#fff',\n fontWeight: 700,\n } as React.CSSProperties,\n reco: {\n padding: '12px 14px',\n borderRadius: 10,\n border: '1px dashed var(--dsw-alias-border, rgba(128,128,128,.45))',\n color: 'var(--dsw-alias-label-secondary, #9a9a9a)',\n fontSize: 13,\n lineHeight: 1.7,\n } as React.CSSProperties,\n cmd: {\n display: 'block',\n marginTop: 8,\n padding: '8px 10px',\n borderRadius: 8,\n background: 'var(--dsw-alias-bg-base, rgba(128,128,128,.12))',\n color: 'var(--dsw-alias-label-primary, inherit)',\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n fontSize: 12,\n userSelect: 'all',\n } as React.CSSProperties,\n moreCard: {\n marginTop: 16,\n padding: '10px 12px',\n borderRadius: 10,\n border: '1px solid var(--dsw-alias-border, rgba(128,128,128,.35))',\n } as React.CSSProperties,\n moreTitle: {\n fontSize: 13,\n fontWeight: 700,\n marginBottom: 4,\n color: 'var(--dsw-alias-label-primary, inherit)',\n } as React.CSSProperties,\n moreRow: {\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: '2px 8px',\n padding: '7px 4px',\n textDecoration: 'none',\n color: 'inherit',\n } as React.CSSProperties,\n morePkg: {\n flex: '0 1 auto',\n minWidth: 0,\n overflowWrap: 'anywhere',\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n fontSize: 12,\n fontWeight: 650,\n } as React.CSSProperties,\n moreDesc: {\n flex: '1 1 180px',\n minWidth: 0,\n fontSize: 11.5,\n lineHeight: 1.6,\n color: 'var(--dsw-alias-label-secondary, #9a9a9a)',\n } as React.CSSProperties,\n moreIcon: {\n flex: '0 0 auto',\n marginLeft: 'auto',\n display: 'inline-flex',\n color: 'var(--dsw-alias-label-secondary, #9a9a9a)',\n } as React.CSSProperties,\n};\n\n/** 缺席卡的画法与流程住 `update-panel.ts`(票 #678:一句人话 +「装上」按钮 + 可复制命令),\n * `recoFor` 的补装命令仍是卡里那条辅助展示(B11 口径不变)。 */\n\n/** 标签解析(resolveSlotLabel 同形:thunk 跟活,无则空字串;见 slots lib:27-29)。 */\nfunction resolveLabel(label: SlotLedgerEntry['options']['label']): string {\n if (typeof label === 'function') return label();\n return label ?? '';\n}\n\n/** 外链图标(行尾那个;纯装饰,语义在链接自己的 aria-label/文字上)。 */\nfunction ExternalIcon(): React.ReactElement {\n return React.createElement(\n 'svg',\n {\n viewBox: '0 0 24 24',\n width: 13,\n height: 13,\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: 1.9,\n strokeLinecap: 'round',\n strokeLinejoin: 'round',\n 'aria-hidden': 'true',\n focusable: 'false',\n },\n React.createElement('path', { d: 'M13.5 4.5H19.5V10.5' }),\n React.createElement('path', { d: 'M19.5 4.5L11 13' }),\n React.createElement('path', { d: 'M18 14.5V18A2 2 0 0 1 16 20H6A2 2 0 0 1 4 18V8A2 2 0 0 1 6 6H9.5' }),\n );\n}\n\n/** 标题行右上角两件:星(去本仓点 Star)+ 气泡(去本仓开 issue),悬停出说明文字。\n *\n * 三件并排里的第三件「检查更新」住隔壁票(#678):本票只留位子——它就接在本组件之前,\n * 不画一个点了没反应的假按钮。窄窗口靠 headRow 的 flexWrap 折到标题下方,\n * 标题与两件都是 flex:'0 0 auto',谁也不挤谁。\n */\nfunction PanelActions(): React.ReactElement {\n return React.createElement(\n 'div',\n { style: S.headActions },\n PANEL_LINKS.map((link) =>\n React.createElement(\n 'a',\n {\n key: link.key,\n href: link.url,\n target: '_blank',\n rel: 'noreferrer',\n title: link.tip,\n 'aria-label': link.tip,\n style: S.iconLink,\n },\n React.createElement('span', { 'aria-hidden': 'true' }, link.glyph),\n ),\n ),\n );\n}\n\n/** 底部「作者其他插件」引流卡:四行(包名 + 一句说明 + 行尾外链图标),点开新窗口。\n *\n * 卡片在页签面板之后,六页签切换它都在(它不属于任何一个页签)。\n */\nfunction MorePluginsCard(): React.ReactElement {\n return React.createElement(\n 'div',\n { style: S.moreCard },\n React.createElement('div', { style: S.moreTitle }, '作者其他插件'),\n MORE_PLUGINS.map((row) =>\n React.createElement(\n 'a',\n {\n key: row.pkg,\n href: row.url,\n target: '_blank',\n rel: 'noreferrer',\n title: row.pkg + ' 的 GitHub 仓库',\n style: S.moreRow,\n },\n React.createElement('span', { style: S.morePkg }, row.pkg),\n React.createElement('span', { style: S.moreDesc }, row.desc),\n React.createElement('span', { style: S.moreIcon }, React.createElement(ExternalIcon, null)),\n ),\n ),\n );\n}\n\n/** 爱生活面板:总设置区 + 检查更新(七家)+ 爱生活页签条(slot 驱动)+ 技能设置页投影/缺席卡。 */\nfunction LifePackSection(props: LifePackSectionProps & { getCall: () => CallFace | null }): React.ReactElement {\n const tabsId = React.useId();\n const tabRefs = React.useRef<Array<HTMLButtonElement | null>>([]);\n const rows: ConfigTabRow[] = props.useTabs((value) => value);\n const present = new Set(rows.map((r) => r.id));\n const face = useUpdateRows(props.getCall);\n // 配置体检(#706):一张表六份报告,总览那行与各家那张表都从它读(同一份数据)。\n // 通道名由各家注册时写进页签槽 options,总管源码里不出现任何一家的通道名。\n const healthTabs = React.useMemo(\n () => rows.filter((row) => row.channel.length > 0).map((row) => ({ id: row.id, channel: row.channel })),\n [rows],\n );\n const health = useHealthPanel(() => props.getCall(), healthTabs);\n const [activeId, setActiveId] = React.useState<string | undefined>(undefined);\n const [visitedIds, setVisitedIds] = React.useState<ReadonlySet<string>>(() => new Set());\n const active = MANAGER_TABS.some((t) => t.plugin === activeId)\n ? (activeId as string)\n : MANAGER_TABS[0].plugin;\n React.useEffect(() => {\n setVisitedIds((previous) => {\n if (previous.has(active)) return previous;\n return new Set([...previous, active]);\n });\n }, [active]);\n function labelFor(tab: ManagerTab): string {\n const row = rows.find((r) => r.id === tab.plugin);\n return row && row.label.length > 0 ? row.label : tab.title;\n }\n /** 按包名取页签标题(总览那行按账本行过,账本里没有的退到导航表的标题)。 */\n function labelForTab(id: string): string {\n const row = rows.find((r) => r.id === id);\n if (row && row.label.length > 0) return row.label;\n const tab = MANAGER_TABS.find((t) => t.plugin === id);\n return tab ? tab.title : id;\n }\n function targetForTab(tab: ManagerTab) {\n return face.targets.find((t) => t.packageName === tab.plugin) ?? null;\n }\n function onTabKeyDown(event: React.KeyboardEvent, index: number): void {\n let nextIndex: number | undefined;\n switch (event.key) {\n case 'ArrowRight': nextIndex = (index + 1) % MANAGER_TABS.length; break;\n case 'ArrowLeft': nextIndex = (index - 1 + MANAGER_TABS.length) % MANAGER_TABS.length; break;\n case 'Home': nextIndex = 0; break;\n case 'End': nextIndex = MANAGER_TABS.length - 1; break;\n default: return;\n }\n event.preventDefault();\n const next = MANAGER_TABS[nextIndex];\n setActiveId(next.plugin);\n tabRefs.current[nextIndex]?.focus();\n }\n return React.createElement(\n 'div',\n null,\n React.createElement(\n 'div',\n { style: S.headRow },\n React.createElement('div', { style: S.head }, '爱生活'),\n // 三件并排:本票的「检查更新」在左,隔壁票(#679)的星与气泡在右,整组靠右(窄窗口折行)。\n React.createElement(\n 'div',\n { style: S.headActions },\n React.createElement(CheckUpdateButton, { face }),\n React.createElement(PanelActions, null),\n ),\n ),\n React.createElement(\n 'div',\n { style: S.meta },\n React.createElement('div', null, '总开关 · 开关(缺省启用,只读)'),\n React.createElement('div', null, '总管 dsh-life-pack · ' + MANAGER_VERSION),\n ),\n React.createElement(UpdateResults, { face }),\n React.createElement(HealthOverview, {\n lights: lightsOf(\n rows.map((row) => ({ id: row.id, title: labelForTab(row.id) })),\n Object.fromEntries(Object.entries(health.rows).map(([id, row]) => [id, row.report ?? undefined])),\n ),\n running: health.running,\n error: health.error,\n onRun: health.run,\n onJump: setActiveId,\n }),\n React.createElement(\n 'div',\n { role: 'tablist', 'aria-label': '爱生活技能页签', style: S.tablist },\n MANAGER_TABS.map((tab, index) => {\n const selected = tab.plugin === active;\n return React.createElement(\n 'button',\n {\n key: tab.plugin,\n ref: (element: HTMLButtonElement | null) => {\n tabRefs.current[index] = element;\n },\n id: tabsId + '-tab-' + tab.plugin,\n type: 'button',\n role: 'tab',\n 'aria-selected': selected,\n 'aria-controls': tabsId + '-panel-' + tab.plugin,\n tabIndex: selected ? 0 : -1,\n style: selected ? { ...S.tab, ...S.tabActive } : S.tab,\n onClick: () => {\n setActiveId(tab.plugin);\n },\n onKeyDown: (event: React.KeyboardEvent) => {\n onTabKeyDown(event, index);\n },\n },\n (present.has(tab.plugin) ? '● ' : '○ ') + labelFor(tab),\n );\n }),\n ),\n MANAGER_TABS.filter((tab) => tab.plugin === active || visitedIds.has(tab.plugin)).map((tab) => {\n const selected = tab.plugin === active;\n return React.createElement(\n 'div',\n {\n key: tab.plugin,\n id: tabsId + '-panel-' + tab.plugin,\n role: 'tabpanel',\n 'aria-labelledby': tabsId + '-tab-' + tab.plugin,\n hidden: !selected,\n },\n present.has(tab.plugin)\n ? React.createElement(\n 'div',\n null,\n props.renderSlot(CONFIG_TAB_SLOT, {}, { only: tab.plugin }) as React.ReactNode,\n // 那家的体检表:与总览那行读同一份快照(`health.rows`),不是各算一遍。\n React.createElement(HealthTable, {\n title: labelFor(tab),\n phase: health.rows[tab.plugin]?.phase ?? 'idle',\n report: health.rows[tab.plugin]?.report ?? null,\n error: health.rows[tab.plugin]?.error ?? null,\n }),\n )\n : React.createElement(AbsentCard, {\n target: targetForTab(tab),\n fallbackCommand: recoFor(tab).installCmd,\n face,\n }),\n );\n }),\n React.createElement(MorePluginsCard, null),\n );\n}\n\nexport function apply(ctx: ClientCtx): void {\n // 调用口取用器:每次取数时现取(connection 后到也不永久缺席),透传给面板组件。\n const getCall = (): CallFace | null => (ctx.connection?.rpc?.call as CallFace | undefined) ?? null;\n // ledger 观测源(settings-plugins:1744-1767 同形;无 locale 面声明,故只订 ledger)。\n let tabsVersion = -1;\n let tabs: ConfigTabRow[] = [];\n const sectionInjected = () => ({\n hooks: {\n tabs: {\n getSnapshot: () => {\n const version = ctx.slots.getVersion(CONFIG_TAB_SLOT);\n if (version !== tabsVersion) {\n tabsVersion = version;\n tabs = ctx.slots\n .entries(CONFIG_TAB_SLOT)\n .map((entry) => ({\n id: entry.options.id ?? '',\n order: entry.options.order ?? 0,\n label: resolveLabel(entry.options.label),\n // #706 配置体检的通道:各家注册时写进 options,缺席即这一家没有体检出口(灯显 —)。\n channel: entry.options.channel ?? '',\n }))\n .sort((a, b) => a.order - b.order);\n }\n return tabs;\n },\n subscribe: (listener: () => void) => ctx.slots.subscribe(CONFIG_TAB_SLOT, listener),\n },\n },\n });\n ctx.slots.inject('settings.section', () =>\n ctx.slots.register(\n {\n name: 'settings.section',\n id: 'dsh-life-pack',\n order: 21,\n label: () => '爱生活',\n inject: sectionInjected,\n children: { 'ilife.config-tab': { kind: 'list', scope: 'root' } },\n },\n (props: LifePackSectionProps) => React.createElement(LifePackSection, { ...props, getCall }),\n ),\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["IDLE","React","React","React","React"],"sources":["../src/nav.ts","../src/update-contract.ts","../src/update-client.ts","../src/update-view.ts","../src/update-panel.ts","../src/health-contract.ts","../src/health-fetch.ts","../src/health-panel.ts","../src/health-view.ts","../src/client.ts"],"sourcesContent":["/** dsh-life-pack 导航表(P10 脚手架,P3 #4 定案 order)。\n *\n * 总管只导航:6 tab 描述子仅做 openTab 路径导航,内容由各单品包自注册\n * slot 提供;总管不 import 任何单品页/单品包(见 boundaries 断言)。\n * 缺席纯条件渲染:present 缺谁就回谁的 reco(推荐安装+补装提示),不轮询。\n * 子页不占栏:卡路里 diet/exercise/goal 等 ilife:calorie:* 后缀只在单品\n * 主面板内导航,绝不在此表另起 tab 行。\n * 60 deck:map 为 matt 探针已占位,本表不动它。\n *\n * 面板外壳的两张文案表也在本文件(票 #679):右上角两个入口 PANEL_LINKS、\n * 底部「作者其他插件」卡 MORE_PLUGINS。文案与网址集中在这里,\n * 组件只负责画——改文案不碰组件(map #671 的 Q11 决议)。\n */\n\nexport interface ManagerTab {\n readonly skill: string;\n readonly slotId: string;\n readonly order: number;\n readonly title: string;\n /** 提供该 tab 的单品插件包名(仅文档级引用,不 import)。 */\n readonly plugin: string;\n}\n\nexport interface RecoTab extends ManagerTab {\n readonly kind: 'reco';\n /** 补装命令(单命令双包口径,总管必须已在位)。 */\n readonly installCmd: string;\n readonly hint: string;\n}\n\nexport const MANAGER_PLUGIN = 'dsh-life-pack' as const;\n\n/** 总管版本号(与 package.json 同步,release 时一起 bump;设置页总设置区版本行唯一来源)。 */\nexport const MANAGER_VERSION = '0.2.5' as const;\n\nexport const DUAL_ADD_PREFIX = 'dsh plugin add dsh-life-pack' as const;\n\nexport function dualInstallCmd(singlePlugin: string): string {\n return DUAL_ADD_PREFIX + ' ' + singlePlugin;\n}\n\n/** P3 定案 6 tab(order 升序即 + 号菜单顺序;已打开条不受 order 控制)。 */\nexport const MANAGER_TABS: readonly ManagerTab[] = [\n { skill: 'memo', slotId: 'ilife:memo', order: 70, title: '备忘录', plugin: 'dsh-memo-ilife' },\n { skill: 'calorie', slotId: 'ilife:calorie', order: 75, title: '卡路里', plugin: 'dsh-calorie' },\n { skill: 'schedule', slotId: 'ilife:schedule', order: 80, title: '作息', plugin: 'dsh-schedule-ilife' },\n { skill: 'home', slotId: 'ilife:home', order: 85, title: '居家', plugin: 'dsh-home-ilife' },\n { skill: 'chef', slotId: 'ilife:chef', order: 90, title: '大厨', plugin: 'dsh-chef' },\n { skill: 'bill', slotId: 'ilife:cookie', order: 95, title: '记账', plugin: 'dsh-bill-ilife' },\n];\n\nexport function recoFor(tab: ManagerTab): RecoTab {\n const installCmd = dualInstallCmd(tab.plugin);\n return {\n ...tab,\n kind: 'reco',\n installCmd,\n hint: '未安装[' + tab.plugin + '],请补装后使用:' + installCmd,\n };\n}\n\nexport type Presence = ReadonlySet<string>;\n\nexport function tabsForPresence(present: Presence): readonly (ManagerTab | RecoTab)[] {\n return MANAGER_TABS.map((t) => (present.has(t.slotId) ? t : recoFor(t)));\n}\n\nexport interface OpenPort {\n openTab(seed: { readonly type: string; readonly path: string }, scope?: { readonly sessionId?: string }): void;\n}\n\nexport interface HasTabsPort extends OpenPort {\n hasTabs(): boolean;\n}\n\n/** 总管导航:只做 openTab 路径导航(内容型打开),缺席由调用方渲染 reco。 */\nexport function openManagerTab(port: HasTabsPort, slotId: string, sessionId?: string): void {\n if (!port.hasTabs()) return;\n port.openTab({ type: slotId, path: slotId }, sessionId ? { sessionId } : undefined);\n}\n\n/** 面板右上角一个入口:图标 + 悬停说明 + 目标网址。 */\nexport interface PanelLinkRow {\n readonly key: 'star' | 'feedback';\n /** 图标字形(照参照实现 dsh-mattpocock-skills-deck,星星只留 ⭐、反馈只留 💬)。 */\n readonly glyph: string;\n /** 鼠标悬停给出的说明文字。 */\n readonly tip: string;\n readonly url: string;\n}\n\n/** 面板右上角两个入口:星(去本仓点 star)+ 气泡(去本仓开 issue)。\n *\n * 两处都指本仓 FeatherHunter/ilife——这是 map #671 裁定过的(「星与气泡指向哪个仓」\n * 一问:反馈要落在本仓的需求池,「引流到作者其他技能」是底部那张卡的事)。\n * 三件并排里的第三件「检查更新」住隔壁票(#678),本表不管它。\n */\nexport const PANEL_LINKS: readonly PanelLinkRow[] = [\n { key: 'star', glyph: '⭐', tip: '去 GitHub 点 Star', url: 'https://github.com/FeatherHunter/ilife' },\n { key: 'feedback', glyph: '💬', tip: '反馈问题', url: 'https://github.com/FeatherHunter/ilife/issues/new' },\n];\n\n/** 底部「作者其他插件」卡里的一行:包名 + 一句说明 + 行尾外链图标指向的仓库。 */\nexport interface MorePluginRow {\n readonly pkg: string;\n readonly desc: string;\n readonly url: string;\n}\n\n/** 「作者其他插件」四行:包名 + 一句说明 + 仓库地址。\n *\n * 文案口径(用户 2026-09-18 拍板):**不写数字**——数字会过期(用户截图里的「34 款」实测已到 38 款),\n * 写错最伤推荐位的可信度;第一行也不用 deck 自己面板里的自指「本面板自己」,改成不自指的说法。\n * 只收真实存在的仓库,网址已逐个验真。第一行的说明描述的是 deck 那个包(工程技能面板),不是爱生活面板。\n */\nexport const MORE_PLUGINS: readonly MorePluginRow[] = [\n {\n pkg: 'dsh-mattpocock-skills-deck',\n desc: '工程技能面板:装好就能在右侧直接用',\n url: 'https://github.com/FeatherHunter/dsh-mattpocock-skills-deck',\n },\n {\n pkg: 'dsh-opencode-palette',\n desc: '多款长时间编程护眼配色,一键换上',\n url: 'https://github.com/FeatherHunter/dsh-opencode-palette',\n },\n {\n pkg: 'dsh-prompt',\n desc: '常用提示模板随手点,不用来回复制粘贴',\n url: 'https://github.com/FeatherHunter/dsh-prompt',\n },\n {\n pkg: 'dsh-im-companion',\n desc: '聊天机器人的伴侣插件:扫码或填凭据就把飞书、微信等聊天接进来',\n url: 'https://github.com/FeatherHunter/dsh-im-companion',\n },\n];\n","/** 总管与面板之间的定案形状:载体、电话名、原因人话表、手工兜底命令。\n *\n * 分工:本文件只管「两侧都认的常量与文案」;宿主半见 `update-host.ts`,面板见 `client.ts`。\n * 电话名分两类:\n * - 七个**更新电话组**(每组三个 `updateStatus` / `updateCheck` / `updateInstall`)由更新包\n * 自己拼(`update.phoneNames`),面板侧取值见构建期派生的 `update-phones.ts`;\n * - 两个**总管自有电话**(装上缺席包、取版本行数据)是本包定义的,见 `MANAGER_ACTIONS`。\n *\n * 原因码的人话文案逐条抄更新包 README 第 8 节「用户该做什么」列与第 12 节排错表;\n * 手工命令形状抄第 9 节(`commands.ts:104-122` 的 `manualCommand`)。\n */\nimport type { BlockedReason } from 'dsh-plugin-update';\n\n/** 载体:宿主注册 `connection.fetch.register` 的路径 / 面板 `connection.rpc.call` 的两段参数。 */\nexport const MANAGER_RPC = {\n /** 载体基段(`connection.rpc.call` 的**第一段**参数)。传错第一段就是 404:真机上踩过一次。 */\n base: '/api',\n /** 单段通道名,须 match `/^\\/[A-Za-z0-9._~-]+$/`(cookbook §6)。 */\n channel: '/ilife-manager',\n /** 面板侧第二段参数(等于通道名去掉前导斜杠那一段)。 */\n endpoint: 'ilife-manager',\n /** 宿主侧注册的完整路径(= `base` + `channel`)。 */\n path: '/api/ilife-manager',\n} as const;\n\n/** 总管自有电话名:更新包的三个动作名是冻结集合(`config.ts:14`),这里另起名字不撞车。 */\nexport const MANAGER_ACTIONS = {\n /** 装上缺席的目标包:入参 `{packageName, version}`,回包 `{packageName, version}`。 */\n install: 'ilife-manager.install',\n /** 七个更新目标的表:入参 `{}`,回包 `{targets: [{key, title, packageName, phones, runningVersion, installedVersion, skill}]}`。\n *\n * 电话名为什么由宿主转交而不是面板侧写死:更新包的三个电话名只有它自己知道\n * (`update.phoneNames`,`host.ts:335`);面板侧既不能 import 更新包(浏览器产物纯度门)\n * 也不该把名字再写一份(写两份必然走散)。宿主把名字表连同版本行一起交出去,\n * 面板一行字面量都不留。 */\n targets: 'ilife-manager.targets',\n} as const;\n\n/** 更新包默认官方源(`config.ts:20`,总管侧拼手工命令时用同一个值)。 */\nexport const DEFAULT_REGISTRY = 'https://registry.npmjs.org/' as const;\n\n/** 装不了 / 装不成的人话原因表:八种 `blockedReason` + 过程错误码(更新包 README 第 8、12 节)。 */\nconst REASON_TEXT: Record<string, string> = {\n 'unknown-profile': '使用范围认不出(名字非法或目录不存在):先检查使用范围名与目录,这种情形不给手工命令。',\n 'source-install': '当前是从源码装的,不是按版本号装的:想走更新,先按版本号重装一次。',\n 'invalid-installation': '已装的包不完整(名字对不上、版本非法、入口文件缺失):重装当前版本,修好已装目录再查。',\n 'installation-changed': '安装位置在使用中途变了:重新打开宿主再查一次;还出现就重装。',\n 'pending-restart': '新版已装到磁盘,正在跑的还是旧版:重启宿主后生效。',\n 'registry-conflict': '本地声明的版本与磁盘实际版本互相矛盾:打开使用范围的清单,把目标包名那行改成版本号再试。',\n 'incompatible-node': '新版要求的 Node 与当前运行的 Node 对不上:先把 Node 升到 22 或更高,再查。',\n 'recovery-required': '上次安装被打断,留下一个半截任务:重新点一次安装;一直出现就查宿主日志。',\n 'check-failed': '查新版失败(联网不通或官方源不可达):检查网络与官方源地址,再查一次。',\n 'invalid-release': '远端发行信息不合规(名字对不上、版本非法、包地址或完整性校验不过):换个版本再查。',\n 'check-expired': '上次查新版的凭证过期了:重新查一次再点安装(不要重试旧编号)。',\n 'update-busy': '同一个使用范围同时只装一个:等当前任务结束再点。',\n 'install-failed': '安装没跑成:按下面那条手工命令在终端执行一次。',\n 'manager-unreachable': '总管的电话没接上(宿主半没注册或版本对不上):重启宿主后再试;仍不行看宿主日志。',\n 'bad-request': '回执异常(请求形状不对):把宿主日志里的事件名报给作者。',\n internal: '回执异常(总管内部错误):把宿主日志里的事件名报给作者。',\n};\n\n/** 原因码 → 人话(认不出的码不猜、原样回码并说明这是未知原因)。 */\nexport function reasonText(code: string): string {\n return REASON_TEXT[code] ?? '未知原因(' + code + '):把宿主日志里的事件名报给作者。';\n}\n\n/** 手工兜底命令(更新包 README 第 9 节形状):使用范围名含特殊字符时加引号。 */\nexport function manualInstallCommand(input: {\n profileName: string | null;\n packageName: string;\n version: string;\n registryUrl?: string;\n}): string | null {\n const name = typeof input.profileName === 'string' ? input.profileName.trim() : '';\n if (!name || name.length > 255 || name.startsWith('-') || ['.', '..', 'node_modules'].includes(name)) return null;\n const version = typeof input.version === 'string' && /^\\d+\\.\\d+\\.\\d+$/.test(input.version) ? input.version : '';\n if (!version) return null;\n const registry = input.registryUrl ?? DEFAULT_REGISTRY;\n const profileArg = /^[A-Za-z0-9_.-]+$/.test(name) ? name : JSON.stringify(name);\n return 'dsh plugin --profile ' + profileArg + ' add --save-exact ' + input.packageName + '@' + version + ' --registry=' + registry;\n}\n\n/** 八种装不了原因码(给门禁与测试对表用;值就是 `BlockedReason` 全集)。 */\nexport const BLOCKED_REASONS: readonly BlockedReason[] = [\n 'unknown-profile',\n 'source-install',\n 'invalid-installation',\n 'installation-changed',\n 'pending-restart',\n 'registry-conflict',\n 'incompatible-node',\n 'recovery-required',\n];\n","/** 面板到宿主的三条流程(纯异步函数:无 DOM、无 react;传输口由调用方注入,便于单测)。\n *\n * 三条流程与更新包 README 的对应关系:\n * - 检查更新:`updateCheck`(第 3 节第 3 步的 `host.call(UPD_CHECK, {})`);\n * - 装上更新:`updateCheck` 拿凭证 → `updateInstall` 提交 → **按间隔轮询 `updateStatus`**\n * 直到任务离开 `installing`/`verifying`(第 3 节第 3 步与第 9 节:安装是后台跑,\n * 调用方不干等;凭证过期 `check-expired` 是正常错误码,重查一次再提交,见第 11 节);\n * - 装上缺席的包:走总管自有的 `ilife-manager.install`(更新包的三个电话只管已装的包)。\n */\nimport { MANAGER_ACTIONS, MANAGER_RPC, reasonText } from './update-contract.js';\nimport type { CheckOutcome, TargetInfo } from './update-view.js';\n\n/** 传输口(DSH 载体 `connection.rpc.call` 的形状,cookbook §6)。 */\nexport type CallFace = (\n channel: string,\n endpoint: string,\n payload: unknown,\n signal?: AbortSignal,\n) => Promise<\n | { readonly ok: true; readonly value: unknown }\n | { readonly ok: false; readonly error: { readonly code: string; readonly message: string; readonly details: Record<string, unknown> } }\n>;\n\nexport interface CallFailure {\n readonly ok: false;\n readonly code: string;\n readonly message: string;\n readonly details: Record<string, unknown>;\n /** 能给的话给一条可复制的手工命令(更新包每次回包都带,见其 README 第 9 节)。 */\n readonly manual: string | null;\n}\n\nexport type CallOutcome<T> = { readonly ok: true; readonly value: T } | CallFailure;\n\n/** 轮询上限:1 秒一次、最多 900 次(覆盖更新包 15 分钟的安装时限)。 */\nconst MAX_POLL_TRIES = 900;\n/** 轮询默认间隔(只有在宿主没给 `pollMs` 时才用;正常取值由宿主转交更新包的 panelPollMs)。 */\nconst FALLBACK_POLL_MS = 1000;\nlet requestSeq = 0;\n\nfunction failure(code: string, details: Record<string, unknown> = {}, manual: string | null = null): CallFailure {\n return { ok: false, code, message: reasonText(code), details, manual };\n}\n\n/** 取数间隔:settle 即清 timer。定时器有界重试的例外依据(p10 静态门三件套):\n * 这里有清理(clearTimeout)、有次数上限(MAX_POLL_TRIES)、间隔取自宿主转交的更新包\n * `panelPollMs`(不写死);用途是更新包 README 第 3 节要求的状态轮询(安装是后台跑,\n * 面板每秒问一次进度),不是无界重试。 */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n const timer = setTimeout(() => {\n clearTimeout(timer);\n resolve();\n }, ms);\n });\n}\n\nasync function callManager<T>(call: CallFace | null, method: string, payload: Record<string, unknown>): Promise<CallOutcome<T>> {\n if (typeof call !== 'function') return failure('internal', { detail: '宿主连接缺席:connection.rpc.call 不可用' });\n let result: Awaited<ReturnType<CallFace>>;\n try {\n // 第一段是**载体基段**(`/api`)、第二段才是本包端点;传错就是打到一个不存在的路由(真机踩过)。\n result = await call(MANAGER_RPC.base, MANAGER_RPC.endpoint, { method, payload });\n } catch (error) {\n // 传输层失败(路由没注册、宿主半版本对不上、请求挂了):不许套用「查新版失败」那句——\n // 它对这种情形是误导(真机上就这么误报过一次)。各层的失败各有各的话。\n return failure('manager-unreachable', { detail: String((error as Error)?.message ?? error) });\n }\n if (!result || typeof result !== 'object' || typeof (result as { ok?: unknown }).ok !== 'boolean') {\n return failure('internal', { detail: '回执信封异常(非 ok 信封)' });\n }\n if (result.ok) return { ok: true, value: result.value as T };\n const error = (result as { error?: { code?: unknown; details?: unknown } }).error;\n const code = typeof error?.code === 'string' ? error.code : 'internal';\n const details = error && typeof error.details === 'object' && error.details !== null ? (error.details as Record<string, unknown>) : {};\n return failure(code, details);\n}\n\n/** 取七个更新目标的表(宿主转交更新包的三个电话名与版本行,面板不写死任何电话名)。 */\nexport async function loadTargets(call: CallFace | null): Promise<CallOutcome<{ targets: TargetInfo[]; pollMs: number }>> {\n const out = await callManager<{ targets?: TargetInfo[]; pollMs?: number }>(call, MANAGER_ACTIONS.targets, {});\n if (!out.ok) return out;\n const targets = Array.isArray(out.value?.targets) ? out.value.targets : [];\n const pollMs = typeof out.value?.pollMs === 'number' && out.value.pollMs > 0 ? out.value.pollMs : FALLBACK_POLL_MS;\n return { ok: true, value: { targets, pollMs } };\n}\n\n/** 查一家:默认查新版(`updateCheck`,顺带回最新版本与凭证);给 `phoneName` 时查那个电话。 */\nexport async function checkTarget(\n call: CallFace | null,\n target: TargetInfo,\n phoneName?: string,\n): Promise<CallOutcome<CheckOutcome>> {\n const name = phoneName ?? target.phones?.check;\n if (!target.phones || !name) return failure('bad-request', { target: target.key });\n return callManager<CheckOutcome>(call, name, {});\n}\n\n/** 装上缺席的包:版本取自查新版拿到的「最新版本」(宿主用更新包的执行器真装)。 */\nexport async function installAbsent(\n call: CallFace | null,\n target: TargetInfo,\n version: string,\n): Promise<CallOutcome<{ packageName: string; version: string }>> {\n return callManager(call, MANAGER_ACTIONS.install, { packageName: target.packageName, version });\n}\n\n/** 装上更新:查新版 → 提交安装 → 有界轮询查状态到任务收尾;凭证过期重查一次再提交。 */\nexport async function updateInstalled(\n call: CallFace | null,\n target: TargetInfo,\n pollMs: number,\n): Promise<CallOutcome<CheckOutcome>> {\n if (!target.phones) return failure('bad-request', { target: target.key });\n const first = await checkTarget(call, target);\n if (!first.ok) return first;\n let checked = first.value;\n if (!checked.receipt) {\n const code = checked.snapshot.blockedReason ?? 'check-failed';\n return failure(code, { target: target.key }, checked.manual);\n }\n requestSeq += 1;\n const requestId = 'ilife-manager-' + Date.now().toString(36) + '-' + String(requestSeq);\n let submitted = await callManager<CheckOutcome>(call, target.phones.install, {\n checkId: checked.receipt.checkId,\n requestId,\n });\n if (!submitted.ok && submitted.code === 'check-expired') {\n const again = await checkTarget(call, target);\n if (!again.ok) return again;\n checked = again.value;\n if (!checked.receipt) {\n return failure(checked.snapshot.blockedReason ?? 'check-failed', { target: target.key }, checked.manual);\n }\n submitted = await callManager<CheckOutcome>(call, target.phones.install, {\n checkId: checked.receipt.checkId,\n requestId: requestId + 'r',\n });\n }\n if (!submitted.ok) return { ...submitted, manual: submitted.manual ?? checked.manual };\n // 安装是后台跑(`service.ts:434-436`:落盘后后台跑,调用方不干等),故按间隔轮询到任务收尾。\n let latest = submitted.value;\n const interval = pollMs > 0 ? pollMs : FALLBACK_POLL_MS;\n for (let tries = 0; ; tries += 1) {\n const job = latest.snapshot.job;\n if (job === null || (job.state !== 'installing' && job.state !== 'verifying')) break;\n if (tries >= MAX_POLL_TRIES) break;\n await sleep(interval);\n const status = await checkTarget(call, target, target.phones.status);\n if (!status.ok) return status;\n latest = status.value;\n }\n return { ok: true, value: latest };\n}\n","/** 面板的视图逻辑(纯函数:无 DOM、无 node、无 react),客户端与单测共用同一份。\n *\n * 判定「有没有新版」不自己算版本号大小:更新核心已经在快照里给了结论\n * (`canInstall` 为真即有新版可装,`blockedReason` 非空即为什么装不了,见更新包 README 第 8 节),\n * 本文件只把结论翻成三种状态与一句话,不另起一套版本比较。\n */\nimport type { CheckReceipt, BlockedReason, UpdateSnapshot } from 'dsh-plugin-update';\nimport { dualInstallCmd } from './nav.js';\nimport { reasonText } from './update-contract.js';\n\n/** 一个更新目标的面板数据(宿主 `ilife-manager.targets` 的每行)。 */\nexport interface TargetInfo {\n readonly key: string;\n readonly title: string;\n readonly packageName: string;\n readonly phones: { readonly status: string; readonly check: string; readonly install: string } | null;\n /** 宿主启动那一刻磁盘上的版本;null = 启动时这个包还没装。 */\n readonly runningVersion: string | null;\n readonly installedVersion: string | null;\n /** 技能包随插件的那条精确 pin(插件包 manifest 里的 `skill-*` 依赖)。 */\n readonly skill: { readonly packageName: string; readonly version: string } | null;\n}\n\n/** 更新电话查到的结果(`updateCheck` / `updateStatus` 回包体)。 */\nexport interface CheckOutcome {\n readonly snapshot: UpdateSnapshot;\n readonly manual: string | null;\n readonly receipt: CheckReceipt | null;\n}\n\n/** 缺席:宿主启动时没装、现在磁盘上也没有(`runningVersion`/`installedVersion` 都是 null)。 */\nexport function isAbsent(target: TargetInfo): boolean {\n return target.runningVersion === null && target.installedVersion === null;\n}\n\nexport type VerdictKind = 'unknown' | 'up-to-date' | 'update-available' | 'blocked';\n\nexport interface Verdict {\n readonly kind: VerdictKind;\n /** 一句话结论(面板那行正文)。 */\n readonly text: string;\n /** 这一行给不给按钮:缺席给「装上」,有新版给「装上更新」,其余不给。 */\n readonly action: 'install' | 'update' | null;\n}\n\n/** 把快照翻成一行结论:还没查 / 已是最新 / 有新版 / 装不了(附人话原因)。 */\nexport function verdictOf(target: TargetInfo, snapshot: UpdateSnapshot): Verdict {\n const absent = isAbsent(target);\n const latest = snapshot.latestVersion;\n if (absent && latest === null) {\n return { kind: 'unknown', text: '未安装;点「检查更新」查最新版本后装上。', action: null };\n }\n if (absent) {\n return { kind: 'update-available', text: '未安装;最新版本 ' + String(latest) + '。', action: 'install' };\n }\n if (snapshot.blockedReason !== null) {\n const blocked = snapshot.blockedReason as BlockedReason;\n if (blocked === 'pending-restart') {\n return { kind: 'blocked', text: reasonText(blocked), action: null };\n }\n return { kind: 'blocked', text: reasonText(blocked), action: null };\n }\n if (latest === null) {\n return { kind: 'unknown', text: '还没查过最新版本;点「检查更新」。', action: null };\n }\n if (snapshot.canInstall) {\n return { kind: 'update-available', text: '有新版:' + String(latest) + ',点「装上更新」。', action: 'update' };\n }\n return { kind: 'up-to-date', text: '已是最新(' + String(latest) + ')。', action: null };\n}\n\n/** 待重启横幅文案(更新包 README 第 10 节:说清新版号与「重启后才生效」两件事)。 */\nexport function pendingRestartText(target: TargetInfo, snapshot: UpdateSnapshot): string | null {\n if (snapshot.blockedReason !== 'pending-restart') return null;\n const installed = snapshot.installedVersion ?? snapshot.job?.targetVersion ?? null;\n const running = snapshot.runningVersion;\n if (installed === null) return '⚠️ 新版已装好,重启宿主后生效。';\n if (installed === running) return '⚠️ 新版 ' + installed + ' 已装好,重启宿主后生效。';\n return '⚠️ 新版 ' + installed + ' 已装好,正在跑的还是 ' + running + ',重启宿主后生效。';\n}\n\n/** 面板展示的那条可复制命令(用户会照着敲的那一条)。\n *\n * 缺席包给人人都会用的**单命令双包**口径(#674 冻结的装入口径:不带版本号、不带任何开关);\n * 已装包给更新包回包里那条(`--save-exact ... --registry=` 是它 README 第 9 节的冻结合同,\n * 本仓不动它——要改只能提上游)。规范词见 docs/plugins/plugin-manager/t678-缺席即装与检查更新.md。 */\nexport function manualForDisplay(target: TargetInfo, manual: string | null): string | null {\n if (isAbsent(target)) return dualInstallCmd(target.packageName);\n return manual;\n}\n\n/** 版本行两行文字:插件包(本家) + 技能包(随插件,不单独查更新)。 */\nexport function versionLines(target: TargetInfo, snapshot: UpdateSnapshot | null): readonly string[] {\n const running = snapshot?.runningVersion ?? target.runningVersion ?? 'unknown';\n const installed = snapshot?.installedVersion ?? target.installedVersion;\n const lines = [target.packageName + ' ' + running + (installed && installed !== running ? '(磁盘已装 ' + installed + ')' : '')];\n if (target.skill) lines.push(target.skill.packageName + ' ' + target.skill.version + '(随插件,不单独查更新)');\n else lines.push('技能包随插件(不单独查更新)');\n return lines;\n}\n","/** 爱生活面板的更新界面:检查更新按钮、七家结果行、待重启横幅、缺席卡的「装上」。\n *\n * 面板侧纪律(沿 `client.ts` 既有口径):React.createElement 手写(禁 JSX)、内联 style、\n * 颜色走 DSH 主题别名(深浅主题自适应,写死值只做回退)、只用 `dsh-ctx` 镜像内的上下文成员、\n * 不 import 更新包(电话名与轮询间隔由宿主转交,见 `update-contract.ts` 的 `MANAGER_ACTIONS.targets`)。\n *\n * 视觉对照(用户给的第二张截图,参照实现 `dsh-mattpocock-skills-deck/src/client/views/SettingsPage.js:152-168`):\n * 标题右侧并排若干件——本文件出「检查更新」一件,隔壁票(爱生活面板头部与底部)在同一个\n * `actions` 容器里补星与气泡两件,故这里把容器单独留出来。\n */\nimport * as React from 'react';\nimport { checkTarget, installAbsent, loadTargets, updateInstalled } from './update-client.js';\nimport type { CallFace, CallFailure } from './update-client.js';\nimport { isAbsent, manualForDisplay, pendingRestartText, verdictOf, versionLines } from './update-view.js';\nimport type { CheckOutcome, TargetInfo } from './update-view.js';\n\n/** 面板视觉(沿用总管既有语言:内联 style,主题别名带回退)。 */\nexport const PANEL_STYLE = {\n head: { fontSize: 15, fontWeight: 700, margin: '2px 0 8px', color: 'var(--dsw-alias-label-primary, inherit)' } as React.CSSProperties,\n headRow: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8, flexWrap: 'wrap' } as React.CSSProperties,\n actions: { display: 'inline-flex', alignItems: 'center', gap: 6 } as React.CSSProperties,\n meta: { color: 'var(--dsw-alias-label-secondary, #9a9a9a)', fontSize: 12, lineHeight: 1.7, marginBottom: 10 } as React.CSSProperties,\n tablist: { display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 10 } as React.CSSProperties,\n tab: {\n border: '1px solid var(--dsw-alias-border, rgba(128,128,128,.35))',\n background: 'transparent',\n color: 'var(--dsw-alias-label-primary, inherit)',\n borderRadius: 999,\n padding: '4px 12px',\n fontSize: 13,\n cursor: 'pointer',\n } as React.CSSProperties,\n tabActive: {\n background: 'var(--dsw-alias-brand-primary, #0a84ff)',\n borderColor: 'transparent',\n color: '#fff',\n fontWeight: 700,\n } as React.CSSProperties,\n reco: {\n padding: '12px 14px',\n borderRadius: 10,\n border: '1px dashed var(--dsw-alias-border, rgba(128,128,128,.45))',\n color: 'var(--dsw-alias-label-secondary, #9a9a9a)',\n fontSize: 13,\n lineHeight: 1.7,\n } as React.CSSProperties,\n cmd: {\n display: 'block',\n marginTop: 8,\n padding: '8px 10px',\n borderRadius: 8,\n background: 'var(--dsw-alias-bg-base, rgba(128,128,128,.12))',\n color: 'var(--dsw-alias-label-primary, inherit)',\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n fontSize: 12,\n userSelect: 'all',\n } as React.CSSProperties,\n btn: {\n border: '1px solid var(--dsw-alias-border, rgba(128,128,128,.35))',\n background: 'transparent',\n color: 'var(--dsw-alias-label-primary, inherit)',\n borderRadius: 8,\n padding: '4px 12px',\n fontSize: 13,\n cursor: 'pointer',\n } as React.CSSProperties,\n banner: {\n padding: '10px 12px',\n marginBottom: 10,\n borderRadius: 8,\n border: '1px solid var(--dsw-alias-state-warning-primary, #d8a300)',\n background: 'var(--dsw-alias-bg-base, rgba(216,163,0,.12))',\n color: 'var(--dsw-alias-label-primary, inherit)',\n fontSize: 13,\n lineHeight: 1.7,\n } as React.CSSProperties,\n row: {\n padding: '10px 12px',\n marginBottom: 8,\n borderRadius: 10,\n border: '1px solid var(--dsw-alias-border, rgba(128,128,128,.3))',\n fontSize: 13,\n lineHeight: 1.7,\n } as React.CSSProperties,\n rowHead: { fontWeight: 700, marginBottom: 2 } as React.CSSProperties,\n rowMeta: { color: 'var(--dsw-alias-label-secondary, #9a9a9a)', fontSize: 12 } as React.CSSProperties,\n reason: { color: 'var(--dsw-alias-state-error-primary, #ff6b6b)', fontSize: 12, marginTop: 4 } as React.CSSProperties,\n skill: { color: 'var(--dsw-alias-label-tertiary, #8a8a8a)', fontSize: 12, marginTop: 4 } as React.CSSProperties,\n overlay: {\n position: 'fixed',\n inset: 0,\n zIndex: 40,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n padding: 16,\n background: 'rgba(0,0,0,.45)',\n } as React.CSSProperties,\n dialog: {\n width: '100%',\n maxWidth: 560,\n maxHeight: '80vh',\n overflow: 'auto',\n padding: '12px 14px',\n borderRadius: 12,\n border: '1px solid var(--dsw-alias-border, rgba(128,128,128,.4))',\n background: 'var(--dsw-alias-bg-elevated, var(--dsw-alias-bg-base, #222))',\n color: 'var(--dsw-alias-label-primary, inherit)',\n boxShadow: '0 12px 32px rgba(0,0,0,.35)',\n } as React.CSSProperties,\n dialogHead: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 8,\n marginBottom: 8,\n } as React.CSSProperties,\n dialogTitle: { fontSize: 14, fontWeight: 700 } as React.CSSProperties,\n close: {\n border: '1px solid var(--dsw-alias-border, rgba(128,128,128,.35))',\n background: 'transparent',\n color: 'var(--dsw-alias-label-primary, inherit)',\n borderRadius: 8,\n width: 26,\n height: 26,\n lineHeight: 1,\n fontSize: 14,\n cursor: 'pointer',\n } as React.CSSProperties,\n dialogNote: { color: 'var(--dsw-alias-label-tertiary, #8a8a8a)', fontSize: 12, marginTop: 4 } as React.CSSProperties,\n};\n\n/** 一行的运行时状态:还没查 / 查着 / 有结果 / 装着 / 出错。 */\nexport interface UpdateRowState {\n readonly phase: 'idle' | 'checking' | 'ready' | 'installing' | 'failed';\n readonly outcome: CheckOutcome | null;\n readonly failure: CallFailure | null;\n}\n\nexport interface UpdateRowsFace {\n readonly targets: readonly TargetInfo[];\n readonly rows: Readonly<Record<string, UpdateRowState>>;\n readonly pollMs: number;\n readonly loadError: string | null;\n readonly checking: boolean;\n /** 结果浮层是否打开(点「检查更新」开,关法三种:×、点遮罩、Esc)。 */\n readonly open: boolean;\n close(): void;\n checkAll(): void;\n act(target: TargetInfo): void;\n}\n\nconst IDLE: UpdateRowState = { phase: 'idle', outcome: null, failure: null };\n\n/** 面板的更新状态源:挂载时取七个目标的表,之后按需查/装(组件与按钮共用一个 face)。 */\nexport function useUpdateRows(getCall: () => CallFace | null): UpdateRowsFace {\n const [targets, setTargets] = React.useState<readonly TargetInfo[]>([]);\n const [rows, setRows] = React.useState<Record<string, UpdateRowState>>({});\n const [pollMs, setPollMs] = React.useState(1000);\n const [loadError, setLoadError] = React.useState<string | null>(null);\n const [checking, setChecking] = React.useState(false);\n const [open, setOpen] = React.useState(false);\n React.useEffect(() => {\n let alive = true;\n void (async () => {\n const loaded = await loadTargets(getCall());\n if (!alive) return;\n if (loaded.ok) {\n setTargets(loaded.value.targets);\n setPollMs(loaded.value.pollMs);\n } else {\n setLoadError(loaded.message);\n }\n })();\n return () => {\n alive = false;\n };\n }, [getCall]);\n const patch = React.useCallback((key: string, next: UpdateRowState) => {\n setRows((previous) => ({ ...previous, [key]: next }));\n }, []);\n const checkAll = React.useCallback(() => {\n setChecking(true);\n setOpen(true);\n const list = targets;\n for (const target of list) patch(target.key, { phase: 'checking', outcome: rows[target.key]?.outcome ?? null, failure: null });\n void Promise.all(\n list.map(async (target) => {\n const result = await checkTarget(getCall(), target);\n patch(target.key, result.ok ? { phase: 'ready', outcome: result.value, failure: null } : { phase: 'failed', outcome: null, failure: result });\n }),\n ).finally(() => setChecking(false));\n }, [getCall, patch, rows, targets]);\n const act = React.useCallback(\n (target: TargetInfo) => {\n const current = rows[target.key] ?? IDLE;\n patch(target.key, { ...current, phase: 'installing', failure: null });\n void (async () => {\n const absent = isAbsent(target);\n let version = current.outcome?.snapshot.latestVersion ?? null;\n if (absent && version === null) {\n const checked = await checkTarget(getCall(), target);\n if (!checked.ok) {\n patch(target.key, { phase: 'failed', outcome: null, failure: checked });\n return;\n }\n patch(target.key, { phase: 'installing', outcome: checked.value, failure: null });\n version = checked.value.snapshot.latestVersion;\n }\n const result = absent\n ? await installAbsent(getCall(), target, version ?? '')\n : await updateInstalled(getCall(), target, pollMs);\n if (result.ok) {\n // 装完不自己编快照:向宿主问一次真实状态(装到磁盘但宿主还跑着旧版 ⇒ 待重启)。\n const refreshed = await checkTarget(getCall(), target, target.phones?.status);\n patch(target.key, refreshed.ok ? { phase: 'ready', outcome: refreshed.value, failure: null } : { phase: 'failed', outcome: null, failure: refreshed });\n return;\n }\n patch(target.key, {\n phase: 'failed',\n outcome: current.outcome,\n failure: { ...result, manual: result.manual ?? current.outcome?.manual ?? null },\n });\n })();\n },\n [getCall, patch, pollMs, rows],\n );\n return { targets, rows, pollMs, loadError, checking, open, close: () => setOpen(false), checkAll, act };\n}\n\n/** 标题右侧的「检查更新」:一个按钮一次查七家(吃 `useUpdateRows` 的表)。 */\nexport function CheckUpdateButton(props: { readonly face: UpdateRowsFace }): React.ReactElement {\n const { checking, checkAll, targets } = props.face;\n const disabled = checking || targets.length === 0;\n return React.createElement(\n 'button',\n {\n type: 'button',\n style: disabled ? { ...PANEL_STYLE.btn, opacity: 0.55, cursor: 'default' } : PANEL_STYLE.btn,\n disabled,\n onClick: checkAll,\n title: '一次查七家(总管自己 + 六个单品)的插件包版本',\n },\n checking ? '检查中…' : '检查更新',\n );\n}\n\n/** 待重启横幅:任何一家成 `pending-restart` 就常驻显示,重启宿主后自动消失(更新包 README 第 10 节)。 */\nfunction RestartBanners(props: { readonly face: UpdateRowsFace }): React.ReactElement | null {\n const lines: string[] = [];\n for (const target of props.face.targets) {\n const outcome = props.face.rows[target.key]?.outcome;\n if (!outcome) continue;\n const text = pendingRestartText(target, outcome.snapshot);\n if (text) lines.push(text);\n }\n if (lines.length === 0) return null;\n return React.createElement(\n 'div',\n { style: PANEL_STYLE.banner },\n lines.map((line, index) => React.createElement('div', { key: String(index) }, line)),\n );\n}\n\n/** 七家结果:装不了的与待重启的常驻(横幅),详细结果放**居中浮层**(点「检查更新」开)。\n *\n * 为什么是浮层:内联展开会把面板本体撑长、且它自身没有关闭控件(真机第一次做成内联后用户反馈\n * 「打开就无法收回了」)。参照实现也是浮层:`dsh-mattpocock-skills-deck/src/client/views/SettingsPage.js`\n * 的 `upd.dialog`。关法三种:右上角 ×、点遮罩、Esc(Esc 靠浮层自己拿焦点后收 keydown,\n * 不摸 window——客户端纪律禁直写 DOM 全局)。\n * 手工命令只在「装不了」或「装失败」的行显示:正常用户用不到,摊在每行上既吵又误导。\n */\nexport function UpdateResults(props: { readonly face: UpdateRowsFace }): React.ReactElement | null {\n const { targets, rows, loadError, checking, open, close } = props.face;\n const dialogRef = React.useRef<HTMLDivElement | null>(null);\n React.useEffect(() => {\n if (open) dialogRef.current?.focus();\n }, [open]);\n const shown = targets.filter((target) => rows[target.key] && rows[target.key].phase !== 'idle');\n if (loadError) return React.createElement('div', { style: PANEL_STYLE.reason }, '更新能力没接上:' + loadError);\n if (targets.length === 0) return null;\n if (shown.length === 0 && !open) return null;\n const body = shown.map((target) => {\n const row = rows[target.key];\n const snapshot = row.outcome?.snapshot ?? null;\n const verdict = snapshot ? verdictOf(target, snapshot) : null;\n const manual = manualForDisplay(target, row.failure?.manual ?? row.outcome?.manual ?? null);\n const busy = row.phase === 'installing';\n const showManual = manual !== null && (row.phase === 'failed' || verdict?.kind === 'blocked');\n return React.createElement(\n 'div',\n { key: target.key, style: PANEL_STYLE.row },\n React.createElement('div', { style: PANEL_STYLE.rowHead }, target.title + ' · ' + target.packageName),\n React.createElement(\n 'div',\n { style: PANEL_STYLE.rowMeta },\n '当前 ' +\n String(snapshot?.runningVersion ?? target.runningVersion ?? '未安装') +\n ' · 最新 ' +\n String(snapshot?.latestVersion ?? '未查'),\n ),\n React.createElement('div', null, busy ? '正在装,请稍候…' : (verdict?.text ?? (checking ? '检查中…' : ''))),\n verdict?.action\n ? React.createElement(\n 'button',\n {\n type: 'button',\n style: busy ? { ...PANEL_STYLE.btn, opacity: 0.55 } : { ...PANEL_STYLE.btn, marginTop: 6 },\n disabled: busy,\n onClick: () => props.face.act(target),\n },\n verdict.action === 'install' ? '装上' : '装上更新',\n )\n : null,\n row.failure ? React.createElement('div', { style: PANEL_STYLE.reason }, '装不上:' + row.failure.message) : null,\n versionLines(target, snapshot).map((line, index) =>\n React.createElement('div', { key: String(index), style: PANEL_STYLE.skill }, line),\n ),\n showManual ? React.createElement('code', { style: PANEL_STYLE.cmd }, manual) : null,\n );\n });\n return React.createElement(\n 'div',\n null,\n React.createElement(RestartBanners, { face: props.face }),\n open\n ? React.createElement(\n 'div',\n {\n style: PANEL_STYLE.overlay,\n role: 'presentation',\n onClick: () => close(),\n },\n React.createElement(\n 'div',\n {\n ref: dialogRef,\n tabIndex: -1,\n role: 'dialog',\n 'aria-label': '检查更新结果',\n style: PANEL_STYLE.dialog,\n onClick: (event: React.MouseEvent) => event.stopPropagation(),\n onKeyDown: (event: React.KeyboardEvent) => {\n if (event.key === 'Escape') close();\n },\n },\n React.createElement(\n 'div',\n { style: PANEL_STYLE.dialogHead },\n React.createElement('div', { style: PANEL_STYLE.dialogTitle }, '检查更新(七家)'),\n React.createElement(\n 'button',\n { type: 'button', style: PANEL_STYLE.close, onClick: () => close(), title: '关闭', 'aria-label': '关闭' },\n '×',\n ),\n ),\n body,\n React.createElement(\n 'div',\n { style: PANEL_STYLE.dialogNote },\n '装与更新都在宿主后台跑:关掉这块不影响正在进行的安装,再点「检查更新」可以看到最新状态。',\n ),\n ),\n )\n : null,\n );\n}\n\n/** 缺席卡:**按宿主的装机读数分两态**,不让层与层的结论互相顶替。\n *\n * - 宿主说磁盘上没有这个包 →「未安装」+「装上」按钮(这是本票原有的能力);\n * - 宿主说装着(`installedVersion` 非空)却没进页签槽 → 说实情、**不给「装上」**:\n * 重装改不了产物里有没有注册代码这件事(真机实测:作息/居家/大厨/记账 的已发布 0.2.0\n * 产物里根本没有页签槽注册,见票 #723)。给出可复制命令仅作参考。\n *\n * 原实现只看页签槽 ledger 就断言「未安装」——那对上面第二种情形是说假话,且点「装上」\n * 会走进更新包的流程(它已经装着 ⇒ 没有新版 ⇒ 没有凭证)并报出误导的「查新版失败」。\n */\nexport function AbsentCard(props: {\n readonly target: TargetInfo | null;\n readonly fallbackCommand: string;\n readonly face: UpdateRowsFace;\n}): React.ReactElement {\n const target = props.target;\n const row = target ? props.face.rows[target.key] : null;\n const busy = row?.phase === 'installing';\n const manual = (target ? manualForDisplay(target, row?.failure?.manual ?? row?.outcome?.manual ?? null) : null) ?? props.fallbackCommand;\n const installed = target ? (target.installedVersion ?? target.runningVersion) : null;\n let reason: string | null = row?.failure?.message ?? null;\n if (target && reason === null && row?.outcome && row.outcome.snapshot.blockedReason !== null) {\n reason = verdictOf(target, row.outcome.snapshot).text;\n }\n const headline = !target\n ? '这个页签对应的插件还没装。'\n : installed === null\n ? '未安装[' + target.packageName + '],装上后这个页签就能用了。'\n : '插件已装(' + installed + '),但它这一版没把设置页接上爱生活面板:要等它发新版才对得上(重启与重装都不会变)。';\n return React.createElement(\n 'div',\n { style: PANEL_STYLE.reco },\n React.createElement('div', null, headline),\n target && installed === null\n ? React.createElement(\n 'button',\n {\n type: 'button',\n style: busy ? { ...PANEL_STYLE.btn, marginTop: 8, opacity: 0.55 } : { ...PANEL_STYLE.btn, marginTop: 8 },\n disabled: busy,\n onClick: () => props.face.act(target),\n },\n busy ? '正在装,请稍候…' : '装上',\n )\n : null,\n reason ? React.createElement('div', { style: PANEL_STYLE.reason }, reason) : null,\n React.createElement('code', { style: PANEL_STYLE.cmd }, manual),\n );\n}\n","/** 配置体检:各家技能回给面板的那份报告的形状(唯一真相在技能侧,本件只是面板侧镜像)。\n *\n * 为什么形状这样定(票 #706「开工前的形状裁定」第一条):**判据住技能侧**。\n * 每条检查项的有效值只有技能源码算得出来(例:`resolveDbDir()` 里「空串=按默认落点」),\n * 插件包对技能的全部能力是 spawn `cmd_read` 与读 stdout 信封,看不到那些算式。所以:\n *\n * 技能侧出**判据**(每条给红/黄/绿 + 一句话 + 去哪修);\n * 插件包出**透传**(把技能回执原样交回,不重写一个字);\n * 总管出**总览与渲染**(零特例:不认任何一家,只认下面这个形状)。\n *\n * 于是「同一份数据、不许两处各算一遍」是结构上的性质:面板一次取数拿到六份报告,\n * 总览一行与各家那张表都从同一个快照读(见 `health-panel.ts` 的单一状态源)。\n *\n * 三档判据的语义(照检查表 `docs/research/check-table-671-life-panel-20260917.html`):\n * · `red`=现在用不了,必须去修;\n * · `yellow`=现在这状态能用,但有人真去用那个功能时会撞上(例:照片目录没配);\n * · `green`=正常。\n */\n\n/** 三档判据。 */\nexport type HealthStatus = 'red' | 'yellow' | 'green';\n\n/** 一条检查项的回执。 */\nexport interface HealthItem {\n /** 稳定标识:配置项就是它在配置文件里的键路径(`db.dir`),非配置项用点式名(`xunji.cli`)。 */\n readonly id: string;\n /** 页面上那一行的中文标题(技能侧定,面板不重写)。 */\n readonly title: string;\n readonly status: HealthStatus;\n /** 一句话:现在是什么状态,带上路径或门槛这类实证。 */\n readonly message: string;\n /** 去哪修。`green` 时可为空。 */\n readonly action: string;\n /** 这个值从哪来(只陈述,不判好坏):`配置文件`/`默认值`/`环境`。非取值类检查项可省。 */\n readonly source?: string;\n}\n\n/** 一家的体检报告。 */\nexport interface HealthReport {\n /** 技能名(`calorie`/`bill`/…),等于该家配置文件的主体名。 */\n readonly skill: string;\n /** 实际生效的那份配置文件路径。 */\n readonly configPath: string;\n /** 实际生效的数据目录。 */\n readonly dataDir: string;\n readonly items: readonly HealthItem[];\n}\n\n/** 体检出口:技能侧在**进分派层之前**拦下的那一类只读命令名(照三个配置命令的先例)。\n *\n * 载荷:入参 `{}`;回包 `{report}`(技能侧 envelope 的 `data`)。**只报不改**:\n * 不建目录、不写文件、不落默认配置——凡是要建目录才算得出的结论,一律当「不在」报。 */\nexport const HEALTH_CHECK_KEY = 'config.check' as const;\n\n/** 面板第二段参数(与各家的端点名同值,和各家的 `RPC_CHANNEL` 配成一次调用)。 */\nexport const HEALTH_ENDPOINT = 'config.check' as const;\n\n/** 三档排序:数字大的更严重(总览一行取**最严重**那档当那一家的灯)。 */\nconst RANK: Readonly<Record<HealthStatus, number>> = { green: 0, yellow: 1, red: 2 };\n\n/** 一家的总判据:全部项里最严重的那一档;一条都没有时回 `null`(不冒充绿)。 */\nexport function worstStatus(items: readonly HealthItem[]): HealthStatus | null {\n let worst: HealthStatus | null = null;\n for (const item of items) {\n if (worst === null || RANK[item.status] > RANK[worst]) worst = item.status;\n }\n return worst;\n}\n\n/** 三档计数(面板那一行「红 N 黄 N」用的就是它)。 */\nexport function countByStatus(items: readonly HealthItem[]): Readonly<Record<HealthStatus, number>> {\n const out = { red: 0, yellow: 0, green: 0 };\n for (const item of items) out[item.status] += 1;\n return out;\n}\n\n/** 回执校验:面板只渲染自己认得的形状,认不出即报「回执异常」,不猜、不返空冒充正常。 */\nexport function isHealthReport(raw: unknown): raw is HealthReport {\n if (typeof raw !== 'object' || raw === null) return false;\n const report = raw as Partial<HealthReport>;\n if (typeof report.skill !== 'string' || report.skill.length === 0) return false;\n if (typeof report.configPath !== 'string' || typeof report.dataDir !== 'string') return false;\n if (!Array.isArray(report.items)) return false;\n return report.items.every((item: unknown) => {\n if (typeof item !== 'object' || item === null) return false;\n const row = item as Partial<HealthItem>;\n return typeof row.id === 'string' && typeof row.title === 'string'\n && (row.status === 'red' || row.status === 'yellow' || row.status === 'green')\n && typeof row.message === 'string' && typeof row.action === 'string';\n });\n}\n","/** 面板到各家的配置体检:一次取数、六份报告(纯异步函数:无 DOM、无 react;传输口注入,便于单测)。\n *\n * 三条纪律:\n * · **只走各家自己的通道**(`rpc.call(channel, HEALTH_ENDPOINT, …)`)——总管不认任何一家、也不加\n * 任何单品的依赖;通道名从「爱生活页签槽」的账本条目带出来(各家注册时写进 options)。\n * · **一次取数,六份报告**:总览那行与各家那张表读的是同一份结果(见 `health-panel.ts` 的单一状态源),\n * 不许两处各算一遍。\n * · 有界超时:一家不回不该拖死整屏(技能侧 spawn 上限 20 s,这里给 25 s)。\n */\nimport { HEALTH_ENDPOINT, isHealthReport } from './health-contract.js';\nimport type { HealthReport } from './health-contract.js';\n\n/** 传输口(DSH 载体 `connection.rpc.call` 的形状,cookbook §6)。 */\nexport type HealthCallFace = (\n channel: string,\n endpoint: string,\n payload: unknown,\n signal?: AbortSignal,\n) => Promise<\n | { readonly ok: true; readonly value: unknown }\n | { readonly ok: false; readonly error: { readonly code: string; readonly message: string; readonly details: Record<string, unknown> } }\n>;\n\n/** 一次取数的时限(毫秒):技能侧 spawn 上限 20 s,这里留一点余量。 */\nexport const HEALTH_TIMEOUT_MS = 25_000 as const;\n\n/** 一家的一行:报告取到了就是 `report`,取不到就是 `error`(缺席的包不进这张表)。 */\nexport interface HealthFetchRow {\n /** 该家插件包名(=爱生活页签槽 id,也是缺席判定的那个 join 键)。 */\n readonly id: string;\n readonly report: HealthReport | null;\n readonly error: string | null;\n}\n\n/** 一次取数的结果:每家一行(顺序照页签顺序)。 */\nexport interface HealthFetchResult {\n readonly rows: readonly HealthFetchRow[];\n /** 取数过程本身的错(通道缺席之类),不是某一家的问题。 */\n readonly error: string | null;\n}\n\n/** 账本条目里本票要用的那一段(页签槽注册时写进 options)。 */\nexport interface HealthTabRow {\n readonly id: string;\n readonly channel: string;\n}\n\nfunction timeoutText(): string {\n return '体检超时(' + String(Math.round(HEALTH_TIMEOUT_MS / 1000)) + 's):技能没在时限内回话。';\n}\n\nasync function fetchOne(call: HealthCallFace, row: HealthTabRow): Promise<{ readonly report: HealthReport | null; readonly error: string | null }> {\n try {\n const result = await call(row.channel, HEALTH_ENDPOINT, {}, AbortSignal.timeout(HEALTH_TIMEOUT_MS));\n if (!result || typeof result !== 'object' || typeof (result as { ok?: unknown }).ok !== 'boolean') {\n return { report: null, error: '回执信封异常(非 ok 信封)。' };\n }\n if (!result.ok) {\n const error = (result as { error?: { code?: unknown; message?: unknown } }).error;\n const message = typeof error?.message === 'string' && error.message.length > 0 ? error.message : '体检没跑起来。';\n return { report: null, error: message };\n }\n const value = (result as { value?: unknown }).value;\n if (!isHealthReport(value)) return { report: null, error: '体检报告形状认不出(技能包与总管版本对不上?)。' };\n return { report: value, error: null };\n } catch (error) {\n if (error instanceof Error && (error.name === 'AbortError' || error.name === 'TimeoutError')) {\n return { report: null, error: timeoutText() };\n }\n return { report: null, error: '体检没跑起来:' + (error instanceof Error ? error.message : String(error)) };\n }\n}\n\n/** 取六家的体检报告(缺席的包不在此列,由调用方按账本判断)。 */\nexport async function loadHealthReports(call: HealthCallFace | null, tabs: readonly HealthTabRow[]): Promise<HealthFetchResult> {\n if (typeof call !== 'function') return { rows: [], error: '宿主连接缺席:connection.rpc.call 不可用' };\n const rows = await Promise.all(tabs.map(async (tab): Promise<HealthFetchRow> => {\n const one = await fetchOne(call, tab);\n return { id: tab.id, report: one.report, error: one.error };\n }));\n return { rows, error: null };\n}\n","/** 配置体检的状态源:**一份快照**喂两处(面板顶部那行总览 + 各家页签那张表)。\n *\n * 为什么是一个 hook 而不是两处各取一次(票 #706 验收第三条「同一份数据,不许两处各算一遍」):\n * 这一处取数、这一处存状态,总览与各家表都从它读 —— 那条验收因此是**结构上的性质**,不是靠自觉。\n *\n * 取数是**按需**的(点「体检一次」才跑):没有轮询、没有定时器(静态门那条「无数据轮询」照旧)。\n */\nimport * as React from 'react';\nimport { loadHealthReports } from './health-fetch.js';\nimport type { HealthCallFace, HealthTabRow } from './health-fetch.js';\nimport { worstStatus } from './health-contract.js';\nimport type { HealthReport, HealthStatus } from './health-contract.js';\n\n/** 一家的状态:没跑过/正在跑/有报告/这一家出错。 */\nexport type HealthPhase = 'idle' | 'running' | 'ready' | 'failed';\n\nexport interface HealthPanelFace {\n /** 一次取数的结果:包名 → 该家的状态(缺席的包不在表里)。 */\n readonly rows: Readonly<Record<string, { readonly phase: HealthPhase; readonly report: HealthReport | null; readonly error: string | null }>>;\n /** 取数过程本身的错(通道缺席之类)。 */\n readonly error: string | null;\n /** 正在跑。 */\n readonly running: boolean;\n /** 跑一次(六家一起)。 */\n run(): void;\n}\n\nconst IDLE = { phase: 'idle' as HealthPhase, report: null, error: null };\n\n/** 一家的灯:没报告=`null`(不冒充绿)。 */\nexport function lightOf(row: { readonly report: HealthReport | null } | undefined): HealthStatus | null {\n return row?.report ? worstStatus(row.report.items) : null;\n}\n\n/** 体检状态源:挂载时不自动跑(体检要读盘、要起子进程,按需跑),点一次跑六家。 */\nexport function useHealthPanel(getCall: () => HealthCallFace | null, tabs: readonly HealthTabRow[]): HealthPanelFace {\n const [rows, setRows] = React.useState<HealthPanelFace['rows']>({});\n const [error, setError] = React.useState<string | null>(null);\n const [running, setRunning] = React.useState(false);\n const run = React.useCallback(() => {\n const diag = (globalThis as { __T706_RUN__?: string[] }).__T706_RUN__;\n if (Array.isArray(diag)) diag.push('run:tabs=' + String(tabs.length));\n setRunning(true);\n setError(null);\n const targets = tabs;\n setRows(Object.fromEntries(targets.map((tab) => [tab.id, { ...IDLE, phase: 'running' as HealthPhase }])));\n void (async () => {\n const loaded = await loadHealthReports(getCall(), targets);\n // 渲染台的调试图(浏览器里没人写它,写入失败无所谓):只记条数与第一条的错。\n try {\n const diag = (globalThis as { __T706_RUN__?: string[] }).__T706_RUN__;\n if (Array.isArray(diag)) diag.push('rows=' + String(loaded.rows.length) + ' err=' + String(loaded.error) + ' first=' + String(loaded.rows[0]?.error ?? 'null'));\n } catch {\n /* 调试图写不进去不影响正经事 */\n }\n const next: Record<string, { phase: HealthPhase; report: HealthReport | null; error: string | null }> = {};\n for (const row of loaded.rows) {\n next[row.id] = { phase: row.report ? 'ready' : 'failed', report: row.report, error: row.error };\n }\n setRows(next);\n setError(loaded.error);\n setRunning(false);\n })();\n }, [getCall, tabs]);\n const face: HealthPanelFace = { rows, error, running, run };\n // 出图页的取数口(渲染台的 hooks 替身没有真事件环,页内点按钮那条路不落定取数)。\n // 只在有人预先挂了 `__T706_FACE_SINK__` 时写一次,浏览器里没人挂它,等于没有这一行。\n const sink = (globalThis as { __T706_FACE_SINK__?: (value: HealthPanelFace) => void }).__T706_FACE_SINK__;\n if (typeof sink === 'function') {\n try {\n sink(face);\n } catch {\n /* 出图口的错不影响正经渲染 */\n }\n }\n return face;\n}\n","/** 配置体检的两个画法:面板顶部那行总览(六家一盏灯)+ 各家那张表。\n *\n * 面板侧纪律(沿 `client.ts`/`update-panel.ts` 既有口径):`createElement` 手写(禁 JSX)、内联 style、\n * 颜色走 DSH 主题别名(深浅主题自适应,写死值只做回退)、不 import 任何单品包、不 import 技能实现。\n *\n * 判据与文案**全部来自各家技能的报告**,本件一个字都不重写——只按三档上色、按状态挑文案。\n */\nimport * as React from 'react';\nimport { countByStatus, worstStatus } from './health-contract.js';\nimport type { HealthItem, HealthReport, HealthStatus } from './health-contract.js';\n\n/** 三档的配色(绿走主题别名;红黄用实色,理由见下)。\n *\n * 红与黄为什么必须落在**不同明度带**上:这两档要一起出现在同一行灯里,用户扫一眼要能分开\n * 「红了(用不了)」与「黄了(能用但要撞上)」。评审连着两轮点「黄灯偏暗与红相近」,所以:\n * · 红=深红(暗、重);\n * · 黄=高饱和的琥珀(亮、跳)——它在白底上的对比度仍然够(`#b45309` 对白 ≈ 4.9:1)。\n * 绿不给底色:它是「正常」,不该和要处理的那两档抢注意力。 */\nconst STATUS_COLOR: Readonly<Record<HealthStatus, string>> = {\n red: '#c0392b',\n yellow: '#e08a00',\n green: 'var(--dsw-alias-state-success-primary, #4ec9a0)',\n};\n\n/** 整行底色的浅一档:饱和降一档,免得红黄行「刺眼」压过正文(评审第二轮的扣分点)。 */\nconst STATUS_TINT: Readonly<Record<HealthStatus, string>> = {\n red: 'rgba(192, 57, 43, 0.06)',\n yellow: 'rgba(224, 138, 0, 0.10)',\n green: 'transparent',\n};\n\n/** 档位词(灯里那几个字)用的色:红黄要**够深**才读得清,故另取一枚比灯更深的值。 */\nconst STATUS_TEXT: Readonly<Record<HealthStatus, string>> = {\n red: '#a5281b',\n yellow: '#8a5200',\n green: 'var(--dsw-alias-state-success-primary, #4ec9a0)',\n};\n\nconst STATUS_LABEL: Readonly<Record<HealthStatus, string>> = { red: '红', yellow: '黄', green: '绿' };\n\n/** 档位的**形状**标记:颜色之外的第二条读数(灰度截图、色弱视角下也分得开谁要处理)。 */\nconst STATUS_MARK: Readonly<Record<HealthStatus, string>> = { red: '✕', yellow: '!', green: '✓' };\n\n/** 面板上的文字色与分隔线(与 `client.ts` 同一套别名)。 */\nconst INK = 'var(--dsw-alias-label-primary, inherit)';\nconst INK_DIM = 'var(--dsw-alias-label-secondary, #9a9a9a)';\nconst BORDER = 'var(--dsw-alias-border, rgba(128,128,128,.35))';\n\nexport const HEALTH_STYLE = {\n box: {\n padding: '10px 12px',\n marginBottom: 10,\n borderRadius: 10,\n border: '1px solid ' + BORDER,\n } as React.CSSProperties,\n headRow: { display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 8, marginBottom: 4 } as React.CSSProperties,\n head: { fontSize: 13, fontWeight: 700, color: INK } as React.CSSProperties,\n /** 「体检一次」不挤在标题右端:它单独占一行、与标题同一起始边(视觉复评两轮点「孤立在右上缺层次」)。 */\n runRow: { margin: '8px 0 10px' } as React.CSSProperties,\n btn: {\n border: '1px solid ' + BORDER,\n background: 'transparent',\n color: INK,\n borderRadius: 8,\n padding: '6px 16px',\n fontSize: 13,\n fontWeight: 600,\n cursor: 'pointer',\n } as React.CSSProperties,\n lightsRow: { display: 'flex', flexWrap: 'wrap', gap: 8 } as React.CSSProperties,\n light: {\n display: 'inline-flex',\n alignItems: 'center',\n gap: 4,\n background: 'transparent',\n border: '1px solid ' + BORDER,\n borderRadius: 999,\n padding: '3px 10px',\n fontSize: 12.5,\n color: INK,\n cursor: 'pointer',\n } as React.CSSProperties,\n lightIdle: { cursor: 'default', color: INK_DIM } as React.CSSProperties,\n meta: { color: INK_DIM, fontSize: 12, lineHeight: 1.7, marginTop: 12 } as React.CSSProperties,\n error: { color: STATUS_COLOR.red, fontSize: 12, lineHeight: 1.7, marginTop: 6 } as React.CSSProperties,\n} as const;\n\n/** 值得一眼看见的那两档(档位名与整行文字都上色;绿行保持淡)。 */\nfunction isAttention(status: HealthStatus): boolean {\n return status === 'red' || status === 'yellow';\n}\n\n/** 「去哪修」那一行的正文:各家交回来的 action 里若已自带「去哪修:」,这里剥掉一层——\n * 面板已经带了这个前缀,两边都写就会印成「去哪修:去哪修:…」。只剥开头那一次,别的一字不动。 */\nexport function actionText(action: string): string {\n const trimmed = action.trim();\n return trimmed.startsWith('去哪修:') ? trimmed.slice(4).trim() : trimmed;\n}\n\n/** 报文里能扫出来的每一段路径(盘符绝对路径;非 Windows 形状的退回 `/` 打头那一支)。 */\nfunction rawPathsIn(text: string): readonly string[] {\n return text.match(/[A-Za-z]:\\/[^\\s()「」,。;]+/g) ?? text.match(/\\/[^\\s()「」,。;]+/g) ?? [];\n}\n\n/** 一段落点的**根**(盘符):`C:/a/b` → `C:/`。用来把「同一个盘、但根下不同枝」的落点分开算,\n * 免得一个 D 盘上的旁证(比如「配了但目录不在:D:/media」)把 C 盘那几条的缩写全拖没。 */\nfunction rootOf(path: string): string {\n const drive = /^[A-Za-z]:\\//.exec(path);\n return drive === null ? '/' : drive[0];\n}\n\n/** 一段落点的公共目录前缀(按 `/` 切、整段比):`C:/a/b/c` + `C:/a/b/d` → `C:/a/b`。 */\nfunction commonDirOf(paths: readonly string[]): string {\n if (paths.length < 2) return '';\n const split = paths.map((path) => path.replace(/[.,。;]+$/, '').split('/'));\n const first = split[0] as string[];\n let size = 0;\n while (size < first.length && split.every((parts) => parts[size] === first[size])) size += 1;\n return size < 1 ? '' : first.slice(0, size).join('/');\n}\n\n/** 一份报文里**按根分开**的落点前缀(长的在前):只给「同一个根下至少两条落点」的根算前缀——\n * 这个根下只有一条落点时不缩(没有第二条可比,缩出来反而是瞎猜)。\n * 为什么要分根:一家报里常有别的盘的旁证(备忘录用 D 盘上那份媒体目录),只算一个总前缀,\n * 一条旁证就能把整张表的缩写全拖没(#706 出图复评:备忘录那张表整片没缩、记账那张缩了)。 */\nexport function dirPrefixesOf(report: HealthReport): readonly string[] {\n return dirPrefixesIn(pathsOf(report).join(' '));\n}\n\n/** `dirPrefixesOf` 的正文版:一段文字里(报文正文 + 表头两条混在一起)按根分组取公共目录前缀。 */\nexport function dirPrefixesIn(text: string): readonly string[] {\n const paths = rawPathsIn(text);\n const roots = [...new Set(paths.map(rootOf))];\n const prefixes: string[] = [];\n for (const root of roots) {\n const prefix = commonDirOf(paths.filter((path) => rootOf(path) === root));\n if (prefix !== '') prefixes.push(prefix);\n }\n // 长的在前:一个落点命中多条前缀时,最长的那个才是它真正的目录(缩短后不歧义)。\n return prefixes.sort((a, b) => b.length - a.length);\n}\n\n/** 那一行「配置文件 … · 数据目录 …」+ 各条报文里的长路径,都缩成「公共前缀 + 短尾巴」。 */\nfunction shorten(path: string, prefixes: readonly string[]): string {\n const hit = prefixes.find((prefix) => path.startsWith(prefix + '/'));\n return hit === undefined ? path : '…/' + path.slice(hit.length + 1);\n}\n\n/** 一家里所有会印出来的路径。 */\nexport function pathsOf(report: HealthReport): readonly string[] {\n const out: string[] = [report.configPath, report.dataDir];\n for (const item of report.items) out.push(item.message);\n return out;\n}\n\n/** 把报文里那一长串路径按公共前缀缩短(只动打印,不动事实)。\n * 只按**扫得出来的那一段段落点**去缩,不做全串替换:既不误伤长路径,也不会把一段路劈成半截。 */\nexport function shortenPathsIn(text: string, prefixes: readonly string[]): string {\n const candidates = rawPathsIn(text);\n if (candidates.length === 0) return text;\n // 长的在前:先缩长的那条,缩完它自己就挡住了它的父目录,不会二次缩。\n const longestFirst = [...new Set(candidates.map((path) => path.replace(/[.,。;]+$/, '')))].sort(\n (a, b) => b.length - a.length,\n );\n let out = text;\n for (const path of longestFirst) {\n const hit = prefixes.find((prefix) => path.startsWith(prefix + '/'));\n if (hit === undefined) continue;\n out = out.split(hit + '/').join('…/');\n }\n return out;\n}\n\n/** 一盏灯:一家一名一档(数到几个红黄绿)。点一下把面板切到那家的页签。 */\nexport interface HealthLightRow {\n readonly id: string;\n readonly title: string;\n readonly status: HealthStatus | null;\n readonly counts: Readonly<Record<HealthStatus, number>>;\n}\n\n/** 从六份报告数出那一行的灯(每家按最严重那一档上色)。 */\nexport function lightsOf(\n tabs: readonly { readonly id: string; readonly title: string }[],\n reports: Readonly<Record<string, HealthReport | undefined>>,\n): readonly HealthLightRow[] {\n return tabs.map((tab) => {\n const report = reports[tab.id];\n return {\n id: tab.id,\n title: tab.title,\n status: report ? worstStatus(report.items) : null,\n counts: countByStatus(report?.items ?? []),\n };\n });\n}\n\n/** 一家的一句话读数:「红 1 黄 2」,全绿就是「绿」。 */\nfunction countsText(counts: Readonly<Record<HealthStatus, number>>): string {\n const parts: string[] = [];\n if (counts.red > 0) parts.push('红 ' + String(counts.red));\n if (counts.yellow > 0) parts.push('黄 ' + String(counts.yellow));\n if (parts.length === 0) return '绿';\n return parts.join(' · ');\n}\n\n/** 顶部那行总览:六家一盏灯 + 一个「体检一次」按钮。 */\nexport function HealthOverview(props: {\n readonly lights: readonly HealthLightRow[];\n readonly running: boolean;\n readonly error: string | null;\n readonly onRun: () => void;\n readonly onJump: (id: string) => void;\n}): React.ReactElement {\n return React.createElement(\n 'div',\n { style: HEALTH_STYLE.box, 'data-ilife-health': 'overview' },\n React.createElement(\n 'div',\n { style: HEALTH_STYLE.headRow },\n React.createElement('div', { style: HEALTH_STYLE.head }, '配置体检'),\n ),\n React.createElement(\n 'div',\n { style: HEALTH_STYLE.runRow },\n React.createElement(\n 'button',\n {\n type: 'button',\n style: props.running ? { ...HEALTH_STYLE.btn, opacity: 0.55, cursor: 'default' } : HEALTH_STYLE.btn,\n disabled: props.running,\n onClick: props.onRun,\n title: '对六家各跑一次配置体检(只看不改:不建目录、不改配置)',\n },\n props.running ? '体检中…' : '体检一次',\n ),\n ),\n React.createElement(\n 'div',\n { style: HEALTH_STYLE.lightsRow, 'data-ilife-health': 'lights' },\n props.lights.map((light) =>\n React.createElement(\n 'button',\n {\n key: light.id,\n type: 'button',\n 'data-ilife-health': 'light',\n 'data-skill': light.id,\n // 档位落到按钮自身的边框与底色上:一眼扫过去先看到颜色,再读家名(票面验收:一屏看红黄)。\n style: light.status === null\n ? { ...HEALTH_STYLE.light, ...HEALTH_STYLE.lightIdle }\n : {\n ...HEALTH_STYLE.light,\n borderColor: STATUS_COLOR[light.status],\n borderWidth: 1.5,\n background: STATUS_TINT[light.status],\n },\n disabled: light.status === null,\n onClick: () => props.onJump(light.id),\n title: light.status === null\n ? '还没体检(或这一家没装)'\n : light.title + ':' + countsText(light.counts),\n },\n React.createElement('span', {\n style: {\n width: 10,\n height: 10,\n borderRadius: '50%',\n background: light.status === null ? INK_DIM : STATUS_COLOR[light.status],\n display: 'inline-block',\n },\n }),\n React.createElement('span', { style: { color: INK, fontWeight: 650 } }, light.title),\n React.createElement(\n 'span',\n { style: { color: light.status === null ? INK_DIM : STATUS_TEXT[light.status], fontWeight: 700 } },\n light.status === null ? '—' : countsText(light.counts),\n ),\n ),\n ),\n ),\n React.createElement(\n 'div',\n { style: HEALTH_STYLE.meta },\n props.error !== null ? props.error : '只看不改 · 灯=那一家最严重的一档 · 点一下跳到那家配置页',\n ),\n );\n}\n\n/** 正正常常的那些:绿条只留「名字」,一句话与「去哪修」都不印(票面验收第一条:正常的收成一行)。 */\nfunction isAttentionItem(item: HealthItem): boolean {\n return isAttention(item.status);\n}\n\n/** 一家那张表:**要处理的**(红黄)一条一块、整行上底带一句话与「去哪修」;\n * **正常的**(绿)收成一行并列的小字,点得到、扫得完(票面验收第一条:正常的收成一行,有问题的才展开)。 */\nexport function HealthTable(props: {\n readonly title: string;\n readonly phase: 'idle' | 'running' | 'ready' | 'failed';\n readonly report: HealthReport | null;\n readonly error: string | null;\n}): React.ReactElement {\n const { report } = props;\n const prefixes: readonly string[] = report ? dirPrefixesOf(report) : [];\n return React.createElement(\n 'div',\n { style: HEALTH_STYLE.box, 'data-ilife-health': 'table' },\n React.createElement(\n 'div',\n { style: HEALTH_STYLE.headRow },\n React.createElement('div', { style: HEALTH_STYLE.head }, props.title + ' · 体检'),\n report ? React.createElement('div', { style: { color: INK_DIM, fontSize: 12 } }, countsText(countByStatus(report.items))) : null,\n ),\n props.phase === 'idle'\n ? React.createElement('div', { style: HEALTH_STYLE.meta }, '还没体检:点上面那个「体检一次」。')\n : null,\n props.phase === 'running' ? React.createElement('div', { style: HEALTH_STYLE.meta }, '正在体检…') : null,\n props.error !== null ? React.createElement('div', { style: HEALTH_STYLE.error }, props.error) : null,\n report\n ? React.createElement(\n 'div',\n null,\n // 落点一律缩到公共前缀之内印(四条长路径并排会把每一行撑成两行,视觉复评点过「像日志 dump」);\n // 前缀本身印在悬停里,屏上不留一长串盘符。\n React.createElement('div', { style: HEALTH_STYLE.meta, title: prefixes.join(' ') },\n '配置文件 ' + shorten(report.configPath, prefixes) + ' · 数据目录 ' + shorten(report.dataDir, prefixes)),\n report.items.filter(isAttentionItem).map((item) =>\n React.createElement(\n 'div',\n {\n key: item.id,\n 'data-ilife-health': 'item',\n 'data-status': item.status,\n // 红黄两档整行上底:扫一眼先看见「要处理的」。\n style: {\n padding: '7px 8px',\n margin: '2px 0',\n borderTop: '1px solid ' + BORDER,\n borderRadius: 6,\n fontSize: 13,\n lineHeight: 1.75,\n background: STATUS_TINT[item.status],\n },\n },\n React.createElement(\n 'div',\n { style: { display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 6 } },\n // 档位不只靠颜色认:色弱/灰度截图下也得一眼看出哪条要处理(灯保留作二次确认)。\n React.createElement('span', {\n style: { color: STATUS_TEXT[item.status], fontWeight: 700, fontSize: 13, lineHeight: 1 },\n 'aria-hidden': 'true',\n }, STATUS_MARK[item.status]),\n React.createElement('span', {\n style: {\n width: 8, height: 8, borderRadius: '50%', display: 'inline-block', background: STATUS_COLOR[item.status],\n },\n }),\n React.createElement('span', { style: { fontWeight: 650, color: INK } }, item.title),\n React.createElement('span', {\n style: { color: STATUS_TEXT[item.status], fontWeight: 700 },\n }, STATUS_LABEL[item.status]),\n item.source ? React.createElement('span', { style: { color: INK_DIM } }, '· 来自' + item.source) : null,\n ),\n React.createElement('div', { style: { color: INK }, title: item.message }, shortenPathsIn(item.message, prefixes)),\n item.action.length > 0\n ? React.createElement('div', { style: { color: INK_DIM } }, '去哪修:' + actionText(item.action))\n : null,\n ),\n ),\n // 正常的那一档:一条都不用点开,名字排成一行(`data-ilife-health=\"ok\"` 供判据核对「一条不少」)。\n report.items.some((item) => !isAttentionItem(item))\n ? React.createElement(\n 'div',\n {\n 'data-ilife-health': 'ok',\n style: {\n display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: '2px 10px',\n marginTop: 8, paddingTop: 6, borderTop: '1px solid ' + BORDER,\n fontSize: 12, lineHeight: 1.6, color: INK_DIM,\n },\n },\n React.createElement('span', { style: { fontWeight: 650, color: INK } }, '正常 ' + String(countByStatus(report.items).green) + ' 条'),\n report.items.filter((item) => !isAttentionItem(item)).map((item) =>\n React.createElement('span', { key: item.id, 'data-ilife-health': 'ok-item' }, '· ' + item.title),\n ),\n )\n : null,\n )\n : null,\n );\n}\n","/** dsh-life-pack client 适配器(六边形:browser 侧;爱生活单卡方案)。\n *\n * 真实 DSH 契约(出处见 docs/agents/dsh-client-contract.md §5/§11):\n * - 本文件经 tsdown 打成 loader 工厂包(browser/CJS + 注册包裹),classic 执行\n * 只注册,副作用全在 factory 内;传递闭包禁 node 内建与 ESM 语法(回路\n * test/client-bundle-48.test.mjs 看门)。\n * - inject 短名 ['slots','connection']:本包现在有 RPC(装与更新的能力由宿主半提供,\n * 电话名与轮询间隔由宿主转交,面板不写死),读了 ctx.connection 就必须声明 'connection'(#48 血例)。\n * - 爱生活页签条走 slot 驱动(settings-plugins 先例,禁纯 useState 手画 tab):\n * section 声明 children 爱生活页签槽,各技能往里注册自家技能设置页;\n * tab 行从 ledger 投影(entries+getVersion+subscribe),面板用 props.renderSlot\n * 按 `{only}` 投影(一次只挂载一个)+ visited 缓存;ledger 无某技能=缺席,\n * 显示推荐安装只读文本(不返空冒充)。\n * - 组件 React.createElement 手写(禁 JSX),无数据轮询、无 document/window/process。\n * - 面板外壳两处(票 #679):标题行右上角两个入口(星/气泡,悬停出说明文字,\n * 窄窗口折到标题下方);页签面板之后是底部「作者其他插件」引流卡(四行,点开新窗口)。\n * 文案与网址都取自 nav.ts 的两张静态表,本文件只画不算。\n */\n\nimport * as React from 'react';\nimport { MANAGER_TABS, MANAGER_VERSION, MORE_PLUGINS, PANEL_LINKS, recoFor } from './nav.js';\nimport type { ManagerTab } from './nav.js';\nimport { AbsentCard, CheckUpdateButton, UpdateResults, useUpdateRows } from './update-panel.js';\nimport type { CallFace } from './update-client.js';\nimport { useHealthPanel } from './health-panel.js';\nimport { HealthOverview, HealthTable, lightsOf } from './health-view.js';\nimport { HEALTH_ENDPOINT } from './health-contract.js';\nimport type {\n ClientCtx,\n ConfigTabRow,\n LifePackSectionProps,\n SlotLedgerEntry,\n} from './dsh-ctx.js';\n\nexport const inject = ['slots', 'connection'];\n\n/** 爱生活页签槽(总管声明的 children,技能设置页注册进来;单段名,避开官方 settings.* 前缀)。 */\nexport const CONFIG_TAB_SLOT = 'ilife.config-tab' as const;\n\n/** 总管视觉(内联 style;颜色走 DSH 主题别名,深浅主题自适应,写死值只做回退;与技能面板同语言)。 */\nconst S = {\n headRow: {\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: 8,\n margin: '2px 0 8px',\n } as React.CSSProperties,\n head: { fontSize: 15, fontWeight: 700, flex: '0 0 auto', color: 'var(--dsw-alias-label-primary, inherit)' } as React.CSSProperties,\n headActions: {\n display: 'inline-flex',\n alignItems: 'center',\n gap: 2,\n marginLeft: 'auto',\n flex: '0 0 auto',\n } as React.CSSProperties,\n iconLink: {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: 26,\n height: 26,\n borderRadius: 6,\n border: '1px solid transparent',\n color: 'var(--dsw-alias-label-primary, inherit)',\n textDecoration: 'none',\n fontSize: 14,\n lineHeight: 1,\n } as React.CSSProperties,\n meta: { color: 'var(--dsw-alias-label-secondary, #9a9a9a)', fontSize: 12, lineHeight: 1.7, marginBottom: 10 } as React.CSSProperties,\n tablist: { display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 10 } as React.CSSProperties,\n tab: {\n border: '1px solid var(--dsw-alias-border, rgba(128,128,128,.35))',\n background: 'transparent',\n color: 'var(--dsw-alias-label-primary, inherit)',\n borderRadius: 999,\n padding: '4px 12px',\n fontSize: 13,\n cursor: 'pointer',\n } as React.CSSProperties,\n tabActive: {\n background: 'var(--dsw-alias-brand-primary, #0a84ff)',\n borderColor: 'transparent',\n color: '#fff',\n fontWeight: 700,\n } as React.CSSProperties,\n reco: {\n padding: '12px 14px',\n borderRadius: 10,\n border: '1px dashed var(--dsw-alias-border, rgba(128,128,128,.45))',\n color: 'var(--dsw-alias-label-secondary, #9a9a9a)',\n fontSize: 13,\n lineHeight: 1.7,\n } as React.CSSProperties,\n cmd: {\n display: 'block',\n marginTop: 8,\n padding: '8px 10px',\n borderRadius: 8,\n background: 'var(--dsw-alias-bg-base, rgba(128,128,128,.12))',\n color: 'var(--dsw-alias-label-primary, inherit)',\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n fontSize: 12,\n userSelect: 'all',\n } as React.CSSProperties,\n moreCard: {\n marginTop: 16,\n padding: '10px 12px',\n borderRadius: 10,\n border: '1px solid var(--dsw-alias-border, rgba(128,128,128,.35))',\n } as React.CSSProperties,\n moreTitle: {\n fontSize: 13,\n fontWeight: 700,\n marginBottom: 4,\n color: 'var(--dsw-alias-label-primary, inherit)',\n } as React.CSSProperties,\n moreRow: {\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: '2px 8px',\n padding: '7px 4px',\n textDecoration: 'none',\n color: 'inherit',\n } as React.CSSProperties,\n morePkg: {\n flex: '0 1 auto',\n minWidth: 0,\n overflowWrap: 'anywhere',\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n fontSize: 12,\n fontWeight: 650,\n } as React.CSSProperties,\n moreDesc: {\n flex: '1 1 180px',\n minWidth: 0,\n fontSize: 11.5,\n lineHeight: 1.6,\n color: 'var(--dsw-alias-label-secondary, #9a9a9a)',\n } as React.CSSProperties,\n moreIcon: {\n flex: '0 0 auto',\n marginLeft: 'auto',\n display: 'inline-flex',\n color: 'var(--dsw-alias-label-secondary, #9a9a9a)',\n } as React.CSSProperties,\n};\n\n/** 缺席卡的画法与流程住 `update-panel.ts`(票 #678:一句人话 +「装上」按钮 + 可复制命令),\n * `recoFor` 的补装命令仍是卡里那条辅助展示(B11 口径不变)。 */\n\n/** 标签解析(resolveSlotLabel 同形:thunk 跟活,无则空字串;见 slots lib:27-29)。 */\nfunction resolveLabel(label: SlotLedgerEntry['options']['label']): string {\n if (typeof label === 'function') return label();\n return label ?? '';\n}\n\n/** 外链图标(行尾那个;纯装饰,语义在链接自己的 aria-label/文字上)。 */\nfunction ExternalIcon(): React.ReactElement {\n return React.createElement(\n 'svg',\n {\n viewBox: '0 0 24 24',\n width: 13,\n height: 13,\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: 1.9,\n strokeLinecap: 'round',\n strokeLinejoin: 'round',\n 'aria-hidden': 'true',\n focusable: 'false',\n },\n React.createElement('path', { d: 'M13.5 4.5H19.5V10.5' }),\n React.createElement('path', { d: 'M19.5 4.5L11 13' }),\n React.createElement('path', { d: 'M18 14.5V18A2 2 0 0 1 16 20H6A2 2 0 0 1 4 18V8A2 2 0 0 1 6 6H9.5' }),\n );\n}\n\n/** 标题行右上角两件:星(去本仓点 Star)+ 气泡(去本仓开 issue),悬停出说明文字。\n *\n * 三件并排里的第三件「检查更新」住隔壁票(#678):本票只留位子——它就接在本组件之前,\n * 不画一个点了没反应的假按钮。窄窗口靠 headRow 的 flexWrap 折到标题下方,\n * 标题与两件都是 flex:'0 0 auto',谁也不挤谁。\n */\nfunction PanelActions(): React.ReactElement {\n return React.createElement(\n 'div',\n { style: S.headActions },\n PANEL_LINKS.map((link) =>\n React.createElement(\n 'a',\n {\n key: link.key,\n href: link.url,\n target: '_blank',\n rel: 'noreferrer',\n title: link.tip,\n 'aria-label': link.tip,\n style: S.iconLink,\n },\n React.createElement('span', { 'aria-hidden': 'true' }, link.glyph),\n ),\n ),\n );\n}\n\n/** 底部「作者其他插件」引流卡:四行(包名 + 一句说明 + 行尾外链图标),点开新窗口。\n *\n * 卡片在页签面板之后,六页签切换它都在(它不属于任何一个页签)。\n */\nfunction MorePluginsCard(): React.ReactElement {\n return React.createElement(\n 'div',\n { style: S.moreCard },\n React.createElement('div', { style: S.moreTitle }, '作者其他插件'),\n MORE_PLUGINS.map((row) =>\n React.createElement(\n 'a',\n {\n key: row.pkg,\n href: row.url,\n target: '_blank',\n rel: 'noreferrer',\n title: row.pkg + ' 的 GitHub 仓库',\n style: S.moreRow,\n },\n React.createElement('span', { style: S.morePkg }, row.pkg),\n React.createElement('span', { style: S.moreDesc }, row.desc),\n React.createElement('span', { style: S.moreIcon }, React.createElement(ExternalIcon, null)),\n ),\n ),\n );\n}\n\n/** 爱生活面板:总设置区 + 检查更新(七家)+ 爱生活页签条(slot 驱动)+ 技能设置页投影/缺席卡。 */\nfunction LifePackSection(props: LifePackSectionProps & { getCall: () => CallFace | null }): React.ReactElement {\n const tabsId = React.useId();\n const tabRefs = React.useRef<Array<HTMLButtonElement | null>>([]);\n const rows: ConfigTabRow[] = props.useTabs((value) => value);\n const present = new Set(rows.map((r) => r.id));\n const face = useUpdateRows(props.getCall);\n // 配置体检(#706):一张表六份报告,总览那行与各家那张表都从它读(同一份数据)。\n // 通道名由各家注册时写进页签槽 options,总管源码里不出现任何一家的通道名。\n const healthTabs = React.useMemo(\n () => rows.filter((row) => row.channel.length > 0).map((row) => ({ id: row.id, channel: row.channel })),\n [rows],\n );\n const health = useHealthPanel(() => props.getCall(), healthTabs);\n const [activeId, setActiveId] = React.useState<string | undefined>(undefined);\n const [visitedIds, setVisitedIds] = React.useState<ReadonlySet<string>>(() => new Set());\n const active = MANAGER_TABS.some((t) => t.plugin === activeId)\n ? (activeId as string)\n : MANAGER_TABS[0].plugin;\n React.useEffect(() => {\n setVisitedIds((previous) => {\n if (previous.has(active)) return previous;\n return new Set([...previous, active]);\n });\n }, [active]);\n function labelFor(tab: ManagerTab): string {\n const row = rows.find((r) => r.id === tab.plugin);\n return row && row.label.length > 0 ? row.label : tab.title;\n }\n /** 按包名取页签标题(总览那行按账本行过,账本里没有的退到导航表的标题)。 */\n function labelForTab(id: string): string {\n const row = rows.find((r) => r.id === id);\n if (row && row.label.length > 0) return row.label;\n const tab = MANAGER_TABS.find((t) => t.plugin === id);\n return tab ? tab.title : id;\n }\n function targetForTab(tab: ManagerTab) {\n return face.targets.find((t) => t.packageName === tab.plugin) ?? null;\n }\n function onTabKeyDown(event: React.KeyboardEvent, index: number): void {\n let nextIndex: number | undefined;\n switch (event.key) {\n case 'ArrowRight': nextIndex = (index + 1) % MANAGER_TABS.length; break;\n case 'ArrowLeft': nextIndex = (index - 1 + MANAGER_TABS.length) % MANAGER_TABS.length; break;\n case 'Home': nextIndex = 0; break;\n case 'End': nextIndex = MANAGER_TABS.length - 1; break;\n default: return;\n }\n event.preventDefault();\n const next = MANAGER_TABS[nextIndex];\n setActiveId(next.plugin);\n tabRefs.current[nextIndex]?.focus();\n }\n return React.createElement(\n 'div',\n null,\n React.createElement(\n 'div',\n { style: S.headRow },\n React.createElement('div', { style: S.head }, '爱生活'),\n // 三件并排:本票的「检查更新」在左,隔壁票(#679)的星与气泡在右,整组靠右(窄窗口折行)。\n React.createElement(\n 'div',\n { style: S.headActions },\n React.createElement(CheckUpdateButton, { face }),\n React.createElement(PanelActions, null),\n ),\n ),\n React.createElement(\n 'div',\n { style: S.meta },\n React.createElement('div', null, '总开关 · 开关(缺省启用,只读)'),\n React.createElement('div', null, '总管 dsh-life-pack · ' + MANAGER_VERSION),\n ),\n React.createElement(UpdateResults, { face }),\n React.createElement(HealthOverview, {\n lights: lightsOf(\n rows.map((row) => ({ id: row.id, title: labelForTab(row.id) })),\n Object.fromEntries(Object.entries(health.rows).map(([id, row]) => [id, row.report ?? undefined])),\n ),\n running: health.running,\n error: health.error,\n onRun: health.run,\n onJump: setActiveId,\n }),\n React.createElement(\n 'div',\n { role: 'tablist', 'aria-label': '爱生活技能页签', style: S.tablist },\n MANAGER_TABS.map((tab, index) => {\n const selected = tab.plugin === active;\n return React.createElement(\n 'button',\n {\n key: tab.plugin,\n ref: (element: HTMLButtonElement | null) => {\n tabRefs.current[index] = element;\n },\n id: tabsId + '-tab-' + tab.plugin,\n type: 'button',\n role: 'tab',\n 'aria-selected': selected,\n 'aria-controls': tabsId + '-panel-' + tab.plugin,\n tabIndex: selected ? 0 : -1,\n style: selected ? { ...S.tab, ...S.tabActive } : S.tab,\n onClick: () => {\n setActiveId(tab.plugin);\n },\n onKeyDown: (event: React.KeyboardEvent) => {\n onTabKeyDown(event, index);\n },\n },\n (present.has(tab.plugin) ? '● ' : '○ ') + labelFor(tab),\n );\n }),\n ),\n MANAGER_TABS.filter((tab) => tab.plugin === active || visitedIds.has(tab.plugin)).map((tab) => {\n const selected = tab.plugin === active;\n return React.createElement(\n 'div',\n {\n key: tab.plugin,\n id: tabsId + '-panel-' + tab.plugin,\n role: 'tabpanel',\n 'aria-labelledby': tabsId + '-tab-' + tab.plugin,\n hidden: !selected,\n },\n present.has(tab.plugin)\n ? React.createElement(\n 'div',\n null,\n props.renderSlot(CONFIG_TAB_SLOT, {}, { only: tab.plugin }) as React.ReactNode,\n // 那家的体检表:与总览那行读同一份快照(`health.rows`),不是各算一遍。\n React.createElement(HealthTable, {\n title: labelFor(tab),\n phase: health.rows[tab.plugin]?.phase ?? 'idle',\n report: health.rows[tab.plugin]?.report ?? null,\n error: health.rows[tab.plugin]?.error ?? null,\n }),\n )\n : React.createElement(AbsentCard, {\n target: targetForTab(tab),\n fallbackCommand: recoFor(tab).installCmd,\n face,\n }),\n );\n }),\n React.createElement(MorePluginsCard, null),\n );\n}\n\nexport function apply(ctx: ClientCtx): void {\n // 调用口取用器:每次取数时现取(connection 后到也不永久缺席),透传给面板组件。\n const getCall = (): CallFace | null => (ctx.connection?.rpc?.call as CallFace | undefined) ?? null;\n // ledger 观测源(settings-plugins:1744-1767 同形;无 locale 面声明,故只订 ledger)。\n let tabsVersion = -1;\n let tabs: ConfigTabRow[] = [];\n const sectionInjected = () => ({\n hooks: {\n tabs: {\n getSnapshot: () => {\n const version = ctx.slots.getVersion(CONFIG_TAB_SLOT);\n if (version !== tabsVersion) {\n tabsVersion = version;\n tabs = ctx.slots\n .entries(CONFIG_TAB_SLOT)\n .map((entry) => ({\n id: entry.options.id ?? '',\n order: entry.options.order ?? 0,\n label: resolveLabel(entry.options.label),\n // #706 配置体检的通道:各家注册时写进 options,缺席即这一家没有体检出口(灯显 —)。\n channel: entry.options.channel ?? '',\n }))\n .sort((a, b) => a.order - b.order);\n }\n return tabs;\n },\n subscribe: (listener: () => void) => ctx.slots.subscribe(CONFIG_TAB_SLOT, listener),\n },\n },\n });\n ctx.slots.inject('settings.section', () =>\n ctx.slots.register(\n {\n name: 'settings.section',\n id: 'dsh-life-pack',\n order: 21,\n label: () => '爱生活',\n inject: sectionInjected,\n children: { 'ilife.config-tab': { kind: 'list', scope: 'root' } },\n },\n (props: LifePackSectionProps) => React.createElement(LifePackSection, { ...props, getCall }),\n ),\n );\n}\n"],"mappings":"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"}
|
package/dist/health-view.d.ts
CHANGED
|
@@ -23,6 +23,18 @@ export declare const HEALTH_STYLE: {
|
|
|
23
23
|
/** 「去哪修」那一行的正文:各家交回来的 action 里若已自带「去哪修:」,这里剥掉一层——
|
|
24
24
|
* 面板已经带了这个前缀,两边都写就会印成「去哪修:去哪修:…」。只剥开头那一次,别的一字不动。 */
|
|
25
25
|
export declare function actionText(action: string): string;
|
|
26
|
+
/** 一份报文里**按根分开**的落点前缀(长的在前):只给「同一个根下至少两条落点」的根算前缀——
|
|
27
|
+
* 这个根下只有一条落点时不缩(没有第二条可比,缩出来反而是瞎猜)。
|
|
28
|
+
* 为什么要分根:一家报里常有别的盘的旁证(备忘录用 D 盘上那份媒体目录),只算一个总前缀,
|
|
29
|
+
* 一条旁证就能把整张表的缩写全拖没(#706 出图复评:备忘录那张表整片没缩、记账那张缩了)。 */
|
|
30
|
+
export declare function dirPrefixesOf(report: HealthReport): readonly string[];
|
|
31
|
+
/** `dirPrefixesOf` 的正文版:一段文字里(报文正文 + 表头两条混在一起)按根分组取公共目录前缀。 */
|
|
32
|
+
export declare function dirPrefixesIn(text: string): readonly string[];
|
|
33
|
+
/** 一家里所有会印出来的路径。 */
|
|
34
|
+
export declare function pathsOf(report: HealthReport): readonly string[];
|
|
35
|
+
/** 把报文里那一长串路径按公共前缀缩短(只动打印,不动事实)。
|
|
36
|
+
* 只按**扫得出来的那一段段落点**去缩,不做全串替换:既不误伤长路径,也不会把一段路劈成半截。 */
|
|
37
|
+
export declare function shortenPathsIn(text: string, prefixes: readonly string[]): string;
|
|
26
38
|
/** 一盏灯:一家一名一档(数到几个红黄绿)。点一下把面板切到那家的页签。 */
|
|
27
39
|
export interface HealthLightRow {
|
|
28
40
|
readonly id: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"health-view.d.ts","sourceRoot":"","sources":["../src/health-view.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAc,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"health-view.d.ts","sourceRoot":"","sources":["../src/health-view.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAc,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAuCnF,eAAO,MAAM,YAAY;kBAMlB,KAAK,CAAC,aAAa;sBACyE,KAAK,CAAC,aAAa;mBAC7D,KAAK,CAAC,aAAa;IAC1E,wDAAwD;qBACpB,KAAK,CAAC,aAAa;kBAUlD,KAAK,CAAC,aAAa;wBACoC,KAAK,CAAC,aAAa;oBAY1E,KAAK,CAAC,aAAa;wBAC4B,KAAK,CAAC,aAAa;mBACG,KAAK,CAAC,aAAa;oBACV,KAAK,CAAC,aAAa;CAC9F,CAAC;AAOX;qDACqD;AACrD,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGjD;AAwBD;;;qDAGqD;AACrD,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,MAAM,EAAE,CAErE;AAED,8DAA8D;AAC9D,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAU7D;AAQD,oBAAoB;AACpB,wBAAgB,OAAO,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,MAAM,EAAE,CAI/D;AAED;sDACsD;AACtD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAchF;AAED,yCAAyC;AACzC,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;CACzD;AAED,iCAAiC;AACjC,wBAAgB,QAAQ,CACtB,IAAI,EAAE,SAAS;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,EAChE,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,CAAC,CAAC,GAC1D,SAAS,cAAc,EAAE,CAU3B;AAWD,iCAAiC;AACjC,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,QAAQ,CAAC,MAAM,EAAE,SAAS,cAAc,EAAE,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC,GAAG,KAAK,CAAC,YAAY,CA0ErB;AAOD;4DAC4D;AAC5D,wBAAgB,WAAW,CAAC,KAAK,EAAE;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;IACxD,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,GAAG,KAAK,CAAC,YAAY,CAyFrB"}
|
package/dist/health-view.js
CHANGED
|
@@ -32,6 +32,8 @@ const STATUS_TEXT = {
|
|
|
32
32
|
green: 'var(--dsw-alias-state-success-primary, #4ec9a0)',
|
|
33
33
|
};
|
|
34
34
|
const STATUS_LABEL = { red: '红', yellow: '黄', green: '绿' };
|
|
35
|
+
/** 档位的**形状**标记:颜色之外的第二条读数(灰度截图、色弱视角下也分得开谁要处理)。 */
|
|
36
|
+
const STATUS_MARK = { red: '✕', yellow: '!', green: '✓' };
|
|
35
37
|
/** 面板上的文字色与分隔线(与 `client.ts` 同一套别名)。 */
|
|
36
38
|
const INK = 'var(--dsw-alias-label-primary, inherit)';
|
|
37
39
|
const INK_DIM = 'var(--dsw-alias-label-secondary, #9a9a9a)';
|
|
@@ -52,8 +54,9 @@ export const HEALTH_STYLE = {
|
|
|
52
54
|
background: 'transparent',
|
|
53
55
|
color: INK,
|
|
54
56
|
borderRadius: 8,
|
|
55
|
-
padding: '
|
|
57
|
+
padding: '6px 16px',
|
|
56
58
|
fontSize: 13,
|
|
59
|
+
fontWeight: 600,
|
|
57
60
|
cursor: 'pointer',
|
|
58
61
|
},
|
|
59
62
|
lightsRow: { display: 'flex', flexWrap: 'wrap', gap: 8 },
|
|
@@ -83,6 +86,76 @@ export function actionText(action) {
|
|
|
83
86
|
const trimmed = action.trim();
|
|
84
87
|
return trimmed.startsWith('去哪修:') ? trimmed.slice(4).trim() : trimmed;
|
|
85
88
|
}
|
|
89
|
+
/** 报文里能扫出来的每一段路径(盘符绝对路径;非 Windows 形状的退回 `/` 打头那一支)。 */
|
|
90
|
+
function rawPathsIn(text) {
|
|
91
|
+
return text.match(/[A-Za-z]:\/[^\s()「」,。;]+/g) ?? text.match(/\/[^\s()「」,。;]+/g) ?? [];
|
|
92
|
+
}
|
|
93
|
+
/** 一段落点的**根**(盘符):`C:/a/b` → `C:/`。用来把「同一个盘、但根下不同枝」的落点分开算,
|
|
94
|
+
* 免得一个 D 盘上的旁证(比如「配了但目录不在:D:/media」)把 C 盘那几条的缩写全拖没。 */
|
|
95
|
+
function rootOf(path) {
|
|
96
|
+
const drive = /^[A-Za-z]:\//.exec(path);
|
|
97
|
+
return drive === null ? '/' : drive[0];
|
|
98
|
+
}
|
|
99
|
+
/** 一段落点的公共目录前缀(按 `/` 切、整段比):`C:/a/b/c` + `C:/a/b/d` → `C:/a/b`。 */
|
|
100
|
+
function commonDirOf(paths) {
|
|
101
|
+
if (paths.length < 2)
|
|
102
|
+
return '';
|
|
103
|
+
const split = paths.map((path) => path.replace(/[.,。;]+$/, '').split('/'));
|
|
104
|
+
const first = split[0];
|
|
105
|
+
let size = 0;
|
|
106
|
+
while (size < first.length && split.every((parts) => parts[size] === first[size]))
|
|
107
|
+
size += 1;
|
|
108
|
+
return size < 1 ? '' : first.slice(0, size).join('/');
|
|
109
|
+
}
|
|
110
|
+
/** 一份报文里**按根分开**的落点前缀(长的在前):只给「同一个根下至少两条落点」的根算前缀——
|
|
111
|
+
* 这个根下只有一条落点时不缩(没有第二条可比,缩出来反而是瞎猜)。
|
|
112
|
+
* 为什么要分根:一家报里常有别的盘的旁证(备忘录用 D 盘上那份媒体目录),只算一个总前缀,
|
|
113
|
+
* 一条旁证就能把整张表的缩写全拖没(#706 出图复评:备忘录那张表整片没缩、记账那张缩了)。 */
|
|
114
|
+
export function dirPrefixesOf(report) {
|
|
115
|
+
return dirPrefixesIn(pathsOf(report).join(' '));
|
|
116
|
+
}
|
|
117
|
+
/** `dirPrefixesOf` 的正文版:一段文字里(报文正文 + 表头两条混在一起)按根分组取公共目录前缀。 */
|
|
118
|
+
export function dirPrefixesIn(text) {
|
|
119
|
+
const paths = rawPathsIn(text);
|
|
120
|
+
const roots = [...new Set(paths.map(rootOf))];
|
|
121
|
+
const prefixes = [];
|
|
122
|
+
for (const root of roots) {
|
|
123
|
+
const prefix = commonDirOf(paths.filter((path) => rootOf(path) === root));
|
|
124
|
+
if (prefix !== '')
|
|
125
|
+
prefixes.push(prefix);
|
|
126
|
+
}
|
|
127
|
+
// 长的在前:一个落点命中多条前缀时,最长的那个才是它真正的目录(缩短后不歧义)。
|
|
128
|
+
return prefixes.sort((a, b) => b.length - a.length);
|
|
129
|
+
}
|
|
130
|
+
/** 那一行「配置文件 … · 数据目录 …」+ 各条报文里的长路径,都缩成「公共前缀 + 短尾巴」。 */
|
|
131
|
+
function shorten(path, prefixes) {
|
|
132
|
+
const hit = prefixes.find((prefix) => path.startsWith(prefix + '/'));
|
|
133
|
+
return hit === undefined ? path : '…/' + path.slice(hit.length + 1);
|
|
134
|
+
}
|
|
135
|
+
/** 一家里所有会印出来的路径。 */
|
|
136
|
+
export function pathsOf(report) {
|
|
137
|
+
const out = [report.configPath, report.dataDir];
|
|
138
|
+
for (const item of report.items)
|
|
139
|
+
out.push(item.message);
|
|
140
|
+
return out;
|
|
141
|
+
}
|
|
142
|
+
/** 把报文里那一长串路径按公共前缀缩短(只动打印,不动事实)。
|
|
143
|
+
* 只按**扫得出来的那一段段落点**去缩,不做全串替换:既不误伤长路径,也不会把一段路劈成半截。 */
|
|
144
|
+
export function shortenPathsIn(text, prefixes) {
|
|
145
|
+
const candidates = rawPathsIn(text);
|
|
146
|
+
if (candidates.length === 0)
|
|
147
|
+
return text;
|
|
148
|
+
// 长的在前:先缩长的那条,缩完它自己就挡住了它的父目录,不会二次缩。
|
|
149
|
+
const longestFirst = [...new Set(candidates.map((path) => path.replace(/[.,。;]+$/, '')))].sort((a, b) => b.length - a.length);
|
|
150
|
+
let out = text;
|
|
151
|
+
for (const path of longestFirst) {
|
|
152
|
+
const hit = prefixes.find((prefix) => path.startsWith(prefix + '/'));
|
|
153
|
+
if (hit === undefined)
|
|
154
|
+
continue;
|
|
155
|
+
out = out.split(hit + '/').join('…/');
|
|
156
|
+
}
|
|
157
|
+
return out;
|
|
158
|
+
}
|
|
86
159
|
/** 从六份报告数出那一行的灯(每家按最严重那一档上色)。 */
|
|
87
160
|
export function lightsOf(tabs, reports) {
|
|
88
161
|
return tabs.map((tab) => {
|
|
@@ -151,10 +224,14 @@ function isAttentionItem(item) {
|
|
|
151
224
|
* **正常的**(绿)收成一行并列的小字,点得到、扫得完(票面验收第一条:正常的收成一行,有问题的才展开)。 */
|
|
152
225
|
export function HealthTable(props) {
|
|
153
226
|
const { report } = props;
|
|
227
|
+
const prefixes = report ? dirPrefixesOf(report) : [];
|
|
154
228
|
return React.createElement('div', { style: HEALTH_STYLE.box, 'data-ilife-health': 'table' }, React.createElement('div', { style: HEALTH_STYLE.headRow }, React.createElement('div', { style: HEALTH_STYLE.head }, props.title + ' · 体检'), report ? React.createElement('div', { style: { color: INK_DIM, fontSize: 12 } }, countsText(countByStatus(report.items))) : null), props.phase === 'idle'
|
|
155
229
|
? React.createElement('div', { style: HEALTH_STYLE.meta }, '还没体检:点上面那个「体检一次」。')
|
|
156
230
|
: null, props.phase === 'running' ? React.createElement('div', { style: HEALTH_STYLE.meta }, '正在体检…') : null, props.error !== null ? React.createElement('div', { style: HEALTH_STYLE.error }, props.error) : null, report
|
|
157
|
-
? React.createElement('div', null,
|
|
231
|
+
? React.createElement('div', null,
|
|
232
|
+
// 落点一律缩到公共前缀之内印(四条长路径并排会把每一行撑成两行,视觉复评点过「像日志 dump」);
|
|
233
|
+
// 前缀本身印在悬停里,屏上不留一长串盘符。
|
|
234
|
+
React.createElement('div', { style: HEALTH_STYLE.meta, title: prefixes.join(' ') }, '配置文件 ' + shorten(report.configPath, prefixes) + ' · 数据目录 ' + shorten(report.dataDir, prefixes)), report.items.filter(isAttentionItem).map((item) => React.createElement('div', {
|
|
158
235
|
key: item.id,
|
|
159
236
|
'data-ilife-health': 'item',
|
|
160
237
|
'data-status': item.status,
|
|
@@ -168,13 +245,18 @@ export function HealthTable(props) {
|
|
|
168
245
|
lineHeight: 1.75,
|
|
169
246
|
background: STATUS_TINT[item.status],
|
|
170
247
|
},
|
|
171
|
-
}, React.createElement('div', { style: { display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 6 } },
|
|
248
|
+
}, React.createElement('div', { style: { display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 6 } },
|
|
249
|
+
// 档位不只靠颜色认:色弱/灰度截图下也得一眼看出哪条要处理(灯保留作二次确认)。
|
|
250
|
+
React.createElement('span', {
|
|
251
|
+
style: { color: STATUS_TEXT[item.status], fontWeight: 700, fontSize: 13, lineHeight: 1 },
|
|
252
|
+
'aria-hidden': 'true',
|
|
253
|
+
}, STATUS_MARK[item.status]), React.createElement('span', {
|
|
172
254
|
style: {
|
|
173
255
|
width: 8, height: 8, borderRadius: '50%', display: 'inline-block', background: STATUS_COLOR[item.status],
|
|
174
256
|
},
|
|
175
257
|
}), React.createElement('span', { style: { fontWeight: 650, color: INK } }, item.title), React.createElement('span', {
|
|
176
258
|
style: { color: STATUS_TEXT[item.status], fontWeight: 700 },
|
|
177
|
-
}, STATUS_LABEL[item.status]), item.source ? React.createElement('span', { style: { color: INK_DIM } }, '· 来自' + item.source) : null), React.createElement('div', { style: { color: INK } }, item.message), item.action.length > 0
|
|
259
|
+
}, STATUS_LABEL[item.status]), item.source ? React.createElement('span', { style: { color: INK_DIM } }, '· 来自' + item.source) : null), React.createElement('div', { style: { color: INK }, title: item.message }, shortenPathsIn(item.message, prefixes)), item.action.length > 0
|
|
178
260
|
? React.createElement('div', { style: { color: INK_DIM } }, '去哪修:' + actionText(item.action))
|
|
179
261
|
: null)),
|
|
180
262
|
// 正常的那一档:一条都不用点开,名字排成一行(`data-ilife-health="ok"` 供判据核对「一条不少」)。
|
package/dist/health-view.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"health-view.js","sourceRoot":"","sources":["../src/health-view.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"health-view.js","sourceRoot":"","sources":["../src/health-view.ts"],"names":[],"mappings":"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"}
|
package/dist/nav.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export interface RecoTab extends ManagerTab {
|
|
|
27
27
|
}
|
|
28
28
|
export declare const MANAGER_PLUGIN: "dsh-life-pack";
|
|
29
29
|
/** 总管版本号(与 package.json 同步,release 时一起 bump;设置页总设置区版本行唯一来源)。 */
|
|
30
|
-
export declare const MANAGER_VERSION: "0.2.
|
|
30
|
+
export declare const MANAGER_VERSION: "0.2.5";
|
|
31
31
|
export declare const DUAL_ADD_PREFIX: "dsh plugin add dsh-life-pack";
|
|
32
32
|
export declare function dualInstallCmd(singlePlugin: string): string;
|
|
33
33
|
/** P3 定案 6 tab(order 升序即 + 号菜单顺序;已打开条不受 order 控制)。 */
|
package/dist/nav.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
export const MANAGER_PLUGIN = 'dsh-life-pack';
|
|
15
15
|
/** 总管版本号(与 package.json 同步,release 时一起 bump;设置页总设置区版本行唯一来源)。 */
|
|
16
|
-
export const MANAGER_VERSION = '0.2.
|
|
16
|
+
export const MANAGER_VERSION = '0.2.5';
|
|
17
17
|
export const DUAL_ADD_PREFIX = 'dsh plugin add dsh-life-pack';
|
|
18
18
|
export function dualInstallCmd(singlePlugin) {
|
|
19
19
|
return DUAL_ADD_PREFIX + ' ' + singlePlugin;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update-client.d.ts","sourceRoot":"","sources":["../src/update-client.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEjE,yDAAyD;AACzD,MAAM,MAAM,QAAQ,GAAG,CACrB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,EAChB,MAAM,CAAC,EAAE,WAAW,KACjB,OAAO,CACR;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAC9C;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAA;CAAE,CACzI,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,kDAAkD;IAClD,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAAG,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"update-client.d.ts","sourceRoot":"","sources":["../src/update-client.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEjE,yDAAyD;AACzD,MAAM,MAAM,QAAQ,GAAG,CACrB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,EAChB,MAAM,CAAC,EAAE,WAAW,KACjB,OAAO,CACR;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAC9C;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAA;CAAE,CACzI,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,kDAAkD;IAClD,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAAG,WAAW,CAAC;AA8CpF,+CAA+C;AAC/C,wBAAsB,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC;IAAE,OAAO,EAAE,UAAU,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAMxH;AAED,gEAAgE;AAChE,wBAAsB,WAAW,CAC/B,IAAI,EAAE,QAAQ,GAAG,IAAI,EACrB,MAAM,EAAE,UAAU,EAClB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,CAIpC;AAED,6CAA6C;AAC7C,wBAAsB,aAAa,CACjC,IAAI,EAAE,QAAQ,GAAG,IAAI,EACrB,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,WAAW,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAEhE;AAED,kDAAkD;AAClD,wBAAsB,eAAe,CACnC,IAAI,EAAE,QAAQ,GAAG,IAAI,EACrB,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,CAyCpC"}
|
package/dist/update-client.js
CHANGED
|
@@ -37,7 +37,9 @@ async function callManager(call, method, payload) {
|
|
|
37
37
|
result = await call(MANAGER_RPC.base, MANAGER_RPC.endpoint, { method, payload });
|
|
38
38
|
}
|
|
39
39
|
catch (error) {
|
|
40
|
-
|
|
40
|
+
// 传输层失败(路由没注册、宿主半版本对不上、请求挂了):不许套用「查新版失败」那句——
|
|
41
|
+
// 它对这种情形是误导(真机上就这么误报过一次)。各层的失败各有各的话。
|
|
42
|
+
return failure('manager-unreachable', { detail: String(error?.message ?? error) });
|
|
41
43
|
}
|
|
42
44
|
if (!result || typeof result !== 'object' || typeof result.ok !== 'boolean') {
|
|
43
45
|
return failure('internal', { detail: '回执信封异常(非 ok 信封)' });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update-client.js","sourceRoot":"","sources":["../src/update-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAyBhF,6CAA6C;AAC7C,MAAM,cAAc,GAAG,GAAG,CAAC;AAC3B,8DAA8D;AAC9D,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAC9B,IAAI,UAAU,GAAG,CAAC,CAAC;AAEnB,SAAS,OAAO,CAAC,IAAY,EAAE,UAAmC,EAAE,EAAE,SAAwB,IAAI;IAChG,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AACzE,CAAC;AAED;;;wBAGwB;AACxB,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO,EAAE,CAAC;QACZ,CAAC,EAAE,EAAE,CAAC,CAAC;IACT,CAAC,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,WAAW,CAAI,IAAqB,EAAE,MAAc,EAAE,OAAgC;IACnG,IAAI,OAAO,IAAI,KAAK,UAAU;QAAE,OAAO,OAAO,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,gCAAgC,EAAE,CAAC,CAAC;IACzG,IAAI,MAAqC,CAAC;IAC1C,IAAI,CAAC;QACH,uDAAuD;QACvD,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IACnF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"update-client.js","sourceRoot":"","sources":["../src/update-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update-contract.d.ts","sourceRoot":"","sources":["../src/update-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,gFAAgF;AAChF,eAAO,MAAM,WAAW;IACtB,kEAAkE;;IAElE,2DAA2D;;IAE3D,gCAAgC;;IAEhC,wCAAwC;;CAEhC,CAAC;AAEX,wDAAwD;AACxD,eAAO,MAAM,eAAe;IAC1B,wEAAwE;;IAExE;;;;;qBAKiB;;CAET,CAAC;AAEX,+CAA+C;AAC/C,eAAO,MAAM,gBAAgB,EAAG,6BAAsC,CAAC;
|
|
1
|
+
{"version":3,"file":"update-contract.d.ts","sourceRoot":"","sources":["../src/update-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,gFAAgF;AAChF,eAAO,MAAM,WAAW;IACtB,kEAAkE;;IAElE,2DAA2D;;IAE3D,gCAAgC;;IAEhC,wCAAwC;;CAEhC,CAAC;AAEX,wDAAwD;AACxD,eAAO,MAAM,eAAe;IAC1B,wEAAwE;;IAExE;;;;;qBAKiB;;CAET,CAAC;AAEX,+CAA+C;AAC/C,eAAO,MAAM,gBAAgB,EAAG,6BAAsC,CAAC;AAsBvE,uCAAuC;AACvC,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,iDAAiD;AACjD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC1C,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,MAAM,GAAG,IAAI,CAQhB;AAED,kDAAkD;AAClD,eAAO,MAAM,eAAe,EAAE,SAAS,aAAa,EASnD,CAAC"}
|
package/dist/update-contract.js
CHANGED
|
@@ -38,6 +38,7 @@ const REASON_TEXT = {
|
|
|
38
38
|
'check-expired': '上次查新版的凭证过期了:重新查一次再点安装(不要重试旧编号)。',
|
|
39
39
|
'update-busy': '同一个使用范围同时只装一个:等当前任务结束再点。',
|
|
40
40
|
'install-failed': '安装没跑成:按下面那条手工命令在终端执行一次。',
|
|
41
|
+
'manager-unreachable': '总管的电话没接上(宿主半没注册或版本对不上):重启宿主后再试;仍不行看宿主日志。',
|
|
41
42
|
'bad-request': '回执异常(请求形状不对):把宿主日志里的事件名报给作者。',
|
|
42
43
|
internal: '回执异常(总管内部错误):把宿主日志里的事件名报给作者。',
|
|
43
44
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update-contract.js","sourceRoot":"","sources":["../src/update-contract.ts"],"names":[],"mappings":"AAaA,gFAAgF;AAChF,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,kEAAkE;IAClE,IAAI,EAAE,MAAM;IACZ,2DAA2D;IAC3D,OAAO,EAAE,gBAAgB;IACzB,gCAAgC;IAChC,QAAQ,EAAE,eAAe;IACzB,wCAAwC;IACxC,IAAI,EAAE,oBAAoB;CAClB,CAAC;AAEX,wDAAwD;AACxD,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,wEAAwE;IACxE,OAAO,EAAE,uBAAuB;IAChC;;;;;qBAKiB;IACjB,OAAO,EAAE,uBAAuB;CACxB,CAAC;AAEX,+CAA+C;AAC/C,MAAM,CAAC,MAAM,gBAAgB,GAAG,6BAAsC,CAAC;AAEvE,uEAAuE;AACvE,MAAM,WAAW,GAA2B;IAC1C,iBAAiB,EAAE,6CAA6C;IAChE,gBAAgB,EAAE,mCAAmC;IACrD,sBAAsB,EAAE,6CAA6C;IACrE,sBAAsB,EAAE,gCAAgC;IACxD,iBAAiB,EAAE,2BAA2B;IAC9C,mBAAmB,EAAE,8CAA8C;IACnE,mBAAmB,EAAE,kDAAkD;IACvE,mBAAmB,EAAE,sCAAsC;IAC3D,cAAc,EAAE,qCAAqC;IACrD,iBAAiB,EAAE,2CAA2C;IAC9D,eAAe,EAAE,iCAAiC;IAClD,aAAa,EAAE,0BAA0B;IACzC,gBAAgB,EAAE,yBAAyB;IAC3C,aAAa,EAAE,8BAA8B;IAC7C,QAAQ,EAAE,8BAA8B;CACzC,CAAC;AAEF,uCAAuC;AACvC,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,WAAW,CAAC,IAAI,CAAC,IAAI,OAAO,GAAG,IAAI,GAAG,mBAAmB,CAAC;AACnE,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,oBAAoB,CAAC,KAKpC;IACC,MAAM,IAAI,GAAG,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACnF,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAClH,MAAM,OAAO,GAAG,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,IAAI,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IAChH,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,IAAI,gBAAgB,CAAC;IACvD,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAChF,OAAO,uBAAuB,GAAG,UAAU,GAAG,oBAAoB,GAAG,KAAK,CAAC,WAAW,GAAG,GAAG,GAAG,OAAO,GAAG,cAAc,GAAG,QAAQ,CAAC;AACrI,CAAC;AAED,kDAAkD;AAClD,MAAM,CAAC,MAAM,eAAe,GAA6B;IACvD,iBAAiB;IACjB,gBAAgB;IAChB,sBAAsB;IACtB,sBAAsB;IACtB,iBAAiB;IACjB,mBAAmB;IACnB,mBAAmB;IACnB,mBAAmB;CACpB,CAAC"}
|
|
1
|
+
{"version":3,"file":"update-contract.js","sourceRoot":"","sources":["../src/update-contract.ts"],"names":[],"mappings":"AAaA,gFAAgF;AAChF,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,kEAAkE;IAClE,IAAI,EAAE,MAAM;IACZ,2DAA2D;IAC3D,OAAO,EAAE,gBAAgB;IACzB,gCAAgC;IAChC,QAAQ,EAAE,eAAe;IACzB,wCAAwC;IACxC,IAAI,EAAE,oBAAoB;CAClB,CAAC;AAEX,wDAAwD;AACxD,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,wEAAwE;IACxE,OAAO,EAAE,uBAAuB;IAChC;;;;;qBAKiB;IACjB,OAAO,EAAE,uBAAuB;CACxB,CAAC;AAEX,+CAA+C;AAC/C,MAAM,CAAC,MAAM,gBAAgB,GAAG,6BAAsC,CAAC;AAEvE,uEAAuE;AACvE,MAAM,WAAW,GAA2B;IAC1C,iBAAiB,EAAE,6CAA6C;IAChE,gBAAgB,EAAE,mCAAmC;IACrD,sBAAsB,EAAE,6CAA6C;IACrE,sBAAsB,EAAE,gCAAgC;IACxD,iBAAiB,EAAE,2BAA2B;IAC9C,mBAAmB,EAAE,8CAA8C;IACnE,mBAAmB,EAAE,kDAAkD;IACvE,mBAAmB,EAAE,sCAAsC;IAC3D,cAAc,EAAE,qCAAqC;IACrD,iBAAiB,EAAE,2CAA2C;IAC9D,eAAe,EAAE,iCAAiC;IAClD,aAAa,EAAE,0BAA0B;IACzC,gBAAgB,EAAE,yBAAyB;IAC3C,qBAAqB,EAAE,0CAA0C;IACjE,aAAa,EAAE,8BAA8B;IAC7C,QAAQ,EAAE,8BAA8B;CACzC,CAAC;AAEF,uCAAuC;AACvC,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,WAAW,CAAC,IAAI,CAAC,IAAI,OAAO,GAAG,IAAI,GAAG,mBAAmB,CAAC;AACnE,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,oBAAoB,CAAC,KAKpC;IACC,MAAM,IAAI,GAAG,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACnF,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAClH,MAAM,OAAO,GAAG,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,IAAI,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IAChH,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,IAAI,gBAAgB,CAAC;IACvD,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAChF,OAAO,uBAAuB,GAAG,UAAU,GAAG,oBAAoB,GAAG,KAAK,CAAC,WAAW,GAAG,GAAG,GAAG,OAAO,GAAG,cAAc,GAAG,QAAQ,CAAC;AACrI,CAAC;AAED,kDAAkD;AAClD,MAAM,CAAC,MAAM,eAAe,GAA6B;IACvD,iBAAiB;IACjB,gBAAgB;IAChB,sBAAsB;IACtB,sBAAsB;IACtB,iBAAiB;IACjB,mBAAmB;IACnB,mBAAmB;IACnB,mBAAmB;CACpB,CAAC"}
|