dsh-life-pack 0.3.55 → 0.3.57

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
@@ -471,14 +471,28 @@ window.__ModuleLoader__.load({
471
471
  path: "/api/ilife-manager"
472
472
  };
473
473
  //#endregion
474
- //#region ../../node_modules/.pnpm/dsh-plugin-update@0.17.0/node_modules/dsh-plugin-update/dist/config.js
474
+ //#region ../../node_modules/.pnpm/dsh-plugin-update@0.18.0/node_modules/dsh-plugin-update/dist/config.js
475
+ const DEFAULT_PANEL_POLL_MS = 1e3;
475
476
  function assertPrefix(value, role) {
476
477
  if (typeof value !== "string" || value.length === 0) throw new Error("[dsh-plugin-update] " + role + " 非法:须为非空字符串(收到 " + JSON.stringify(value) + ")");
477
478
  if (value.includes(".") || value.includes("/") || value.includes("\\") || /\s/.test(value)) throw new Error("[dsh-plugin-update] " + role + " 非法:不得含有点、路径分隔符或空白(收到 " + JSON.stringify(value) + ")");
478
479
  return value;
479
480
  }
481
+ function buildPhoneNames(prefix) {
482
+ const checked = assertPrefix(prefix, "电话名前缀 prefix");
483
+ return {
484
+ updateStatus: checked + ".updateStatus",
485
+ updateCheck: checked + ".updateCheck",
486
+ updateInstall: checked + ".updateInstall",
487
+ updateChangelog: checked + ".updateChangelog",
488
+ logAppend: checked + ".logAppend"
489
+ };
490
+ }
491
+ function buildLogAppendPhoneName(prefix) {
492
+ return buildPhoneNames(prefix).logAppend;
493
+ }
480
494
  //#endregion
481
- //#region ../../node_modules/.pnpm/dsh-plugin-update@0.17.0/node_modules/dsh-plugin-update/dist/redaction.js
495
+ //#region ../../node_modules/.pnpm/dsh-plugin-update@0.18.0/node_modules/dsh-plugin-update/dist/redaction.js
482
496
  const COPY_BUDGET_CHARS = 1500;
483
497
  const REDACTED_PATH = "<路径>";
484
498
  const REDACTED_SECRET = "<脱敏>";
@@ -542,7 +556,7 @@ window.__ModuleLoader__.load({
542
556
  return truncateForCopy(scrubWithoutBudget(flat));
543
557
  }
544
558
  //#endregion
545
- //#region ../../node_modules/.pnpm/dsh-plugin-update@0.17.0/node_modules/dsh-plugin-update/dist/service.js
559
+ //#region ../../node_modules/.pnpm/dsh-plugin-update@0.18.0/node_modules/dsh-plugin-update/dist/service.js
546
560
  function updateError(code) {
547
561
  return Object.assign(new Error(code), { code });
548
562
  }
@@ -629,7 +643,7 @@ window.__ModuleLoader__.load({
629
643
  return 0;
630
644
  }
631
645
  //#endregion
632
- //#region ../../node_modules/.pnpm/dsh-plugin-update@0.17.0/node_modules/dsh-plugin-update/dist/lang.js
646
+ //#region ../../node_modules/.pnpm/dsh-plugin-update@0.18.0/node_modules/dsh-plugin-update/dist/lang.js
633
647
  function normalizeLangTag(tag) {
634
648
  if (typeof tag !== "string") return "zh";
635
649
  const s = tag.trim().toLowerCase().replace(/_/g, "-");
@@ -771,7 +785,7 @@ window.__ModuleLoader__.load({
771
785
  };
772
786
  }
773
787
  //#endregion
774
- //#region ../../node_modules/.pnpm/dsh-plugin-update@0.17.0/node_modules/dsh-plugin-update/dist/bilingual.js
788
+ //#region ../../node_modules/.pnpm/dsh-plugin-update@0.18.0/node_modules/dsh-plugin-update/dist/bilingual.js
775
789
  const BILINGUAL_STRINGS = {
776
790
  "entry.label.idle": {
777
791
  en: "Check for updates",
@@ -2382,9 +2396,14 @@ window.__ModuleLoader__.load({
2382
2396
  en: "Last install was interrupted, leaving a partial task",
2383
2397
  zh: "上次安装异常中断,存在未完成任务",
2384
2398
  draft: true
2399
+ },
2400
+ "install-button.action.installed": {
2401
+ en: "Installed",
2402
+ zh: "已安装",
2403
+ draft: true
2385
2404
  }
2386
2405
  };
2387
- function escapeHtml$3(value) {
2406
+ function escapeHtml$4(value) {
2388
2407
  return String(value ?? "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
2389
2408
  }
2390
2409
  function formatTemplate(template, values) {
@@ -2408,12 +2427,12 @@ window.__ModuleLoader__.load({
2408
2427
  function copyHTML(key, lang, values) {
2409
2428
  const l = normalizeLangTag(lang ?? "zh");
2410
2429
  const e = bilingualEntry(key);
2411
- const text = escapeHtml$3(formatTemplate(l === "en" ? e.en : e.zh, values));
2430
+ const text = escapeHtml$4(formatTemplate(l === "en" ? e.en : e.zh, values));
2412
2431
  return "<span class=\"dsh-upd-bi\"><span lang=\"" + l + "\">" + text + "</span></span>";
2413
2432
  }
2414
2433
  const BILINGUAL_CSS = [".dsh-upd-bi{display:inline;overflow-wrap:anywhere}", ".dsh-upd-bi [lang]{overflow-wrap:anywhere}"].join("\n");
2415
2434
  //#endregion
2416
- //#region ../../node_modules/.pnpm/dsh-plugin-update@0.17.0/node_modules/dsh-plugin-update/dist/changelog.js
2435
+ //#region ../../node_modules/.pnpm/dsh-plugin-update@0.18.0/node_modules/dsh-plugin-update/dist/changelog.js
2417
2436
  const CHANGELOG_MAX_CHARS = 65536;
2418
2437
  const CHANGELOG_ALL_CATEGORIES = [
2419
2438
  "Added",
@@ -3521,12 +3540,258 @@ ${note}${blocks.join("\n")}
3521
3540
  }
3522
3541
  }
3523
3542
  //#endregion
3524
- //#region ../../node_modules/.pnpm/dsh-plugin-update@0.17.0/node_modules/dsh-plugin-update/dist/log-events.js
3543
+ //#region ../../node_modules/.pnpm/dsh-plugin-update@0.18.0/node_modules/dsh-plugin-update/dist/log-events.js
3525
3544
  const LOG_EVENT_CALL = "host.call";
3526
3545
  const LOG_EVENT_CALL_FAIL = "host.call.fail";
3527
3546
  const LOG_EVENT_INSTALL_EXEC = "update.install.exec";
3547
+ const CLIENT_LOG_FLUSH_MS = 1e3;
3548
+ const CLIENT_LOG_RETRY_DELAYS_MS = [250, 1e3];
3549
+ const CLIENT_LOG_SEND_TIMEOUT_MS = 5e3;
3550
+ function positiveInt(value, fallback) {
3551
+ const n = typeof value === "number" && Number.isFinite(value) ? Math.floor(value) : fallback;
3552
+ return n > 0 ? n : fallback;
3553
+ }
3554
+ function nonNegativeInt(value, fallback) {
3555
+ const n = typeof value === "number" && Number.isFinite(value) ? Math.floor(value) : fallback;
3556
+ return n >= 0 ? n : fallback;
3557
+ }
3558
+ function resolveClientLogTimer() {
3559
+ try {
3560
+ const g = globalThis;
3561
+ const set = g["setTimeout"];
3562
+ const clear = g["clearTimeout"];
3563
+ if (typeof set === "function" && typeof clear === "function") return {
3564
+ set: (fn, ms) => set.call(g, fn, ms),
3565
+ clear: (handle) => clear.call(g, handle)
3566
+ };
3567
+ } catch {}
3568
+ return null;
3569
+ }
3570
+ function resolveClientLogVisibility() {
3571
+ try {
3572
+ const doc = globalThis.document;
3573
+ if (doc && typeof doc.addEventListener === "function") return doc;
3574
+ } catch {}
3575
+ return null;
3576
+ }
3577
+ function createClientLogChannel(options) {
3578
+ const call = options && typeof options.call === "function" ? options.call : null;
3579
+ const phoneName = options && typeof options.phoneName === "string" ? options.phoneName : "";
3580
+ const capacity = positiveInt(options?.maxQueue, 200);
3581
+ const batchSize = positiveInt(options?.batchSize, 50);
3582
+ const flushMs = positiveInt(options?.flushIntervalMs, CLIENT_LOG_FLUSH_MS);
3583
+ const maxRetries = nonNegativeInt(options?.maxRetries, 2);
3584
+ const retryDelays = Array.isArray(options?.retryDelaysMs) && options.retryDelaysMs.length > 0 ? options.retryDelaysMs : CLIENT_LOG_RETRY_DELAYS_MS;
3585
+ const sendTimeoutMs = options?.sendTimeoutMs === void 0 ? CLIENT_LOG_SEND_TIMEOUT_MS : Number(options.sendTimeoutMs);
3586
+ const timer = options?.timer === void 0 ? resolveClientLogTimer() : options.timer;
3587
+ const visibility = options?.visibility === void 0 ? resolveClientLogVisibility() : options.visibility;
3588
+ const now = typeof options?.now === "function" ? options.now : () => Date.now();
3589
+ const onDrop = typeof options?.onDrop === "function" ? options.onDrop : null;
3590
+ const slots = new Array(capacity).fill(null);
3591
+ let head = 0;
3592
+ let count = 0;
3593
+ let dropped = 0;
3594
+ let sent = 0;
3595
+ let disposed = false;
3596
+ let scheduled = null;
3597
+ let inFlight = false;
3598
+ function noteDrop(row, reason) {
3599
+ dropped++;
3600
+ if (!onDrop) return;
3601
+ try {
3602
+ onDrop(row, reason);
3603
+ } catch {}
3604
+ }
3605
+ function push(row) {
3606
+ if (count === capacity) {
3607
+ const evicted = slots[head];
3608
+ slots[head] = row;
3609
+ head = (head + 1) % capacity;
3610
+ noteDrop(evicted, "overflow");
3611
+ return;
3612
+ }
3613
+ slots[(head + count) % capacity] = row;
3614
+ count++;
3615
+ }
3616
+ function shift() {
3617
+ if (count === 0) return null;
3618
+ const row = slots[head];
3619
+ slots[head] = null;
3620
+ head = (head + 1) % capacity;
3621
+ count--;
3622
+ return row;
3623
+ }
3624
+ function enabled() {
3625
+ return !disposed && call !== null && phoneName !== "";
3626
+ }
3627
+ function schedule(ms) {
3628
+ if (!timer || disposed || scheduled !== null) return;
3629
+ try {
3630
+ scheduled = timer.set(() => {
3631
+ scheduled = null;
3632
+ flush();
3633
+ }, ms);
3634
+ } catch {
3635
+ scheduled = null;
3636
+ }
3637
+ }
3638
+ function delay(ms) {
3639
+ if (!timer || !(ms > 0)) return Promise.resolve();
3640
+ return new Promise((resolve) => {
3641
+ try {
3642
+ timer.set(resolve, ms);
3643
+ } catch {
3644
+ resolve();
3645
+ }
3646
+ });
3647
+ }
3648
+ async function sendOnce(rows) {
3649
+ const payload = { rows: rows.map((r) => ({
3650
+ level: r.level,
3651
+ event: r.event,
3652
+ fields: r.fields,
3653
+ ts: r.ts
3654
+ })) };
3655
+ const pendingCall = call ? call(phoneName, payload) : Promise.reject(/* @__PURE__ */ new Error("no-channel"));
3656
+ if (!(sendTimeoutMs > 0) || !timer) return await pendingCall;
3657
+ return await new Promise((resolve, reject) => {
3658
+ let done = false;
3659
+ let handle = null;
3660
+ try {
3661
+ handle = timer.set(() => {
3662
+ if (done) return;
3663
+ done = true;
3664
+ reject(/* @__PURE__ */ new Error("log-append-timeout"));
3665
+ }, sendTimeoutMs);
3666
+ } catch {
3667
+ handle = null;
3668
+ }
3669
+ pendingCall.then((reply) => {
3670
+ if (done) return;
3671
+ done = true;
3672
+ if (handle !== null) try {
3673
+ timer.clear(handle);
3674
+ } catch {}
3675
+ resolve(reply);
3676
+ }, (error) => {
3677
+ if (done) return;
3678
+ done = true;
3679
+ if (handle !== null) try {
3680
+ timer.clear(handle);
3681
+ } catch {}
3682
+ reject(error);
3683
+ });
3684
+ });
3685
+ }
3686
+ async function sendWithRetry(rows) {
3687
+ let attempt = 0;
3688
+ for (;;) {
3689
+ try {
3690
+ const reply = await sendOnce(rows);
3691
+ if (reply && typeof reply === "object" && typeof reply["accepted"] === "number" && typeof reply["dropped"] === "number") return {
3692
+ ok: true,
3693
+ reply
3694
+ };
3695
+ } catch {}
3696
+ if (attempt >= maxRetries) return {
3697
+ ok: false,
3698
+ reply: null
3699
+ };
3700
+ const wait = retryDelays[Math.min(attempt, retryDelays.length - 1)];
3701
+ attempt++;
3702
+ await delay(typeof wait === "number" && Number.isFinite(wait) ? wait : 0);
3703
+ }
3704
+ }
3705
+ async function flush() {
3706
+ if (disposed || inFlight || count === 0) return;
3707
+ if (!enabled()) {
3708
+ while (count > 0) noteDrop(shift(), "no-channel");
3709
+ return;
3710
+ }
3711
+ inFlight = true;
3712
+ const batch = [];
3713
+ while (batch.length < batchSize && count > 0) {
3714
+ const row = shift();
3715
+ if (!row) break;
3716
+ batch.push(row);
3717
+ }
3718
+ try {
3719
+ const result = await sendWithRetry(batch);
3720
+ if (result.ok && result.reply) {
3721
+ const accepted = Number(result.reply["accepted"]);
3722
+ const hostDropped = Number(result.reply["dropped"]);
3723
+ sent += Number.isFinite(accepted) ? accepted : batch.length;
3724
+ let lost = Number.isFinite(hostDropped) ? hostDropped : 0;
3725
+ while (lost > 0) {
3726
+ noteDrop(null, "host-refused");
3727
+ lost--;
3728
+ }
3729
+ } else for (const row of batch) noteDrop(row, "send-failed");
3730
+ } catch {
3731
+ for (const row of batch) noteDrop(row, "send-failed");
3732
+ } finally {
3733
+ inFlight = false;
3734
+ }
3735
+ if (disposed) return;
3736
+ if (count >= batchSize) schedule(0);
3737
+ else if (count > 0) schedule(flushMs);
3738
+ }
3739
+ function onVisibilityChange() {
3740
+ try {
3741
+ const state = visibility?.visibilityState;
3742
+ if (visibility?.hidden === true || state === "hidden") flush();
3743
+ } catch {}
3744
+ }
3745
+ if (visibility && typeof visibility.addEventListener === "function") try {
3746
+ visibility.addEventListener("visibilitychange", onVisibilityChange);
3747
+ } catch {}
3748
+ function emit(level, event, fields) {
3749
+ try {
3750
+ const eventName = typeof event === "string" ? event : "";
3751
+ if (!eventName) return;
3752
+ const row = {
3753
+ level: typeof level === "string" && level ? level : "info",
3754
+ event: eventName,
3755
+ fields: fields && typeof fields === "object" ? fields : {},
3756
+ ts: now()
3757
+ };
3758
+ if (disposed) {
3759
+ noteDrop(row, "disposed");
3760
+ return;
3761
+ }
3762
+ if (!enabled()) {
3763
+ noteDrop(row, "no-channel");
3764
+ return;
3765
+ }
3766
+ push(row);
3767
+ if (count >= batchSize) schedule(0);
3768
+ else schedule(flushMs);
3769
+ } catch {}
3770
+ }
3771
+ function dispose() {
3772
+ if (disposed) return;
3773
+ disposed = true;
3774
+ if (scheduled !== null && timer) try {
3775
+ timer.clear(scheduled);
3776
+ } catch {}
3777
+ scheduled = null;
3778
+ while (count > 0) noteDrop(shift(), "disposed");
3779
+ if (visibility && typeof visibility.removeEventListener === "function") try {
3780
+ visibility.removeEventListener("visibilitychange", onVisibilityChange);
3781
+ } catch {}
3782
+ }
3783
+ return {
3784
+ emit,
3785
+ flush,
3786
+ pending: () => count,
3787
+ dropped: () => dropped,
3788
+ sent: () => sent,
3789
+ enabled,
3790
+ dispose
3791
+ };
3792
+ }
3528
3793
  //#endregion
3529
- //#region ../../node_modules/.pnpm/dsh-plugin-update@0.17.0/node_modules/dsh-plugin-update/dist/codes.js
3794
+ //#region ../../node_modules/.pnpm/dsh-plugin-update@0.18.0/node_modules/dsh-plugin-update/dist/codes.js
3530
3795
  const BLOCKED_REASONS = [
3531
3796
  "unknown-profile",
3532
3797
  "channel-mismatch",
@@ -3560,7 +3825,7 @@ ${note}${blocks.join("\n")}
3560
3825
  return typeof code === "string" && isOneOf(CHECK_SIDE_FAILURE_CODES, code.trim());
3561
3826
  }
3562
3827
  //#endregion
3563
- //#region ../../node_modules/.pnpm/dsh-plugin-update@0.17.0/node_modules/dsh-plugin-update/dist/panel.js
3828
+ //#region ../../node_modules/.pnpm/dsh-plugin-update@0.18.0/node_modules/dsh-plugin-update/dist/panel.js
3564
3829
  function normalizePanelTheme(value) {
3565
3830
  return value === "archive" ? "archive" : "default";
3566
3831
  }
@@ -3865,6 +4130,10 @@ ${note}${blocks.join("\n")}
3865
4130
  for (const key of Object.keys(raw)) if (!Object.prototype.hasOwnProperty.call(DIAG_KNOWN_TYPES, key)) out.unknownKeys.push(key);
3866
4131
  return out;
3867
4132
  }
4133
+ function pickText(value, fallback) {
4134
+ if (typeof value === "string" && value.trim()) return value.trim();
4135
+ return fallback;
4136
+ }
3868
4137
  function queueTextOf(queuePosition, lang, _diagQueuePos) {
3869
4138
  const l = normalizeLangTag(lang ?? "zh");
3870
4139
  const pos = typeof queuePosition === "number" ? queuePosition : null;
@@ -3872,6 +4141,52 @@ ${note}${blocks.join("\n")}
3872
4141
  if (typeof pos === "number") return copyText("panel.diag.queue.position", l, { n: pos });
3873
4142
  return copyText("panel.diag.queue.absent", l);
3874
4143
  }
4144
+ function buildUpdateDiagCopy(input, langOverride) {
4145
+ const l = normalizeLangTag(langOverride ?? input.lang ?? "zh");
4146
+ const unknown = copyText("panel.diag.copy.unknown", l);
4147
+ const unknownPkg = copyText("panel.diag.copy.unknown-package", l);
4148
+ const rawCode = String(input.code ?? "").trim() || "internal";
4149
+ const copy = failureCopy(rawCode, l) ?? failureCopy("unknown", l);
4150
+ const diag = readDiagTolerant(input.diag);
4151
+ const detail = redactForCopy(diag.detail ?? input.detail ?? "") || copyText("panel.diag.copy.no-detail", l);
4152
+ const pluginName = pickText(diag.targetPackageName ?? input.pluginId, unknownPkg);
4153
+ const runVer = pickText(diag.runningVersion ?? input.runningVersion, "?");
4154
+ const instVer = pickText(input.installedVersion ?? diag.latestVersion, "?");
4155
+ const host = pickText(diag.environmentKind ?? input.hostKind, unknown);
4156
+ const routeRaw = diag.route ?? input.route;
4157
+ const requestRaw = diag.requestId ?? input.requestId;
4158
+ const checkRaw = diag.checkId ?? input.checkId;
4159
+ const queue = queueTextOf(input.queuePosition ?? null, l);
4160
+ const prov = [copyText("panel.diag.copy.field.plugin", l, { plugin: pluginName }), copyText("panel.diag.copy.field.version", l, {
4161
+ run: runVer,
4162
+ inst: instVer
4163
+ })];
4164
+ const targetRaw = input.targetVersion;
4165
+ if (typeof targetRaw === "string" && targetRaw.trim()) prov.push(copyText("panel.diag.copy.field.target", l, { version: targetRaw.trim() }));
4166
+ prov.push(copyText("panel.diag.copy.field.host", l, { host }));
4167
+ prov.push(copyText("panel.diag.copy.field.profile", l, { profile: pickText(input.profileName, unknown) }));
4168
+ if (typeof routeRaw === "string" && routeRaw.trim()) prov.push(copyText("panel.diag.copy.field.route", l, { route: routeRaw.trim() }));
4169
+ if (diag.stage) prov.push(copyText("panel.diag.copy.field.stage", l, { stage: diag.stage }));
4170
+ if (diag.method) prov.push(copyText("panel.diag.copy.field.method", l, { method: diag.method }));
4171
+ if (typeof diag.httpStatus === "number") prov.push(`HTTP=${diag.httpStatus}`);
4172
+ if (typeof diag.exitCode === "number") prov.push(`exit=${diag.exitCode}`);
4173
+ if (typeof diag.latencyMs === "number") prov.push(`${copyText("panel.diag.copy.field.latency", l, { latency: diag.latencyMs })}ms`);
4174
+ if (diag.registryHost) prov.push(copyText("panel.diag.copy.field.registry", l, { host: diag.registryHost }));
4175
+ else prov.push(copyText("panel.diag.copy.field.registry-unknown", l));
4176
+ if (diag.action) prov.push(copyText("panel.diag.copy.field.action", l, { action: diag.action }));
4177
+ if (typeof requestRaw === "string" && requestRaw.trim()) prov.push(copyText("panel.diag.copy.field.request", l, { request: requestRaw.trim() }));
4178
+ if (typeof checkRaw === "string" && checkRaw.trim()) prov.push(copyText("panel.diag.copy.field.check", l, { check: checkRaw.trim() }));
4179
+ prov.push(copyText("panel.diag.copy.field.queue", l, { queue }));
4180
+ const format = input.format === "line" ? "line" : "block";
4181
+ const provLine = redactForCopy(prov.join(" · "));
4182
+ if (format === "line") return redactForCopy(`[update-diag] code=${rawCode} \xB7 ${copy.zh} \xB7 ${copyText("panel.diag.copy.line.summary", l, { summary: detail })} \xB7 ${provLine} \xB7 ${copyText("panel.diag.copy.line.remedy", l, { remedy: copy.act })}`);
4183
+ return [
4184
+ `[update-diag] ${rawCode} \u2014 ${copy.zh}`,
4185
+ ` ${copyText("panel.diag.copy.block.summary", l, { summary: detail })}`,
4186
+ ` ${copyText("panel.diag.copy.block.source", l, { source: provLine })}`,
4187
+ ` ${copyText("panel.diag.copy.block.remedy", l, { remedy: copy.act })}`
4188
+ ].join("\n");
4189
+ }
3875
4190
  const PANEL_SKIPPED_MAX = 50;
3876
4191
  function panelSkipKey(pluginId) {
3877
4192
  return `dsh-upd-skipped/${String(pluginId)}`;
@@ -4495,7 +4810,7 @@ ${note}${blocks.join("\n")}
4495
4810
  "@media (forced-colors: active){.dsh-upd[data-theme=\"archive\"]{box-shadow:none}.dsh-upd[data-theme=\"archive\"]::before{background:none;box-shadow:none;border-color:CanvasText;color:CanvasText}.dsh-upd[data-theme=\"archive\"] .dsh-upd-banner{border:1px solid CanvasText}.dsh-upd[data-theme=\"archive\"] .dsh-upd-banner::before{border-color:CanvasText;color:CanvasText;background:Canvas}.dsh-upd[data-theme=\"archive\"] button{border:1px solid ButtonText}.dsh-upd[data-theme=\"archive\"] button[data-primary=\"1\"]{background:ButtonFace;color:ButtonText;border-color:ButtonText}.dsh-upd[data-theme=\"archive\"] .dsh-upd-banner[data-kind=\"restart\"]>div:first-child::before{background-image:none;content:\"⚠\"}}",
4496
4811
  "@media (prefers-reduced-motion: reduce){.dsh-upd[data-theme=\"archive\"] *{transition:none !important;animation:none !important}}"
4497
4812
  ].join("\n");
4498
- function escapeHtml$2(text) {
4813
+ function escapeHtml$3(text) {
4499
4814
  return String(text).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
4500
4815
  }
4501
4816
  const CHAPTER_KEYS = [
@@ -4526,18 +4841,18 @@ ${note}${blocks.join("\n")}
4526
4841
  }
4527
4842
  function chapterOf(index, inner, note = "", lang) {
4528
4843
  const no = String(index).padStart(2, "0");
4529
- return `<section class="dsh-upd-chapter" data-chapter="${no}"><div class="dsh-upd-chap-head"><span class="dsh-upd-chap-no">${no}</span><h3 class="dsh-upd-chap-title">${escapeHtml$2(chapterTitle(index, normalizeLangTag(lang ?? "zh")))}</h3><span class="dsh-upd-chap-rule"></span>${note}</div>${inner}</section>`;
4844
+ return `<section class="dsh-upd-chapter" data-chapter="${no}"><div class="dsh-upd-chap-head"><span class="dsh-upd-chap-no">${no}</span><h3 class="dsh-upd-chap-title">${escapeHtml$3(chapterTitle(index, normalizeLangTag(lang ?? "zh")))}</h3><span class="dsh-upd-chap-rule"></span>${note}</div>${inner}</section>`;
4530
4845
  }
4531
4846
  function skeletonStrip(loading, lang) {
4532
4847
  if (!loading) return "";
4533
4848
  const l = normalizeLangTag(lang ?? "zh");
4534
- const cell = (k) => `<div><span class="dsh-upd-strip-k">${escapeHtml$2(k)}</span><span class="dsh-upd-strip-v dsh-upd-skv" aria-hidden="true">\u2026</span></div>`;
4849
+ const cell = (k) => `<div><span class="dsh-upd-strip-k">${escapeHtml$3(k)}</span><span class="dsh-upd-strip-v dsh-upd-skv" aria-hidden="true">\u2026</span></div>`;
4535
4850
  return `<div class="dsh-upd-strip" aria-hidden="true">` + cell(copyText("panel.strip.running", l)) + cell(copyText("panel.strip.installed", l)) + cell(copyText("panel.strip.latest", l)) + `</div>`;
4536
4851
  }
4537
4852
  function versionStrip(snapshot, lang) {
4538
4853
  const l = normalizeLangTag(lang ?? "zh");
4539
4854
  const unknown = copyText("panel.meta.unknown", l);
4540
- const cell = (k, v) => `<div><span class="dsh-upd-strip-k">${escapeHtml$2(k)}</span><span class="dsh-upd-strip-v">${escapeHtml$2(v ?? unknown)}</span></div>`;
4855
+ const cell = (k, v) => `<div><span class="dsh-upd-strip-k">${escapeHtml$3(k)}</span><span class="dsh-upd-strip-v">${escapeHtml$3(v ?? unknown)}</span></div>`;
4541
4856
  if (!snapshot) return "";
4542
4857
  return `<div class="dsh-upd-strip">` + cell(copyText("panel.strip.running", l), snapshot.runningVersion) + cell(copyText("panel.strip.installed", l), snapshot.installed === false ? copyText("panel.banner.not-installed", l) : snapshot.installedVersion) + cell(copyText("panel.strip.latest", l), snapshot.latestVersion) + `</div>`;
4543
4858
  }
@@ -4548,7 +4863,7 @@ ${note}${blocks.join("\n")}
4548
4863
  if (state !== "installing" && state !== "verifying") return "";
4549
4864
  const l = normalizeLangTag(lang ?? "zh");
4550
4865
  const width = state === "installing" ? 60 : 90;
4551
- return `<div class="dsh-upd-prog" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="${width}"><i class="dsh-upd-prog-bar" style="width:${width}%"></i></div><div class="dsh-upd-progtxt">${escapeHtml$2(state === "installing" ? copyText("panel.progress.installing", l) : copyText("panel.progress.verifying", l))}</div>`;
4866
+ return `<div class="dsh-upd-prog" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="${width}"><i class="dsh-upd-prog-bar" style="width:${width}%"></i></div><div class="dsh-upd-progtxt">${escapeHtml$3(state === "installing" ? copyText("panel.progress.installing", l) : copyText("panel.progress.verifying", l))}</div>`;
4552
4867
  }
4553
4868
  function renderUpdatePanelKernel(input, view, lang) {
4554
4869
  const { snapshot, manual, queue, mode, showOthers, pluginId, copyNotice } = input;
@@ -4558,12 +4873,12 @@ ${note}${blocks.join("\n")}
4558
4873
  const b = view.banner;
4559
4874
  const seal = view.seal;
4560
4875
  const parts = [];
4561
- parts.push("<div class=\"dsh-upd-masthead\"><span class=\"dsh-upd-masthead-kicker\">" + escapeHtml$2(copyText("panel.masthead.kicker", l)) + "</span><span class=\"dsh-upd-masthead-title\">" + escapeHtml$2(copyText("panel.masthead.title", l)) + " <i>" + escapeHtml$2(copyText("panel.masthead.volume", l)) + "</i></span></div>");
4562
- parts.push(`<div class="dsh-upd-head"><span class="dsh-upd-name">${escapeHtml$2(pluginId)}</span><span class="dsh-upd-meta">${escapeHtml$2(copyText("panel.meta.label", l))} <b>${escapeHtml$2(profileName ?? copyText("panel.meta.unknown", l))}</b><span class="dsh-upd-proftag">profile</span></span></div>`);
4563
- parts.push(`<div class="dsh-upd-banner" data-kind="${b.kind}" data-mini="${escapeHtml$2(seal.mini)}" role="status" aria-live="polite">`);
4564
- parts.push(`<div>${b.kind === "restart" ? "" : `<span class="dsh-upd-sealmini" aria-hidden="true">${escapeHtml$2(seal.mini)}</span>`}<strong>${escapeHtml$2(b.title)}</strong></div>`);
4876
+ parts.push("<div class=\"dsh-upd-masthead\"><span class=\"dsh-upd-masthead-kicker\">" + escapeHtml$3(copyText("panel.masthead.kicker", l)) + "</span><span class=\"dsh-upd-masthead-title\">" + escapeHtml$3(copyText("panel.masthead.title", l)) + " <i>" + escapeHtml$3(copyText("panel.masthead.volume", l)) + "</i></span></div>");
4877
+ parts.push(`<div class="dsh-upd-head"><span class="dsh-upd-name">${escapeHtml$3(pluginId)}</span><span class="dsh-upd-meta">${escapeHtml$3(copyText("panel.meta.label", l))} <b>${escapeHtml$3(profileName ?? copyText("panel.meta.unknown", l))}</b><span class="dsh-upd-proftag">profile</span></span></div>`);
4878
+ parts.push(`<div class="dsh-upd-banner" data-kind="${b.kind}" data-mini="${escapeHtml$3(seal.mini)}" role="status" aria-live="polite">`);
4879
+ parts.push(`<div>${b.kind === "restart" ? "" : `<span class="dsh-upd-sealmini" aria-hidden="true">${escapeHtml$3(seal.mini)}</span>`}<strong>${escapeHtml$3(b.title)}</strong></div>`);
4565
4880
  parts.push("</div>");
4566
- if (b.action) parts.push(`<div class="dsh-upd-banner-sub">${escapeHtml$2(b.action)}</div>`);
4881
+ if (b.action) parts.push(`<div class="dsh-upd-banner-sub">${escapeHtml$3(b.action)}</div>`);
4567
4882
  parts.push(snapshot ? versionStrip(snapshot, l) : skeletonStrip(view.banner.kind === "loading", l));
4568
4883
  const showActions = input.actions !== "none";
4569
4884
  const actions = [];
@@ -4574,17 +4889,17 @@ ${note}${blocks.join("\n")}
4574
4889
  const jobState = snapshot?.job?.state;
4575
4890
  const macroBusy = busyAct === "check" || busyAct === "install" || jobState === "installing" || jobState === "verifying";
4576
4891
  actions.push("<div class=\"dsh-upd-actions\">");
4577
- actions.push((checkBusy ? `<button type="button" data-action="check" disabled aria-busy="true" title="${escapeHtml$2(copyText("panel.action.checking-busy-title", l))}">${escapeHtml$2(copyText("panel.action.checking-busy", l))}</button>` : `<button type="button" data-action="check" title="${escapeHtml$2(copyText("panel.action.check-title", l))}"${macroBusy ? " disabled" : ""}>${escapeHtml$2(copyText("panel.action.check", l))}</button>`) + (installBusy ? `<button type="button" data-action="install" data-primary="1" disabled aria-busy="true" title="${escapeHtml$2(copyText("panel.action.installing-busy-title", l))}">${escapeHtml$2(copyText("panel.action.installing-busy", l))}</button>` : `<button type="button" data-action="install" data-primary="1" title="${escapeHtml$2(copyText("panel.action.install-title", l))}"${macroBusy || !view.installEnabled ? " disabled" : ""}>${escapeHtml$2(view.installLabel)}</button>`));
4578
- if (snapshot?.latestVersion && !view.skippedLatest && view.banner.kind === "update") actions.push(`<button type="button" data-action="skip" title="${escapeHtml$2(copyText("panel.action.skip-title", l))}">${escapeHtml$2(copyText("panel.action.skip", l))}</button>`);
4579
- if (view.showReset && snapshot?.latestVersion) actions.push(`<button type="button" data-action="reset-skip" title="${escapeHtml$2(copyText("panel.action.unskip-title", l))}">${escapeHtml$2(copyText("panel.action.unskip", l, { version: snapshot.latestVersion }))}</button>`);
4580
- if (view.showManual && manual) actions.push(`<button type="button" data-action="copy-manual" title="${escapeHtml$2(copyText("panel.action.copy-manual-title", l))}">${escapeHtml$2(copyText("panel.action.copy-manual", l))}</button>`);
4581
- if (b.kind === "restart") actions.push(`<button type="button" data-action="restart-hint" title="${escapeHtml$2(copyText("panel.action.restart-host-title", l))}">${escapeHtml$2(copyText("panel.action.restart-host", l))}</button>`);
4582
- if (b.kind === "failed") actions.push(`<button type="button" data-action="dismiss-failure" title="${escapeHtml$2(copyText("panel.action.dismiss-title", l))}">${escapeHtml$2(copyText("panel.action.dismiss", l))}</button>`);
4583
- if (snapshot) actions.push(`<button type="button" data-action="copy-diag" title="${escapeHtml$2(copyText("panel.action.copy-diag-title", l))}">${escapeHtml$2(copyText("panel.action.copy-diag", l))}</button>`);
4892
+ actions.push((checkBusy ? `<button type="button" data-action="check" disabled aria-busy="true" title="${escapeHtml$3(copyText("panel.action.checking-busy-title", l))}">${escapeHtml$3(copyText("panel.action.checking-busy", l))}</button>` : `<button type="button" data-action="check" title="${escapeHtml$3(copyText("panel.action.check-title", l))}"${macroBusy ? " disabled" : ""}>${escapeHtml$3(copyText("panel.action.check", l))}</button>`) + (installBusy ? `<button type="button" data-action="install" data-primary="1" disabled aria-busy="true" title="${escapeHtml$3(copyText("panel.action.installing-busy-title", l))}">${escapeHtml$3(copyText("panel.action.installing-busy", l))}</button>` : `<button type="button" data-action="install" data-primary="1" title="${escapeHtml$3(copyText("panel.action.install-title", l))}"${macroBusy || !view.installEnabled ? " disabled" : ""}>${escapeHtml$3(view.installLabel)}</button>`));
4893
+ if (snapshot?.latestVersion && !view.skippedLatest && view.banner.kind === "update") actions.push(`<button type="button" data-action="skip" title="${escapeHtml$3(copyText("panel.action.skip-title", l))}">${escapeHtml$3(copyText("panel.action.skip", l))}</button>`);
4894
+ if (view.showReset && snapshot?.latestVersion) actions.push(`<button type="button" data-action="reset-skip" title="${escapeHtml$3(copyText("panel.action.unskip-title", l))}">${escapeHtml$3(copyText("panel.action.unskip", l, { version: snapshot.latestVersion }))}</button>`);
4895
+ if (view.showManual && manual) actions.push(`<button type="button" data-action="copy-manual" title="${escapeHtml$3(copyText("panel.action.copy-manual-title", l))}">${escapeHtml$3(copyText("panel.action.copy-manual", l))}</button>`);
4896
+ if (b.kind === "restart") actions.push(`<button type="button" data-action="restart-hint" title="${escapeHtml$3(copyText("panel.action.restart-host-title", l))}">${escapeHtml$3(copyText("panel.action.restart-host", l))}</button>`);
4897
+ if (b.kind === "failed") actions.push(`<button type="button" data-action="dismiss-failure" title="${escapeHtml$3(copyText("panel.action.dismiss-title", l))}">${escapeHtml$3(copyText("panel.action.dismiss", l))}</button>`);
4898
+ if (snapshot) actions.push(`<button type="button" data-action="copy-diag" title="${escapeHtml$3(copyText("panel.action.copy-diag-title", l))}">${escapeHtml$3(copyText("panel.action.copy-diag", l))}</button>`);
4584
4899
  actions.push("</div>");
4585
4900
  }
4586
4901
  actions.push(progressBar(snapshot, l));
4587
- if (view.skippedLatest && snapshot?.latestVersion) actions.push(`<div class="dsh-upd-skipline"><span class="dsh-upd-tag">${escapeHtml$2(copyText("panel.skip.line-tag", l, { version: snapshot.latestVersion }))}</span>${escapeHtml$2(copyText("panel.skip.line-note", l))}</div>`);
4902
+ if (view.skippedLatest && snapshot?.latestVersion) actions.push(`<div class="dsh-upd-skipline"><span class="dsh-upd-tag">${escapeHtml$3(copyText("panel.skip.line-tag", l, { version: snapshot.latestVersion }))}</span>${escapeHtml$3(copyText("panel.skip.line-note", l))}</div>`);
4588
4903
  const chapters = [];
4589
4904
  chapters.push(chapterOf(1, actions.join(""), "", l));
4590
4905
  {
@@ -4596,7 +4911,7 @@ ${note}${blocks.join("\n")}
4596
4911
  const entries = report.entries;
4597
4912
  const ranged = changelogForUpdate(entries, snapshot.runningVersion, snapshot.latestVersion, snapshot.installedVersion);
4598
4913
  if (ranged.length === 0 && mdText.trim() && entries.length === 0) {
4599
- inner = `<div class="dsh-upd-changelog-wrap"><div class="dsh-upd-changelog-neutral">${escapeHtml$2(copyText("panel.changelog.unavailable", l))}</div>${truncationNoteHTML(report.truncation, l)}</div>`;
4914
+ inner = `<div class="dsh-upd-changelog-wrap"><div class="dsh-upd-changelog-neutral">${escapeHtml$3(copyText("panel.changelog.unavailable", l))}</div>${truncationNoteHTML(report.truncation, l)}</div>`;
4600
4915
  hasLog = false;
4601
4916
  } else {
4602
4917
  const changelogHTML = renderChangelogHTML(ranged, {
@@ -4623,7 +4938,7 @@ ${note}${blocks.join("\n")}
4623
4938
  yankedBanner = "";
4624
4939
  }
4625
4940
  const logOpen = input.changelogCollapsed !== true;
4626
- inner = `<div class="dsh-upd-changelog-wrap"><div>${escapeHtml$2(rangeTitle)}</div><div class="dsh-upd-changelog-foldbox" data-open="${logOpen ? "1" : "0"}"><div class="dsh-upd-changelog-foldbox-inner">${yankedBanner}
4941
+ inner = `<div class="dsh-upd-changelog-wrap"><div>${escapeHtml$3(rangeTitle)}</div><div class="dsh-upd-changelog-foldbox" data-open="${logOpen ? "1" : "0"}"><div class="dsh-upd-changelog-foldbox-inner">${yankedBanner}
4627
4942
  ${changelogHTML}
4628
4943
  </div></div></div>`;
4629
4944
  hasLog = Array.isArray(ranged) && ranged.length > 0;
@@ -4631,9 +4946,9 @@ ${changelogHTML}
4631
4946
  } catch {
4632
4947
  inner = "";
4633
4948
  }
4634
- if (!inner) inner = `<div class="dsh-upd-changelog-wrap"><div class="dsh-upd-changelog-neutral">${escapeHtml$2(snapshot && snapshot.latestVersion ? copyText("panel.changelog.unavailable", l) : copyText("panel.changelog.unavailable-empty", l))}</div></div>`;
4949
+ if (!inner) inner = `<div class="dsh-upd-changelog-wrap"><div class="dsh-upd-changelog-neutral">${escapeHtml$3(snapshot && snapshot.latestVersion ? copyText("panel.changelog.unavailable", l) : copyText("panel.changelog.unavailable-empty", l))}</div></div>`;
4635
4950
  const logCollapsed = input.changelogCollapsed === true;
4636
- const logNote = showActions && hasLog ? "<span class=\"dsh-upd-chap-note\"><button type=\"button\" data-action=\"toggle-changelog\" title=\"" + escapeHtml$2(copyText("panel.changelog.toggle-title", l)) + `">${escapeHtml$2(logCollapsed ? copyText("panel.changelog.expand", l) : copyText("panel.changelog.collapse", l))}</button></span>` : "";
4951
+ const logNote = showActions && hasLog ? "<span class=\"dsh-upd-chap-note\"><button type=\"button\" data-action=\"toggle-changelog\" title=\"" + escapeHtml$3(copyText("panel.changelog.toggle-title", l)) + `">${escapeHtml$3(logCollapsed ? copyText("panel.changelog.expand", l) : copyText("panel.changelog.collapse", l))}</button></span>` : "";
4637
4952
  chapters.push(chapterOf(2, inner, logNote, l));
4638
4953
  }
4639
4954
  if (!!queue && (queue.busy || queue.waiting.length > 0) && queue) {
@@ -4648,42 +4963,42 @@ ${changelogHTML}
4648
4963
  const pos = typeof queue.position === "number" ? queue.position : null;
4649
4964
  const posText = pos === null ? copyText("panel.queue.pos-absent", l) : copyText("panel.queue.pos-n", l, { n: pos });
4650
4965
  const posNote = pos === null ? "" : pos === 1 ? copyText("panel.queue.pos-next", l) : copyText("panel.queue.pos-ahead", l, { n: pos - 1 });
4651
- const rows = [`<div class="dsh-upd-qrow"><span class="dsh-upd-qdot" data-tone="${busy ? "busy" : "idle"}"></span><span class="dsh-upd-qk">${escapeHtml$2(copyText("panel.queue.row-installing", l))}</span><span class="dsh-upd-qv">${escapeHtml$2(ownerShown + ownerVer)}</span><span class="dsh-upd-qn">${escapeHtml$2(busy ? copyText("panel.queue.row-installing-note", l) : copyText("panel.queue.row-idle-note", l))}</span></div>`, `<div class="dsh-upd-qrow"><span class="dsh-upd-qdot" data-tone="you"></span><span class="dsh-upd-qk">${escapeHtml$2(copyText("panel.queue.row-position", l))}</span><span class="dsh-upd-qv">${escapeHtml$2(posText)}</span><span class="dsh-upd-qn">${escapeHtml$2(posNote)}</span></div>`];
4966
+ const rows = [`<div class="dsh-upd-qrow"><span class="dsh-upd-qdot" data-tone="${busy ? "busy" : "idle"}"></span><span class="dsh-upd-qk">${escapeHtml$3(copyText("panel.queue.row-installing", l))}</span><span class="dsh-upd-qv">${escapeHtml$3(ownerShown + ownerVer)}</span><span class="dsh-upd-qn">${escapeHtml$3(busy ? copyText("panel.queue.row-installing-note", l) : copyText("panel.queue.row-idle-note", l))}</span></div>`, `<div class="dsh-upd-qrow"><span class="dsh-upd-qdot" data-tone="you"></span><span class="dsh-upd-qk">${escapeHtml$3(copyText("panel.queue.row-position", l))}</span><span class="dsh-upd-qv">${escapeHtml$3(posText)}</span><span class="dsh-upd-qn">${escapeHtml$3(posNote)}</span></div>`];
4652
4967
  if (reveal && queue.waiting.length > 0) {
4653
4968
  const seq = queue.waiting.map((e) => `${e.pluginId}${e.targetVersion ? `@${e.targetVersion}` : ""}`).join(" → ");
4654
- rows.push(`<div class="dsh-upd-qrow"><span class="dsh-upd-qdot"></span><span class="dsh-upd-qk">${escapeHtml$2(copyText("panel.queue.row-order", l))}</span><span class="dsh-upd-qseq">${escapeHtml$2(seq)}</span></div>`);
4969
+ rows.push(`<div class="dsh-upd-qrow"><span class="dsh-upd-qdot"></span><span class="dsh-upd-qk">${escapeHtml$3(copyText("panel.queue.row-order", l))}</span><span class="dsh-upd-qseq">${escapeHtml$3(seq)}</span></div>`);
4655
4970
  }
4656
- const note = showActions ? `<span class="dsh-upd-chap-note"><button type="button" data-action="toggle-queue">${escapeHtml$2(reveal ? copyText("panel.queue.toggle-hide", l) : copyText("panel.queue.toggle-show", l))}</button></span>` : "";
4971
+ const note = showActions ? `<span class="dsh-upd-chap-note"><button type="button" data-action="toggle-queue">${escapeHtml$3(reveal ? copyText("panel.queue.toggle-hide", l) : copyText("panel.queue.toggle-show", l))}</button></span>` : "";
4657
4972
  chapters.push(chapterOf(3, `<div class="dsh-upd-queue">${rows.join("")}</div>`, note, l));
4658
- } else chapters.push(chapterOf(3, `<div class="dsh-upd-queue"><div class="dsh-upd-changelog-neutral">${escapeHtml$2(view.queueNote ?? copyText("panel.queue.empty", l))}</div></div>`, "", l));
4973
+ } else chapters.push(chapterOf(3, `<div class="dsh-upd-queue"><div class="dsh-upd-changelog-neutral">${escapeHtml$3(view.queueNote ?? copyText("panel.queue.empty", l))}</div></div>`, "", l));
4659
4974
  {
4660
4975
  const errLines = [];
4661
4976
  const failedNow = b.kind === "failed" || b.kind === "blocked";
4662
4977
  const failRef = input.failure;
4663
4978
  if (failedNow) {
4664
4979
  const shownCode = b.kind === "blocked" ? snapshot?.blockedReason ?? b.kind : typeof input.lastError === "string" && input.lastError.trim() ? input.lastError : "install-failed";
4665
- errLines.push(`<div class="dsh-upd-err">${escapeHtml$2(copyText("panel.error.code-label", l))} <code>${escapeHtml$2(String(shownCode))}</code>${l === "en" ? ":" : ":"}${escapeHtml$2(copyText("panel.error.code-note", l))}</div>`);
4980
+ errLines.push(`<div class="dsh-upd-err">${escapeHtml$3(copyText("panel.error.code-label", l))} <code>${escapeHtml$3(String(shownCode))}</code>${l === "en" ? ":" : ":"}${escapeHtml$3(copyText("panel.error.code-note", l))}</div>`);
4666
4981
  if (b.kind === "failed" && failRef) {
4667
4982
  const keys = [];
4668
- if (typeof failRef.requestId === "string" && failRef.requestId) keys.push(`${escapeHtml$2(copyText("panel.error.query-request", l))} <code>${escapeHtml$2(failRef.requestId)}</code>`);
4669
- if (typeof failRef.checkId === "string" && failRef.checkId) keys.push(`${escapeHtml$2(copyText("panel.error.query-check", l))} <code>${escapeHtml$2(failRef.checkId)}</code>`);
4983
+ if (typeof failRef.requestId === "string" && failRef.requestId) keys.push(`${escapeHtml$3(copyText("panel.error.query-request", l))} <code>${escapeHtml$3(failRef.requestId)}</code>`);
4984
+ if (typeof failRef.checkId === "string" && failRef.checkId) keys.push(`${escapeHtml$3(copyText("panel.error.query-check", l))} <code>${escapeHtml$3(failRef.checkId)}</code>`);
4670
4985
  const at = formatLatchTime(failRef.atMs, input.lang ?? l);
4671
- if (at) keys.push(`${escapeHtml$2(copyText("panel.error.failed-at", l, { time: at }))}`);
4986
+ if (at) keys.push(`${escapeHtml$3(copyText("panel.error.failed-at", l, { time: at }))}`);
4672
4987
  if (keys.length > 0) errLines.push(`<div class="dsh-upd-err">${copyText("panel.error.query-keys", l, { keys: keys.join(" · ") })}</div>`);
4673
- if (typeof failRef.targetVersion === "string" && failRef.targetVersion.trim()) errLines.push(`<div class="dsh-upd-err">${escapeHtml$2(copyText("panel.error.target-version", l, { version: failRef.targetVersion.trim() }))}</div>`);
4674
- if (!failRef.volatile) errLines.push(`<div class="dsh-upd-err">${escapeHtml$2(copyText("panel.error.evidence-frozen", l))}</div>`);
4675
- else errLines.push(`<div class="dsh-upd-err">${escapeHtml$2(copyText("panel.error.evidence-transient", l))}</div>`);
4988
+ if (typeof failRef.targetVersion === "string" && failRef.targetVersion.trim()) errLines.push(`<div class="dsh-upd-err">${escapeHtml$3(copyText("panel.error.target-version", l, { version: failRef.targetVersion.trim() }))}</div>`);
4989
+ if (!failRef.volatile) errLines.push(`<div class="dsh-upd-err">${escapeHtml$3(copyText("panel.error.evidence-frozen", l))}</div>`);
4990
+ else errLines.push(`<div class="dsh-upd-err">${escapeHtml$3(copyText("panel.error.evidence-transient", l))}</div>`);
4676
4991
  }
4677
- } else errLines.push(`<div class="dsh-upd-changelog-neutral">${escapeHtml$2(copyText("panel.error.no-failure", l))}</div>`);
4992
+ } else errLines.push(`<div class="dsh-upd-changelog-neutral">${escapeHtml$3(copyText("panel.error.no-failure", l))}</div>`);
4678
4993
  if (input.showLogHint !== false) {
4679
4994
  const logDirInput = input.logDir;
4680
4995
  const logDirKnown = typeof logDirInput === "string" && logDirInput.trim() ? logDirInput.trim() : null;
4681
4996
  const logDirShown = logDirKnown ?? "<DSH_HOME>/logs/<derived>";
4682
4997
  const logCmdShown = logDirKnown ? `npx dsh-log ${logDirKnown}` : "npx dsh-log <log-dir>";
4683
4998
  errLines.push(`<div class="dsh-upd-log">${copyText("panel.error.log-hint", l, {
4684
- dir: `<code>${escapeHtml$2(logDirShown)}</code>`,
4685
- cmd: `<code>${escapeHtml$2(logCmdShown)}</code>`,
4686
- pluginId: `<code>${escapeHtml$2(pluginId)}</code>`,
4999
+ dir: `<code>${escapeHtml$3(logDirShown)}</code>`,
5000
+ cmd: `<code>${escapeHtml$3(logCmdShown)}</code>`,
5001
+ pluginId: `<code>${escapeHtml$3(pluginId)}</code>`,
4687
5002
  e1: `<code>${LOG_EVENT_CALL}</code>`,
4688
5003
  e2: `<code>${LOG_EVENT_CALL_FAIL}</code>`,
4689
5004
  e3: `<code>${LOG_EVENT_INSTALL_EXEC}</code>`
@@ -4694,13 +5009,13 @@ ${changelogHTML}
4694
5009
  eExec: `<code>${LOG_EVENT_INSTALL_EXEC}</code>`
4695
5010
  })}</div>`);
4696
5011
  }
4697
- if (copyNotice) errLines.push(`<div class="dsh-upd-copy" role="status">${escapeHtml$2(copyNotice)}</div>`);
5012
+ if (copyNotice) errLines.push(`<div class="dsh-upd-copy" role="status">${escapeHtml$3(copyNotice)}</div>`);
4698
5013
  else errLines.push("<div class=\"dsh-upd-copy dsh-upd-copy--empty\" aria-hidden=\"true\"></div>");
4699
5014
  chapters.push(chapterOf(4, errLines.join(""), "", l));
4700
5015
  }
4701
- chapters.push(chapterOf(5, view.showManual && manual ? `<div class="dsh-upd-manual"><div>${escapeHtml$2(copyText("panel.manual.heading", l))}</div><code>${escapeHtml$2(manual)}</code></div>` : `<div class="dsh-upd-manual"><div class="dsh-upd-changelog-neutral">${escapeHtml$2(copyText("panel.manual.absent", l))}</div></div>`, "", l));
5016
+ chapters.push(chapterOf(5, view.showManual && manual ? `<div class="dsh-upd-manual"><div>${escapeHtml$3(copyText("panel.manual.heading", l))}</div><code>${escapeHtml$3(manual)}</code></div>` : `<div class="dsh-upd-manual"><div class="dsh-upd-changelog-neutral">${escapeHtml$3(copyText("panel.manual.absent", l))}</div></div>`, "", l));
4702
5017
  parts.push("<div class=\"dsh-upd-body\">" + chapters.join("\n") + "</div>");
4703
- if (showActions && mode === "dialog") parts.push("<div class=\"dsh-upd-footer\"><span class=\"dsh-upd-foot-note\">" + escapeHtml$2(copyText("panel.footer.note", l)) + `</span><button type="button" data-action="close-view" title="${escapeHtml$2(copyText("panel.footer.close-title", l))}">${escapeHtml$2(copyText("panel.footer.close", l))}</button></div>`);
5018
+ if (showActions && mode === "dialog") parts.push("<div class=\"dsh-upd-footer\"><span class=\"dsh-upd-foot-note\">" + escapeHtml$3(copyText("panel.footer.note", l)) + `</span><button type="button" data-action="close-view" title="${escapeHtml$3(copyText("panel.footer.close-title", l))}">${escapeHtml$3(copyText("panel.footer.close", l))}</button></div>`);
4704
5019
  return parts.join("\n");
4705
5020
  }
4706
5021
  function renderUpdatePanelHTML(input, lang) {
@@ -4711,10 +5026,10 @@ ${changelogHTML}
4711
5026
  const attr = archive ? " data-theme=\"archive\"" : "";
4712
5027
  const tokensStyle = themeTokensStyleFor(input.themeTokens ?? void 0);
4713
5028
  const tokensAttr = tokensStyle ? ` style="${tokensStyle}"` : "";
4714
- const sealAttr = ` data-seal="${escapeHtml$2(view.seal.text)}" data-seal-tone="${view.seal.tone}"`;
4715
- const body = input.mode === "dialog" ? `<div class="dsh-upd-overlay" data-mode="dialog"><div class="dsh-upd" data-mode="dialog" data-plugin="${escapeHtml$2(input.pluginId)}"${sealAttr}${attr}${tokensAttr}>
5029
+ const sealAttr = ` data-seal="${escapeHtml$3(view.seal.text)}" data-seal-tone="${view.seal.tone}"`;
5030
+ const body = input.mode === "dialog" ? `<div class="dsh-upd-overlay" data-mode="dialog"><div class="dsh-upd" data-mode="dialog" data-plugin="${escapeHtml$3(input.pluginId)}"${sealAttr}${attr}${tokensAttr}>
4716
5031
  ${kernel}
4717
- </div></div>` : `<div class="dsh-upd" data-mode="embedded" data-plugin="${escapeHtml$2(input.pluginId)}"${sealAttr}${attr}${tokensAttr}>
5032
+ </div></div>` : `<div class="dsh-upd" data-mode="embedded" data-plugin="${escapeHtml$3(input.pluginId)}"${sealAttr}${attr}${tokensAttr}>
4718
5033
  ${kernel}
4719
5034
  </div>`;
4720
5035
  return `<style>${archive ? `${UPDATE_PANEL_CSS}
@@ -4722,7 +5037,7 @@ ${UPDATE_PANEL_ARCHIVE_CSS}` : UPDATE_PANEL_CSS}</style>
4722
5037
  ${body}`;
4723
5038
  }
4724
5039
  //#endregion
4725
- //#region ../../node_modules/.pnpm/dsh-plugin-update@0.17.0/node_modules/dsh-plugin-update/dist/entry.js
5040
+ //#region ../../node_modules/.pnpm/dsh-plugin-update@0.18.0/node_modules/dsh-plugin-update/dist/entry.js
4726
5041
  const UPDATE_ENTRY_CSS = [
4727
5042
  ".dsh-upd-entry{display:inline-flex;align-items:center;gap:8px;font:13px/1.6 var(--dsh-update-font-sans,system-ui,\"Microsoft YaHei\",sans-serif);font-size:var(--dsh-update-entry-font-size,13px);color:var(--dsh-update-text,#1f2937)}",
4728
5043
  ".dsh-upd-entry-btn{font:inherit;border:1px solid var(--dsh-update-border,#d1d5db);border-radius:var(--dsh-update-entry-border-radius,6px);",
@@ -4836,7 +5151,7 @@ ${body}`;
4836
5151
  }
4837
5152
  }
4838
5153
  //#endregion
4839
- //#region ../../node_modules/.pnpm/dsh-plugin-update@0.17.0/node_modules/dsh-plugin-update/dist/panel-batch.js
5154
+ //#region ../../node_modules/.pnpm/dsh-plugin-update@0.18.0/node_modules/dsh-plugin-update/dist/panel-batch.js
4840
5155
  const BATCH_PANEL_POLL = {
4841
5156
  defaultMs: 1500,
4842
5157
  minMs: 250
@@ -4901,11 +5216,11 @@ ${body}`;
4901
5216
  return batchText("batch.row.queued-n", l, { n: String(position) });
4902
5217
  }
4903
5218
  function knowledgeEntryOf(inventory, key) {
4904
- if (!isObject$1(inventory)) return null;
5219
+ if (!isObject$2(inventory)) return null;
4905
5220
  const entries = inventory["entries"];
4906
- if (!isObject$1(entries)) return null;
5221
+ if (!isObject$2(entries)) return null;
4907
5222
  const item = entries[key];
4908
- if (!isObject$1(item)) return null;
5223
+ if (!isObject$2(item)) return null;
4909
5224
  const e = item;
4910
5225
  const canInstallRaw = e["canInstall"];
4911
5226
  const installedRaw = e["installed"];
@@ -4940,10 +5255,10 @@ ${body}`;
4940
5255
  }
4941
5256
  }
4942
5257
  function sessionEntriesOf(session) {
4943
- if (!isObject$1(session)) return null;
5258
+ if (!isObject$2(session)) return null;
4944
5259
  const entries = session["entries"];
4945
5260
  if (!Array.isArray(entries)) return null;
4946
- return entries.filter((item) => isObject$1(item));
5261
+ return entries.filter((item) => isObject$2(item));
4947
5262
  }
4948
5263
  function entryPhaseOf(entry) {
4949
5264
  const phase = entry["phase"];
@@ -5058,12 +5373,12 @@ ${body}`;
5058
5373
  function batchRowVersionHTML(row, knowledge, lang) {
5059
5374
  const parts = batchRowVersionParts(row, knowledge);
5060
5375
  if (parts.hasUpdate && parts.latest) {
5061
- const snapshot = isObject$1(row.snapshot) ? row.snapshot : null;
5376
+ const snapshot = isObject$2(row.snapshot) ? row.snapshot : null;
5062
5377
  const cur = parts.current ?? (snapshot !== null && snapshot["installed"] === false ? batchText("batch.row.not-installed", lang) : "?");
5063
5378
  const newCls = asBatchPhase(row.phase) === "done" ? "dsh-upd-bver-new-ok" : "dsh-upd-bver-new";
5064
- return "<span class=\"dsh-upd-bver\"><span class=\"dsh-upd-bver-cur\">" + escapeHtml$1(cur) + "</span><span class=\"dsh-upd-bver-arrow\" aria-hidden=\"true\"> → </span><span class=\"" + newCls + "\">" + escapeHtml$1(parts.latest) + "</span></span>";
5379
+ return "<span class=\"dsh-upd-bver\"><span class=\"dsh-upd-bver-cur\">" + escapeHtml$2(cur) + "</span><span class=\"dsh-upd-bver-arrow\" aria-hidden=\"true\"> → </span><span class=\"" + newCls + "\">" + escapeHtml$2(parts.latest) + "</span></span>";
5065
5380
  }
5066
- if (parts.current) return "<span class=\"dsh-upd-bver\">" + escapeHtml$1(parts.current) + "</span>";
5381
+ if (parts.current) return "<span class=\"dsh-upd-bver\">" + escapeHtml$2(parts.current) + "</span>";
5067
5382
  return "";
5068
5383
  }
5069
5384
  function batchRowPendingStatus(row, knowledge, lang) {
@@ -5109,20 +5424,20 @@ ${body}`;
5109
5424
  };
5110
5425
  const parts = [];
5111
5426
  parts.push("<div class=\"dsh-upd-batch-head\">");
5112
- parts.push("<div class=\"dsh-upd-batch-title\">" + escapeHtml$1(batchText("batch.header.title", lang)) + " · <i>" + escapeHtml$1(batchText("batch.seal.ledger", lang)) + "</i></div>");
5427
+ parts.push("<div class=\"dsh-upd-batch-title\">" + escapeHtml$2(batchText("batch.header.title", lang)) + " · <i>" + escapeHtml$2(batchText("batch.seal.ledger", lang)) + "</i></div>");
5113
5428
  parts.push("<div class=\"dsh-upd-batch-macros\">");
5114
- parts.push("<button type=\"button\" data-act=\"check\"" + disabled + " title=\"" + escapeHtml$1(batchText("batch.action.check-title", lang)) + "\">" + escapeHtml$1(batchText("batch.action.check", lang)) + "</button>");
5115
- parts.push("<button type=\"button\" data-act=\"install\" data-primary=\"1\"" + disabled + " title=\"" + escapeHtml$1(batchText("batch.action.install-all-title", lang)) + "\">" + escapeHtml$1(batchText("batch.action.install-all", lang)) + "</button>");
5116
- if (mode === "dialog") parts.push("<button type=\"button\" data-act=\"close\" title=\"" + escapeHtml$1(batchText("batch.action.close-title", lang)) + "\">" + escapeHtml$1(batchText("batch.action.close", lang)) + "</button>");
5429
+ parts.push("<button type=\"button\" data-act=\"check\"" + disabled + " title=\"" + escapeHtml$2(batchText("batch.action.check-title", lang)) + "\">" + escapeHtml$2(batchText("batch.action.check", lang)) + "</button>");
5430
+ parts.push("<button type=\"button\" data-act=\"install\" data-primary=\"1\"" + disabled + " title=\"" + escapeHtml$2(batchText("batch.action.install-all-title", lang)) + "\">" + escapeHtml$2(batchText("batch.action.install-all", lang)) + "</button>");
5431
+ if (mode === "dialog") parts.push("<button type=\"button\" data-act=\"close\" title=\"" + escapeHtml$2(batchText("batch.action.close-title", lang)) + "\">" + escapeHtml$2(batchText("batch.action.close", lang)) + "</button>");
5117
5432
  parts.push("</div>");
5118
5433
  parts.push("</div>");
5119
5434
  const summary = loaded ? batchSummaryText(counts, rows, total, installing, lastError !== null, lang) : batchText("batch.banner.loading", lang);
5120
- parts.push("<div class=\"dsh-upd-batch-sum\" role=\"status\" aria-live=\"polite\">" + escapeHtml$1(summary) + "</div>");
5435
+ parts.push("<div class=\"dsh-upd-batch-sum\" role=\"status\" aria-live=\"polite\">" + escapeHtml$2(summary) + "</div>");
5121
5436
  parts.push(bannersHTML(rows, titles, lastError, lang));
5122
- const session = isObject$1(input.session) ? input.session : null;
5437
+ const session = isObject$2(input.session) ? input.session : null;
5123
5438
  const unfinished = unfinishedCount(rows, session ?? void 0);
5124
5439
  const showControls = total > 0 && hasUnfinishedRows(rows, session ?? void 0);
5125
- const prefs = isObject$1(input.prefs) ? input.prefs : null;
5440
+ const prefs = isObject$2(input.prefs) ? input.prefs : null;
5126
5441
  const checkOnOpen = prefs === null ? null : prefs["checkOnOpen"] === false ? false : true;
5127
5442
  parts.push("<div class=\"dsh-upd-btable\">");
5128
5443
  for (const row of rows) {
@@ -5144,26 +5459,26 @@ ${body}`;
5144
5459
  }));
5145
5460
  }
5146
5461
  parts.push("</div>");
5147
- if (total > 0) parts.push("<div class=\"dsh-upd-batch-ledger\">" + escapeHtml$1(batchLedgerText(counts, lang)) + "</div>");
5462
+ if (total > 0) parts.push("<div class=\"dsh-upd-batch-ledger\">" + escapeHtml$2(batchLedgerText(counts, lang)) + "</div>");
5148
5463
  if (showControls) {
5149
5464
  const more = [];
5150
- more.push("<button type=\"button\" data-act=\"resume\" title=\"" + escapeHtml$1(batchText("batch.action.resume-title", lang)) + "\">" + escapeHtml$1(batchText("batch.action.resume", lang, { count: String(unfinished) })) + "</button>");
5465
+ more.push("<button type=\"button\" data-act=\"resume\" title=\"" + escapeHtml$2(batchText("batch.action.resume-title", lang)) + "\">" + escapeHtml$2(batchText("batch.action.resume", lang, { count: String(unfinished) })) + "</button>");
5151
5466
  const confirmCancel = input.confirmCancel === true;
5152
5467
  const discardLabel = confirmCancel ? batchText("batch.action.confirm-discard", lang) : batchText("batch.action.discard", lang);
5153
- more.push("<button type=\"button\" data-act=\"cancel\"" + disabled + (confirmCancel ? " data-confirm=\"1\" title=\"" + escapeHtml$1(batchText("batch.notice.cancel-confirm", lang)) + "\"" : " title=\"" + escapeHtml$1(batchText("batch.action.discard", lang)) + "\"") + ">" + escapeHtml$1(discardLabel) + "</button>");
5468
+ more.push("<button type=\"button\" data-act=\"cancel\"" + disabled + (confirmCancel ? " data-confirm=\"1\" title=\"" + escapeHtml$2(batchText("batch.notice.cancel-confirm", lang)) + "\"" : " title=\"" + escapeHtml$2(batchText("batch.action.discard", lang)) + "\"") + ">" + escapeHtml$2(discardLabel) + "</button>");
5154
5469
  parts.push("<div class=\"dsh-upd-batch-more\">" + more.join("") + "</div>");
5155
- parts.push("<div class=\"dsh-upd-batch-fact\" role=\"note\">" + escapeHtml$1(batchText("batch.fact.close-safe", lang)) + "</div>");
5156
- if (macroBusy) parts.push("<div class=\"dsh-upd-batch-fact\" role=\"note\">" + escapeHtml$1(batchText("batch.notice.busy-cancel", lang)) + "</div>");
5470
+ parts.push("<div class=\"dsh-upd-batch-fact\" role=\"note\">" + escapeHtml$2(batchText("batch.fact.close-safe", lang)) + "</div>");
5471
+ if (macroBusy) parts.push("<div class=\"dsh-upd-batch-fact\" role=\"note\">" + escapeHtml$2(batchText("batch.notice.busy-cancel", lang)) + "</div>");
5157
5472
  }
5158
- if (prefs !== null && checkOnOpen !== null) parts.push("<div class=\"dsh-upd-batch-prefs\"><button type=\"button\" data-act=\"toggle-check-on-open\" aria-pressed=\"" + (checkOnOpen ? "true" : "false") + "\">" + escapeHtml$1((checkOnOpen ? "[x] " : "[ ] ") + batchText("batch.setting.check-on-open", lang)) + "</button></div>");
5159
- if (notice !== null && detailNoticeKey === null) parts.push("<div class=\"dsh-upd-batch-notice\" role=\"status\">" + escapeHtml$1(notice) + "</div>");
5473
+ if (prefs !== null && checkOnOpen !== null) parts.push("<div class=\"dsh-upd-batch-prefs\"><button type=\"button\" data-act=\"toggle-check-on-open\" aria-pressed=\"" + (checkOnOpen ? "true" : "false") + "\">" + escapeHtml$2((checkOnOpen ? "[x] " : "[ ] ") + batchText("batch.setting.check-on-open", lang)) + "</button></div>");
5474
+ if (notice !== null && detailNoticeKey === null) parts.push("<div class=\"dsh-upd-batch-notice\" role=\"status\">" + escapeHtml$2(notice) + "</div>");
5160
5475
  const kernel = parts.join(String.fromCharCode(10));
5161
5476
  const archive = normalizePanelTheme(theme) === "archive";
5162
5477
  const attr = archive ? " data-theme=\"archive\"" : "";
5163
5478
  const tokensStyle = themeTokensStyleFor(input.themeTokens ?? void 0);
5164
5479
  const tokensAttr = tokensStyle ? " style=\"" + tokensStyle + "\"" : "";
5165
5480
  const seal = batchSealOf(counts, lang);
5166
- const root = "<div class=\"dsh-upd dsh-upd-batch\" data-mode=\"" + mode + "\" data-seal=\"" + escapeHtml$1(seal.text) + "\" data-seal-tone=\"" + seal.tone + "\"" + attr + tokensAttr + ">\n" + kernel + "\n</div>";
5481
+ const root = "<div class=\"dsh-upd dsh-upd-batch\" data-mode=\"" + mode + "\" data-seal=\"" + escapeHtml$2(seal.text) + "\" data-seal-tone=\"" + seal.tone + "\"" + attr + tokensAttr + ">\n" + kernel + "\n</div>";
5167
5482
  const body = mode === "dialog" ? "<div class=\"dsh-upd-overlay\" data-mode=\"dialog\">" + root + "</div>" : root;
5168
5483
  let detailDialog = "";
5169
5484
  if (expandedKey !== null) {
@@ -5230,34 +5545,34 @@ ${body}`;
5230
5545
  const copy = failureCopy(lastError, l);
5231
5546
  const detail = copy?.zh ?? failureCopy("unknown", l)?.zh ?? "";
5232
5547
  const act = copy?.act ?? batchText("batch.banner.error-action-fallback", l);
5233
- parts.push("<div class=\"dsh-upd-banner\" data-kind=\"failed\" data-mini=\"阻\" role=\"status\"><div><span class=\"dsh-upd-sealmini\" aria-hidden=\"true\">阻</span><strong>" + escapeHtml$1(batchText("batch.banner.error-title", l, {
5548
+ parts.push("<div class=\"dsh-upd-banner\" data-kind=\"failed\" data-mini=\"阻\" role=\"status\"><div><span class=\"dsh-upd-sealmini\" aria-hidden=\"true\">阻</span><strong>" + escapeHtml$2(batchText("batch.banner.error-title", l, {
5234
5549
  code: lastError,
5235
5550
  detail
5236
5551
  })) + "</strong></div></div>");
5237
- if (act) parts.push("<div class=\"dsh-upd-banner-sub\">" + escapeHtml$1(act) + "</div>");
5552
+ if (act) parts.push("<div class=\"dsh-upd-banner-sub\">" + escapeHtml$2(act) + "</div>");
5238
5553
  }
5239
5554
  const failed = rows.filter((row) => asBatchPhase(row.phase) === "failed" && !isQueueBusyRow(row));
5240
5555
  if (failed.length > 0) {
5241
5556
  const lines = failed.map((row) => {
5242
5557
  const code = row.error || "install-failed";
5243
5558
  const copy = failureCopy(code, l);
5244
- return "<div>" + escapeHtml$1(titleOf(row, titles)) + ":<code>" + escapeHtml$1(code) + "</code> " + escapeHtml$1(copy?.zh ?? failureCopy("unknown", l)?.zh ?? "") + "</div>";
5559
+ return "<div>" + escapeHtml$2(titleOf(row, titles)) + ":<code>" + escapeHtml$2(code) + "</code> " + escapeHtml$2(copy?.zh ?? failureCopy("unknown", l)?.zh ?? "") + "</div>";
5245
5560
  }).join("");
5246
5561
  const failedAct = batchText("batch.banner.failed-action", l);
5247
- parts.push("<div class=\"dsh-upd-banner\" data-kind=\"failed\" data-mini=\"阻\" role=\"status\"><div><span class=\"dsh-upd-sealmini\" aria-hidden=\"true\">阻</span><strong>" + escapeHtml$1(batchText("batch.banner.failed-title", l, { n: String(failed.length) })) + "</strong></div><div class=\"dsh-upd-blist\">" + lines + "</div></div>");
5248
- if (failedAct) parts.push("<div class=\"dsh-upd-banner-sub\">" + escapeHtml$1(failedAct) + "</div>");
5562
+ parts.push("<div class=\"dsh-upd-banner\" data-kind=\"failed\" data-mini=\"阻\" role=\"status\"><div><span class=\"dsh-upd-sealmini\" aria-hidden=\"true\">阻</span><strong>" + escapeHtml$2(batchText("batch.banner.failed-title", l, { n: String(failed.length) })) + "</strong></div><div class=\"dsh-upd-blist\">" + lines + "</div></div>");
5563
+ if (failedAct) parts.push("<div class=\"dsh-upd-banner-sub\">" + escapeHtml$2(failedAct) + "</div>");
5249
5564
  }
5250
5565
  const restart = rows.filter((row) => row.restartRequired === true);
5251
5566
  if (restart.length > 0) {
5252
5567
  const restartAct = batchText("batch.banner.restart-action", l);
5253
- parts.push("<div class=\"dsh-upd-banner\" data-kind=\"restart\" role=\"status\"><div><strong>" + escapeHtml$1(batchText("batch.banner.restart-title", l, { n: String(restart.length) })) + "</strong></div><div class=\"dsh-upd-browline\"><span class=\"dsh-upd-blist\">" + restart.map((row) => escapeHtml$1(titleOf(row, titles))).join("、") + "</span><button type=\"button\" data-act=\"restart\">" + escapeHtml$1(batchText("batch.banner.restart-button", l)) + "</button></div></div>");
5254
- if (restartAct) parts.push("<div class=\"dsh-upd-banner-sub\">" + escapeHtml$1(restartAct) + "</div>");
5568
+ parts.push("<div class=\"dsh-upd-banner\" data-kind=\"restart\" role=\"status\"><div><strong>" + escapeHtml$2(batchText("batch.banner.restart-title", l, { n: String(restart.length) })) + "</strong></div><div class=\"dsh-upd-browline\"><span class=\"dsh-upd-blist\">" + restart.map((row) => escapeHtml$2(titleOf(row, titles))).join("、") + "</span><button type=\"button\" data-act=\"restart\">" + escapeHtml$2(batchText("batch.banner.restart-button", l)) + "</button></div></div>");
5569
+ if (restartAct) parts.push("<div class=\"dsh-upd-banner-sub\">" + escapeHtml$2(restartAct) + "</div>");
5255
5570
  }
5256
5571
  return parts.join("");
5257
5572
  }
5258
5573
  function rowSetHTML(row, ctx) {
5259
5574
  const phase = asBatchPhase(row.phase);
5260
- const keyAttr = escapeHtml$1(row.key);
5575
+ const keyAttr = escapeHtml$2(row.key);
5261
5576
  const skipped = ctx.skipped;
5262
5577
  const queued = isQueuedRow(row);
5263
5578
  const position = queued ? queuePositionOf(row) : null;
@@ -5265,55 +5580,55 @@ ${body}`;
5265
5580
  const rowStatusText = queued ? batchQueuedStatus(position, ctx.lang) : ctx.worldLatest !== null ? batchText("batch.row.update", ctx.lang, { version: ctx.worldLatest }) : ctx.inRound ? batchRowKnowledgeText(row, ctx.knowledge, ctx.lang) ?? batchRowStatus(row, skipped, ctx.lang) : batchRowPendingStatus(row, ctx.knowledge, ctx.lang) ?? batchRowStatus(row, skipped, ctx.lang);
5266
5581
  const actions = [];
5267
5582
  const off = ctx.inFlight ? " disabled" : "";
5268
- if (phase === "installing") actions.push("<button type=\"button\" data-act=\"row-install\" data-key=\"" + keyAttr + "\" disabled>" + escapeHtml$1(batchText("batch.row-action.installing", ctx.lang)) + "</button>");
5583
+ if (phase === "installing") actions.push("<button type=\"button\" data-act=\"row-install\" data-key=\"" + keyAttr + "\" disabled>" + escapeHtml$2(batchText("batch.row-action.installing", ctx.lang)) + "</button>");
5269
5584
  else if (queued) {
5270
- if (cancelQueuePhoneOf(row) !== null && queuedRequestIdOf(row) !== null) actions.push("<button type=\"button\" data-act=\"row-cancel-queue\" data-key=\"" + keyAttr + "\"" + off + ">" + escapeHtml$1(batchText("batch.row-action.cancel-queue", ctx.lang)) + "</button>");
5271
- } else if (phase === "ready" && skipped === null) actions.push("<button type=\"button\" data-act=\"row-install\" data-key=\"" + keyAttr + "\" data-primary=\"1\"" + off + ">" + escapeHtml$1(ctx.busy ? batchText("batch.row-action.queue", ctx.lang) : batchText("batch.row-action.install-row", ctx.lang)) + "</button>");
5272
- else if (phase === "ready" && skipped !== null) actions.push("<button type=\"button\" data-act=\"row-resume-skip\" data-key=\"" + keyAttr + "\"" + off + ">" + escapeHtml$1(batchText("batch.row-action.unskip", ctx.lang, { version: skipped })) + "</button>");
5273
- else if (phase === "failed") actions.push("<button type=\"button\" data-act=\"row-install\" data-key=\"" + keyAttr + "\"" + off + ">" + escapeHtml$1(ctx.busy ? batchText("batch.row-action.queue", ctx.lang) : batchText("batch.row-action.retry", ctx.lang)) + "</button>");
5274
- if (row.restartRequired === true) actions.push("<button type=\"button\" data-act=\"restart\" data-key=\"" + keyAttr + "\">" + escapeHtml$1(batchText("batch.row-action.restart", ctx.lang)) + "</button>");
5275
- actions.push("<button type=\"button\" data-act=\"toggle-details\" data-key=\"" + keyAttr + "\">" + escapeHtml$1(ctx.expanded ? batchText("batch.row-action.hide-detail", ctx.lang) : batchText("batch.row-action.show-detail", ctx.lang)) + "</button>");
5585
+ if (cancelQueuePhoneOf(row) !== null && queuedRequestIdOf(row) !== null) actions.push("<button type=\"button\" data-act=\"row-cancel-queue\" data-key=\"" + keyAttr + "\"" + off + ">" + escapeHtml$2(batchText("batch.row-action.cancel-queue", ctx.lang)) + "</button>");
5586
+ } else if (phase === "ready" && skipped === null) actions.push("<button type=\"button\" data-act=\"row-install\" data-key=\"" + keyAttr + "\" data-primary=\"1\"" + off + ">" + escapeHtml$2(ctx.busy ? batchText("batch.row-action.queue", ctx.lang) : batchText("batch.row-action.install-row", ctx.lang)) + "</button>");
5587
+ else if (phase === "ready" && skipped !== null) actions.push("<button type=\"button\" data-act=\"row-resume-skip\" data-key=\"" + keyAttr + "\"" + off + ">" + escapeHtml$2(batchText("batch.row-action.unskip", ctx.lang, { version: skipped })) + "</button>");
5588
+ else if (phase === "failed") actions.push("<button type=\"button\" data-act=\"row-install\" data-key=\"" + keyAttr + "\"" + off + ">" + escapeHtml$2(ctx.busy ? batchText("batch.row-action.queue", ctx.lang) : batchText("batch.row-action.retry", ctx.lang)) + "</button>");
5589
+ if (row.restartRequired === true) actions.push("<button type=\"button\" data-act=\"restart\" data-key=\"" + keyAttr + "\">" + escapeHtml$2(batchText("batch.row-action.restart", ctx.lang)) + "</button>");
5590
+ actions.push("<button type=\"button\" data-act=\"toggle-details\" data-key=\"" + keyAttr + "\">" + escapeHtml$2(ctx.expanded ? batchText("batch.row-action.hide-detail", ctx.lang) : batchText("batch.row-action.show-detail", ctx.lang)) + "</button>");
5276
5591
  const failLine = phase === "failed" && !queued ? (() => {
5277
5592
  const failCode = row.error || "install-failed";
5278
5593
  const failDetail = isCheckSideFailureCode(jobFailureOf(row)?.code ?? (typeof row.error === "string" && row.error ? row.error : null)) ? batchText("batch.row.failed", ctx.lang) : failureCopy(failCode, ctx.lang)?.zh ?? failureCopy("unknown", ctx.lang)?.zh ?? "";
5279
- const escaped = escapeHtml$1(batchText("batch.row.error-label", ctx.lang, {
5594
+ const escaped = escapeHtml$2(batchText("batch.row.error-label", ctx.lang, {
5280
5595
  code: failCode,
5281
5596
  detail: failDetail
5282
5597
  }));
5283
- const codeEsc = escapeHtml$1(failCode);
5598
+ const codeEsc = escapeHtml$2(failCode);
5284
5599
  return "<span class=\"dsh-upd-bfail\">" + (escaped.includes(codeEsc) ? escaped.replace(codeEsc, "<code>" + codeEsc + "</code>") : escaped) + "</span>";
5285
5600
  })() : "";
5286
- const main = "<button type=\"button\" class=\"dsh-upd-brow-main\" data-act=\"toggle-details\" data-key=\"" + keyAttr + "\" aria-expanded=\"" + (ctx.expanded ? "true" : "false") + "\"><span class=\"dsh-upd-updot\" data-tone=\"" + dotToneOf(row, phase, skipped, queued, ctx.worldLatest) + "\"></span><span class=\"dsh-upd-bname\">" + escapeHtml$1(titleOf(row, ctx.titles)) + "</span>" + versionHTML + "<span class=\"dsh-upd-bstat\">" + escapeHtml$1(rowStatusText) + (ctx.inRound && !queued ? "(" + escapeHtml$1(batchText("batch.row.unfinished-tag", ctx.lang)) + ")" : "") + "</span>" + failLine + "</button>";
5287
- return "<div class=\"dsh-upd-brow-set\" data-key=\"" + keyAttr + "\"><div class=\"dsh-upd-brow\" data-phase=\"" + escapeHtml$1(phase) + "\" data-key=\"" + keyAttr + "\"" + (queued ? " data-queued=\"1\"" : "") + ">" + main + "<span class=\"dsh-upd-brow-actions\">" + actions.join("") + "</span></div></div>";
5601
+ const main = "<button type=\"button\" class=\"dsh-upd-brow-main\" data-act=\"toggle-details\" data-key=\"" + keyAttr + "\" aria-expanded=\"" + (ctx.expanded ? "true" : "false") + "\"><span class=\"dsh-upd-updot\" data-tone=\"" + dotToneOf(row, phase, skipped, queued, ctx.worldLatest) + "\"></span><span class=\"dsh-upd-bname\">" + escapeHtml$2(titleOf(row, ctx.titles)) + "</span>" + versionHTML + "<span class=\"dsh-upd-bstat\">" + escapeHtml$2(rowStatusText) + (ctx.inRound && !queued ? "(" + escapeHtml$2(batchText("batch.row.unfinished-tag", ctx.lang)) + ")" : "") + "</span>" + failLine + "</button>";
5602
+ return "<div class=\"dsh-upd-brow-set\" data-key=\"" + keyAttr + "\"><div class=\"dsh-upd-brow\" data-phase=\"" + escapeHtml$2(phase) + "\" data-key=\"" + keyAttr + "\"" + (queued ? " data-queued=\"1\"" : "") + ">" + main + "<span class=\"dsh-upd-brow-actions\">" + actions.join("") + "</span></div></div>";
5288
5603
  }
5289
5604
  function detailActionsHTML(row, ctx) {
5290
5605
  const phase = asBatchPhase(row.phase);
5291
- const keyAttr = escapeHtml$1(row.key);
5606
+ const keyAttr = escapeHtml$2(row.key);
5292
5607
  const version = latestVersionOf(row);
5293
5608
  const queued = isQueuedRow(row);
5294
5609
  const off = ctx.inFlight ? " disabled" : "";
5295
5610
  const buttons = [];
5296
- if (phase === "installing") buttons.push("<button type=\"button\" data-act=\"row-install\" data-key=\"" + keyAttr + "\" disabled>" + escapeHtml$1(batchText("batch.row-action.installing", ctx.lang)) + "</button>");
5611
+ if (phase === "installing") buttons.push("<button type=\"button\" data-act=\"row-install\" data-key=\"" + keyAttr + "\" disabled>" + escapeHtml$2(batchText("batch.row-action.installing", ctx.lang)) + "</button>");
5297
5612
  else if (queued) {
5298
- if (cancelQueuePhoneOf(row) !== null && queuedRequestIdOf(row) !== null) buttons.push("<button type=\"button\" data-act=\"row-cancel-queue\" data-key=\"" + keyAttr + "\"" + off + ">" + escapeHtml$1(batchText("batch.row-action.cancel-queue", ctx.lang)) + "</button>");
5299
- } else if (phase === "failed") buttons.push("<button type=\"button\" data-act=\"row-install\" data-key=\"" + keyAttr + "\"" + off + ">" + escapeHtml$1(ctx.busy ? batchText("batch.row-action.queue", ctx.lang) : batchText("batch.row-action.retry", ctx.lang)) + "</button>");
5300
- else if (phase === "ready" && ctx.skipped === null) buttons.push("<button type=\"button\" data-act=\"row-install\" data-key=\"" + keyAttr + "\" data-primary=\"1\"" + off + ">" + escapeHtml$1(ctx.busy ? batchText("batch.row-action.queue", ctx.lang) : version !== null ? batchText("batch.row-action.install-version", ctx.lang, { version }) : batchText("batch.row-action.install-generic", ctx.lang)) + "</button>");
5301
- if (phase !== "installing" && singleCheckPhoneOf(row) !== null) buttons.push("<button type=\"button\" data-act=\"row-check\" data-key=\"" + keyAttr + "\"" + off + ">" + escapeHtml$1(batchText("batch.action.check", ctx.lang)) + "</button>");
5302
- if (!queued && phase === "ready" && ctx.skipped === null && version !== null) buttons.push("<button type=\"button\" data-act=\"row-skip\" data-key=\"" + keyAttr + "\"" + off + ">" + escapeHtml$1(batchText("batch.row-action.skip", ctx.lang)) + "</button>");
5303
- if (ctx.skipped !== null) buttons.push("<button type=\"button\" data-act=\"row-resume-skip\" data-key=\"" + keyAttr + "\"" + off + ">" + escapeHtml$1(batchText("batch.row-action.unskip", ctx.lang, { version: ctx.skipped })) + "</button>");
5304
- if (typeof row.manual === "string" && row.manual) buttons.push("<button type=\"button\" data-act=\"row-copy-manual\" data-key=\"" + keyAttr + "\"" + off + ">" + escapeHtml$1(batchText("batch.row-action.copy-manual", ctx.lang)) + "</button>");
5305
- buttons.push("<button type=\"button\" data-act=\"row-copy-diag\" data-key=\"" + keyAttr + "\"" + off + ">" + escapeHtml$1(batchText("batch.row-action.copy-diag", ctx.lang)) + "</button>");
5613
+ if (cancelQueuePhoneOf(row) !== null && queuedRequestIdOf(row) !== null) buttons.push("<button type=\"button\" data-act=\"row-cancel-queue\" data-key=\"" + keyAttr + "\"" + off + ">" + escapeHtml$2(batchText("batch.row-action.cancel-queue", ctx.lang)) + "</button>");
5614
+ } else if (phase === "failed") buttons.push("<button type=\"button\" data-act=\"row-install\" data-key=\"" + keyAttr + "\"" + off + ">" + escapeHtml$2(ctx.busy ? batchText("batch.row-action.queue", ctx.lang) : batchText("batch.row-action.retry", ctx.lang)) + "</button>");
5615
+ else if (phase === "ready" && ctx.skipped === null) buttons.push("<button type=\"button\" data-act=\"row-install\" data-key=\"" + keyAttr + "\" data-primary=\"1\"" + off + ">" + escapeHtml$2(ctx.busy ? batchText("batch.row-action.queue", ctx.lang) : version !== null ? batchText("batch.row-action.install-version", ctx.lang, { version }) : batchText("batch.row-action.install-generic", ctx.lang)) + "</button>");
5616
+ if (phase !== "installing" && singleCheckPhoneOf(row) !== null) buttons.push("<button type=\"button\" data-act=\"row-check\" data-key=\"" + keyAttr + "\"" + off + ">" + escapeHtml$2(batchText("batch.action.check", ctx.lang)) + "</button>");
5617
+ if (!queued && phase === "ready" && ctx.skipped === null && version !== null) buttons.push("<button type=\"button\" data-act=\"row-skip\" data-key=\"" + keyAttr + "\"" + off + ">" + escapeHtml$2(batchText("batch.row-action.skip", ctx.lang)) + "</button>");
5618
+ if (ctx.skipped !== null) buttons.push("<button type=\"button\" data-act=\"row-resume-skip\" data-key=\"" + keyAttr + "\"" + off + ">" + escapeHtml$2(batchText("batch.row-action.unskip", ctx.lang, { version: ctx.skipped })) + "</button>");
5619
+ if (typeof row.manual === "string" && row.manual) buttons.push("<button type=\"button\" data-act=\"row-copy-manual\" data-key=\"" + keyAttr + "\"" + off + ">" + escapeHtml$2(batchText("batch.row-action.copy-manual", ctx.lang)) + "</button>");
5620
+ buttons.push("<button type=\"button\" data-act=\"row-copy-diag\" data-key=\"" + keyAttr + "\"" + off + ">" + escapeHtml$2(batchText("batch.row-action.copy-diag", ctx.lang)) + "</button>");
5306
5621
  return "<span class=\"dsh-upd-bdetail-actions\">" + buttons.join("") + "</span>";
5307
5622
  }
5308
5623
  function stripActionButtons(html) {
5309
5624
  return html.replace(/<button\b[^>]*data-action=[^>]*>[\s\S]*?<\/button>/g, "");
5310
5625
  }
5311
5626
  function detailFooterHTML(row, ctx) {
5312
- const keyAttr = escapeHtml$1(row.key);
5313
- return "<div class=\"dsh-upd-footer\"><span class=\"dsh-upd-foot-note\">" + escapeHtml$1(batchText("panel.footer.note", ctx.lang)) + "</span><button type=\"button\" data-act=\"detail-close\" data-key=\"" + keyAttr + "\" title=\"" + escapeHtml$1(batchText("panel.footer.close-title", ctx.lang)) + "\">" + escapeHtml$1(batchText("panel.footer.close", ctx.lang)) + "</button></div>";
5627
+ const keyAttr = escapeHtml$2(row.key);
5628
+ return "<div class=\"dsh-upd-footer\"><span class=\"dsh-upd-foot-note\">" + escapeHtml$2(batchText("panel.footer.note", ctx.lang)) + "</span><button type=\"button\" data-act=\"detail-close\" data-key=\"" + keyAttr + "\" title=\"" + escapeHtml$2(batchText("panel.footer.close-title", ctx.lang)) + "\">" + escapeHtml$2(batchText("panel.footer.close", ctx.lang)) + "</button></div>";
5314
5629
  }
5315
5630
  function detailDialogHTML(row, ctx) {
5316
- const keyAttr = escapeHtml$1(row.key);
5631
+ const keyAttr = escapeHtml$2(row.key);
5317
5632
  const withoutStyle = stripActionButtons(renderUpdatePanelHTML({
5318
5633
  snapshot: asSnapshotLike(row.snapshot),
5319
5634
  manual: typeof row.manual === "string" ? row.manual : null,
@@ -5332,7 +5647,7 @@ ${body}`;
5332
5647
  hostKind: typeof row.hostKind === "string" && row.hostKind ? row.hostKind : null,
5333
5648
  actions: "none"
5334
5649
  }, ctx.lang)).replace(/^<style>[\s\S]*?<\/style>\s*/, "");
5335
- const bar = "<div class=\"dsh-upd-bdetail-dialog-bar\" data-detail-bar=\"" + keyAttr + "\">" + detailActionsHTML(row, ctx) + "</div>" + (ctx.notice !== null ? "<div class=\"dsh-upd-bdetail-notice\" role=\"status\">" + escapeHtml$1(ctx.notice) + "</div>" : "");
5650
+ const bar = "<div class=\"dsh-upd-bdetail-dialog-bar\" data-detail-bar=\"" + keyAttr + "\">" + detailActionsHTML(row, ctx) + "</div>" + (ctx.notice !== null ? "<div class=\"dsh-upd-bdetail-notice\" role=\"status\">" + escapeHtml$2(ctx.notice) + "</div>" : "");
5336
5651
  const withBar = withoutStyle.replace("<div class=\"dsh-upd-overlay\"", "<div class=\"dsh-upd-overlay dsh-upd-bdetail-dialog\" data-detail-key=\"" + keyAttr + "\"").replace("<div class=\"dsh-upd-body\">", bar + "<div class=\"dsh-upd-body\">");
5337
5652
  const footer = detailFooterHTML(row, ctx);
5338
5653
  const at = withBar.lastIndexOf("</div></div>");
@@ -5441,10 +5756,10 @@ ${body}`;
5441
5756
  ".dsh-upd[data-theme=\"archive\"] .dsh-upd-banner>.dsh-upd-browline .dsh-upd-blist{flex:1 1 auto;min-width:220px;text-align:left;margin:0;color:var(--dsh-update-text-muted)}",
5442
5757
  ".dsh-upd[data-theme=\"archive\"] .dsh-upd-banner>.dsh-upd-browline button{flex:none;margin:0;margin-left:auto;font-size:13px;line-height:1.45;padding:6px 12px;min-width:0;background:transparent}"
5443
5758
  ].join(String.fromCharCode(10));
5444
- function escapeHtml$1(text) {
5759
+ function escapeHtml$2(text) {
5445
5760
  return String(text).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
5446
5761
  }
5447
- function isObject$1(value) {
5762
+ function isObject$2(value) {
5448
5763
  return !!value && typeof value === "object" && !Array.isArray(value);
5449
5764
  }
5450
5765
  const BATCH_PHASES = [
@@ -5480,13 +5795,13 @@ ${body}`;
5480
5795
  return null;
5481
5796
  }
5482
5797
  function singleCheckPhoneOf(row) {
5483
- const phones = isObject$1(row.phoneNames) ? row.phoneNames : null;
5798
+ const phones = isObject$2(row.phoneNames) ? row.phoneNames : null;
5484
5799
  if (!phones) return null;
5485
5800
  const check = phones["updateCheck"];
5486
5801
  return typeof check === "string" && check ? check : null;
5487
5802
  }
5488
5803
  function cancelQueuePhoneOf(row) {
5489
- const phones = isObject$1(row.phoneNames) ? row.phoneNames : null;
5804
+ const phones = isObject$2(row.phoneNames) ? row.phoneNames : null;
5490
5805
  if (!phones) return null;
5491
5806
  const install = phones["updateInstall"];
5492
5807
  return typeof install === "string" && install ? install : null;
@@ -5495,13 +5810,13 @@ ${body}`;
5495
5810
  return typeof value === "string" && BATCH_PHASES.includes(value) ? value : "pending";
5496
5811
  }
5497
5812
  function asSnapshotLike(value) {
5498
- if (!isObject$1(value)) return null;
5813
+ if (!isObject$2(value)) return null;
5499
5814
  if (typeof value["runningVersion"] !== "string") return null;
5500
5815
  if (typeof value["canInstall"] !== "boolean") return null;
5501
5816
  return value;
5502
5817
  }
5503
5818
  function asQueueLike(value) {
5504
- if (!isObject$1(value) || typeof value["busy"] !== "boolean") return null;
5819
+ if (!isObject$2(value) || typeof value["busy"] !== "boolean") return null;
5505
5820
  return value;
5506
5821
  }
5507
5822
  function titleOf(row, titles) {
@@ -5515,11 +5830,11 @@ ${body}`;
5515
5830
  function latestVersionOf(row) {
5516
5831
  if (typeof row.targetVersion === "string" && row.targetVersion) return row.targetVersion;
5517
5832
  const snapshot = row.snapshot;
5518
- if (!isObject$1(snapshot)) return null;
5833
+ if (!isObject$2(snapshot)) return null;
5519
5834
  const latest = snapshot["latestVersion"];
5520
5835
  return typeof latest === "string" && latest ? latest : null;
5521
5836
  }
5522
- async function defaultCopyText(text) {
5837
+ async function defaultCopyText$1(text) {
5523
5838
  try {
5524
5839
  const clip = globalThis["navigator"]?.clipboard;
5525
5840
  const write = clip?.writeText;
@@ -5531,7 +5846,7 @@ ${body}`;
5531
5846
  }
5532
5847
  function currentVersionOf(row) {
5533
5848
  const snapshot = row.snapshot;
5534
- if (!isObject$1(snapshot)) return null;
5849
+ if (!isObject$2(snapshot)) return null;
5535
5850
  if (snapshot["installed"] === false) return null;
5536
5851
  const running = snapshot["runningVersion"];
5537
5852
  if (typeof running === "string" && running) return running;
@@ -5540,9 +5855,9 @@ ${body}`;
5540
5855
  return null;
5541
5856
  }
5542
5857
  function jobFailureOf(row) {
5543
- const snapshot = isObject$1(row.snapshot) ? row.snapshot : null;
5858
+ const snapshot = isObject$2(row.snapshot) ? row.snapshot : null;
5544
5859
  if (!snapshot) return null;
5545
- const job = isObject$1(snapshot["job"]) ? snapshot["job"] : null;
5860
+ const job = isObject$2(snapshot["job"]) ? snapshot["job"] : null;
5546
5861
  if (!job) return null;
5547
5862
  const state = typeof job["state"] === "string" ? job["state"] : "";
5548
5863
  if (state !== "failed" && state !== "interrupted") return null;
@@ -5579,9 +5894,9 @@ ${body}`;
5579
5894
  return parts.length > 0 ? parts.join(" · ") : null;
5580
5895
  }
5581
5896
  function diagTextOf(row, lang) {
5582
- const snapshot = isObject$1(row.snapshot) ? row.snapshot : null;
5583
- const queue = isObject$1(row.queue) ? row.queue : null;
5584
- const diag = isObject$1(row.diag) ? row.diag : null;
5897
+ const snapshot = isObject$2(row.snapshot) ? row.snapshot : null;
5898
+ const queue = isObject$2(row.queue) ? row.queue : null;
5899
+ const diag = isObject$2(row.diag) ? row.diag : null;
5585
5900
  const text = (value) => typeof value === "string" && value ? value : null;
5586
5901
  const job = jobFailureOf(row);
5587
5902
  const diagDetail = diag ? text(diag["detail"]) : null;
@@ -5604,7 +5919,7 @@ ${body}`;
5604
5919
  });
5605
5920
  }
5606
5921
  function isBusyReply(reply) {
5607
- if (!isObject$1(reply) || reply["ok"] === true) return false;
5922
+ if (!isObject$2(reply) || reply["ok"] === true) return false;
5608
5923
  const kind = typeof reply["errorKind"] === "string" ? reply["errorKind"] : "";
5609
5924
  const err = typeof reply["error"] === "string" ? reply["error"] : "";
5610
5925
  return kind === "update-busy" || err === "update-busy";
@@ -5614,7 +5929,7 @@ ${body}`;
5614
5929
  const out = [];
5615
5930
  const seen = /* @__PURE__ */ new Set();
5616
5931
  for (const item of value) {
5617
- if (!isObject$1(item)) continue;
5932
+ if (!isObject$2(item)) continue;
5618
5933
  const key = typeof item["key"] === "string" && item["key"] ? item["key"] : "";
5619
5934
  if (!key || seen.has(key)) continue;
5620
5935
  seen.add(key);
@@ -5651,7 +5966,7 @@ ${body}`;
5651
5966
  profileName: null
5652
5967
  }));
5653
5968
  }
5654
- function getTimer() {
5969
+ function getTimer$1() {
5655
5970
  const g = globalThis;
5656
5971
  const set = g["setInterval"];
5657
5972
  const clear = g["clearInterval"];
@@ -5683,7 +5998,7 @@ ${body}`;
5683
5998
  const titles = options.titles && typeof options.titles === "object" ? options.titles : {};
5684
5999
  const onRestartRequested = options.onRestartRequested;
5685
6000
  const onCloseRequested = typeof options.onCloseRequested === "function" ? options.onCloseRequested : null;
5686
- const copyText = options.copyText ?? defaultCopyText;
6001
+ const copyText = options.copyText ?? defaultCopyText$1;
5687
6002
  const skipStores = /* @__PURE__ */ new Map();
5688
6003
  const autoChangelogEnabled = options.autoChangelog !== false;
5689
6004
  const rowChangelog = /* @__PURE__ */ new Map();
@@ -5724,7 +6039,7 @@ ${body}`;
5724
6039
  return out;
5725
6040
  }
5726
6041
  function changelogPhoneOf(row) {
5727
- const phones2 = isObject$1(row.phoneNames) ? row.phoneNames : null;
6042
+ const phones2 = isObject$2(row.phoneNames) ? row.phoneNames : null;
5728
6043
  if (!phones2) return null;
5729
6044
  const name = phones2["updateChangelog"];
5730
6045
  return typeof name === "string" && name ? name : null;
@@ -5765,7 +6080,7 @@ ${body}`;
5765
6080
  Promise.resolve().then(() => call(phone2, { version })).then((reply) => {
5766
6081
  rowInflight.delete(key);
5767
6082
  if (!mounted || seq !== rowAutoSeq) return;
5768
- if (!isObject$1(reply) || reply["ok"] !== true) {
6083
+ if (!isObject$2(reply) || reply["ok"] !== true) {
5769
6084
  try {
5770
6085
  rowFailedAt.set(key + "\0" + version, Date.now());
5771
6086
  } catch {
@@ -5923,7 +6238,7 @@ ${body}`;
5923
6238
  render();
5924
6239
  }
5925
6240
  function applyReply(reply) {
5926
- if (!isObject$1(reply)) {
6241
+ if (!isObject$2(reply)) {
5927
6242
  lastError = "internal";
5928
6243
  return;
5929
6244
  }
@@ -5931,7 +6246,7 @@ ${body}`;
5931
6246
  const hasSession = "session" in reply && reply["session"] !== void 0;
5932
6247
  const hasRows = "rows" in reply && reply["rows"] !== void 0;
5933
6248
  if (!hasSession && !hasRows) {
5934
- if (isObject$1(reply["prefs"])) lastPrefs = reply["prefs"];
6249
+ if (isObject$2(reply["prefs"])) lastPrefs = reply["prefs"];
5935
6250
  return;
5936
6251
  }
5937
6252
  if (hasSession) {
@@ -5945,12 +6260,12 @@ ${body}`;
5945
6260
  const parsed = readRows(reply["rows"]);
5946
6261
  if (parsed.length > 0) rows = parsed;
5947
6262
  }
5948
- if (isObject$1(reply["inventory"])) {
6263
+ if (isObject$2(reply["inventory"])) {
5949
6264
  lastInventory = reply["inventory"];
5950
6265
  const at = reply["inventory"]["updatedAt"];
5951
6266
  if (typeof at === "number" && Number.isFinite(at) && at > 0) lastCheckedAt = at;
5952
6267
  }
5953
- if (isObject$1(reply["prefs"])) lastPrefs = reply["prefs"];
6268
+ if (isObject$2(reply["prefs"])) lastPrefs = reply["prefs"];
5954
6269
  loaded = true;
5955
6270
  lastError = null;
5956
6271
  if (expandedKey !== null && !rows.some((row) => row.key === expandedKey)) expandedKey = null;
@@ -5991,7 +6306,7 @@ ${body}`;
5991
6306
  }
5992
6307
  applyReply(reply);
5993
6308
  rowFailedAt.clear();
5994
- out = isObject$1(reply) ? reply : null;
6309
+ out = isObject$2(reply) ? reply : null;
5995
6310
  } catch {
5996
6311
  if (!mounted) return null;
5997
6312
  lastError = "check-failed";
@@ -6008,7 +6323,7 @@ ${body}`;
6008
6323
  return unfinishedCount(rows, lastSession ?? void 0);
6009
6324
  }
6010
6325
  function checkOnOpenEffective() {
6011
- if (isObject$1(lastPrefs)) {
6326
+ if (isObject$2(lastPrefs)) {
6012
6327
  const v = lastPrefs["checkOnOpen"];
6013
6328
  if (v === false) return false;
6014
6329
  if (v === true) return true;
@@ -6065,7 +6380,7 @@ ${body}`;
6065
6380
  const next = !checkOnOpenEffective();
6066
6381
  const reply = await phone(phones.prefsSave, { checkOnOpen: next });
6067
6382
  if (!mounted) return;
6068
- if (reply && reply["ok"] === true && isObject$1(reply["prefs"])) lastPrefs = reply["prefs"];
6383
+ if (reply && reply["ok"] === true && isObject$2(reply["prefs"])) lastPrefs = reply["prefs"];
6069
6384
  render();
6070
6385
  return;
6071
6386
  }
@@ -6111,7 +6426,7 @@ ${body}`;
6111
6426
  includeQueue: true
6112
6427
  });
6113
6428
  if (!mounted) return;
6114
- if (isObject$1(reply) && reply["ok"] !== true) {
6429
+ if (isObject$2(reply) && reply["ok"] !== true) {
6115
6430
  const rec = reply;
6116
6431
  const kind2 = typeof rec["errorKind"] === "string" && rec["errorKind"].trim() ? rec["errorKind"].trim() : "";
6117
6432
  const err = typeof rec["error"] === "string" && rec["error"].trim() ? rec["error"].trim() : "";
@@ -6265,7 +6580,7 @@ ${body}`;
6265
6580
  try {
6266
6581
  const reply = await call(phones.resume, {});
6267
6582
  if (!mounted) return;
6268
- if (isObject$1(reply) && reply["ok"] === true) {
6583
+ if (isObject$2(reply) && reply["ok"] === true) {
6269
6584
  applyReply(reply);
6270
6585
  if (reply["resumed"] !== false) {
6271
6586
  say(batchText("batch.notice.auto-resumed", currentLang(), { count: String(remainingCount()) }));
@@ -6291,7 +6606,7 @@ ${body}`;
6291
6606
  try {
6292
6607
  const reply = await call(phones.check, {});
6293
6608
  if (!mounted) return;
6294
- if (isObject$1(reply) && reply["ok"] === true) {
6609
+ if (isObject$2(reply) && reply["ok"] === true) {
6295
6610
  applyReply(reply);
6296
6611
  rowFailedAt.clear();
6297
6612
  render();
@@ -6333,7 +6648,7 @@ ${body}`;
6333
6648
  try {
6334
6649
  container.addEventListener?.("keydown", onKeyDown);
6335
6650
  } catch {}
6336
- const timer = getTimer();
6651
+ const timer = getTimer$1();
6337
6652
  const handle = timer.set(() => {
6338
6653
  if (inFlight && inFlightIsCheck) return;
6339
6654
  refresh();
@@ -6355,15 +6670,15 @@ ${body}`;
6355
6670
  };
6356
6671
  }
6357
6672
  //#endregion
6358
- //#region ../../node_modules/.pnpm/dsh-plugin-update@0.17.0/node_modules/dsh-plugin-update/dist/entry-batch.js
6359
- function isObject(value) {
6673
+ //#region ../../node_modules/.pnpm/dsh-plugin-update@0.18.0/node_modules/dsh-plugin-update/dist/entry-batch.js
6674
+ function isObject$1(value) {
6360
6675
  return !!value && typeof value === "object" && !Array.isArray(value);
6361
6676
  }
6362
6677
  function asRows(value) {
6363
6678
  if (!Array.isArray(value)) return null;
6364
6679
  return value;
6365
6680
  }
6366
- function escapeHtml(value) {
6681
+ function escapeHtml$1(value) {
6367
6682
  return String(value).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
6368
6683
  }
6369
6684
  function batchEntrySummary(state, lang) {
@@ -6492,7 +6807,7 @@ ${body}`;
6492
6807
  };
6493
6808
  async function panelCall(name, args) {
6494
6809
  const reply = await call(name, args);
6495
- return isObject(reply) ? reply : {};
6810
+ return isObject$1(reply) ? reply : {};
6496
6811
  }
6497
6812
  function stateOf() {
6498
6813
  return {
@@ -6514,14 +6829,14 @@ ${body}`;
6514
6829
  function entryHTML() {
6515
6830
  const lang = currentLang();
6516
6831
  const summary = batchEntrySummary(stateOf(), lang);
6517
- const labelHTML = labelOverride ? escapeHtml(labelOverride) : activating ? copyHTML("batch-entry.action.checking", lang) : copyHTML(batchEntryBilingualKeyFor(stateOf()), lang, batchEntryBilingualValuesFor(stateOf()));
6832
+ const labelHTML = labelOverride ? escapeHtml$1(labelOverride) : activating ? copyHTML("batch-entry.action.checking", lang) : copyHTML(batchEntryBilingualKeyFor(stateOf()), lang, batchEntryBilingualValuesFor(stateOf()));
6518
6833
  const labelText = labelOverride ?? (activating ? copyText("batch-entry.action.checking", lang) : copyText(batchEntryBilingualKeyFor(stateOf()), lang, batchEntryBilingualValuesFor(stateOf())));
6519
6834
  const busyAttr = activating ? " disabled aria-busy=\"true\"" : "";
6520
6835
  const themeAttr = theme === "archive" ? " data-theme=\"archive\"" : "";
6521
6836
  const tokensStyle = themeTokensStyleFor(themeTokens ?? void 0);
6522
6837
  const tokensAttr = tokensStyle ? " style=\"" + tokensStyle + "\"" : "";
6523
- const control = variant === "badge" ? "<button type=\"button\" class=\"dsh-upd-entry-dot\" " + ENTRY_ATTR + "=\"activate\" title=\"" + escapeHtml(labelText) + "\" aria-label=\"" + escapeHtml(labelText) + "\"" + busyAttr + "></button>" : "<button type=\"button\" class=\"dsh-upd-entry-btn\" " + ENTRY_ATTR + "=\"activate\"" + busyAttr + ">" + labelHTML + "</button>";
6524
- const noteHTML = note ? "<span class=\"dsh-upd-entry-note\" data-dsh-upd-note=\"1\">" + escapeHtml(note) + "</span>" : "";
6838
+ const control = variant === "badge" ? "<button type=\"button\" class=\"dsh-upd-entry-dot\" " + ENTRY_ATTR + "=\"activate\" title=\"" + escapeHtml$1(labelText) + "\" aria-label=\"" + escapeHtml$1(labelText) + "\"" + busyAttr + "></button>" : "<button type=\"button\" class=\"dsh-upd-entry-btn\" " + ENTRY_ATTR + "=\"activate\"" + busyAttr + ">" + labelHTML + "</button>";
6839
+ const noteHTML = note ? "<span class=\"dsh-upd-entry-note\" data-dsh-upd-note=\"1\">" + escapeHtml$1(note) + "</span>" : "";
6525
6840
  return "<style>" + UPDATE_ENTRY_CSS + "\n" + BILINGUAL_CSS + "</style>\n<span class=\"dsh-upd-entry\" data-variant=\"" + variant + "\" data-state=\"" + summary.kind + "\"" + themeAttr + tokensAttr + ">" + control + noteHTML + "</span>";
6526
6841
  }
6527
6842
  function render() {
@@ -6530,14 +6845,14 @@ ${body}`;
6530
6845
  container.innerHTML = entryHTML();
6531
6846
  }
6532
6847
  function applyReply(reply) {
6533
- if (!isObject(reply) || reply["ok"] !== true) {
6534
- error = failureCodeOf(isObject(reply) ? reply : null, "check-failed");
6848
+ if (!isObject$1(reply) || reply["ok"] !== true) {
6849
+ error = failureCodeOf(isObject$1(reply) ? reply : null, "check-failed");
6535
6850
  return;
6536
6851
  }
6537
6852
  const next = asRows(reply["rows"]);
6538
6853
  if (next) rows = next;
6539
- if (isObject(reply) && "inventory" in reply) inventory = reply["inventory"] ?? null;
6540
- if (isObject(reply) && "session" in reply) session = reply["session"] ?? null;
6854
+ if (isObject$1(reply) && "inventory" in reply) inventory = reply["inventory"] ?? null;
6855
+ if (isObject$1(reply) && "session" in reply) session = reply["session"] ?? null;
6541
6856
  error = null;
6542
6857
  loaded = true;
6543
6858
  }
@@ -6712,14 +7027,856 @@ ${body}`;
6712
7027
  unmount
6713
7028
  };
6714
7029
  }
7030
+ const INSTALL_BUTTON_CSS = [
7031
+ ".dsh-upd-ib{display:flex;flex-direction:column;gap:8px;font:inherit}",
7032
+ ".dsh-upd-ib-status{font-weight:600;overflow-wrap:anywhere}",
7033
+ ".dsh-upd-ib-sub{opacity:.85;overflow-wrap:anywhere}",
7034
+ ".dsh-upd-ib-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}",
7035
+ ".dsh-upd-ib button{cursor:pointer}",
7036
+ ".dsh-upd-ib button[disabled]{cursor:default}",
7037
+ ".dsh-upd-ib-manual summary{cursor:pointer}",
7038
+ ".dsh-upd-ib-manual code{display:block;white-space:pre-wrap;overflow-wrap:anywhere}",
7039
+ ".dsh-upd-ib-notice{opacity:.8}",
7040
+ ".dsh-upd-ib[data-theme=\"archive\"] .dsh-upd-ib-status{font-family:serif}"
7041
+ ].join("\n");
7042
+ function isObject(value) {
7043
+ return typeof value === "object" && value !== null && !Array.isArray(value);
7044
+ }
7045
+ function escapeHtml(value) {
7046
+ return String(value ?? "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
7047
+ }
7048
+ function asSnapshot(value) {
7049
+ if (!isObject(value)) return null;
7050
+ if (typeof value["canInstall"] !== "boolean") return null;
7051
+ return value;
7052
+ }
7053
+ function asQueue(value) {
7054
+ if (!isObject(value) || typeof value["busy"] !== "boolean") return null;
7055
+ return value;
7056
+ }
7057
+ function randomRequestId() {
7058
+ try {
7059
+ const rand = Math.floor(Math.random() * 16777215).toString(36);
7060
+ return `r${Date.now().toString(36)}${rand}`.slice(0, 64);
7061
+ } catch {
7062
+ return `r${Date.now()}`;
7063
+ }
7064
+ }
7065
+ function jobTargetOf(value) {
7066
+ try {
7067
+ const tv = (value?.job)?.targetVersion;
7068
+ return typeof tv === "string" && tv.trim() ? tv.trim() : null;
7069
+ } catch {
7070
+ return null;
7071
+ }
7072
+ }
7073
+ function utf8ByteLength(text) {
7074
+ let bytes = 0;
7075
+ for (let i = 0; i < text.length; i++) {
7076
+ const code = text.charCodeAt(i);
7077
+ if (code < 128) bytes += 1;
7078
+ else if (code < 2048) bytes += 2;
7079
+ else if (code >= 55296 && code <= 56319 && i + 1 < text.length) {
7080
+ bytes += 4;
7081
+ i++;
7082
+ } else bytes += 3;
7083
+ }
7084
+ return bytes;
7085
+ }
7086
+ function getTimer() {
7087
+ const g = globalThis;
7088
+ const set = g["setInterval"];
7089
+ const clear = g["clearInterval"];
7090
+ if (typeof set === "function" && typeof clear === "function") return {
7091
+ set: (fn, ms) => set.call(g, fn, ms),
7092
+ clear: (handle) => clear.call(g, handle)
7093
+ };
7094
+ return {
7095
+ set: () => null,
7096
+ clear: () => {}
7097
+ };
7098
+ }
7099
+ async function defaultCopyText(text) {
7100
+ try {
7101
+ const clip = globalThis["navigator"]?.clipboard;
7102
+ const write = clip?.writeText;
7103
+ if (clip && typeof write === "function") {
7104
+ await write.call(clip, text);
7105
+ return;
7106
+ }
7107
+ } catch {}
7108
+ }
7109
+ function installButtonViewModel(input) {
7110
+ const l = normalizeLangTag(input.lang ?? "zh");
7111
+ const view = panelViewModel({
7112
+ snapshot: input.snapshot,
7113
+ manual: input.manual,
7114
+ queue: input.queue,
7115
+ skippedLatest: false,
7116
+ lastError: input.lastError,
7117
+ errorKind: input.errorKind ?? null
7118
+ }, l);
7119
+ const jobState = (input.snapshot?.job ?? null)?.state ?? null;
7120
+ const jobActive = jobState === "installing" || jobState === "verifying";
7121
+ if (input.pollCapped === true && jobActive && !input.busyAct) return {
7122
+ role: "check",
7123
+ buttonLabel: copyText("panel.action.check", l),
7124
+ buttonEnabled: true,
7125
+ buttonBusy: false,
7126
+ showButton: true,
7127
+ statusTitle: view.banner.title,
7128
+ statusAction: view.banner.action,
7129
+ showManual: view.showManual,
7130
+ queueNote: view.queueNote,
7131
+ bannerKind: view.banner.kind
7132
+ };
7133
+ if (input.busyAct === "check" || input.busyAct === "install" || jobActive) return {
7134
+ role: "none",
7135
+ buttonLabel: input.busyAct === "check" ? copyText("panel.action.checking-busy", l) : input.busyAct === "install" ? copyText("panel.action.installing-busy", l) : view.installLabel,
7136
+ buttonEnabled: false,
7137
+ buttonBusy: true,
7138
+ showButton: true,
7139
+ statusTitle: view.banner.title,
7140
+ statusAction: view.banner.action,
7141
+ showManual: view.showManual,
7142
+ queueNote: view.queueNote,
7143
+ bannerKind: view.banner.kind
7144
+ };
7145
+ if (view.installEnabled) return {
7146
+ role: "install",
7147
+ buttonLabel: view.installLabel,
7148
+ buttonEnabled: true,
7149
+ buttonBusy: false,
7150
+ showButton: true,
7151
+ statusTitle: view.banner.title,
7152
+ statusAction: view.banner.action,
7153
+ showManual: view.showManual,
7154
+ queueNote: view.queueNote,
7155
+ bannerKind: view.banner.kind
7156
+ };
7157
+ if (!input.snapshot || !input.snapshot.latestVersion) return {
7158
+ role: "check",
7159
+ buttonLabel: copyText("panel.action.check", l),
7160
+ buttonEnabled: true,
7161
+ buttonBusy: false,
7162
+ showButton: true,
7163
+ statusTitle: view.banner.title,
7164
+ statusAction: view.banner.action,
7165
+ showManual: view.showManual,
7166
+ queueNote: view.queueNote,
7167
+ bannerKind: view.banner.kind
7168
+ };
7169
+ if (input.lastError && isCheckSideFailureCode(input.lastError)) return {
7170
+ role: "check",
7171
+ buttonLabel: copyText("panel.action.check", l),
7172
+ buttonEnabled: true,
7173
+ buttonBusy: false,
7174
+ showButton: true,
7175
+ statusTitle: view.banner.title,
7176
+ statusAction: view.banner.action,
7177
+ showManual: view.showManual,
7178
+ queueNote: view.queueNote,
7179
+ bannerKind: view.banner.kind
7180
+ };
7181
+ const done = view.banner.kind === "done";
7182
+ return {
7183
+ role: "none",
7184
+ buttonLabel: done ? copyText("install-button.action.installed", l) : view.installLabel,
7185
+ buttonEnabled: false,
7186
+ buttonBusy: false,
7187
+ showButton: done,
7188
+ statusTitle: view.banner.title,
7189
+ statusAction: view.banner.action,
7190
+ showManual: view.showManual,
7191
+ queueNote: view.queueNote,
7192
+ bannerKind: view.banner.kind
7193
+ };
7194
+ }
7195
+ function renderInstallButtonHTML(view, opts) {
7196
+ const l = opts.lang;
7197
+ const parts = [];
7198
+ parts.push("<style>" + INSTALL_BUTTON_CSS + "</style>");
7199
+ parts.push("<div class=\"dsh-upd-ib\" data-theme=\"" + opts.theme + "\">");
7200
+ parts.push("<div class=\"dsh-upd-ib-status dsh-upd-ib-kind-" + escapeHtml(view.bannerKind) + "\">" + escapeHtml(view.statusTitle) + "</div>");
7201
+ const sub = [view.statusAction, view.queueNote].filter((t) => typeof t === "string" && t.trim());
7202
+ if (sub.length > 0) parts.push("<div class=\"dsh-upd-ib-sub\">" + escapeHtml(sub.join(" ")) + "</div>");
7203
+ if (view.showButton) {
7204
+ const actionAttr = view.role === "none" ? "" : " data-action=\"" + (view.role === "check" ? "check" : "install") + "\"";
7205
+ const disabled = view.buttonEnabled ? "" : " disabled";
7206
+ const busy = view.buttonBusy ? " aria-busy=\"true\"" : "";
7207
+ parts.push("<div class=\"dsh-upd-ib-row\"><button type=\"button\"" + actionAttr + " data-primary=\"1\"" + disabled + busy + ">" + escapeHtml(view.buttonLabel) + "</button></div>");
7208
+ }
7209
+ if (view.bannerKind === "failed") parts.push("<div class=\"dsh-upd-ib-row\"><button type=\"button\" data-action=\"copy-diag\" title=\"" + escapeHtml(copyText("panel.action.copy-diag-title", l)) + "\">" + escapeHtml(copyText("panel.action.copy-diag", l)) + "</button></div>");
7210
+ if (view.showManual && opts.manual) parts.push("<details class=\"dsh-upd-ib-manual\"><summary>" + escapeHtml(copyText("panel.chapter.manual", l)) + "</summary><code>" + escapeHtml(opts.manual) + "</code><button type=\"button\" data-action=\"copy-manual\" title=\"" + escapeHtml(copyText("panel.action.copy-manual-title", l)) + "\">" + escapeHtml(copyText("panel.action.copy-manual", l)) + "</button></details>");
7211
+ if (opts.notice) parts.push("<div class=\"dsh-upd-ib-notice\" role=\"status\">" + escapeHtml(opts.notice) + "</div>");
7212
+ parts.push("</div>");
7213
+ return parts.join("");
7214
+ }
7215
+ function mountInstallButton(container, options) {
7216
+ const logOptionRead = options && typeof options === "object" ? options.clientLog : void 0;
7217
+ const clientLogDisabled = logOptionRead === null;
7218
+ const clientLogMountName = logOptionRead && typeof logOptionRead === "object" && typeof logOptionRead.mount === "string" && logOptionRead.mount ? logOptionRead.mount : "";
7219
+ let clientLog = logOptionRead && typeof logOptionRead === "object" && logOptionRead.channel ? logOptionRead.channel : null;
7220
+ let clientLogOwned = false;
7221
+ function logClient(level, event, fields) {
7222
+ const channel = clientLog;
7223
+ if (!channel) return;
7224
+ try {
7225
+ channel.emit(level, event, fields);
7226
+ } catch {}
7227
+ }
7228
+ function logMountFailure(kind) {
7229
+ logClient("error", "update.panel.render.fail", { kind });
7230
+ }
7231
+ if (!container || typeof container.innerHTML !== "string") {
7232
+ logMountFailure("container");
7233
+ throw new Error("[dsh-plugin-update] install button needs a container with innerHTML");
7234
+ }
7235
+ if (!options || typeof options !== "object") {
7236
+ logMountFailure("plugin-id");
7237
+ throw new Error("[dsh-plugin-update] install button needs options: pluginId is required");
7238
+ }
7239
+ const pluginId = options.pluginId;
7240
+ if (typeof pluginId !== "string" || !pluginId) {
7241
+ logMountFailure("plugin-id");
7242
+ throw new Error(`[dsh-plugin-update] install button needs pluginId: non-empty string (got ${JSON.stringify(pluginId)})`);
7243
+ }
7244
+ if (typeof options.call !== "function") {
7245
+ logMountFailure("call");
7246
+ throw new Error("[dsh-plugin-update] install button needs call (the only channel to host phones)");
7247
+ }
7248
+ const prefix = options.prefix === void 0 ? "wf" : options.prefix;
7249
+ let phoneNames;
7250
+ try {
7251
+ phoneNames = buildPhoneNames(prefix);
7252
+ } catch (err) {
7253
+ logMountFailure("prefix");
7254
+ throw err;
7255
+ }
7256
+ if (!clientLog && !clientLogDisabled) try {
7257
+ clientLog = createClientLogChannel({
7258
+ call: options.call,
7259
+ phoneName: buildLogAppendPhoneName(prefix)
7260
+ });
7261
+ clientLogOwned = true;
7262
+ } catch {
7263
+ clientLog = null;
7264
+ }
7265
+ const pollMs = options.pollMs === void 0 ? DEFAULT_PANEL_POLL_MS : options.pollMs;
7266
+ if (typeof pollMs !== "number" || !Number.isFinite(pollMs) || pollMs < 250) {
7267
+ logMountFailure("poll-ms");
7268
+ throw new Error(`[dsh-plugin-update] install button pollMs must be >= 250ms (got ${JSON.stringify(options.pollMs)})`);
7269
+ }
7270
+ const autoCheck = options.autoCheck ?? "mount";
7271
+ if (autoCheck !== "mount" && autoCheck !== "never") {
7272
+ logMountFailure("auto-check");
7273
+ throw new Error(`[dsh-plugin-update] install button autoCheck must be mount or never (got ${JSON.stringify(options.autoCheck)})`);
7274
+ }
7275
+ if (options.theme !== void 0 && options.theme !== "default" && options.theme !== "archive") {
7276
+ logMountFailure("theme");
7277
+ throw new Error(`[dsh-plugin-update] install button theme must be default or archive (got ${JSON.stringify(options.theme)})`);
7278
+ }
7279
+ const theme = options.theme ?? "default";
7280
+ try {
7281
+ themeTokensStyleFor(options.themeTokens ?? void 0);
7282
+ } catch (err) {
7283
+ logMountFailure("theme-tokens");
7284
+ throw err;
7285
+ }
7286
+ const localeOpt = options.locale ?? void 0;
7287
+ if (localeOpt !== void 0 && localeOpt !== null) {
7288
+ const isStr = typeof localeOpt === "string";
7289
+ const isObj = typeof localeOpt === "object" && typeof localeOpt.getActive === "function";
7290
+ if (!isStr && !isObj) {
7291
+ logMountFailure("locale");
7292
+ throw new Error("[dsh-plugin-update] invalid locale: expected zh / en / BCP47 or { getActive(), subscribe? }");
7293
+ }
7294
+ if (isStr && !localeOpt.trim()) {
7295
+ logMountFailure("locale");
7296
+ throw new Error("[dsh-plugin-update] invalid locale: empty string");
7297
+ }
7298
+ }
7299
+ function currentLang() {
7300
+ return resolveLang(localeOpt);
7301
+ }
7302
+ const showOthers = options.showOthers === true;
7303
+ const profileNameOption = typeof options.profileName === "string" && options.profileName ? options.profileName : null;
7304
+ const copyTextOut = options.copyText ?? defaultCopyText;
7305
+ const call = options.call;
7306
+ let mounted = true;
7307
+ let snapshot = null;
7308
+ let manual = null;
7309
+ let queue = null;
7310
+ let receipt = null;
7311
+ let requestId = null;
7312
+ let latch = null;
7313
+ let busyAct = null;
7314
+ let ensuring = false;
7315
+ let pollCount = 0;
7316
+ let pollCapped = false;
7317
+ let envHostKind = null;
7318
+ let envProfileName = null;
7319
+ let copyNotice = null;
7320
+ let noticeExpiresAt = 0;
7321
+ let actionBytes = -1;
7322
+ let actionTruncated = false;
7323
+ function latchNow() {
7324
+ try {
7325
+ const n = Date.now();
7326
+ return Number.isFinite(n) ? n : null;
7327
+ } catch {
7328
+ return null;
7329
+ }
7330
+ }
7331
+ function currentEnvPair() {
7332
+ return {
7333
+ hostKind: envHostKind,
7334
+ profileName: profileNameOption ?? envProfileName
7335
+ };
7336
+ }
7337
+ function thrownDetail(err) {
7338
+ try {
7339
+ const raw = err instanceof Error ? err.message : typeof err === "string" ? err : null;
7340
+ if (typeof raw !== "string") return null;
7341
+ const t = raw.trim();
7342
+ if (!t) return null;
7343
+ if (/^[a-z][a-z-]*$/.test(t) && t.length <= 32) return null;
7344
+ return redactForCopy(t) || null;
7345
+ } catch {
7346
+ return null;
7347
+ }
7348
+ }
7349
+ function thrownBusy(err) {
7350
+ try {
7351
+ if (typeof err === "string") return err.trim() === "update-busy";
7352
+ if (err instanceof Error) return err.message.trim() === "update-busy";
7353
+ if (isObject(err)) {
7354
+ const e = typeof err["error"] === "string" ? err["error"].trim() : "";
7355
+ const k = typeof err["errorKind"] === "string" ? err["errorKind"].trim() : "";
7356
+ return e === "update-busy" || k === "update-busy";
7357
+ }
7358
+ } catch {}
7359
+ return false;
7360
+ }
7361
+ function setLatch(next) {
7362
+ latch = next;
7363
+ }
7364
+ function clearLatch() {
7365
+ latch = null;
7366
+ }
7367
+ function latchFromReply(reply, source) {
7368
+ const env = currentEnvPair();
7369
+ return {
7370
+ code: failureCodeOf({
7371
+ error: reply["error"],
7372
+ errorKind: reply["errorKind"]
7373
+ }, source === "install" ? "install-failed" : "check-failed"),
7374
+ kind: typeof reply["errorKind"] === "string" && reply["errorKind"].trim() ? reply["errorKind"].trim() : null,
7375
+ detail: null,
7376
+ diag: Object.prototype.hasOwnProperty.call(reply, "diag") ? reply["diag"] : null,
7377
+ requestId: source === "install" ? requestId : null,
7378
+ checkId: source === "install" ? receipt?.checkId ?? null : null,
7379
+ runningVersion: snapshot?.runningVersion ?? null,
7380
+ installedVersion: snapshot?.installedVersion ?? null,
7381
+ latestVersion: snapshot?.latestVersion ?? null,
7382
+ targetVersion: jobTargetOf(reply["snapshot"]),
7383
+ hostKind: env.hostKind,
7384
+ profileName: env.profileName,
7385
+ source,
7386
+ volatile: false,
7387
+ atMs: latchNow()
7388
+ };
7389
+ }
7390
+ function latchFromJob(job, snap) {
7391
+ const env = currentEnvPair();
7392
+ const message = typeof job.message === "string" ? job.message : null;
7393
+ const detail = message && message.includes(":") ? message.slice(message.indexOf(":") + 1).trim() || null : message;
7394
+ return {
7395
+ code: messageCodeOf(message) || "install-failed",
7396
+ kind: null,
7397
+ detail,
7398
+ diag: latch?.diag ?? null,
7399
+ requestId: job.requestId ?? latch?.requestId ?? requestId,
7400
+ checkId: receipt?.checkId ?? latch?.checkId ?? null,
7401
+ runningVersion: snap?.runningVersion ?? snapshot?.runningVersion ?? null,
7402
+ installedVersion: snap?.installedVersion ?? snapshot?.installedVersion ?? null,
7403
+ latestVersion: snap?.latestVersion ?? snapshot?.latestVersion ?? null,
7404
+ targetVersion: jobTargetOf({ job }),
7405
+ hostKind: env.hostKind ?? latch?.hostKind ?? null,
7406
+ profileName: env.profileName ?? latch?.profileName ?? null,
7407
+ source: "install",
7408
+ volatile: false,
7409
+ atMs: latchNow()
7410
+ };
7411
+ }
7412
+ function volatileLatch(source) {
7413
+ const env = currentEnvPair();
7414
+ return {
7415
+ code: "check-failed",
7416
+ kind: null,
7417
+ detail: null,
7418
+ diag: null,
7419
+ requestId,
7420
+ checkId: receipt?.checkId ?? null,
7421
+ runningVersion: snapshot?.runningVersion ?? null,
7422
+ installedVersion: snapshot?.installedVersion ?? null,
7423
+ latestVersion: snapshot?.latestVersion ?? null,
7424
+ targetVersion: null,
7425
+ hostKind: env.hostKind,
7426
+ profileName: env.profileName,
7427
+ source,
7428
+ volatile: true,
7429
+ atMs: latchNow()
7430
+ };
7431
+ }
7432
+ function applyStatusReply(reply, via) {
7433
+ if (!isObject(reply)) return;
7434
+ if (reply["ok"] === true) {
7435
+ const s = asSnapshot(reply["snapshot"]);
7436
+ if (s) snapshot = s;
7437
+ manual = typeof reply["manual"] === "string" ? reply["manual"] : null;
7438
+ if (reply["receipt"] && isObject(reply["receipt"]) && typeof reply["receipt"]["checkId"] === "string") receipt = { checkId: reply["receipt"]["checkId"] };
7439
+ const q = asQueue(reply["queue"]);
7440
+ if (q) queue = q;
7441
+ const env = reply["env"];
7442
+ if (isObject(env)) {
7443
+ const pn = env["profileName"];
7444
+ const hk = env["environmentKind"];
7445
+ if (typeof pn === "string" && pn.trim()) envProfileName = pn.trim();
7446
+ if (typeof hk === "string" && hk.trim()) envHostKind = hk.trim();
7447
+ }
7448
+ const jobState = snapshot?.job?.state ?? null;
7449
+ if (jobState === "installing" || jobState === "verifying") clearLatch();
7450
+ else if (jobState === "completed" || jobState === "restart-required") clearLatch();
7451
+ else if ((jobState === "failed" || jobState === "interrupted") && snapshot?.job) {
7452
+ const next = latchFromJob(snapshot.job, snapshot);
7453
+ if (!latch || latch.volatile || latch.code !== next.code || latch.targetVersion !== next.targetVersion || latch.latestVersion !== next.latestVersion) setLatch(next);
7454
+ } else if (via === "install") clearLatch();
7455
+ else if (via === "check" && latch?.source === "check") clearLatch();
7456
+ else if (latch?.volatile) clearLatch();
7457
+ } else {
7458
+ const kindText = typeof reply["errorKind"] === "string" ? reply["errorKind"].trim() : "";
7459
+ const errText = typeof reply["error"] === "string" ? reply["error"].trim() : "";
7460
+ if ((kindText || errText) !== "update-busy") setLatch(latchFromReply(reply, via === "install" ? "install" : "check"));
7461
+ try {
7462
+ const env = reply["env"];
7463
+ if (isObject(env)) {
7464
+ const pn = env["profileName"];
7465
+ const hk = env["environmentKind"];
7466
+ if (typeof pn === "string" && pn.trim()) envProfileName = pn.trim();
7467
+ if (typeof hk === "string" && hk.trim()) envHostKind = hk.trim();
7468
+ }
7469
+ } catch {}
7470
+ try {
7471
+ const q = asQueue(reply["queue"]);
7472
+ if (q) queue = q;
7473
+ } catch {}
7474
+ }
7475
+ }
7476
+ function queueArgs() {
7477
+ return {
7478
+ includeQueue: true,
7479
+ includeEnv: true,
7480
+ showOthers,
7481
+ ...requestId ? { requestId } : {}
7482
+ };
7483
+ }
7484
+ function currentView() {
7485
+ return installButtonViewModel({
7486
+ snapshot,
7487
+ manual,
7488
+ queue,
7489
+ lastError: latch?.code ?? null,
7490
+ errorKind: latch?.kind ?? null,
7491
+ busyAct,
7492
+ pollCapped,
7493
+ lang: currentLang()
7494
+ });
7495
+ }
7496
+ function paint() {
7497
+ if (!mounted) return;
7498
+ try {
7499
+ if (copyNotice && noticeExpiresAt && Date.now() > noticeExpiresAt) {
7500
+ copyNotice = null;
7501
+ noticeExpiresAt = 0;
7502
+ }
7503
+ const lang = currentLang();
7504
+ const html = renderInstallButtonHTML(currentView(), {
7505
+ manual,
7506
+ notice: copyNotice,
7507
+ theme,
7508
+ lang
7509
+ });
7510
+ try {
7511
+ container.innerHTML = html;
7512
+ } catch {}
7513
+ } catch {
7514
+ logClient("error", "update.panel.render.fail", { kind: "unknown" });
7515
+ }
7516
+ }
7517
+ function sayCopyKey(key) {
7518
+ try {
7519
+ copyNotice = copyText(key, currentLang());
7520
+ noticeExpiresAt = Date.now() + 5e3;
7521
+ } catch {
7522
+ copyNotice = null;
7523
+ noticeExpiresAt = 0;
7524
+ }
7525
+ }
7526
+ async function refresh() {
7527
+ if (!mounted) return;
7528
+ try {
7529
+ const reply = await call(phoneNames.updateStatus, queueArgs());
7530
+ if (!mounted) return;
7531
+ applyStatusReply(reply, "refresh");
7532
+ } catch (err) {
7533
+ if (!mounted) return;
7534
+ if (!thrownBusy(err)) setLatch(volatileLatch("check"));
7535
+ }
7536
+ if (!mounted) return;
7537
+ if (autoCheck !== "never" && !busyAct && !ensuring && snapshot && !snapshot.latestVersion) {
7538
+ ensuring = true;
7539
+ try {
7540
+ const reply = await call(phoneNames.updateCheck, queueArgs());
7541
+ if (!mounted) return;
7542
+ applyStatusReply(reply, "check");
7543
+ } catch {
7544
+ if (!mounted) return;
7545
+ setLatch(volatileLatch("check"));
7546
+ } finally {
7547
+ ensuring = false;
7548
+ }
7549
+ }
7550
+ paint();
7551
+ }
7552
+ function jobActive() {
7553
+ const st = snapshot?.job?.state ?? null;
7554
+ return st === "installing" || st === "verifying";
7555
+ }
7556
+ async function doCheck() {
7557
+ try {
7558
+ const reply = await call(phoneNames.updateCheck, queueArgs());
7559
+ if (!mounted) return;
7560
+ applyStatusReply(reply, "check");
7561
+ } catch (err) {
7562
+ if (!mounted) return;
7563
+ if (thrownBusy(err)) {
7564
+ await refresh();
7565
+ return;
7566
+ }
7567
+ const env = currentEnvPair();
7568
+ setLatch({
7569
+ code: "check-failed",
7570
+ kind: null,
7571
+ detail: thrownDetail(err),
7572
+ diag: null,
7573
+ requestId: null,
7574
+ checkId: null,
7575
+ runningVersion: snapshot?.runningVersion ?? null,
7576
+ installedVersion: snapshot?.installedVersion ?? null,
7577
+ latestVersion: snapshot?.latestVersion ?? null,
7578
+ targetVersion: null,
7579
+ hostKind: env.hostKind,
7580
+ profileName: env.profileName,
7581
+ source: "check",
7582
+ volatile: false,
7583
+ atMs: latchNow()
7584
+ });
7585
+ }
7586
+ }
7587
+ async function doInstall() {
7588
+ if (!receipt) try {
7589
+ const checked = await call(phoneNames.updateCheck, queueArgs());
7590
+ if (!mounted) return;
7591
+ applyStatusReply(checked, "check");
7592
+ } catch (err) {
7593
+ if (!mounted) return;
7594
+ if (thrownBusy(err)) {
7595
+ await refresh();
7596
+ return;
7597
+ }
7598
+ const env = currentEnvPair();
7599
+ setLatch({
7600
+ code: "check-failed",
7601
+ kind: null,
7602
+ detail: thrownDetail(err),
7603
+ diag: null,
7604
+ requestId: null,
7605
+ checkId: null,
7606
+ runningVersion: snapshot?.runningVersion ?? null,
7607
+ installedVersion: snapshot?.installedVersion ?? null,
7608
+ latestVersion: snapshot?.latestVersion ?? null,
7609
+ targetVersion: null,
7610
+ hostKind: env.hostKind,
7611
+ profileName: env.profileName,
7612
+ source: "check",
7613
+ volatile: false,
7614
+ atMs: latchNow()
7615
+ });
7616
+ return;
7617
+ }
7618
+ if (!mounted) return;
7619
+ if (!receipt) {
7620
+ const env = currentEnvPair();
7621
+ setLatch({
7622
+ code: "check-expired",
7623
+ kind: "check-expired",
7624
+ detail: null,
7625
+ diag: null,
7626
+ requestId,
7627
+ checkId: null,
7628
+ runningVersion: snapshot?.runningVersion ?? null,
7629
+ installedVersion: snapshot?.installedVersion ?? null,
7630
+ latestVersion: snapshot?.latestVersion ?? null,
7631
+ targetVersion: null,
7632
+ hostKind: env.hostKind,
7633
+ profileName: env.profileName,
7634
+ source: "install",
7635
+ volatile: false,
7636
+ atMs: latchNow()
7637
+ });
7638
+ return;
7639
+ }
7640
+ requestId = randomRequestId();
7641
+ pollCount = 0;
7642
+ pollCapped = false;
7643
+ try {
7644
+ const reply = await call(phoneNames.updateInstall, {
7645
+ checkId: receipt.checkId,
7646
+ requestId,
7647
+ ...queueArgs()
7648
+ });
7649
+ if (!mounted) return;
7650
+ applyStatusReply(reply, "install");
7651
+ } catch (err) {
7652
+ if (!mounted) return;
7653
+ if (thrownBusy(err)) {
7654
+ await refresh();
7655
+ return;
7656
+ }
7657
+ const env = currentEnvPair();
7658
+ setLatch({
7659
+ code: "install-failed",
7660
+ kind: null,
7661
+ detail: thrownDetail(err),
7662
+ diag: null,
7663
+ requestId,
7664
+ checkId: receipt?.checkId ?? null,
7665
+ runningVersion: snapshot?.runningVersion ?? null,
7666
+ installedVersion: snapshot?.installedVersion ?? null,
7667
+ latestVersion: snapshot?.latestVersion ?? null,
7668
+ targetVersion: null,
7669
+ hostKind: env.hostKind,
7670
+ profileName: env.profileName,
7671
+ source: "install",
7672
+ volatile: false,
7673
+ atMs: latchNow()
7674
+ });
7675
+ }
7676
+ }
7677
+ function diagText() {
7678
+ if (!latch || latch.volatile) return null;
7679
+ try {
7680
+ return buildUpdateDiagCopy({
7681
+ pluginId,
7682
+ code: latch.code,
7683
+ detail: latch.detail,
7684
+ runningVersion: latch.runningVersion,
7685
+ installedVersion: latch.installedVersion,
7686
+ latestVersion: latch.latestVersion,
7687
+ hostKind: latch.hostKind,
7688
+ profileName: latch.profileName,
7689
+ queuePosition: queue && typeof queue.position === "number" ? queue.position : null,
7690
+ requestId: latch.requestId,
7691
+ manual,
7692
+ targetVersion: latch.targetVersion,
7693
+ diag: latch.diag,
7694
+ checkId: latch.checkId,
7695
+ lang: currentLang()
7696
+ }, currentLang());
7697
+ } catch {
7698
+ return null;
7699
+ }
7700
+ }
7701
+ async function act(kind) {
7702
+ if (!mounted) return;
7703
+ actionBytes = -1;
7704
+ actionTruncated = false;
7705
+ try {
7706
+ await runAction(kind);
7707
+ } finally {
7708
+ logClient("info", "update.panel.action", {
7709
+ action: kind,
7710
+ ...actionBytes >= 0 ? {
7711
+ bytes: actionBytes,
7712
+ truncated: actionTruncated
7713
+ } : {}
7714
+ });
7715
+ }
7716
+ }
7717
+ async function runAction(kind) {
7718
+ copyNotice = null;
7719
+ switch (kind) {
7720
+ case "check":
7721
+ if (busyAct) return;
7722
+ busyAct = "check";
7723
+ copyNotice = copyText("panel.toast.checking", currentLang());
7724
+ paint();
7725
+ try {
7726
+ await doCheck();
7727
+ } finally {
7728
+ busyAct = null;
7729
+ }
7730
+ paint();
7731
+ return;
7732
+ case "install":
7733
+ if (busyAct) return;
7734
+ busyAct = "install";
7735
+ copyNotice = copyText("panel.toast.installing", currentLang());
7736
+ paint();
7737
+ try {
7738
+ await doInstall();
7739
+ } finally {
7740
+ busyAct = null;
7741
+ }
7742
+ paint();
7743
+ return;
7744
+ case "copy-manual":
7745
+ if (manual) try {
7746
+ await copyTextOut(manual);
7747
+ sayCopyKey("panel.toast.copy-manual-ok");
7748
+ } catch {
7749
+ sayCopyKey("panel.toast.copy-manual-fail");
7750
+ }
7751
+ paint();
7752
+ return;
7753
+ case "copy-diag": {
7754
+ const text = diagText();
7755
+ if (text) {
7756
+ try {
7757
+ await copyTextOut(text);
7758
+ sayCopyKey("panel.toast.copy-diag-ok");
7759
+ } catch {
7760
+ sayCopyKey("panel.toast.copy-diag-fail");
7761
+ }
7762
+ actionBytes = utf8ByteLength(text);
7763
+ actionTruncated = false;
7764
+ }
7765
+ paint();
7766
+ return;
7767
+ }
7768
+ }
7769
+ }
7770
+ function onClick(ev) {
7771
+ try {
7772
+ const t = ev;
7773
+ const btn = t?.target && typeof t.target.closest === "function" ? t.target.closest("[data-action]") : null;
7774
+ const kind = btn?.getAttribute ? btn.getAttribute("data-action") : null;
7775
+ if (kind !== "install" && kind !== "check" && kind !== "copy-manual" && kind !== "copy-diag") return;
7776
+ act(kind);
7777
+ } catch {}
7778
+ }
7779
+ function unmount() {
7780
+ if (!mounted) return;
7781
+ mounted = false;
7782
+ try {
7783
+ unsubLang();
7784
+ } catch {}
7785
+ try {
7786
+ timer.clear(handle);
7787
+ } catch {}
7788
+ try {
7789
+ container.removeEventListener?.("click", onClick);
7790
+ } catch {}
7791
+ if (clientLogOwned && clientLog) try {
7792
+ clientLog.dispose();
7793
+ } catch {}
7794
+ }
7795
+ const unsubLang = subscribeLang(() => {
7796
+ paint();
7797
+ }, localeOpt);
7798
+ paint();
7799
+ try {
7800
+ container.addEventListener?.("click", onClick);
7801
+ } catch {}
7802
+ const timer = getTimer();
7803
+ const handle = timer.set(() => {
7804
+ if (!mounted || busyAct || pollCapped) return;
7805
+ if (!jobActive()) return;
7806
+ if (pollCount >= 300) {
7807
+ pollCapped = true;
7808
+ try {
7809
+ timer.clear(handle);
7810
+ } catch {}
7811
+ paint();
7812
+ return;
7813
+ }
7814
+ pollCount += 1;
7815
+ refresh();
7816
+ }, pollMs);
7817
+ if (autoCheck === "mount") refresh();
7818
+ function state() {
7819
+ const jobState = snapshot?.job?.state ?? null;
7820
+ return {
7821
+ snapshot,
7822
+ manual,
7823
+ queue,
7824
+ failedCode: latch && !latch.volatile ? latch.code : null,
7825
+ busy: !!busyAct || jobState === "installing" || jobState === "verifying"
7826
+ };
7827
+ }
7828
+ logClient("info", "update.panel.mount", {
7829
+ mode: clientLogMountName || "install-button",
7830
+ theme,
7831
+ lang: currentLang(),
7832
+ pollMs
7833
+ });
7834
+ return {
7835
+ state,
7836
+ refresh,
7837
+ unmount
7838
+ };
7839
+ }
7840
+ //#endregion
7841
+ //#region src/install.ts
7842
+ /** dsh-life-pack 安装口径(P10 脚手架,P1 #2 定案单命令双包)。
7843
+ *
7844
+ * 真相(#2 真机结论):dsh plugin 是 pnpm 薄转发,add 单品等价 pnpm add,
7845
+ * 传递依赖落盘是;激活否:reconcile 只扫直接 dependencies,传递的 manager
7846
+ * 不进 bundles;pnpm 隔离布局下从 profile 解析不到它。
7847
+ *
7848
+ * 口径:任何单品落地时总管必须已在位导航。实现为单命令双包:
7849
+ * dsh plugin add dsh-life-pack dsh-calorie
7850
+ * 两者皆直接依赖,由 reconcile 按序激活。单品 package 内保留对总管的
7851
+ * dependencies 只作本地开发兜底,不作为单 add 即激活的依据。
7852
+ * 不许单卸总管:缺席时总管对应 tab 显示推荐安装并提示补装(见 nav.ts)。
7853
+ * 安装验收以 bundles 双含为准,另加单 add 单品后 bundles 无总管的负向断言。
7854
+ */
7855
+ const MANAGER_PACKAGE = "dsh-life-pack";
7856
+ //#endregion
7857
+ //#region src/update-targets.ts
7858
+ /** 七个更新目标(总管自己 + 六个单品),薄接线唯一定义地(票 1170)。
7859
+ *
7860
+ * 包名不新开第二源:六单品取自 nav.ts 的 MANAGER_TABS,总管自己取自 install.ts。
7861
+ * 七个 phonePrefix 必须互不相同,否则串台。
7862
+ */
7863
+ const MANAGER_TARGET_KEY = "life-pack";
6715
7864
  /** 批量电话前缀:宿主与面板共用,唯一定义地(面板 mount 参数与宿主登记同源)。 */
6716
7865
  const BATCH_PREFIX = "life";
6717
- [...MANAGER_TABS.map((tab) => ({
7866
+ const UPDATE_TARGETS = [{
7867
+ key: MANAGER_TARGET_KEY,
7868
+ title: "爱生活",
7869
+ packageName: MANAGER_PACKAGE,
7870
+ phonePrefix: "ilife-life-pack"
7871
+ }, ...MANAGER_TABS.map((tab) => ({
6718
7872
  key: tab.skill,
6719
7873
  title: tab.title,
6720
7874
  packageName: tab.plugin,
6721
7875
  phonePrefix: "ilife-" + tab.skill
6722
7876
  }))];
7877
+ function targetFor(packageName) {
7878
+ return UPDATE_TARGETS.find((target) => target.packageName === packageName);
7879
+ }
6723
7880
  //#endregion
6724
7881
  //#region src/update-dialog.ts
6725
7882
  /** 面板薄包装(票 1170 起,浏览器侧:无 node 内建,可进 client 束;完全上游 UI,本包零自家样式)。
@@ -6788,6 +7945,29 @@ ${body}`;
6788
7945
  label: overrides?.label
6789
7946
  });
6790
7947
  }
7948
+ /** 缺席页签挂单包安装按钮(上游 0.18.0 安装控件,#1282):pluginId 与 prefix 取更新目标表
7949
+ * 同源(与批量侧 `life-<key>`/`ilife-<skill>` 同一份推导),不手拼;文案样式零自家东西。
7950
+ * 目标表里没有该包(不该发生)回 null,调用方不渲染挂载位。 */
7951
+ function mountLifeInstallButton(container, call, tab) {
7952
+ const target = targetFor(tab.plugin);
7953
+ if (target === void 0) return null;
7954
+ const adaptedCall = async (name, args) => {
7955
+ const reply = await call(name, args);
7956
+ if (typeof reply === "object" && reply !== null) return reply;
7957
+ return {
7958
+ ok: false,
7959
+ error: "internal",
7960
+ errorKind: "internal"
7961
+ };
7962
+ };
7963
+ return mountInstallButton(container, {
7964
+ pluginId: "life-" + tab.skill,
7965
+ call: adaptedCall,
7966
+ prefix: target.phonePrefix,
7967
+ theme: "archive",
7968
+ autoCheck: "mount"
7969
+ });
7970
+ }
6791
7971
  //#endregion
6792
7972
  //#region src/config-panel-contract.ts
6793
7973
  /** T1 交互 tokens(#1160,唯一定义地,真相源 #1159 参数表)。
@@ -8696,6 +9876,11 @@ ${body}`;
8696
9876
  fontSize: 12,
8697
9877
  userSelect: "all"
8698
9878
  },
9879
+ /** 缺席页签的安装按钮挂载位(#1282):容器只占位,按钮本体由上游安装控件渲染;落在提示文案与手动命令之间。 */
9880
+ installSlot: {
9881
+ display: "block",
9882
+ marginTop: 8
9883
+ },
8699
9884
  moreCard: {
8700
9885
  marginTop: 16,
8701
9886
  padding: "10px 12px",
@@ -9242,6 +10427,28 @@ ${body}`;
9242
10427
  *
9243
10428
  * 卡片在页签面板之后,六页签切换它都在(它不属于任何一个页签)。
9244
10429
  */
10430
+ /** 缺席页签的单包安装按钮(#1282):挂载位+挂载一体,连接不到或目标表无此包就不画。
10431
+ *
10432
+ * 与标题行批量入口同形(ref 占位+effect 挂载+卸载 unmount),区别只有两处:调的是单包安装
10433
+ * 件(`prefix: ilife-<skill>` 的单包五电话),以及容器落在缺席提示与手动命令之间。 */
10434
+ function TabInstallSlot(props) {
10435
+ const slotRef = react.useRef(null);
10436
+ const callReady = props.getCall() !== null;
10437
+ react.useEffect(() => {
10438
+ const mount = slotRef.current;
10439
+ if (mount === null || !callReady) return;
10440
+ const button = mountLifeInstallButton(mount, managerCallAdapter(props.getCall()), props.tab);
10441
+ if (button === null) return;
10442
+ return () => {
10443
+ button.unmount();
10444
+ };
10445
+ }, [callReady, props.tab]);
10446
+ return react.createElement("span", {
10447
+ ref: slotRef,
10448
+ style: S.installSlot,
10449
+ "data-ilife-install": "slot"
10450
+ });
10451
+ }
9245
10452
  function MorePluginsCard() {
9246
10453
  return react.createElement("div", { style: S.moreCard }, react.createElement("div", { style: S.moreTitle }, "作者其他插件"), MORE_PLUGINS.map((row) => react.createElement("a", {
9247
10454
  key: row.pkg,
@@ -9254,7 +10461,7 @@ ${body}`;
9254
10461
  }, 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)))));
9255
10462
  }
9256
10463
  /** 版本胶囊那一行字:只在这里拼一次,屏上与用例读的是同一串。 */
9257
- const MANAGER_VERSION_TEXT = "dsh-life-pack · 0.3.55";
10464
+ const MANAGER_VERSION_TEXT = "dsh-life-pack · 0.3.57";
9258
10465
  /** 右下角那本书离面板两沿的距离:用户口径「一直处于面板右下角、不随列表滑动消失」
9259
10466
  * ⇒ sticky 吸附(面板相对,视口多大都落在面板角上);INSET=右沿,BOTTOM=底沿。 */
9260
10467
  const MANUAL_ENTRY_INSET = 16;
@@ -9572,7 +10779,10 @@ ${body}`;
9572
10779
  error: health.rows[tab.plugin]?.error ?? null
9573
10780
  })) : (() => {
9574
10781
  const reco = recoFor(tab);
9575
- return react.createElement("div", { style: S.reco }, reco.hint, react.createElement("span", { style: S.cmd }, reco.installCmd));
10782
+ return react.createElement("div", { style: S.reco }, reco.hint, react.createElement(TabInstallSlot, {
10783
+ tab,
10784
+ getCall: props.getCall
10785
+ }), react.createElement("span", { style: S.cmd }, reco.installCmd));
9576
10786
  })());
9577
10787
  }), react.createElement(MorePluginsCard, null), react.createElement("div", {
9578
10788
  style: {