dsh-life-pack 0.3.19 → 0.3.20

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 CHANGED
@@ -535,6 +535,29 @@ window.__ModuleLoader__.load({
535
535
  if (typeof raw === "string" && raw.length > 0) return failure.code + " detail=" + raw.slice(0, 300);
536
536
  return failure.code;
537
537
  }
538
+ /** 失败原文那一行(票 #988):宿主回包 `details.detail` 里那句人话,面板把它摊在原因句下面。
539
+ *
540
+ * 为什么要摊:`install-failed` 这句人话对每一种装不上都长一个样,光看它分不出「这个宿主没有安装出口」
541
+ * 与「pnpm 退出码非零」。原文由宿主半取好并回传(`update-host.ts` 的 `installErrorDetail`),
542
+ * 这里只取值与截断(长文本会撑爆那一行)。没有原文回 null——面板不自己编原因。 */
543
+ function failureDetailOf(failure) {
544
+ const raw = failure?.details?.detail;
545
+ if (typeof raw !== "string") return null;
546
+ const text = raw.trim();
547
+ return text.length === 0 ? null : text.slice(0, 300);
548
+ }
549
+ /** 题头两颗按钮的悬停标题(票 #986 第二半:目标表未就绪时说真因)。
550
+ *
551
+ * 住这里(不是面板组件旁边):标题口径只有一个定义地,面板与单测共用同一份;
552
+ * 忙时沿用 update-busy 原句(与禁用判据同源),未就绪且空闲时说「还在读更新目标」,
553
+ * 就绪后回到调用方给的动作说明(本函数不写死那两句动作说明,由调用方传入)。
554
+ *
555
+ * 入参只取判据形状(blocked 与 empty),不 import 面板钩子。 */
556
+ function headerButtonTitle(input) {
557
+ if (input.blocked) return reasonText("update-busy");
558
+ if (input.empty) return "还在读更新目标,稍候再试";
559
+ return input.readyText ?? "";
560
+ }
538
561
  //#endregion
539
562
  //#region src/update-queue.ts
540
563
  /** 任一行 installing 即忙:题头检查更新禁用、行按钮全局互斥、checkAll/act 入口直接返回的同一判据。 */
@@ -901,6 +924,13 @@ window.__ModuleLoader__.load({
901
924
  marginTop: 4
902
925
  }
903
926
  };
927
+ /** 失败原文那一块(票 #988):宿主回来的细节单放一个可复制块(`cmd` 样式带 `userSelect: all`,
928
+ * 点一下全选即拷走),不与可执行的手工命令拼在同一块里——拼一起用户会整块拷去终端敲。
929
+ * 两处失败行(结果行与缺席卡)共用这一块,口径一处。 */
930
+ function failureDetailCode(detail) {
931
+ if (!detail) return null;
932
+ return react.createElement("code", { style: PANEL_STYLE.cmd }, "宿主原话:" + detail);
933
+ }
904
934
  const ROW_TONE = {
905
935
  update: {
906
936
  mark: "↑",
@@ -1033,6 +1063,10 @@ window.__ModuleLoader__.load({
1033
1063
  react.useEffect(() => {
1034
1064
  reload(true);
1035
1065
  }, [reload]);
1066
+ /** 取数失败后的手动重试(票 #986 第二半):不依赖目标表,挂载那次的退避表复用。 */
1067
+ const retry = react.useCallback(() => {
1068
+ reload(true);
1069
+ }, [reload]);
1036
1070
  const patch = react.useCallback((key, next) => {
1037
1071
  setRows((previous) => ({
1038
1072
  ...previous,
@@ -1052,6 +1086,7 @@ window.__ModuleLoader__.load({
1052
1086
  checking,
1053
1087
  updatingAll,
1054
1088
  open,
1089
+ retry,
1055
1090
  close: () => setOpen(resolveDialogOpen("hide")),
1056
1091
  showProgress: () => setOpen(resolveDialogOpen("show")),
1057
1092
  checkAll: react.useCallback(() => {
@@ -1193,6 +1228,21 @@ window.__ModuleLoader__.load({
1193
1228
  ])
1194
1229
  };
1195
1230
  }
1231
+ /** 取数失败的出口卡(票 #986 第二半:失败必须有出口)。
1232
+ *
1233
+ * 纯组件(无钩子):错误原文+一颗可点的「重试」。重试不依赖目标表——
1234
+ * 目标表为空时两题头按钮仍禁用,但这颗可点;点它重走取数,成功后按钮与行恢复。
1235
+ */
1236
+ function TargetsLoadError(props) {
1237
+ return react.createElement("div", { style: PANEL_STYLE.reason }, "更新能力没接上:" + props.message, react.createElement("button", {
1238
+ type: "button",
1239
+ style: {
1240
+ ...PANEL_STYLE.btn,
1241
+ marginLeft: 8
1242
+ },
1243
+ onClick: props.onRetry
1244
+ }, "重试"));
1245
+ }
1196
1246
  /** 标题右侧两件:「检查更新」一次查七家 + 「全部更新」按顺序串行装(吃 `useUpdateRows` 的表)。
1197
1247
  *
1198
1248
  * 禁用形状(#925 第 2 条 + #980 检查中):任一行 installing、一键串行中或检查轮未收尾时两件都点不得;人话沿用 `update-busy` 原句
@@ -1205,30 +1255,37 @@ window.__ModuleLoader__.load({
1205
1255
  updatingAll,
1206
1256
  checking
1207
1257
  });
1208
- const checkDisabled = blocked || targets.length === 0;
1209
- const allDisabled = blocked || targets.length === 0;
1210
- const busyText = reasonText("update-busy");
1258
+ const targetsEmpty = targets.length === 0;
1259
+ const headerDisabled = blocked || targetsEmpty;
1211
1260
  const installingNow = hasInstallingRow(rows) || updatingAll;
1212
1261
  return react.createElement("span", { style: PANEL_STYLE.actions }, react.createElement("button", {
1213
1262
  type: "button",
1214
- style: checkDisabled ? {
1263
+ style: headerDisabled ? {
1215
1264
  ...PANEL_STYLE.btn,
1216
1265
  opacity: .55,
1217
1266
  cursor: "default"
1218
1267
  } : PANEL_STYLE.btn,
1219
- disabled: checkDisabled,
1268
+ disabled: headerDisabled,
1220
1269
  onClick: checkAll,
1221
- title: blocked ? busyText : "检查总管与六家插件的版本"
1270
+ title: headerButtonTitle({
1271
+ blocked,
1272
+ empty: targetsEmpty,
1273
+ readyText: "检查总管与六家插件的版本"
1274
+ })
1222
1275
  }, checking ? "检查中…" : "检查更新"), react.createElement("button", {
1223
1276
  type: "button",
1224
- style: allDisabled ? {
1277
+ style: headerDisabled ? {
1225
1278
  ...PANEL_STYLE.btn,
1226
1279
  opacity: .55,
1227
1280
  cursor: "default"
1228
1281
  } : PANEL_STYLE.btn,
1229
- disabled: allDisabled,
1282
+ disabled: headerDisabled,
1230
1283
  onClick: updateAll,
1231
- title: blocked ? busyText : "按顺序逐家装上更新(一家收尾才起下一家)"
1284
+ title: headerButtonTitle({
1285
+ blocked,
1286
+ empty: targetsEmpty,
1287
+ readyText: "按顺序逐家装上更新(一家收尾才起下一家)"
1288
+ })
1232
1289
  }, installingNow ? "更新中…" : "全部更新"));
1233
1290
  }
1234
1291
  /** 待重启横幅:一行总账,只点名哪几家要重启(理由与做法写在各家卡片上,见 `restartBannerText`)。 */
@@ -1252,13 +1309,16 @@ window.__ModuleLoader__.load({
1252
1309
  * 手工命令只在「装不了」或「装失败」的行显示:正常用户用不到,摊在每行上既吵又误导。
1253
1310
  */
1254
1311
  function UpdateResults(props) {
1255
- const { targets, rows, loadError, checking, updatingAll, open, close, showProgress } = props.face;
1312
+ const { targets, rows, loadError, checking, updatingAll, open, close, showProgress, retry } = props.face;
1256
1313
  const dialogRef = react.useRef(null);
1257
1314
  react.useEffect(() => {
1258
1315
  if (open) dialogRef.current?.focus();
1259
1316
  }, [open]);
1260
1317
  const shown = targets.filter((target) => rows[target.key] && rows[target.key].phase !== "idle");
1261
- if (loadError) return react.createElement("div", { style: PANEL_STYLE.reason }, "更新能力没接上:" + loadError);
1318
+ if (loadError) return react.createElement(TargetsLoadError, {
1319
+ message: loadError,
1320
+ onRetry: retry
1321
+ });
1262
1322
  if (targets.length === 0) return null;
1263
1323
  if (shown.length === 0 && !open) return null;
1264
1324
  const locked = shouldBlockBatchStart({
@@ -1317,7 +1377,7 @@ window.__ModuleLoader__.load({
1317
1377
  onClick: () => {
1318
1378
  props.face.act(target, buttonAction);
1319
1379
  }
1320
- }, ACTION_LABEL[buttonAction]) : null, row.failure ? react.createElement("div", { style: PANEL_STYLE.reason }, "装不上:" + row.failure.message) : null, versionLines(target, snapshot).map((line, index) => react.createElement("div", {
1380
+ }, ACTION_LABEL[buttonAction]) : null, row.failure ? react.createElement("div", { style: PANEL_STYLE.reason }, "装不上:" + row.failure.message) : null, failureDetailCode(failureDetailOf(row.failure)), versionLines(target, snapshot).map((line, index) => react.createElement("div", {
1321
1381
  key: String(index),
1322
1382
  style: PANEL_STYLE.skill
1323
1383
  }, line)), showManual ? react.createElement("div", { style: PANEL_STYLE.skill }, "在终端里执行这条命令可以手动完成这一步:") : null, showManual ? react.createElement("code", { style: PANEL_STYLE.cmd }, manual) : null);
@@ -1421,7 +1481,7 @@ window.__ModuleLoader__.load({
1421
1481
  disabled: locked,
1422
1482
  title: locked ? reasonText("update-busy") : void 0,
1423
1483
  onClick: () => props.face.act(target, "recheck")
1424
- }, ACTION_LABEL.recheck) : null, reason ? react.createElement("div", { style: PANEL_STYLE.reason }, reason) : null, react.createElement("code", { style: PANEL_STYLE.cmd }, manual));
1484
+ }, ACTION_LABEL.recheck) : null, reason ? react.createElement("div", { style: PANEL_STYLE.reason }, reason) : null, failureDetailCode(failureDetailOf(row?.failure)), react.createElement("code", { style: PANEL_STYLE.cmd }, manual));
1425
1485
  }
1426
1486
  //#endregion
1427
1487
  //#region src/health-contract.ts
@@ -3050,7 +3110,7 @@ window.__ModuleLoader__.load({
3050
3110
  }, react.createElement("span", { style: S.morePkg }, row.pkg), react.createElement("span", { style: S.moreDesc }, row.desc), react.createElement("span", { style: S.moreIcon }, react.createElement(ExternalIcon, null)))));
3051
3111
  }
3052
3112
  /** 版本胶囊那一行字:只在这里拼一次,屏上与用例读的是同一串。 */
3053
- const MANAGER_VERSION_TEXT = "dsh-life-pack · 0.3.19";
3113
+ const MANAGER_VERSION_TEXT = "dsh-life-pack · 0.3.20";
3054
3114
  /** 爱生活面板:总设置区 + 检查更新(七家)+ 爱生活页签条(slot 驱动)+ 技能设置页投影/缺席卡。 */
3055
3115
  function LifePackSection(props) {
3056
3116
  const tabsId = react.useId();