dsh-plugin 1.0.0 → 1.1.0

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/client/client.js CHANGED
@@ -54,8 +54,8 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
54
54
  installNow: "直接安装",
55
55
  installing: "安装中…",
56
56
  installDone: "安装成功",
57
- installResultTitle: "安装完成",
58
- installResultDesc: "插件已安装。",
57
+ installResultTitle: "插件安装成功",
58
+ installResultDesc: "",
59
59
  confirmUpdateTitle: "确认更新",
60
60
  updateNow: "直接更新",
61
61
  updating: "更新中…",
@@ -91,6 +91,7 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
91
91
  notificationsDesc: "安装、卸载任务的成败都会记录在这里,即使错过提示也能随时回来查看。",
92
92
  notificationsEmpty: "暂无通知记录",
93
93
  notificationsClear: "清空通知",
94
+ removeNotification: "删除这条通知",
94
95
  failCopy: "复制完整错误信息",
95
96
  failIssueHint: "带着错误日志去作者仓库一键提交 Issue(正文含官网收录链接)",
96
97
  failIssueBig: "一键提交 BUG 到 GitHub Issue 为开源作贡献",
@@ -165,8 +166,8 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
165
166
  installNow: "Install",
166
167
  installing: "Installing…",
167
168
  installDone: "Installed",
168
- installResultTitle: "Installed",
169
- installResultDesc: "The plugin has been installed.",
169
+ installResultTitle: "Plugin installed successfully",
170
+ installResultDesc: "",
170
171
  confirmUpdateTitle: "Confirm update",
171
172
  updateNow: "Update",
172
173
  updating: "Updating…",
@@ -202,6 +203,7 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
202
203
  notificationsDesc: "Every install and remove result is logged here — even if you missed the prompt, you can always check back.",
203
204
  notificationsEmpty: "No notifications yet",
204
205
  notificationsClear: "Clear notifications",
206
+ removeNotification: "Remove this notification",
205
207
  failCopy: "Copy full log",
206
208
  failIssueHint: "Open a pre-filled issue on the author repo with this error log (includes catalog links)",
207
209
  failIssueBig: "Report this bug to GitHub — contribute to open source",
@@ -240,40 +242,40 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
240
242
  document.head.appendChild(tag);
241
243
  }
242
244
  var Header_module_css_default = {
243
- "tab": "qikqja_tab",
244
245
  "adText": "qikqja_adText",
245
- "failBtn": "qikqja_failBtn",
246
- "root": "qikqja_root",
247
- "header": "qikqja_header",
248
- "githubIcon": "qikqja_githubIcon",
249
- "search": "qikqja_search",
250
- "title": "qikqja_title",
251
- "segCount": "qikqja_segCount",
252
- "logoIcon": "qikqja_logoIcon",
253
- "installedBtnDisabled": "qikqja_installedBtnDisabled",
246
+ "tab": "qikqja_tab",
247
+ "copyIcon": "qikqja_copyIcon",
248
+ "filterResults": "qikqja_filterResults",
254
249
  "failBadge": "qikqja_failBadge",
255
- "tagline": "qikqja_tagline",
256
- "headerTitleRow": "qikqja_headerTitleRow",
257
- "version": "qikqja_version",
258
250
  "headerRight": "qikqja_headerRight",
259
- "controls": "qikqja_controls",
251
+ "brandTitle": "qikqja_brandTitle",
260
252
  "taglineLink": "qikqja_taglineLink",
261
- "copyIcon": "qikqja_copyIcon",
253
+ "search": "qikqja_search",
254
+ "installedBtn": "qikqja_installedBtn",
255
+ "tabCount": "qikqja_tabCount",
256
+ "resultCount": "qikqja_resultCount",
257
+ "segCountActive": "qikqja_segCountActive",
262
258
  "adArrow": "qikqja_adArrow",
263
- "installedBtnActive": "qikqja_installedBtnActive",
264
- "adBadge": "qikqja_adBadge",
265
- "tabs": "qikqja_tabs",
259
+ "controls": "qikqja_controls",
260
+ "installedBtnDisabled": "qikqja_installedBtnDisabled",
261
+ "root": "qikqja_root",
266
262
  "githubLink": "qikqja_githubLink",
267
- "brandTitle": "qikqja_brandTitle",
263
+ "header": "qikqja_header",
264
+ "logoIcon": "qikqja_logoIcon",
265
+ "tabs": "qikqja_tabs",
268
266
  "adBanner": "qikqja_adBanner",
269
- "filterResults": "qikqja_filterResults",
270
- "resultCount": "qikqja_resultCount",
271
- "searchRow": "qikqja_searchRow",
272
- "segCountActive": "qikqja_segCountActive",
273
- "installedBtn": "qikqja_installedBtn",
267
+ "failBtn": "qikqja_failBtn",
268
+ "githubIcon": "qikqja_githubIcon",
269
+ "adBadge": "qikqja_adBadge",
270
+ "headerTitleRow": "qikqja_headerTitleRow",
271
+ "tagline": "qikqja_tagline",
272
+ "title": "qikqja_title",
273
+ "installedBtnActive": "qikqja_installedBtnActive",
274
+ "segCount": "qikqja_segCount",
274
275
  "langBtn": "qikqja_langBtn",
276
+ "version": "qikqja_version",
275
277
  "tabActive": "qikqja_tabActive",
276
- "tabCount": "qikqja_tabCount"
278
+ "searchRow": "qikqja_searchRow"
277
279
  };
278
280
  //#endregion
279
281
  //#region src/client/lib/failures.ts
@@ -281,7 +283,8 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
281
283
  const MAX = 50;
282
284
  /**
283
285
  * 失败归类,三态。无论底层机制如何(pnpm 白名单拦截 / 构建脚本被忽略 / prepare 失败),
284
- * 对用户而言结果都一样 —— 用官方默认安装方式装不上,就是插件仓库的问题,一律引导提 Issue:
286
+ * 对用户而言结果都一样 —— 当前安装通道(npm 或 git)装不上,就是插件分发/依赖的问题,
287
+ * 一律引导提 Issue:
285
288
  * - pnpmIgnoredBuild:插件依赖里的原生模块构建脚本被 pnpm 默认拦截(如 node-pty,
286
289
  * `ERR_PNPM_IGNORED_BUILDS`)。只影响带原生模块的插件,其他插件不受影响 —— 差异在
287
290
  * 插件的依赖选择,属插件依赖/打包问题 → 引导去仓库提 Issue(建议改用预编译版本)
@@ -393,6 +396,12 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
393
396
  save([]);
394
397
  return [];
395
398
  }
399
+ /** 按 id 删除单条通知记录,返回更新后的列表(仅移除该条,不影响其余记录)。 */
400
+ function removeNotification(id) {
401
+ const next = loadNotifications().filter((r) => r.id !== id);
402
+ save(next);
403
+ return next;
404
+ }
396
405
  //#endregion
397
406
  //#region src/client/lib/catalog.ts
398
407
  /** 插件中心官网地址。 */
@@ -404,7 +413,7 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
404
413
  * tsdown 构建时用 define 把 __PLUGIN_VERSION__ 替换成 package.json 的版本号;
405
414
  * node --test 直接 import 本模块时该标识符不存在,typeof 守卫兜底为空串。
406
415
  */
407
- const PLUGIN_VERSION = "1.0.0";
416
+ const PLUGIN_VERSION = "1.1.0";
408
417
  /** dsh-plugin.org 中文页挂在 /zh/ 前缀下,英文在根路径。 */
409
418
  function langPathOf(lang) {
410
419
  return lang === "zh" ? "zh/" : "";
@@ -426,15 +435,17 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
426
435
  }
427
436
  /**
428
437
  * 一键反馈 GitHub Issue 的预填链接:标题带「来自 dsh-plugin.org」标识,正文只带
429
- * 核心信息 —— 原因判定 + 关键错误代码 + 宿主机器环境快照 + 错误核心摘要(完整日志
430
- * 太长,塞进 URL 会被 GitHub 以「request URL too long」拒绝,故只收集重点)。
431
- * 错误弹窗、失败记录共用此逻辑。
438
+ * 核心信息 —— 原因判定 + 关键错误代码 + 尝试过的安装方式 + 宿主机器环境快照 +
439
+ * 错误核心摘要(完整日志太长,塞进 URL 会被 GitHub 以「request URL too long」拒绝,
440
+ * 故只收集重点)。错误弹窗、失败记录共用此逻辑。
432
441
  * env 取不到时为 null,链接照常生成、只是少环境段。
442
+ * attempts(尝试过的安装方式,npm 反查 + 实际执行命令):作者看到我们查过/试过的命令,
443
+ * 组织 scope 与 GitHub 用户名不一致时也能直接指认正确的 npm 包名。
433
444
  */
434
- function pluginIssueUrl(repo, message, env) {
445
+ function pluginIssueUrl(repo, message, env, command, attempts) {
435
446
  const title = `[dsh-plugin.org | dsh-plugin-hub] Install/Remove failed: ${repo}`;
436
447
  const kind = classifyFailure(message);
437
- const reason = /\[packaging\]/i.test(message) ? "plugin does NOT support the official default install method (dsh plugin add github:owner/repo — requires build output committed to the repo or a prepare script); its git distribution lacks the entry file declared in package.json" : kind === "pluginPrepare" ? "plugin prepare/build script failed during install (packaging/distribution issue)" : kind === "pnpmIgnoredBuild" ? "plugin depends on a native module whose build script pnpm blocks by default (use a prebuilt variant)" : "plugin-side install failure";
448
+ const reason = /\[packaging\]/i.test(message) ? "plugin distribution is incomplete — the entry file declared in package.json is missing from the published package (github tarball or npm package); please commit build output or publish a complete package" : kind === "pluginPrepare" ? "plugin prepare/build script failed during install (packaging/distribution issue)" : kind === "pnpmIgnoredBuild" ? "plugin depends on a native module whose build script pnpm blocks by default (use a prebuilt variant)" : "plugin-side install failure";
438
449
  const code = coreErrorCode(message);
439
450
  const build = (coreChars) => {
440
451
  const body = [
@@ -444,12 +455,17 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
444
455
  "",
445
456
  `## [DSH-Plugin 插件中心](${SITE_URL}) · 安装 Plugin 失败错误信息`,
446
457
  `本错误信息由 [dsh-plugin-hub](${GITHUB_URL}) 插件中心的安装程序自动生成,随本次安装失败一并提交。`,
447
- `- 使用的安装命令(官方默认安装方式):\`dsh plugin${env?.profile ? ` --profile ${env.profile}` : ""} add github:${repo}\``,
458
+ `- 实际执行的安装命令:\`${command ?? `dsh plugin${env?.profile ? ` --profile ${env.profile}` : ""} add github:${repo}`}\``,
448
459
  `- 执行结果:安装失败,未能安装该插件。`,
460
+ ...attempts && attempts.length > 0 ? [
461
+ "",
462
+ "## Attempted install channels(已尝试的安装方式)",
463
+ ...attempts.map((a) => `- ${a}`)
464
+ ] : [],
449
465
  .../\[packaging\]/i.test(message) ? [
450
466
  "",
451
- "## 官方默认安装方式",
452
- "DSH 生态的官方默认安装方式是 `dsh plugin add github:owner/repo`(git 直装):插件仓库需提交构建产物,或在 package.json 提供 `prepare` 脚本让 pnpm 安装时自动构建。当前插件两者皆不具备,因此无法按官方方式安装。"
467
+ "## 安装方式说明",
468
+ "DSH 插件支持两种官方安装通道:`dsh plugin add <npm-package>`(npm 分发,需发布完整构建产物)与 `dsh plugin add github:owner/repo`(git 直装,仓库需提交构建产物或在 package.json 提供 `prepare` 脚本)。当前插件的分发物缺少 package.json 声明的入口文件,请按所用通道补齐后重新发布。"
453
469
  ] : [],
454
470
  "",
455
471
  "## Environment",
@@ -520,7 +536,10 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
520
536
  topics: Array.isArray(raw.t) ? raw.t : void 0,
521
537
  features: Array.isArray(raw.f) ? raw.f : void 0,
522
538
  description: typeof raw.d === "string" ? raw.d : void 0,
523
- source: typeof raw.r === "string" ? { repo: raw.r } : void 0,
539
+ source: typeof raw.r === "string" ? { repo: raw.r } : raw.r !== null && typeof raw.r === "object" ? {
540
+ repo: typeof raw.r.repo === "string" ? raw.r.repo : void 0,
541
+ npmPackage: typeof raw.r.npmPackage === "string" ? raw.r.npmPackage : void 0
542
+ } : void 0,
524
543
  compatibility: typeof raw.v === "string" ? { status: raw.v } : void 0,
525
544
  dates: {
526
545
  repoUpdatedAt: typeof raw.u === "string" ? raw.u : void 0,
@@ -533,6 +552,28 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
533
552
  };
534
553
  return raw;
535
554
  }
555
+ /**
556
+ * 安装通道决策(用户无感知):目录探测到 npm 包名 → 用 npm 包名安装
557
+ * (走 npm registry tarball,更快、与 GitHub 网络无关);无 npm 包名 → git 直装。
558
+ * 返回值 target 即传给后端 /install 的安装目标(npm 包名 或 owner/repo)。
559
+ */
560
+ function installTargetOf(p) {
561
+ const pkg = (p.source?.npmPackage ?? "").trim();
562
+ const repo = (p.source?.repo ?? "").trim();
563
+ if (pkg && repo) return {
564
+ target: pkg,
565
+ via: "npm"
566
+ };
567
+ return {
568
+ target: repo,
569
+ via: "github"
570
+ };
571
+ }
572
+ /** 展示用安装命令(复制/弹窗):npm 通道显示包名,git 通道显示 github: 源。 */
573
+ function installCommandOf(p, withProfile = false) {
574
+ const { target, via } = installTargetOf(p);
575
+ return via === "npm" ? `dsh plugin${withProfile ? " --profile web" : ""} add ${target}` : `dsh plugin${withProfile ? " --profile web" : ""} add github:${target}`;
576
+ }
536
577
  const CATEGORY_LABELS = {
537
578
  interface: {
538
579
  zh: "界面与体验",
@@ -664,7 +705,8 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
664
705
  const [installedFilter, setInstalledFilter] = (0, react.useState)("all");
665
706
  /** 当前 profile 已安装插件:npm 包名 -> manifest spec(来自宿主本地路由) */
666
707
  const [installed, setInstalled] = (0, react.useState)({});
667
- /** 安装时记录的目录信号:repo(小写) -> { version, updatedAt }(来自宿主本地路由) */
708
+ /** 安装时记录的目录信号:repo(小写) -> { version, updatedAt }(来自宿主本地路由);
709
+ * npmPackage 为 npm 优先通道反查命中的包名映射(目录数据未下发时客户端靠它把依赖 key 匹配回仓库) */
668
710
  const [versions, setVersions] = (0, react.useState)({});
669
711
  (0, react.useEffect)(() => {
670
712
  let cancelled = false;
@@ -706,12 +748,16 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
706
748
  (0, react.useEffect)(() => {
707
749
  refreshInstalled();
708
750
  }, []);
709
- /** 插件是否已安装:匹配 installed spec 中的 `github:<owner>/<repo>`;命中返回 npm 包名。 */
751
+ /** 插件是否已安装:匹配 installed spec 中的 `github:<owner>/<repo>`,或 npm 通道安装的依赖包名;命中返回 npm 包名。 */
710
752
  const installedName = (p) => {
711
753
  const repo = p.source?.repo;
712
754
  if (!repo) return null;
713
755
  const needle = `github:${repo.toLowerCase()}`;
714
756
  for (const [name, spec] of Object.entries(installed)) if (spec.toLowerCase().includes(needle)) return name;
757
+ const pkg = ((p.source?.npmPackage || versions[repo.toLowerCase()]?.npmPackage) ?? "").toLowerCase();
758
+ if (pkg) {
759
+ for (const name of Object.keys(installed)) if (name.toLowerCase() === pkg) return name;
760
+ }
715
761
  return null;
716
762
  };
717
763
  /** 该插件安装时记录的目录版本(无记录/未安装 → null)。 */
@@ -832,11 +878,15 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
832
878
  resolvePendingRef.current = resolvePending;
833
879
  /** 当前打开弹窗所对应的任务 id:该任务完成时弹窗切换为结果视图 */
834
880
  const modalTaskRef = (0, react.useRef)(null);
881
+ /** 已开始收尾但尚未结束的任务 id(服务端 /active 已消失 → 查 /status 中):并发轮询时跳过,避免重复收尾 */
882
+ const settlingRef = (0, react.useRef)(/* @__PURE__ */ new Set());
835
883
  /** 轮询定时器句柄(队列清空/组件卸载时清理) */
836
884
  const pollRef = (0, react.useRef)(null);
837
885
  /** 请求在途的目标集合(同步防重):双击安装/卸载时第二击直接忽略。
838
886
  * 本地队列任务要等 fetch 返回后才入队,仅靠 queueRef 检查拦不住请求窗口内的重复点击。 */
839
887
  const submittingRef = (0, react.useRef)(/* @__PURE__ */ new Set());
888
+ /** 乐观入队临时 id 计数器:递减产生唯一负数,与服务端自增正数 id 永不冲突。 */
889
+ const tempIdRef = (0, react.useRef)(0);
840
890
  /** 请求在途标记:弹窗据此禁用确认按钮,避免等待响应期间被再次点击。 */
841
891
  const [submitting, setSubmitting] = (0, react.useState)(false);
842
892
  /** 停止后台任务轮询(任务结束或组件卸载时清理)。 */
@@ -928,24 +978,58 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
928
978
  }
929
979
  } else {
930
980
  const detail = lines.length > 0 ? [...lines].reverse().join("\n") : q.kind === "uninstall" ? t("uninstallFail") : t("installFail");
931
- onError(detail, q.repo, q.kind);
981
+ onError(detail, q.repo, q.kind, q.command, q.attempts);
932
982
  }
933
983
  maybeStopPoll();
934
984
  };
985
+ /** 卸载成功收尾前的进度过渡:任务已在服务端结束,但保留本地展示,
986
+ * 让进度条在 ~2.4s 内缓缓跑到 100% 再切结果/Toast,给用户一个交互过程,
987
+ * 而不是命令一执行进度条就一闪消失。 */
988
+ const settleDone = (q, lines) => {
989
+ stopPoll();
990
+ const from = Math.min(q.progress, 90);
991
+ const steps = 20;
992
+ const stepMs = 120;
993
+ let step = 0;
994
+ applyQueue((prev) => prev.map((x) => x.id === q.id ? {
995
+ ...x,
996
+ status: "running"
997
+ } : x));
998
+ const timer = window.setInterval(() => {
999
+ step += 1;
1000
+ const progress = Math.round(from + (100 - from) * (step / steps));
1001
+ applyQueue((prev) => prev.map((x) => x.id === q.id ? {
1002
+ ...x,
1003
+ progress
1004
+ } : x));
1005
+ if (step >= steps) {
1006
+ window.clearInterval(timer);
1007
+ finishQueueTask(true, q, lines);
1008
+ if (queueRef.current.length > 0) pollQueue();
1009
+ }
1010
+ }, stepMs);
1011
+ };
935
1012
  /** 任务在 /active 中消失 = 已结束:查 /status 拿终态并收尾(cancelled 静默移除)。 */
936
1013
  const settleTask = async (q) => {
937
1014
  let status = "failed";
938
1015
  let lines = [];
1016
+ let attempts;
939
1017
  try {
940
1018
  const res = await fetch(`/dsh-plugin-hub/status?task=${q.id}`, { cache: "no-store" });
941
1019
  if (res.ok) {
942
1020
  const data = await res.json();
943
1021
  status = data.task?.status ?? "failed";
944
1022
  lines = data.task?.lines ?? [];
1023
+ attempts = Array.isArray(data.task?.attempts) ? data.task.attempts : void 0;
945
1024
  }
946
1025
  } catch {}
947
- if (status === "done") finishQueueTask(true, q, lines);
948
- else if (status === "failed") finishQueueTask(false, q, lines);
1026
+ if (status === "done") {
1027
+ if (q.kind === "uninstall") settleDone(q, lines);
1028
+ else finishQueueTask(true, q, lines);
1029
+ } else if (status === "failed") finishQueueTask(false, {
1030
+ ...q,
1031
+ attempts
1032
+ }, lines);
949
1033
  else {
950
1034
  applyQueue((prev) => prev.filter((x) => x.id !== q.id));
951
1035
  maybeStopPoll();
@@ -980,13 +1064,26 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
980
1064
  updatedAt: prevTask?.updatedAt,
981
1065
  status: a.status === "running" ? "running" : "pending",
982
1066
  progress: typeof a.progress === "number" ? a.progress : prevTask?.progress ?? 0,
983
- lines: Array.isArray(a.lines) ? a.lines : prevTask?.lines ?? []
1067
+ lines: Array.isArray(a.lines) ? a.lines : prevTask?.lines ?? [],
1068
+ attempts: Array.isArray(a.attempts) ? a.attempts : prevTask?.attempts ?? []
984
1069
  });
985
1070
  }
1071
+ const keepOpt = prev.filter((q) => q.optimistic && !next.some((x) => x.id === q.id));
1072
+ if (keepOpt.length > 0) next.push(...keepOpt);
1073
+ const keepGone = prev.filter((q) => !byId.has(q.id) && !next.some((x) => x.id === q.id) && q.status !== "cancelling" && !q.optimistic);
1074
+ if (keepGone.length > 0) next.push(...keepGone);
986
1075
  return next;
987
1076
  });
988
- const gone = prevQueue.filter((q) => !byId.has(q.id) && q.status !== "cancelling");
989
- for (const q of gone) await settleTask(q);
1077
+ const gone = prevQueue.filter((q) => !byId.has(q.id) && q.status !== "cancelling" && !q.optimistic && !settlingRef.current.has(q.id));
1078
+ for (const q of gone) {
1079
+ if (!queueRef.current.some((x) => x.id === q.id)) continue;
1080
+ settlingRef.current.add(q.id);
1081
+ try {
1082
+ await settleTask(q);
1083
+ } finally {
1084
+ settlingRef.current.delete(q.id);
1085
+ }
1086
+ }
990
1087
  } catch {}
991
1088
  }, 600);
992
1089
  };
@@ -1001,14 +1098,17 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
1001
1098
  applyPending(parsePendingRestarts(data.pendingRestarts));
1002
1099
  const items = (data.tasks ?? []).filter((a) => typeof a.id === "number").map((a) => {
1003
1100
  const isRemove = a.action === "remove";
1101
+ const display = typeof a.displayTarget === "string" ? a.displayTarget.replace(/^github:/, "") : "";
1102
+ const fallback = typeof a.target === "string" ? a.target.replace(/^github:/, "") : "";
1004
1103
  return {
1005
1104
  id: a.id,
1006
1105
  kind: isRemove ? "uninstall" : "install",
1007
- target: typeof a.target === "string" ? a.target.replace(/^github:/, "") : "",
1008
- repo: isRemove ? null : typeof a.target === "string" ? a.target.replace(/^github:/, "") : null,
1106
+ target: isRemove ? fallback : display || fallback,
1107
+ repo: isRemove ? null : display || fallback,
1009
1108
  status: a.status === "running" ? "running" : "pending",
1010
1109
  progress: typeof a.progress === "number" ? a.progress : 0,
1011
- lines: Array.isArray(a.lines) ? a.lines : []
1110
+ lines: Array.isArray(a.lines) ? a.lines : [],
1111
+ attempts: Array.isArray(a.attempts) ? a.attempts : []
1012
1112
  };
1013
1113
  });
1014
1114
  if (items.length > 0 || pendingRef.current.length > 0) {
@@ -1026,45 +1126,61 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
1026
1126
  const installNow = async (p, opts) => {
1027
1127
  const repo = p.source?.repo ?? "";
1028
1128
  if (!repo) return;
1129
+ const { target } = installTargetOf(p);
1130
+ if (!target) return;
1029
1131
  if (queueRef.current.some((q) => q.kind === "install" && q.target === repo)) return;
1030
1132
  if (submittingRef.current.has(repo)) return;
1031
1133
  submittingRef.current.add(repo);
1134
+ tempIdRef.current -= 1;
1135
+ const tempId = tempIdRef.current;
1136
+ modalTaskRef.current = tempId;
1137
+ applyQueue((prev) => [...prev, {
1138
+ id: tempId,
1139
+ kind: "install",
1140
+ target: repo,
1141
+ repo,
1142
+ desc: p.description,
1143
+ version: p.version,
1144
+ updatedAt: p.dates?.repoUpdatedAt,
1145
+ status: "running",
1146
+ progress: 0,
1147
+ lines: [],
1148
+ optimistic: true,
1149
+ command: installCommandOf(p, true),
1150
+ attempts: []
1151
+ }]);
1032
1152
  setSubmitting(true);
1033
1153
  try {
1034
1154
  const res = await fetch("/dsh-plugin-hub/install", {
1035
1155
  method: "POST",
1036
1156
  headers: { "content-type": "application/json" },
1037
1157
  body: JSON.stringify({
1038
- repo,
1158
+ repo: target,
1159
+ display: repo,
1039
1160
  mode: opts?.update ? "update" : void 0
1040
1161
  })
1041
1162
  });
1042
1163
  const data = await res.json();
1043
1164
  if (!data.ok || typeof data.task !== "number") {
1044
- onError(data.error ?? `HTTP ${res.status}`, repo, "install");
1165
+ applyQueue((prev) => prev.filter((x) => x.id !== tempId));
1166
+ onError(data.error ?? `HTTP ${res.status}`, repo, "install", installCommandOf(p, true), data.attempts);
1045
1167
  return;
1046
1168
  }
1047
1169
  const taskId = data.task;
1048
1170
  modalTaskRef.current = taskId;
1049
- applyQueue((prev) => [...prev, {
1171
+ applyQueue((prev) => prev.map((x) => x.id === tempId ? {
1172
+ ...x,
1050
1173
  id: taskId,
1051
- kind: "install",
1052
- target: repo,
1053
- repo,
1054
- desc: p.description,
1055
- version: p.version,
1056
- updatedAt: p.dates?.repoUpdatedAt,
1057
- status: "pending",
1058
- progress: 0,
1059
- lines: []
1060
- }]);
1174
+ optimistic: void 0
1175
+ } : x));
1061
1176
  pendingInfoRef.current.set(repo, {
1062
1177
  desc: p.description,
1063
1178
  version: p.version
1064
1179
  });
1065
1180
  pollQueue();
1066
1181
  } catch {
1067
- onError(t("installFail"), repo, "install");
1182
+ applyQueue((prev) => prev.filter((x) => x.id !== tempId));
1183
+ onError(t("installFail"), repo, "install", installCommandOf(p, true));
1068
1184
  } finally {
1069
1185
  submittingRef.current.delete(repo);
1070
1186
  setSubmitting(false);
@@ -1150,7 +1266,7 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
1150
1266
  }
1151
1267
  //#endregion
1152
1268
  //#region \0dsh-css:src/client/styles/Modal.module.css.mjs
1153
- const css$3 = ".BiQ1zG_overlay{z-index:998;-webkit-user-select:none;user-select:none;background:#00000061;justify-content:center;align-items:center;animation:.16s ease-out BiQ1zG_overlayIn;display:flex;position:fixed;top:0;bottom:0;left:0;right:0}.BiQ1zG_modal,.BiQ1zG_errorModal{background:var(--hub-bg-1);border:1px solid var(--hub-border-2);border-radius:10px;flex-direction:column;gap:10px;width:420px;max-width:calc(100vw - 32px);max-height:calc(100vh - 64px);padding:14px 16px;animation:.18s ease-out BiQ1zG_modalIn;display:flex;box-shadow:0 12px 40px #0000003d}.BiQ1zG_errorModal{width:640px;max-width:calc(100vw - 48px)}.BiQ1zG_modalHead{flex-shrink:0;justify-content:space-between;align-items:center;gap:8px;display:flex}.BiQ1zG_modalTitle{color:var(--hub-text-primary);font-size:14px;font-weight:600;line-height:20px}.BiQ1zG_modalTitleBusy{color:var(--hub-brand)}.BiQ1zG_modalTitleQueued{color:var(--hub-warning)}.BiQ1zG_modalClose{width:24px;height:24px;color:var(--hub-text-tertiary);cursor:pointer;-webkit-user-select:none;user-select:none;background:0 0;border:none;border-radius:6px;flex-shrink:0;justify-content:center;align-items:center;font-size:16px;line-height:1;display:inline-flex}.BiQ1zG_modalClose:hover{color:var(--hub-text-primary);background:var(--hub-bg-hover)}.BiQ1zG_modalCloseIcon{flex-shrink:0;width:14px;height:14px}.BiQ1zG_modalDesc{color:var(--hub-text-secondary);font-size:12px;line-height:18px}.BiQ1zG_trustHint{color:var(--hub-danger-text);background:var(--hub-danger-tint);border:1px solid var(--hub-danger-border-soft);border-radius:6px;padding:6px 10px;font-size:12px;font-weight:500;line-height:18px}.BiQ1zG_modalRow{align-items:baseline;gap:8px;min-width:0;font-size:12px;line-height:18px;display:flex}.BiQ1zG_modalLabel{min-width:64px;color:var(--hub-text-tertiary);flex-shrink:0}.BiQ1zG_modalValue{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--hub-text-primary);font-weight:500;overflow:hidden}.BiQ1zG_modalLink{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--hub-brand);cursor:pointer;-webkit-user-select:none;user-select:none;align-items:center;gap:4px;font-weight:500;text-decoration:none;transition:color .12s;display:inline-flex;overflow:hidden}.BiQ1zG_modalLink:hover{color:var(--hub-brand-hover);text-decoration:underline}.BiQ1zG_linkIcon{flex-shrink:0}.BiQ1zG_modalCmd{color:var(--hub-text-primary);background:var(--hub-bg-2);border:1px solid var(--hub-border-2);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:6px;justify-content:space-between;align-items:center;gap:8px;padding:6px 6px 6px 10px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px;line-height:18px;transition:border-color .12s,background .12s;display:flex}.BiQ1zG_modalCmd:hover{border-color:var(--hub-border-ghost);background:var(--hub-bg-3)}.BiQ1zG_modalCmdText{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.BiQ1zG_modalCmdCopy{color:var(--hub-brand);cursor:pointer;-webkit-user-select:none;user-select:none;background:0 0;border:none;border-radius:4px;flex-shrink:0;align-items:center;gap:3px;padding:1px 7px;font-family:inherit;font-size:11px;line-height:16px;transition:color .12s,background .12s;display:inline-flex}.BiQ1zG_modalCmdCopy:hover{color:var(--hub-brand-hover);background:var(--hub-bg-2)}.BiQ1zG_modalActions{justify-content:flex-end;align-items:center;gap:8px;margin-top:2px;display:flex}.BiQ1zG_modalBody{flex-direction:column;flex:auto;gap:10px;min-height:0;display:flex;overflow-y:auto}.BiQ1zG_toast{z-index:1000;background:var(--hub-btn-fill);color:var(--hub-text-on-fill);pointer-events:none;white-space:nowrap;border:none;border-radius:8px;padding:10px 16px;font-size:12px;font-weight:500;line-height:18px;animation:.22s ease-out BiQ1zG_toastIn;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);box-shadow:0 6px 24px #00000047}@keyframes BiQ1zG_toastIn{0%{opacity:0;transform:translate(-50%,-44%)}to{opacity:1;transform:translate(-50%,-50%)}}.BiQ1zG_toastFail{background:var(--hub-danger);color:#fff;border-color:#ffffff3d}.BiQ1zG_queueSection{flex-direction:column;gap:6px;display:flex}.BiQ1zG_queueSectionTitle{color:var(--hub-text-secondary);padding:4px 2px 0;font-size:12px;font-weight:600;line-height:18px}.BiQ1zG_pendingRowStatus{color:var(--hub-warn);flex-shrink:0;font-weight:500}.BiQ1zG_pendingRowActions{flex-shrink:0;gap:8px;margin-left:auto;display:flex}.BiQ1zG_queueRow{border:1px solid var(--hub-border-2);background:var(--hub-bg-2);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:8px;flex-direction:column;gap:5px;padding:8px 10px;font-size:12px;line-height:18px;transition:background .12s;display:flex}.BiQ1zG_queueRow:hover{background:var(--hub-brand-tint)}.BiQ1zG_queueRowHead{align-items:center;gap:10px;display:flex}.BiQ1zG_queueRowTarget{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--hub-text-primary);flex:1;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;overflow:hidden}.BiQ1zG_queueRowDesc{color:var(--hub-text-tertiary);-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.BiQ1zG_queueRowBody{align-items:center;gap:8px;display:flex}.BiQ1zG_queueRowStatus{color:var(--hub-brand);flex-shrink:0;font-weight:500}.BiQ1zG_queueRowTrack{flex:1;min-width:0}.BiQ1zG_queueRowPct{color:var(--hub-text-tertiary);font-variant-numeric:tabular-nums;flex-shrink:0}.BiQ1zG_stripCancel{color:var(--hub-text-secondary);cursor:pointer;-webkit-user-select:none;user-select:none;background:0 0;border:none;border-radius:6px;flex-shrink:0;padding:2px 10px;font-size:12px;line-height:18px;transition:background .12s,color .12s}.BiQ1zG_stripCancel:hover{background:var(--hub-danger-tint);color:var(--hub-danger-text)}.BiQ1zG_stripCancel:disabled{opacity:.45;cursor:default}.BiQ1zG_queuedHint{color:var(--hub-brand);background:var(--hub-brand-tint);border:1px solid var(--hub-brand-border-soft);border-radius:6px;padding:5px 10px;font-size:12px;line-height:18px}.BiQ1zG_errorTitle{color:var(--hub-danger-text);font-size:14px;font-weight:600;line-height:20px}.BiQ1zG_errorBox{border:1px solid var(--hub-danger-border);background:var(--hub-danger-tint-weak);max-height:240px;color:var(--hub-text-primary);white-space:pre-wrap;word-break:break-word;-webkit-user-select:none;user-select:none;border-radius:6px;margin:0;padding:10px 12px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px;line-height:17px;overflow:auto}.BiQ1zG_errorCopySoft{color:var(--hub-text-tertiary);cursor:pointer;-webkit-user-select:none;user-select:none;background:0 0;border:none;border-radius:4px;flex-shrink:0;align-items:center;padding:2px 8px;font-size:11px;line-height:16px;transition:color .12s,background .12s;display:inline-flex}.BiQ1zG_errorCopySoft:hover{color:var(--hub-text-secondary);background:var(--hub-bg-2)}.BiQ1zG_errorHint{color:var(--hub-text-tertiary);font-size:12px;line-height:18px}.BiQ1zG_modalCancel,.BiQ1zG_modalCopy{color:var(--hub-text-secondary);cursor:pointer;-webkit-user-select:none;user-select:none;background:0 0;border:none;border-radius:6px;padding:5px 14px;font-size:12px;line-height:18px;transition:color .12s,background .12s}.BiQ1zG_modalCancel:hover,.BiQ1zG_modalCopy:hover{color:var(--hub-text-primary);background:var(--hub-bg-hover)}.BiQ1zG_modalInstall{color:var(--hub-text-on-fill);background:var(--hub-btn-fill);cursor:pointer;-webkit-user-select:none;user-select:none;border:none;border-radius:6px;padding:5px 14px;font-size:12px;font-weight:600;line-height:18px;transition:background .12s}.BiQ1zG_modalInstall:hover{background:var(--hub-btn-hover)}.BiQ1zG_modalCopy:disabled,.BiQ1zG_modalInstall:disabled,.BiQ1zG_modalCancel:disabled,.BiQ1zG_modalClose:disabled,.BiQ1zG_uninstallConfirm:disabled{opacity:.55;cursor:not-allowed;pointer-events:none}.BiQ1zG_uninstallConfirm{color:#fff;background:var(--hub-danger);cursor:pointer;-webkit-user-select:none;user-select:none;border:none;border-radius:6px;padding:5px 14px;font-size:12px;font-weight:600;line-height:18px;transition:background .12s}.BiQ1zG_uninstallConfirm:hover{background:var(--hub-danger-hover)}.BiQ1zG_result{text-align:center;flex-direction:column;align-items:center;gap:5px;padding:10px 0 2px;display:flex}.BiQ1zG_resultCheck{background:var(--hub-success-tint);width:40px;height:40px;color:var(--hub-success);border-radius:50%;justify-content:center;align-items:center;margin-bottom:3px;display:inline-flex}.BiQ1zG_resultCheckIcon{flex-shrink:0;width:20px;height:20px}.BiQ1zG_resultTitle{color:var(--hub-text-primary);font-size:13px;font-weight:600;line-height:20px}.BiQ1zG_resultDesc{color:var(--hub-text-secondary);font-size:12px;line-height:18px}.BiQ1zG_resultRestarting{color:var(--hub-text-tertiary);padding:12px 0 6px;font-size:12px;line-height:18px}.BiQ1zG_restartLater{color:var(--hub-text-secondary);cursor:pointer;-webkit-user-select:none;user-select:none;background:0 0;border:none;border-radius:6px;padding:5px 14px;font-size:12px;line-height:18px;transition:color .12s,background .12s}.BiQ1zG_restartLater:hover{color:var(--hub-text-primary);background:var(--hub-bg-hover)}.BiQ1zG_restartNow{color:var(--hub-text-on-fill);background:var(--hub-btn-fill);cursor:pointer;-webkit-user-select:none;user-select:none;border:none;border-radius:6px;padding:5px 14px;font-size:12px;font-weight:600;line-height:18px;transition:background .12s}.BiQ1zG_restartNow:hover{background:var(--hub-btn-hover)}.BiQ1zG_restartNow:disabled{opacity:.55;cursor:not-allowed;pointer-events:none}.BiQ1zG_result .BiQ1zG_modalActions{justify-content:center;gap:10px;margin-top:0;padding:6px 0 2px}.BiQ1zG_result .BiQ1zG_modalActions .BiQ1zG_restartLater,.BiQ1zG_result .BiQ1zG_modalActions .BiQ1zG_restartNow{min-width:100px}.BiQ1zG_progress{margin:10px 0 2px}.BiQ1zG_progressHead{justify-content:flex-end;align-items:center;margin-bottom:3px;display:flex}.BiQ1zG_progressText{color:var(--hub-text-secondary);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px;line-height:14px}.BiQ1zG_progressTrack{background:var(--hub-border-2);border-radius:2px;height:4px;overflow:hidden}.BiQ1zG_progressFill{background:var(--hub-brand);border-radius:2px;height:100%;transition:width .32s}.BiQ1zG_progressFillFail{background:var(--hub-danger)}@keyframes BiQ1zG_overlayIn{0%{opacity:0}to{opacity:1}}@keyframes BiQ1zG_modalIn{0%{opacity:0;transform:translateY(6px)scale(.98)}to{opacity:1;transform:translateY(0)scale(1)}}.BiQ1zG_noticeList{flex-direction:column;gap:10px;padding-right:2px;display:flex}.BiQ1zG_noticeRow{border:1px solid var(--hub-border-2);background:var(--hub-bg-2);border-radius:8px;align-items:center;gap:10px;padding:10px 12px;display:flex}.BiQ1zG_noticeBadgeOk,.BiQ1zG_noticeBadgeFail{border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;width:28px;height:28px;display:inline-flex;box-shadow:0 2px 6px #0000002e}.BiQ1zG_noticeBadgeOk{background:var(--hub-success)}.BiQ1zG_noticeBadgeFail{background:var(--hub-danger)}.BiQ1zG_noticeBadgeIcon{flex-shrink:0;width:12px;height:12px}.BiQ1zG_noticeMain{flex-direction:column;flex:1;gap:8px;min-width:0;display:flex}.BiQ1zG_noticeHead{align-items:center;gap:8px;min-width:0;display:flex}.BiQ1zG_noticeTextOk{color:var(--hub-success);flex-shrink:0;font-size:12px;font-weight:600;line-height:18px}.BiQ1zG_noticeTextFail{color:var(--hub-danger-text);flex-shrink:0;font-size:12px;font-weight:600;line-height:18px}.BiQ1zG_failList{flex-direction:column;gap:12px;padding-right:2px;display:flex}.BiQ1zG_failRow{border:1px solid var(--hub-border-2);background:var(--hub-bg-2);border-radius:8px;flex-direction:column;gap:8px;padding:10px 12px;display:flex}.BiQ1zG_failHead{align-items:center;gap:8px;min-width:0;display:flex}.BiQ1zG_failKind{border:1px solid #0000;border-radius:4px;flex-shrink:0;padding:0 6px;font-size:10px;font-weight:500;line-height:16px}.BiQ1zG_failKindInstall{color:var(--hub-danger-text);border-color:var(--hub-danger-border);background:var(--hub-danger-tint)}.BiQ1zG_failKindUninstall{color:var(--hub-warn);border-color:var(--hub-warn-border);background:var(--hub-warn-tint)}.BiQ1zG_failRepo{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--hub-brand);cursor:pointer;-webkit-user-select:none;user-select:none;flex:1;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12px;line-height:18px;text-decoration:none;overflow:hidden}.BiQ1zG_failRepo:hover{text-decoration:underline}.BiQ1zG_failTime{color:var(--hub-text-tertiary);font-variant-numeric:tabular-nums;flex-shrink:0;font-size:11px;line-height:16px}.BiQ1zG_failCopy{color:var(--hub-text-tertiary);cursor:pointer;-webkit-user-select:none;user-select:none;background:0 0;border:none;border-radius:4px;flex-shrink:0;align-items:center;padding:2px 8px;font-size:11px;line-height:16px;transition:color .12s,background .12s;display:inline-flex}.BiQ1zG_failCopy:hover{color:var(--hub-text-secondary);background:var(--hub-bg-2)}.BiQ1zG_failEmpty{text-align:center;color:var(--hub-text-tertiary);padding:24px 0;font-size:12px;line-height:18px}.BiQ1zG_failClear{color:var(--hub-danger);cursor:pointer;-webkit-user-select:none;user-select:none;background:0 0;border:none;border-radius:6px;padding:5px 14px;font-size:12px;line-height:18px;transition:color .12s,background .12s}.BiQ1zG_failClear:hover{color:#fff;background:var(--hub-danger)}.BiQ1zG_failBigIssue{box-sizing:border-box;text-align:center;color:#fff;background:var(--hub-danger);border:1px solid var(--hub-danger);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:8px;width:100%;margin-top:4px;padding:3px 16px;font-size:13px;font-weight:600;line-height:18px;text-decoration:none;transition:background .12s,border-color .12s,box-shadow .12s;display:block}.BiQ1zG_failBigIssue:hover{background:var(--hub-danger-hover);border-color:var(--hub-danger-hover);box-shadow:0 3px 10px #d1242f59}.BiQ1zG_failPrepareHint{color:var(--hub-warning);background:var(--hub-warning-tint);border:1px solid var(--hub-warning-border);border-radius:6px;margin-top:6px;padding:8px 12px;font-size:12px;line-height:18px}";
1269
+ const css$3 = ".BiQ1zG_overlay{z-index:998;-webkit-user-select:none;user-select:none;background:#00000061;justify-content:center;align-items:center;animation:.16s ease-out BiQ1zG_overlayIn;display:flex;position:fixed;top:0;bottom:0;left:0;right:0}.BiQ1zG_modal,.BiQ1zG_errorModal{background:var(--hub-bg-1);border:1px solid var(--hub-border-2);border-radius:10px;flex-direction:column;gap:10px;width:420px;max-width:calc(100vw - 32px);max-height:calc(100vh - 64px);padding:14px 16px;animation:.18s ease-out BiQ1zG_modalIn;display:flex;box-shadow:0 12px 40px #0000003d}.BiQ1zG_errorModal{width:640px;max-width:calc(100vw - 48px)}.BiQ1zG_modalHead{flex-shrink:0;justify-content:space-between;align-items:center;gap:8px;display:flex}.BiQ1zG_modalTitle{color:var(--hub-text-primary);font-size:14px;font-weight:600;line-height:20px}.BiQ1zG_modalTitleBusy{color:var(--hub-brand)}.BiQ1zG_modalTitleQueued{color:var(--hub-warning)}.BiQ1zG_modalClose{width:24px;height:24px;color:var(--hub-text-tertiary);cursor:pointer;-webkit-user-select:none;user-select:none;background:0 0;border:none;border-radius:6px;flex-shrink:0;justify-content:center;align-items:center;font-size:16px;line-height:1;display:inline-flex}.BiQ1zG_modalClose:hover{color:var(--hub-text-primary);background:var(--hub-bg-hover)}.BiQ1zG_modalCloseIcon{flex-shrink:0;width:14px;height:14px}.BiQ1zG_modalDesc{color:var(--hub-text-secondary);font-size:12px;line-height:18px}.BiQ1zG_trustHint{color:var(--hub-danger-text);background:var(--hub-danger-tint);border:1px solid var(--hub-danger-border-soft);border-radius:6px;padding:6px 10px;font-size:12px;font-weight:500;line-height:18px}.BiQ1zG_modalRow{align-items:baseline;gap:8px;min-width:0;font-size:12px;line-height:18px;display:flex}.BiQ1zG_modalLabel{min-width:64px;color:var(--hub-text-tertiary);flex-shrink:0}.BiQ1zG_modalValue{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--hub-text-primary);font-weight:500;overflow:hidden}.BiQ1zG_modalLink{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--hub-brand);cursor:pointer;-webkit-user-select:none;user-select:none;align-items:center;gap:4px;font-weight:500;text-decoration:none;transition:color .12s;display:inline-flex;overflow:hidden}.BiQ1zG_modalLink:hover{color:var(--hub-brand-hover);text-decoration:underline}.BiQ1zG_linkIcon{flex-shrink:0}.BiQ1zG_modalCmd{color:var(--hub-text-primary);background:var(--hub-bg-2);border:1px solid var(--hub-border-2);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:6px;justify-content:space-between;align-items:center;gap:8px;padding:6px 6px 6px 10px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px;line-height:18px;transition:border-color .12s,background .12s;display:flex}.BiQ1zG_modalCmd:hover{border-color:var(--hub-border-ghost);background:var(--hub-bg-3)}.BiQ1zG_modalCmdText{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.BiQ1zG_modalCmdCopy{color:var(--hub-brand);cursor:pointer;-webkit-user-select:none;user-select:none;background:0 0;border:none;border-radius:4px;flex-shrink:0;align-items:center;gap:3px;padding:1px 7px;font-family:inherit;font-size:11px;line-height:16px;transition:color .12s,background .12s;display:inline-flex}.BiQ1zG_modalCmdCopy:hover{color:var(--hub-brand-hover);background:var(--hub-bg-2)}.BiQ1zG_modalActions{justify-content:flex-end;align-items:center;gap:8px;margin-top:2px;display:flex}.BiQ1zG_modalBody{flex-direction:column;flex:auto;gap:10px;min-height:0;display:flex;overflow-y:auto}.BiQ1zG_toast{z-index:1000;background:var(--hub-btn-fill);color:var(--hub-text-on-fill);pointer-events:none;white-space:nowrap;border:none;border-radius:8px;padding:10px 16px;font-size:12px;font-weight:500;line-height:18px;animation:.22s ease-out BiQ1zG_toastIn;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);box-shadow:0 6px 24px #00000047}@keyframes BiQ1zG_toastIn{0%{opacity:0;transform:translate(-50%,-44%)}to{opacity:1;transform:translate(-50%,-50%)}}.BiQ1zG_toastFail{background:var(--hub-danger);color:#fff;border-color:#ffffff3d}.BiQ1zG_queueSection{flex-direction:column;gap:6px;display:flex}.BiQ1zG_queueSectionTitle{color:var(--hub-text-secondary);padding:4px 2px 0;font-size:12px;font-weight:600;line-height:18px}.BiQ1zG_pendingRowStatus{color:var(--hub-warn);flex-shrink:0;font-weight:500}.BiQ1zG_pendingRowActions{flex-shrink:0;gap:8px;margin-left:auto;display:flex}.BiQ1zG_queueRow{border:1px solid var(--hub-border-2);background:var(--hub-bg-2);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:8px;flex-direction:column;gap:5px;padding:8px 10px;font-size:12px;line-height:18px;transition:background .12s;display:flex}.BiQ1zG_queueRow:hover{background:var(--hub-brand-tint)}.BiQ1zG_queueRowHead{align-items:center;gap:10px;display:flex}.BiQ1zG_queueRowTarget{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--hub-text-primary);flex:1;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;overflow:hidden}.BiQ1zG_queueRowDesc{color:var(--hub-text-tertiary);-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.BiQ1zG_queueRowBody{align-items:center;gap:8px;display:flex}.BiQ1zG_queueRowStatus{color:var(--hub-brand);flex-shrink:0;font-weight:500}.BiQ1zG_queueRowTrack{flex:1;min-width:0}.BiQ1zG_queueRowPct{color:var(--hub-text-tertiary);font-variant-numeric:tabular-nums;flex-shrink:0}.BiQ1zG_stripCancel{color:var(--hub-text-secondary);cursor:pointer;-webkit-user-select:none;user-select:none;background:0 0;border:none;border-radius:6px;flex-shrink:0;padding:2px 10px;font-size:12px;line-height:18px;transition:background .12s,color .12s}.BiQ1zG_stripCancel:hover{background:var(--hub-danger-tint);color:var(--hub-danger-text)}.BiQ1zG_stripCancel:disabled{opacity:.45;cursor:default}.BiQ1zG_queuedHint{color:var(--hub-brand);background:var(--hub-brand-tint);border:1px solid var(--hub-brand-border-soft);border-radius:6px;padding:5px 10px;font-size:12px;line-height:18px}.BiQ1zG_errorTitle{color:var(--hub-danger-text);font-size:14px;font-weight:600;line-height:20px}.BiQ1zG_errorBox{border:1px solid var(--hub-danger-border);background:var(--hub-danger-tint-weak);max-height:240px;color:var(--hub-text-primary);white-space:pre-wrap;word-break:break-word;-webkit-user-select:none;user-select:none;border-radius:6px;margin:0;padding:10px 12px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px;line-height:17px;overflow:auto}.BiQ1zG_errorCopySoft{color:var(--hub-text-tertiary);cursor:pointer;-webkit-user-select:none;user-select:none;background:0 0;border:none;border-radius:4px;flex-shrink:0;align-items:center;padding:2px 8px;font-size:11px;line-height:16px;transition:color .12s,background .12s;display:inline-flex}.BiQ1zG_errorCopySoft:hover{color:var(--hub-text-secondary);background:var(--hub-bg-2)}.BiQ1zG_errorHint{color:var(--hub-text-tertiary);font-size:12px;line-height:18px}.BiQ1zG_modalCancel,.BiQ1zG_modalCopy{color:var(--hub-text-secondary);cursor:pointer;-webkit-user-select:none;user-select:none;background:0 0;border:none;border-radius:6px;padding:5px 14px;font-size:12px;line-height:18px;transition:color .12s,background .12s}.BiQ1zG_modalCancel:hover,.BiQ1zG_modalCopy:hover{color:var(--hub-text-primary);background:var(--hub-bg-hover)}.BiQ1zG_modalInstall{color:var(--hub-text-on-fill);background:var(--hub-btn-fill);cursor:pointer;-webkit-user-select:none;user-select:none;border:none;border-radius:6px;padding:5px 14px;font-size:12px;font-weight:600;line-height:18px;transition:background .12s}.BiQ1zG_modalInstall:hover{background:var(--hub-btn-hover)}.BiQ1zG_modalCopy:disabled,.BiQ1zG_modalInstall:disabled,.BiQ1zG_modalCancel:disabled,.BiQ1zG_modalClose:disabled,.BiQ1zG_uninstallConfirm:disabled{opacity:.55;cursor:not-allowed;pointer-events:none}.BiQ1zG_uninstallConfirm{color:#fff;background:var(--hub-danger);cursor:pointer;-webkit-user-select:none;user-select:none;border:none;border-radius:6px;padding:5px 14px;font-size:12px;font-weight:600;line-height:18px;transition:background .12s}.BiQ1zG_uninstallConfirm:hover{background:var(--hub-danger-hover)}.BiQ1zG_result{text-align:center;flex-direction:column;align-items:center;gap:5px;padding:10px 0 2px;display:flex}.BiQ1zG_resultCheck{background:var(--hub-success-tint);width:40px;height:40px;color:var(--hub-success);border-radius:50%;justify-content:center;align-items:center;margin-bottom:3px;display:inline-flex}.BiQ1zG_resultCheckIcon{flex-shrink:0;width:20px;height:20px}.BiQ1zG_resultTitle{color:var(--hub-text-primary);font-size:13px;font-weight:600;line-height:20px}.BiQ1zG_resultDesc{color:var(--hub-text-secondary);font-size:12px;line-height:18px}.BiQ1zG_resultRestarting{color:var(--hub-text-tertiary);padding:12px 0 6px;font-size:12px;line-height:18px}.BiQ1zG_restartLater{color:var(--hub-text-secondary);cursor:pointer;-webkit-user-select:none;user-select:none;background:0 0;border:none;border-radius:6px;padding:5px 14px;font-size:12px;line-height:18px;transition:color .12s,background .12s}.BiQ1zG_restartLater:hover{color:var(--hub-text-primary);background:var(--hub-bg-hover)}.BiQ1zG_restartNow{color:var(--hub-text-on-fill);background:var(--hub-btn-fill);cursor:pointer;-webkit-user-select:none;user-select:none;border:none;border-radius:6px;padding:5px 14px;font-size:12px;font-weight:600;line-height:18px;transition:background .12s}.BiQ1zG_restartNow:hover{background:var(--hub-btn-hover)}.BiQ1zG_restartNow:disabled{opacity:.55;cursor:not-allowed;pointer-events:none}.BiQ1zG_result .BiQ1zG_modalActions{justify-content:center;gap:10px;margin-top:0;padding:6px 0 2px}.BiQ1zG_result .BiQ1zG_modalActions .BiQ1zG_restartLater,.BiQ1zG_result .BiQ1zG_modalActions .BiQ1zG_restartNow{min-width:100px}.BiQ1zG_progress{margin:10px 0 2px}.BiQ1zG_progressHead{justify-content:flex-end;align-items:center;margin-bottom:3px;display:flex}.BiQ1zG_progressText{color:var(--hub-text-secondary);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px;line-height:14px}.BiQ1zG_progressTrack{background:var(--hub-border-2);border-radius:2px;height:4px;overflow:hidden}.BiQ1zG_progressFill{background:var(--hub-brand);border-radius:2px;height:100%;transition:width .32s}.BiQ1zG_progressFillFail{background:var(--hub-danger)}@keyframes BiQ1zG_overlayIn{0%{opacity:0}to{opacity:1}}@keyframes BiQ1zG_modalIn{0%{opacity:0;transform:translateY(6px)scale(.98)}to{opacity:1;transform:translateY(0)scale(1)}}.BiQ1zG_noticeList{flex-direction:column;gap:10px;padding-right:2px;display:flex}.BiQ1zG_noticeRow{border:1px solid var(--hub-border-2);background:var(--hub-bg-2);border-radius:8px;flex-direction:column;align-items:stretch;gap:6px;padding:10px 12px;display:flex}.BiQ1zG_noticeRowMain{align-items:center;gap:10px;width:100%;min-width:0;display:flex}.BiQ1zG_noticeBadgeOk,.BiQ1zG_noticeBadgeFail{border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;width:28px;height:28px;display:inline-flex;box-shadow:0 2px 6px #0000002e}.BiQ1zG_noticeBadgeOk{background:var(--hub-success)}.BiQ1zG_noticeBadgeFail{background:var(--hub-danger)}.BiQ1zG_noticeBadgeIcon{flex-shrink:0;width:12px;height:12px}.BiQ1zG_noticeMain{flex-direction:column;flex:1;gap:8px;min-width:0;display:flex}.BiQ1zG_noticeHead{align-items:center;gap:8px;min-width:0;display:flex}.BiQ1zG_noticeTextOk{color:var(--hub-success);flex-shrink:0;font-size:12px;font-weight:600;line-height:18px}.BiQ1zG_noticeTextFail{color:var(--hub-danger-text);flex-shrink:0;font-size:12px;font-weight:600;line-height:18px}.BiQ1zG_failList{flex-direction:column;gap:12px;padding-right:2px;display:flex}.BiQ1zG_failRow{border:1px solid var(--hub-border-2);background:var(--hub-bg-2);border-radius:8px;flex-direction:column;gap:8px;padding:10px 12px;display:flex}.BiQ1zG_failHead{align-items:center;gap:8px;min-width:0;display:flex}.BiQ1zG_failKind{border:1px solid #0000;border-radius:4px;flex-shrink:0;padding:0 6px;font-size:10px;font-weight:500;line-height:16px}.BiQ1zG_failKindInstall{color:var(--hub-danger-text);border-color:var(--hub-danger-border);background:var(--hub-danger-tint)}.BiQ1zG_failKindUninstall{color:var(--hub-warn);border-color:var(--hub-warn-border);background:var(--hub-warn-tint)}.BiQ1zG_failRepo{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--hub-brand);cursor:pointer;-webkit-user-select:none;user-select:none;flex:1;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12px;line-height:18px;text-decoration:none;overflow:hidden}.BiQ1zG_failRepo:hover{text-decoration:underline}.BiQ1zG_noticeFoot{justify-content:flex-end;align-items:center;display:flex}.BiQ1zG_noticeTime{color:var(--hub-text-tertiary);font-variant-numeric:tabular-nums;flex-shrink:0;font-size:11px;line-height:16px}.BiQ1zG_noticeRemove{width:22px;height:22px;color:var(--hub-text-tertiary);cursor:pointer;-webkit-user-select:none;user-select:none;background:0 0;border:none;border-radius:5px;flex-shrink:0;justify-content:center;align-items:center;margin-left:auto;transition:color .12s,background .12s;display:inline-flex}.BiQ1zG_noticeRemove:hover{color:var(--hub-danger-text);background:var(--hub-danger-tint)}.BiQ1zG_failCopy{color:var(--hub-text-tertiary);cursor:pointer;-webkit-user-select:none;user-select:none;background:0 0;border:none;border-radius:4px;flex-shrink:0;align-items:center;padding:2px 8px;font-size:11px;line-height:16px;transition:color .12s,background .12s;display:inline-flex}.BiQ1zG_failCopy:hover{color:var(--hub-text-secondary);background:var(--hub-bg-2)}.BiQ1zG_failEmpty{text-align:center;color:var(--hub-text-tertiary);padding:24px 0;font-size:12px;line-height:18px}.BiQ1zG_failClear{color:var(--hub-danger);cursor:pointer;-webkit-user-select:none;user-select:none;background:0 0;border:none;border-radius:6px;padding:5px 14px;font-size:12px;line-height:18px;transition:color .12s,background .12s}.BiQ1zG_failClear:hover{color:#fff;background:var(--hub-danger)}.BiQ1zG_failBigIssue{box-sizing:border-box;text-align:center;color:#fff;background:var(--hub-danger);border:1px solid var(--hub-danger);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:8px;width:100%;margin-top:4px;padding:3px 16px;font-size:13px;font-weight:600;line-height:18px;text-decoration:none;transition:background .12s,border-color .12s,box-shadow .12s;display:block}.BiQ1zG_failBigIssue:hover{background:var(--hub-danger-hover);border-color:var(--hub-danger-hover);box-shadow:0 3px 10px #d1242f59}.BiQ1zG_failPrepareHint{color:var(--hub-warning);background:var(--hub-warning-tint);border:1px solid var(--hub-warning-border);border-radius:6px;margin-top:6px;padding:8px 12px;font-size:12px;line-height:18px}";
1154
1270
  const tagId$3 = "dsh-plugin/Modal.module.css";
1155
1271
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
1156
1272
  const tag = document.createElement("style");
@@ -1160,90 +1276,93 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
1160
1276
  document.head.appendChild(tag);
1161
1277
  }
1162
1278
  var Modal_module_css_default = {
1163
- "queueRowTrack": "BiQ1zG_queueRowTrack",
1164
- "pendingRowStatus": "BiQ1zG_pendingRowStatus",
1165
- "resultRestarting": "BiQ1zG_resultRestarting",
1166
- "resultTitle": "BiQ1zG_resultTitle",
1167
- "linkIcon": "BiQ1zG_linkIcon",
1168
- "errorHint": "BiQ1zG_errorHint",
1169
- "modalCloseIcon": "BiQ1zG_modalCloseIcon",
1170
- "modalCmdText": "BiQ1zG_modalCmdText",
1171
- "failList": "BiQ1zG_failList",
1172
- "failCopy": "BiQ1zG_failCopy",
1173
- "pendingRowActions": "BiQ1zG_pendingRowActions",
1174
- "modalTitle": "BiQ1zG_modalTitle",
1175
- "toastIn": "BiQ1zG_toastIn",
1176
1279
  "queueRowTarget": "BiQ1zG_queueRowTarget",
1177
- "restartLater": "BiQ1zG_restartLater",
1178
- "progressFillFail": "BiQ1zG_progressFillFail",
1179
- "toast": "BiQ1zG_toast",
1280
+ "failClear": "BiQ1zG_failClear",
1281
+ "modalValue": "BiQ1zG_modalValue",
1180
1282
  "modalTitleQueued": "BiQ1zG_modalTitleQueued",
1181
- "queueSection": "BiQ1zG_queueSection",
1182
- "resultCheck": "BiQ1zG_resultCheck",
1183
- "progressFill": "BiQ1zG_progressFill",
1184
- "trustHint": "BiQ1zG_trustHint",
1185
- "modalCancel": "BiQ1zG_modalCancel",
1186
- "modalInstall": "BiQ1zG_modalInstall",
1283
+ "overlay": "BiQ1zG_overlay",
1187
1284
  "noticeRow": "BiQ1zG_noticeRow",
1188
- "failClear": "BiQ1zG_failClear",
1189
- "failEmpty": "BiQ1zG_failEmpty",
1190
- "overlayIn": "BiQ1zG_overlayIn",
1191
- "errorCopySoft": "BiQ1zG_errorCopySoft",
1285
+ "toast": "BiQ1zG_toast",
1286
+ "restartLater": "BiQ1zG_restartLater",
1192
1287
  "resultCheckIcon": "BiQ1zG_resultCheckIcon",
1193
- "failBigIssue": "BiQ1zG_failBigIssue",
1194
- "modalActions": "BiQ1zG_modalActions",
1195
- "progressTrack": "BiQ1zG_progressTrack",
1196
- "modalCmd": "BiQ1zG_modalCmd",
1197
- "failTime": "BiQ1zG_failTime",
1198
- "overlay": "BiQ1zG_overlay",
1199
- "failHead": "BiQ1zG_failHead",
1200
- "queueRowDesc": "BiQ1zG_queueRowDesc",
1288
+ "linkIcon": "BiQ1zG_linkIcon",
1289
+ "failKindUninstall": "BiQ1zG_failKindUninstall",
1201
1290
  "failRepo": "BiQ1zG_failRepo",
1202
- "modalCopy": "BiQ1zG_modalCopy",
1203
- "uninstallConfirm": "BiQ1zG_uninstallConfirm",
1204
- "modalHead": "BiQ1zG_modalHead",
1205
- "restartNow": "BiQ1zG_restartNow",
1206
- "progressHead": "BiQ1zG_progressHead",
1207
- "queueRowHead": "BiQ1zG_queueRowHead",
1208
- "noticeBadgeOk": "BiQ1zG_noticeBadgeOk",
1291
+ "modalCmd": "BiQ1zG_modalCmd",
1292
+ "modal": "BiQ1zG_modal",
1209
1293
  "queueRowPct": "BiQ1zG_queueRowPct",
1210
- "queueRowBody": "BiQ1zG_queueRowBody",
1211
- "modalTitleBusy": "BiQ1zG_modalTitleBusy",
1212
1294
  "failKind": "BiQ1zG_failKind",
1213
- "errorBox": "BiQ1zG_errorBox",
1214
- "modalLink": "BiQ1zG_modalLink",
1215
- "failKindUninstall": "BiQ1zG_failKindUninstall",
1216
- "modalRow": "BiQ1zG_modalRow",
1217
- "toastFail": "BiQ1zG_toastFail",
1218
- "progress": "BiQ1zG_progress",
1219
- "modalDesc": "BiQ1zG_modalDesc",
1220
- "failKindInstall": "BiQ1zG_failKindInstall",
1221
- "modal": "BiQ1zG_modal",
1222
- "stripCancel": "BiQ1zG_stripCancel",
1223
- "progressText": "BiQ1zG_progressText",
1224
- "modalClose": "BiQ1zG_modalClose",
1225
- "queueSectionTitle": "BiQ1zG_queueSectionTitle",
1295
+ "modalTitle": "BiQ1zG_modalTitle",
1296
+ "modalTitleBusy": "BiQ1zG_modalTitleBusy",
1226
1297
  "modalBody": "BiQ1zG_modalBody",
1227
- "modalLabel": "BiQ1zG_modalLabel",
1228
- "noticeMain": "BiQ1zG_noticeMain",
1229
- "noticeTextOk": "BiQ1zG_noticeTextOk",
1298
+ "modalCloseIcon": "BiQ1zG_modalCloseIcon",
1299
+ "errorCopySoft": "BiQ1zG_errorCopySoft",
1300
+ "modalCancel": "BiQ1zG_modalCancel",
1301
+ "overlayIn": "BiQ1zG_overlayIn",
1302
+ "modalClose": "BiQ1zG_modalClose",
1303
+ "modalCopy": "BiQ1zG_modalCopy",
1304
+ "modalCmdText": "BiQ1zG_modalCmdText",
1305
+ "queueSection": "BiQ1zG_queueSection",
1230
1306
  "queueRow": "BiQ1zG_queueRow",
1231
- "queueRowStatus": "BiQ1zG_queueRowStatus",
1232
- "noticeBadgeFail": "BiQ1zG_noticeBadgeFail",
1233
- "noticeBadgeIcon": "BiQ1zG_noticeBadgeIcon",
1234
- "modalIn": "BiQ1zG_modalIn",
1307
+ "errorHint": "BiQ1zG_errorHint",
1308
+ "noticeMain": "BiQ1zG_noticeMain",
1309
+ "noticeFoot": "BiQ1zG_noticeFoot",
1310
+ "failCopy": "BiQ1zG_failCopy",
1311
+ "failBigIssue": "BiQ1zG_failBigIssue",
1312
+ "modalRow": "BiQ1zG_modalRow",
1313
+ "queueRowBody": "BiQ1zG_queueRowBody",
1314
+ "queueRowTrack": "BiQ1zG_queueRowTrack",
1315
+ "errorBox": "BiQ1zG_errorBox",
1316
+ "progressHead": "BiQ1zG_progressHead",
1235
1317
  "noticeHead": "BiQ1zG_noticeHead",
1236
- "modalCmdCopy": "BiQ1zG_modalCmdCopy",
1237
- "failRow": "BiQ1zG_failRow",
1238
- "result": "BiQ1zG_result",
1239
- "errorModal": "BiQ1zG_errorModal",
1318
+ "progressFillFail": "BiQ1zG_progressFillFail",
1319
+ "noticeTextFail": "BiQ1zG_noticeTextFail",
1320
+ "noticeRemove": "BiQ1zG_noticeRemove",
1321
+ "modalLabel": "BiQ1zG_modalLabel",
1322
+ "pendingRowActions": "BiQ1zG_pendingRowActions",
1323
+ "resultTitle": "BiQ1zG_resultTitle",
1324
+ "restartNow": "BiQ1zG_restartNow",
1325
+ "noticeBadgeIcon": "BiQ1zG_noticeBadgeIcon",
1240
1326
  "failPrepareHint": "BiQ1zG_failPrepareHint",
1327
+ "noticeBadgeOk": "BiQ1zG_noticeBadgeOk",
1328
+ "failEmpty": "BiQ1zG_failEmpty",
1329
+ "result": "BiQ1zG_result",
1330
+ "modalInstall": "BiQ1zG_modalInstall",
1331
+ "noticeTextOk": "BiQ1zG_noticeTextOk",
1332
+ "noticeList": "BiQ1zG_noticeList",
1333
+ "queueSectionTitle": "BiQ1zG_queueSectionTitle",
1334
+ "stripCancel": "BiQ1zG_stripCancel",
1335
+ "progress": "BiQ1zG_progress",
1336
+ "modalDesc": "BiQ1zG_modalDesc",
1337
+ "modalIn": "BiQ1zG_modalIn",
1241
1338
  "errorTitle": "BiQ1zG_errorTitle",
1339
+ "failList": "BiQ1zG_failList",
1340
+ "noticeTime": "BiQ1zG_noticeTime",
1242
1341
  "queuedHint": "BiQ1zG_queuedHint",
1243
- "modalValue": "BiQ1zG_modalValue",
1244
1342
  "resultDesc": "BiQ1zG_resultDesc",
1245
- "noticeTextFail": "BiQ1zG_noticeTextFail",
1246
- "noticeList": "BiQ1zG_noticeList"
1343
+ "trustHint": "BiQ1zG_trustHint",
1344
+ "noticeRowMain": "BiQ1zG_noticeRowMain",
1345
+ "queueRowDesc": "BiQ1zG_queueRowDesc",
1346
+ "modalHead": "BiQ1zG_modalHead",
1347
+ "queueRowStatus": "BiQ1zG_queueRowStatus",
1348
+ "uninstallConfirm": "BiQ1zG_uninstallConfirm",
1349
+ "failKindInstall": "BiQ1zG_failKindInstall",
1350
+ "toastFail": "BiQ1zG_toastFail",
1351
+ "queueRowHead": "BiQ1zG_queueRowHead",
1352
+ "resultRestarting": "BiQ1zG_resultRestarting",
1353
+ "resultCheck": "BiQ1zG_resultCheck",
1354
+ "failRow": "BiQ1zG_failRow",
1355
+ "pendingRowStatus": "BiQ1zG_pendingRowStatus",
1356
+ "failHead": "BiQ1zG_failHead",
1357
+ "progressFill": "BiQ1zG_progressFill",
1358
+ "progressTrack": "BiQ1zG_progressTrack",
1359
+ "modalActions": "BiQ1zG_modalActions",
1360
+ "noticeBadgeFail": "BiQ1zG_noticeBadgeFail",
1361
+ "modalLink": "BiQ1zG_modalLink",
1362
+ "errorModal": "BiQ1zG_errorModal",
1363
+ "progressText": "BiQ1zG_progressText",
1364
+ "modalCmdCopy": "BiQ1zG_modalCmdCopy",
1365
+ "toastIn": "BiQ1zG_toastIn"
1247
1366
  };
1248
1367
  //#endregion
1249
1368
  //#region src/client/components/icons.tsx
@@ -1437,7 +1556,7 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
1437
1556
  strokeWidth: 2,
1438
1557
  strokeLinecap: "round",
1439
1558
  strokeLinejoin: "round"
1440
- }))), (0, react.createElement)("div", { className: Modal_module_css_default.resultTitle }, title), (0, react.createElement)("div", { className: Modal_module_css_default.resultDesc }, desc), (0, react.createElement)("div", { className: Modal_module_css_default.resultRestarting }, restarting ? t("restarting") : t("restartHint")), (0, react.createElement)("div", { className: Modal_module_css_default.modalActions }, (0, react.createElement)("button", {
1559
+ }))), (0, react.createElement)("div", { className: Modal_module_css_default.resultTitle }, title), desc ? (0, react.createElement)("div", { className: Modal_module_css_default.resultDesc }, desc) : null, (0, react.createElement)("div", { className: Modal_module_css_default.resultRestarting }, restarting ? t("restarting") : t("restartHint")), (0, react.createElement)("div", { className: Modal_module_css_default.modalActions }, (0, react.createElement)("button", {
1441
1560
  className: Modal_module_css_default.restartLater,
1442
1561
  onClick: onClose,
1443
1562
  disabled: restarting
@@ -1492,7 +1611,7 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
1492
1611
  title: t("copyInstallCommand"),
1493
1612
  role: "button",
1494
1613
  tabIndex: 0
1495
- }, (0, react.createElement)("span", { className: Modal_module_css_default.modalCmdText }, `dsh plugin add github:${plugin.source?.repo ?? ""}`), (0, react.createElement)("span", { className: Modal_module_css_default.modalCmdCopy }, (0, react.createElement)(CopyIcon), t("copyCmdLabel"))), task && task.status === "pending" ? (0, react.createElement)("div", { className: Modal_module_css_default.queuedHint }, t("queuedHint")) : null, task ? (0, react.createElement)(ProgressView, { task }) : null, (0, react.createElement)("div", { className: Modal_module_css_default.modalActions }, (0, react.createElement)("button", {
1614
+ }, (0, react.createElement)("span", { className: Modal_module_css_default.modalCmdText }, installCommandOf(plugin)), (0, react.createElement)("span", { className: Modal_module_css_default.modalCmdCopy }, (0, react.createElement)(CopyIcon), t("copyCmdLabel"))), task && task.status === "pending" ? (0, react.createElement)("div", { className: Modal_module_css_default.queuedHint }, t("queuedHint")) : null, task ? (0, react.createElement)(ProgressView, { task }) : null, (0, react.createElement)("div", { className: Modal_module_css_default.modalActions }, (0, react.createElement)("button", {
1496
1615
  className: Modal_module_css_default.modalCopy,
1497
1616
  disabled: busy,
1498
1617
  onClick: onCopy
@@ -1553,7 +1672,7 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
1553
1672
  }
1554
1673
  /** 预填插件仓库的 GitHub Issue 链接:标题带插件名,正文附完整错误信息,方便用户一键反馈。 */
1555
1674
  /** 安装/卸载失败弹窗:布局与失败记录一致(类型徽标 + 仓库超链接 + 隐蔽复制按钮),报错完整展示,底部一键提交 Issue。 */
1556
- function ErrorModal({ message, repo, kind, t, env, onCopy, onClose }) {
1675
+ function ErrorModal({ message, repo, kind, command, attempts, t, env, onCopy, onClose }) {
1557
1676
  const failureKind = classifyFailure(message);
1558
1677
  return (0, react.createElement)("div", {
1559
1678
  className: Modal_module_css_default.overlay,
@@ -1579,13 +1698,13 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
1579
1698
  onClick: () => onCopy(message)
1580
1699
  }, t("errorCopy"))), (0, react.createElement)("pre", { className: Modal_module_css_default.errorBox }, message), failureKind === "pluginPrepare" || failureKind === "pnpmIgnoredBuild" ? (0, react.createElement)("div", null, [(0, react.createElement)("div", { className: Modal_module_css_default.failPrepareHint }, failureKind === "pnpmIgnoredBuild" ? t("failIgnoredBuild") : /\[packaging\]/i.test(message) ? t("failPackagingHint") : t("failPrepareHint")), repo ? (0, react.createElement)("a", {
1581
1700
  className: Modal_module_css_default.failBigIssue,
1582
- href: pluginIssueUrl(repo, message, env),
1701
+ href: pluginIssueUrl(repo, message, env, command, attempts),
1583
1702
  target: "_blank",
1584
1703
  rel: "noopener noreferrer",
1585
1704
  title: t("failIssueHint")
1586
1705
  }, t("failIssueBig")) : null]) : repo ? (0, react.createElement)("a", {
1587
1706
  className: Modal_module_css_default.failBigIssue,
1588
- href: pluginIssueUrl(repo, message, env),
1707
+ href: pluginIssueUrl(repo, message, env, command, attempts),
1589
1708
  target: "_blank",
1590
1709
  rel: "noopener noreferrer",
1591
1710
  title: t("failIssueHint")
@@ -1616,12 +1735,11 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
1616
1735
  * failures keep their copy / fix / file-an-issue actions. Opened from the
1617
1736
  * header entry button.
1618
1737
  */
1619
- /** 记录时间紧凑展示:今年内 MM-DD HH:mm,跨年补年份前缀。 */
1738
+ /** 记录时间完整展示:YYYY-MM-DD HH:mm:ss(每条通知都带精确到秒的时间戳)。 */
1620
1739
  function fmtTime(at) {
1621
1740
  const d = new Date(at);
1622
1741
  const pad = (n) => String(n).padStart(2, "0");
1623
- const mmdd = `${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
1624
- return d.getFullYear() === (/* @__PURE__ */ new Date()).getFullYear() ? mmdd : `${d.getFullYear()}-${mmdd}`;
1742
+ return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
1625
1743
  }
1626
1744
  /** 圆形状态徽标内的白色图形:成功为对勾、失败为叉。 */
1627
1745
  function BadgeGlyph({ ok }) {
@@ -1645,7 +1763,7 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
1645
1763
  strokeLinecap: "round"
1646
1764
  }));
1647
1765
  }
1648
- function NotificationsModal({ records, tasks, pendingRestarts, t, env, onClose, onCopy, onClear, cancelTask, restarting, onRestart }) {
1766
+ function NotificationsModal({ records, tasks, pendingRestarts, t, env, onClose, onCopy, onClear, onRemove, cancelTask, restarting, onRestart }) {
1649
1767
  return (0, react.createElement)("div", {
1650
1768
  className: Modal_module_css_default.overlay,
1651
1769
  onClick: (e) => {
@@ -1699,35 +1817,43 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
1699
1817
  return (0, react.createElement)("div", {
1700
1818
  key: r.id,
1701
1819
  className: Modal_module_css_default.noticeRow
1702
- }, (0, react.createElement)("div", { className: r.ok ? Modal_module_css_default.noticeBadgeOk : Modal_module_css_default.noticeBadgeFail }, (0, react.createElement)(BadgeGlyph, { ok: r.ok })), (0, react.createElement)("div", { className: Modal_module_css_default.noticeMain }, (0, react.createElement)("div", { className: Modal_module_css_default.noticeHead }, (0, react.createElement)("span", { className: r.ok ? Modal_module_css_default.noticeTextOk : Modal_module_css_default.noticeTextFail }, r.ok ? r.kind === "install" ? t("installDone") : t("uninstallDone") : r.kind === "install" ? t("errorTitleInstall") : t("errorTitleUninstall")), r.repo ? (0, react.createElement)("a", {
1820
+ }, (0, react.createElement)("div", { className: Modal_module_css_default.noticeRowMain }, (0, react.createElement)("div", { className: r.ok ? Modal_module_css_default.noticeBadgeOk : Modal_module_css_default.noticeBadgeFail }, (0, react.createElement)(BadgeGlyph, { ok: r.ok })), (0, react.createElement)("div", { className: Modal_module_css_default.noticeMain }, (0, react.createElement)("div", { className: Modal_module_css_default.noticeHead }, (0, react.createElement)("span", { className: r.ok ? Modal_module_css_default.noticeTextOk : Modal_module_css_default.noticeTextFail }, r.ok ? r.kind === "install" ? t("installDone") : t("uninstallDone") : r.kind === "install" ? t("errorTitleInstall") : t("errorTitleUninstall")), r.repo ? (0, react.createElement)("a", {
1703
1821
  className: Modal_module_css_default.failRepo,
1704
1822
  href: pluginSiteUrl(r.repo),
1705
1823
  target: "_blank",
1706
1824
  rel: "noopener noreferrer",
1707
1825
  title: r.repo
1708
- }, r.repo) : null, (0, react.createElement)("span", {
1709
- className: Modal_module_css_default.failTime,
1710
- title: new Date(r.at).toLocaleString()
1711
- }, fmtTime(r.at)), !r.ok && (0, react.createElement)("button", {
1826
+ }, r.repo) : null, !r.ok && (0, react.createElement)("button", {
1712
1827
  className: Modal_module_css_default.failCopy,
1713
1828
  onClick: () => onCopy(r.message)
1714
- }, t("failCopy"))), !r.ok && (() => {
1829
+ }, t("failCopy")), (0, react.createElement)("button", {
1830
+ className: Modal_module_css_default.noticeRemove,
1831
+ "aria-label": t("removeNotification"),
1832
+ title: t("removeNotification"),
1833
+ onClick: (e) => {
1834
+ e.stopPropagation();
1835
+ onRemove(r.id);
1836
+ }
1837
+ }, (0, react.createElement)(CloseIcon))), !r.ok && (() => {
1715
1838
  const kind = classifyFailure(r.message);
1716
1839
  if (kind === "pluginPrepare" || kind === "pnpmIgnoredBuild") return (0, react.createElement)("div", null, [(0, react.createElement)("div", { className: Modal_module_css_default.failPrepareHint }, kind === "pnpmIgnoredBuild" ? t("failIgnoredBuild") : /\[packaging\]/i.test(r.message) ? t("failPackagingHint") : t("failPrepareHint")), r.repo ? (0, react.createElement)("a", {
1717
1840
  className: Modal_module_css_default.failBigIssue,
1718
- href: pluginIssueUrl(r.repo, r.message, env),
1841
+ href: pluginIssueUrl(r.repo, r.message, env, r.command, r.attempts),
1719
1842
  target: "_blank",
1720
1843
  rel: "noopener noreferrer",
1721
1844
  title: t("failIssueHint")
1722
1845
  }, t("failIssueBig")) : null]);
1723
1846
  return r.repo ? (0, react.createElement)("a", {
1724
1847
  className: Modal_module_css_default.failBigIssue,
1725
- href: pluginIssueUrl(r.repo, r.message, env),
1848
+ href: pluginIssueUrl(r.repo, r.message, env, r.command, r.attempts),
1726
1849
  target: "_blank",
1727
1850
  rel: "noopener noreferrer",
1728
1851
  title: t("failIssueHint")
1729
1852
  }, t("failIssueBig")) : null;
1730
- })()));
1853
+ })())), (0, react.createElement)("div", { className: Modal_module_css_default.noticeFoot }, (0, react.createElement)("span", {
1854
+ className: Modal_module_css_default.noticeTime,
1855
+ title: new Date(r.at).toLocaleString()
1856
+ }, fmtTime(r.at))));
1731
1857
  })), (0, react.createElement)("div", { className: Modal_module_css_default.modalActions }, records.length > 0 ? (0, react.createElement)("button", {
1732
1858
  className: Modal_module_css_default.failClear,
1733
1859
  onClick: onClear
@@ -1813,16 +1939,16 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
1813
1939
  }
1814
1940
  var Dropdown_module_css_default = {
1815
1941
  "dropdownPanel": "B_Gxsq_dropdownPanel",
1816
- "dropdownCountActive": "B_Gxsq_dropdownCountActive",
1817
- "dropdownCount": "B_Gxsq_dropdownCount",
1818
- "dropdown": "B_Gxsq_dropdown",
1819
1942
  "dropdownArrowOpen": "B_Gxsq_dropdownArrowOpen",
1820
- "dropdownLabel": "B_Gxsq_dropdownLabel",
1821
1943
  "dropdownItemActive": "B_Gxsq_dropdownItemActive",
1822
- "dropdownItem": "B_Gxsq_dropdownItem",
1823
- "dropdownBtn": "B_Gxsq_dropdownBtn",
1944
+ "dropdownCountActive": "B_Gxsq_dropdownCountActive",
1945
+ "dropdownLabel": "B_Gxsq_dropdownLabel",
1946
+ "dropdown": "B_Gxsq_dropdown",
1824
1947
  "dropdownArrow": "B_Gxsq_dropdownArrow",
1825
- "dropdownItemLabel": "B_Gxsq_dropdownItemLabel"
1948
+ "dropdownBtn": "B_Gxsq_dropdownBtn",
1949
+ "dropdownItem": "B_Gxsq_dropdownItem",
1950
+ "dropdownItemLabel": "B_Gxsq_dropdownItemLabel",
1951
+ "dropdownCount": "B_Gxsq_dropdownCount"
1826
1952
  };
1827
1953
  //#endregion
1828
1954
  //#region src/client/components/Dropdown.tsx
@@ -1927,7 +2053,7 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
1927
2053
  }
1928
2054
  //#endregion
1929
2055
  //#region \0dsh-css:src/client/styles/List.module.css.mjs
1930
- const css$1 = "._3XaZHa_body{flex-direction:column;flex:1;min-height:0;display:flex}._3XaZHa_list{flex-direction:column;flex:1;gap:6px;min-height:0;padding:2px 4px 4px 2px;display:flex;overflow-y:auto}._3XaZHa_card{border:1px solid var(--hub-border-2);background:var(--hub-bg-1);border-radius:8px;justify-content:space-between;align-items:stretch;gap:12px;padding:9px 12px;transition:border-color .12s,background .12s;display:flex}._3XaZHa_card:hover{border-color:var(--hub-brand);background:var(--hub-bg-2)}._3XaZHa_cardMain{flex-direction:column;gap:4px;min-width:0;display:flex}._3XaZHa_cardHead{align-items:center;gap:6px;min-width:0;display:flex}._3XaZHa_cardTitle{white-space:nowrap;text-overflow:ellipsis;font-size:13px;font-weight:600;line-height:18px;overflow:hidden}._3XaZHa_categoryBadge,._3XaZHa_verified,._3XaZHa_versionBadge,._3XaZHa_updateBadge{border:1px solid #0000;border-radius:4px;flex-shrink:0;padding:0 6px;font-size:10px;line-height:16px}._3XaZHa_categoryBadge{color:var(--hub-brand);border-color:var(--hub-border-ghost)}._3XaZHa_verified{color:var(--hub-success);border-color:var(--hub-success-border)}._3XaZHa_versionBadge{color:var(--hub-text-secondary);border-color:var(--hub-border-input)}._3XaZHa_updateBadge{color:var(--hub-warn);border-color:var(--hub-warn-border);background:var(--hub-warn-tint)}._3XaZHa_desc{color:var(--hub-text-secondary);-webkit-line-clamp:2;-webkit-box-orient:vertical;margin:0;font-size:12px;line-height:18px;display:-webkit-box;overflow:hidden}._3XaZHa_topics{flex-wrap:wrap;align-items:center;gap:4px;min-width:0;display:flex}._3XaZHa_topic{color:var(--hub-text-tertiary);background:var(--hub-bg-3);white-space:nowrap;border-radius:4px;flex-shrink:0;padding:0 6px;font-size:10px;line-height:16px}._3XaZHa_cardSide{flex-direction:column;flex-shrink:0;justify-content:space-between;align-items:flex-end;gap:6px;display:flex}._3XaZHa_stats{flex-direction:column;align-items:flex-end;gap:1px;display:flex}._3XaZHa_star{color:var(--hub-warn);white-space:nowrap;font-size:11px;line-height:16px}._3XaZHa_fork{color:var(--hub-text-tertiary);white-space:nowrap;font-size:11px;line-height:16px}._3XaZHa_date{color:var(--hub-text-tertiary);white-space:nowrap;font-size:10px;line-height:14px}._3XaZHa_installBtn,._3XaZHa_installBtnCopied,._3XaZHa_installBtnInstalled,._3XaZHa_installBtnUpdate,._3XaZHa_uninstallBtn,._3XaZHa_detailBtn{cursor:pointer;border-radius:6px;padding:2px 10px;font-size:11px;line-height:18px;transition:color .12s,border-color .12s,background .12s}._3XaZHa_installBtnInstalled{color:var(--hub-success);background:var(--hub-success-tint);cursor:default;-webkit-user-select:none;user-select:none;border:none}._3XaZHa_installBtnUpdate{color:#fff;background:var(--hub-warn);-webkit-user-select:none;user-select:none;border:none;font-weight:500}._3XaZHa_installBtnUpdate:hover{background:var(--hub-warn-strong)}._3XaZHa_uninstallBtn{color:var(--hub-danger);-webkit-user-select:none;user-select:none;background:0 0;border:none}._3XaZHa_uninstallBtn:hover{color:#fff;background:var(--hub-danger)}._3XaZHa_installBtn{color:var(--hub-text-on-fill);background:var(--hub-btn-fill);-webkit-user-select:none;user-select:none;border:none;font-weight:500}._3XaZHa_installBtn:hover{background:var(--hub-btn-hover)}._3XaZHa_detailBtn{color:var(--hub-text-secondary);-webkit-user-select:none;user-select:none;background:0 0;border:none;align-items:center;text-decoration:none;display:inline-flex}._3XaZHa_detailBtn:hover{color:var(--hub-text-primary);background:var(--hub-bg-hover)}._3XaZHa_actions{align-items:center;gap:6px;display:flex}._3XaZHa_installBtnCopied{color:var(--hub-success);background:var(--hub-success-tint);-webkit-user-select:none;user-select:none;border:none}._3XaZHa_state{text-align:center;min-height:160px;color:var(--hub-text-tertiary);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:8px;padding:24px;font-size:12px;line-height:18px;display:flex}._3XaZHa_stateTitle{color:var(--hub-text-primary);font-size:13px;font-weight:600}._3XaZHa_stateDesc{max-width:420px}._3XaZHa_retryBtn{color:var(--hub-text-secondary);cursor:pointer;-webkit-user-select:none;user-select:none;background:0 0;border:none;border-radius:6px;margin-top:4px;padding:4px 12px;font-size:12px;line-height:18px}._3XaZHa_retryBtn:hover{color:var(--hub-text-primary);background:var(--hub-bg-hover)}._3XaZHa_footer{border-top:1px solid var(--hub-border-1);flex-shrink:0;justify-content:flex-end;align-items:center;gap:8px;padding:6px 4px 0;display:flex}._3XaZHa_footLink{color:var(--hub-brand);white-space:nowrap;-webkit-user-select:none;user-select:none;font-size:11px;line-height:16px;text-decoration:none}._3XaZHa_footLink:hover{text-decoration:underline}";
2056
+ const css$1 = "._3XaZHa_body{flex-direction:column;flex:1;min-height:0;display:flex}._3XaZHa_list{flex-direction:column;flex:1;gap:6px;min-height:0;padding:2px 4px 4px 2px;display:flex;overflow-y:auto}._3XaZHa_card{border:1px solid var(--hub-border-2);background:var(--hub-bg-1);border-radius:8px;justify-content:space-between;align-items:stretch;gap:12px;padding:9px 12px;transition:border-color .12s,background .12s;display:flex}._3XaZHa_card:hover{border-color:var(--hub-brand);background:var(--hub-bg-2)}._3XaZHa_cardMain{flex-direction:column;gap:4px;min-width:0;display:flex}._3XaZHa_cardHead{align-items:center;gap:6px;min-width:0;display:flex}._3XaZHa_cardTitle{white-space:nowrap;text-overflow:ellipsis;font-size:13px;font-weight:600;line-height:18px;overflow:hidden}._3XaZHa_categoryBadge,._3XaZHa_verified,._3XaZHa_versionBadge,._3XaZHa_updateBadge{border:1px solid #0000;border-radius:4px;flex-shrink:0;padding:0 6px;font-size:10px;line-height:16px}._3XaZHa_categoryBadge{color:var(--hub-brand);border-color:var(--hub-border-ghost)}._3XaZHa_verified{color:var(--hub-success);border-color:var(--hub-success-border)}._3XaZHa_versionBadge{color:var(--hub-text-secondary);border-color:var(--hub-border-input)}._3XaZHa_updateBadge{color:var(--hub-warn);border-color:var(--hub-warn-border);background:var(--hub-warn-tint)}._3XaZHa_desc{color:var(--hub-text-secondary);-webkit-line-clamp:2;-webkit-box-orient:vertical;margin:0;font-size:12px;line-height:18px;display:-webkit-box;overflow:hidden}._3XaZHa_topics{flex-wrap:wrap;align-items:center;gap:4px;min-width:0;display:flex}._3XaZHa_topic{color:var(--hub-text-tertiary);background:var(--hub-bg-3);white-space:nowrap;border-radius:4px;flex-shrink:0;padding:0 6px;font-size:10px;line-height:16px}._3XaZHa_cardSide{flex-direction:column;flex-shrink:0;justify-content:space-between;align-items:flex-end;gap:6px;display:flex}._3XaZHa_stats{flex-direction:column;align-items:flex-end;gap:1px;display:flex}._3XaZHa_star{color:var(--hub-warn);white-space:nowrap;font-size:11px;line-height:16px}._3XaZHa_fork{color:var(--hub-text-tertiary);white-space:nowrap;font-size:11px;line-height:16px}._3XaZHa_date{color:var(--hub-text-tertiary);white-space:nowrap;font-size:10px;line-height:14px}._3XaZHa_installBtn,._3XaZHa_installBtnCopied,._3XaZHa_installBtnInstalled,._3XaZHa_installBtnUpdate,._3XaZHa_uninstallBtn,._3XaZHa_detailBtn{cursor:pointer;border-radius:6px;padding:2px 10px;font-size:11px;line-height:18px;transition:color .12s,border-color .12s,background .12s}._3XaZHa_installBtnInstalled{color:var(--hub-success);background:var(--hub-success-tint);cursor:default;-webkit-user-select:none;user-select:none;border:none}._3XaZHa_installBtnUpdate{color:#fff;background:var(--hub-warn);-webkit-user-select:none;user-select:none;border:none;font-weight:500}._3XaZHa_installBtnUpdate:hover{background:var(--hub-warn-strong)}._3XaZHa_uninstallBtn{color:var(--hub-danger);background:var(--hub-danger-tint);-webkit-user-select:none;user-select:none;border:none}._3XaZHa_uninstallBtn:hover{color:#fff;background:var(--hub-danger-hover)}._3XaZHa_installBtn{color:var(--hub-text-on-fill);background:var(--hub-btn-fill);-webkit-user-select:none;user-select:none;border:none;font-weight:500}._3XaZHa_installBtn:hover{background:var(--hub-btn-hover)}._3XaZHa_detailBtn{color:var(--hub-text-secondary);-webkit-user-select:none;user-select:none;background:0 0;border:none;align-items:center;text-decoration:none;display:inline-flex}._3XaZHa_detailBtn:hover{color:var(--hub-text-primary);background:var(--hub-bg-hover)}._3XaZHa_actions{align-items:center;gap:6px;display:flex}._3XaZHa_installBtnCopied{color:var(--hub-success);background:var(--hub-success-tint);-webkit-user-select:none;user-select:none;border:none}._3XaZHa_state{text-align:center;min-height:160px;color:var(--hub-text-tertiary);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:8px;padding:24px;font-size:12px;line-height:18px;display:flex}._3XaZHa_stateTitle{color:var(--hub-text-primary);font-size:13px;font-weight:600}._3XaZHa_stateDesc{max-width:420px}._3XaZHa_retryBtn{color:var(--hub-text-secondary);cursor:pointer;-webkit-user-select:none;user-select:none;background:0 0;border:none;border-radius:6px;margin-top:4px;padding:4px 12px;font-size:12px;line-height:18px}._3XaZHa_retryBtn:hover{color:var(--hub-text-primary);background:var(--hub-bg-hover)}._3XaZHa_footer{border-top:1px solid var(--hub-border-1);flex-shrink:0;justify-content:flex-end;align-items:center;gap:8px;padding:6px 4px 0;display:flex}._3XaZHa_footLink{color:var(--hub-brand);white-space:nowrap;-webkit-user-select:none;user-select:none;font-size:11px;line-height:16px;text-decoration:none}._3XaZHa_footLink:hover{text-decoration:underline}";
1931
2057
  const tagId$1 = "dsh-plugin/List.module.css";
1932
2058
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
1933
2059
  const tag = document.createElement("style");
@@ -1937,37 +2063,37 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
1937
2063
  document.head.appendChild(tag);
1938
2064
  }
1939
2065
  var List_module_css_default = {
1940
- "footer": "_3XaZHa_footer",
1941
- "state": "_3XaZHa_state",
1942
- "actions": "_3XaZHa_actions",
1943
- "updateBadge": "_3XaZHa_updateBadge",
1944
- "installBtnInstalled": "_3XaZHa_installBtnInstalled",
1945
- "stateDesc": "_3XaZHa_stateDesc",
1946
- "body": "_3XaZHa_body",
2066
+ "topic": "_3XaZHa_topic",
1947
2067
  "verified": "_3XaZHa_verified",
1948
- "topics": "_3XaZHa_topics",
1949
- "desc": "_3XaZHa_desc",
1950
- "installBtn": "_3XaZHa_installBtn",
1951
2068
  "uninstallBtn": "_3XaZHa_uninstallBtn",
1952
- "detailBtn": "_3XaZHa_detailBtn",
2069
+ "actions": "_3XaZHa_actions",
2070
+ "stateTitle": "_3XaZHa_stateTitle",
1953
2071
  "cardMain": "_3XaZHa_cardMain",
2072
+ "installBtn": "_3XaZHa_installBtn",
2073
+ "cardTitle": "_3XaZHa_cardTitle",
2074
+ "star": "_3XaZHa_star",
2075
+ "card": "_3XaZHa_card",
2076
+ "categoryBadge": "_3XaZHa_categoryBadge",
2077
+ "fork": "_3XaZHa_fork",
2078
+ "stateDesc": "_3XaZHa_stateDesc",
2079
+ "retryBtn": "_3XaZHa_retryBtn",
2080
+ "updateBadge": "_3XaZHa_updateBadge",
2081
+ "detailBtn": "_3XaZHa_detailBtn",
2082
+ "versionBadge": "_3XaZHa_versionBadge",
2083
+ "state": "_3XaZHa_state",
2084
+ "date": "_3XaZHa_date",
1954
2085
  "stats": "_3XaZHa_stats",
1955
- "installBtnCopied": "_3XaZHa_installBtnCopied",
1956
- "stateTitle": "_3XaZHa_stateTitle",
2086
+ "body": "_3XaZHa_body",
2087
+ "cardHead": "_3XaZHa_cardHead",
1957
2088
  "list": "_3XaZHa_list",
2089
+ "installBtnCopied": "_3XaZHa_installBtnCopied",
2090
+ "cardSide": "_3XaZHa_cardSide",
1958
2091
  "footLink": "_3XaZHa_footLink",
1959
- "versionBadge": "_3XaZHa_versionBadge",
2092
+ "topics": "_3XaZHa_topics",
2093
+ "installBtnInstalled": "_3XaZHa_installBtnInstalled",
2094
+ "desc": "_3XaZHa_desc",
1960
2095
  "installBtnUpdate": "_3XaZHa_installBtnUpdate",
1961
- "cardHead": "_3XaZHa_cardHead",
1962
- "star": "_3XaZHa_star",
1963
- "fork": "_3XaZHa_fork",
1964
- "cardSide": "_3XaZHa_cardSide",
1965
- "cardTitle": "_3XaZHa_cardTitle",
1966
- "date": "_3XaZHa_date",
1967
- "retryBtn": "_3XaZHa_retryBtn",
1968
- "topic": "_3XaZHa_topic",
1969
- "categoryBadge": "_3XaZHa_categoryBadge",
1970
- "card": "_3XaZHa_card"
2096
+ "footer": "_3XaZHa_footer"
1971
2097
  };
1972
2098
  //#endregion
1973
2099
  //#region src/client/lib/format.ts
@@ -2108,7 +2234,7 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
2108
2234
  const [uninstallDone, setUninstallDone] = (0, react.useState)(false);
2109
2235
  /** 结果视图「立即重启」:请求宿主重启后进入等待,服务回来后整页刷新 */
2110
2236
  const [restarting, setRestarting] = (0, react.useState)(false);
2111
- /** 操作失败完整信息 + 所属插件仓库 + 失败类型(决定弹窗标题「安装失败/卸载失败」) */
2237
+ /** 操作失败完整信息 + 所属插件仓库 + 失败类型(决定弹窗标题「安装失败/卸载失败」)+ 实际执行的安装命令 + 尝试过的安装方式(issue 预填用) */
2112
2238
  const [errorMsg, setErrorMsg] = (0, react.useState)(null);
2113
2239
  /** 安装/卸载任务通知记录:localStorage 持久化,成败即落盘,即使错过弹窗也能回来查看 */
2114
2240
  const [notifications, setNotifications] = (0, react.useState)(() => loadNotifications());
@@ -2149,16 +2275,20 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
2149
2275
  repo: repo ?? ""
2150
2276
  }));
2151
2277
  },
2152
- onError: (message, repo, kind) => {
2278
+ onError: (message, repo, kind, command, attempts) => {
2153
2279
  setErrorMsg({
2154
2280
  message,
2155
2281
  repo,
2156
- kind
2282
+ kind,
2283
+ command,
2284
+ attempts
2157
2285
  });
2158
2286
  setNotifications(addFailure({
2159
2287
  kind,
2160
2288
  repo: repo ?? "",
2161
- message
2289
+ message,
2290
+ command,
2291
+ attempts
2162
2292
  }));
2163
2293
  },
2164
2294
  installPlugin: confirmPlugin,
@@ -2216,10 +2346,10 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
2216
2346
  return ok;
2217
2347
  }
2218
2348
  };
2219
- /** 弹窗动作一:复制安装命令到剪贴板,引导去终端粘贴执行。 */
2349
+ /** 弹窗动作一:复制安装命令到剪贴板,引导去终端粘贴执行(npm 通道显示包名命令)。 */
2220
2350
  const copyCommand = async (p) => {
2221
2351
  const repo = p.source?.repo ?? "";
2222
- if (await doCopy(`dsh plugin add github:${repo}`)) {
2352
+ if (await doCopy(installCommandOf(p))) {
2223
2353
  setCopied(repo);
2224
2354
  setToast({
2225
2355
  id: Date.now(),
@@ -2363,6 +2493,8 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
2363
2493
  message: errorMsg.message,
2364
2494
  repo: errorMsg.repo,
2365
2495
  kind: errorMsg.kind,
2496
+ command: errorMsg.command,
2497
+ attempts: errorMsg.attempts,
2366
2498
  t,
2367
2499
  env,
2368
2500
  onCopy: (text) => {
@@ -2388,6 +2520,7 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
2388
2520
  });
2389
2521
  },
2390
2522
  onClear: () => setNotifications(clearNotifications()),
2523
+ onRemove: (id) => setNotifications(removeNotification(id)),
2391
2524
  cancelTask: queue.cancelTask,
2392
2525
  restarting,
2393
2526
  onRestart: () => {
@@ -2397,7 +2530,7 @@ window.__ModuleLoader__.load({ id: "dsh-plugin", factory: (require) => {
2397
2530
  }
2398
2531
  //#endregion
2399
2532
  //#region \0dsh-css:src/client/styles/tokens.module.css.mjs
2400
- const css = ":root,body[data-ds-dark-theme]{--hub-text-primary:var(--dsw-alias-label-primary,#1f2328);--hub-text-secondary:var(--dsw-alias-label-secondary,#6b7280);--hub-text-tertiary:var(--dsw-alias-label-tertiary,#8b93a1);--hub-text-disabled:var(--dsw-alias-label-disabled,#aab1bd);--hub-text-on-fill:var(--dsw-alias-label-primary-foreground,#fff);--hub-bg-1:var(--dsw-alias-bg-layer-1,#fff);--hub-bg-2:var(--dsw-alias-bg-layer-2,#80808014);--hub-bg-3:#8080801a;--hub-bg-btn:#8080801f;--hub-bg-hover:var(--dsw-alias-interactive-bg-hover,#80808029);--hub-bg-on-fill:#80808038;--hub-border-1:var(--dsw-alias-border-l1,#eceef1);--hub-border-2:var(--dsw-alias-border-l2,#e5e7eb);--hub-border-ghost:var(--dsw-alias-button-ghost-active-border,#4f6ef740);--hub-border-input:var(--dsw-alias-input-border,#6b728040);--hub-brand:var(--dsw-alias-state-business-primary,#4f6ef7);--hub-brand-hover:#3b5bdb;--hub-brand-tint:#4f6ef70f;--hub-brand-tint-strong:#4f6ef71f;--hub-brand-border:#4f6ef759;--hub-brand-border-soft:#4f6ef738;--hub-purple-1:#4f46e5;--hub-purple-2:#7c3aed;--hub-purple-border:#8b5cf68c;--hub-purple-tint:#4f46e514;--hub-purple-shadow:#4f46e547;--hub-purple-shadow-strong:#7c3aed6b;--hub-btn-fill:var(--dsw-alias-button-primary-fill,#1f2328);--hub-btn-hover:var(--dsw-alias-button-primary-hover,#43454a);--hub-success:var(--dsw-alias-state-success-primary,#1a7f37);--hub-success-tint:#22c55e24;--hub-success-border:var(--dsw-alias-state-success-secondary,#1a7f374d);--hub-warn:var(--dsw-alias-state-warn-primary,#b8860b);--hub-warn-tint:#b8860b14;--hub-warn-border:#b8860b59;--hub-warn-strong:#b8860bd9;--hub-warning:var(--dsw-alias-state-warning-primary,#b45309);--hub-warning-tint:#b4530914;--hub-warning-border:#b453094d;--hub-danger:var(--dsw-alias-state-danger-primary,#d1242f);--hub-danger-hover:var(--dsw-alias-state-danger-hover,#b91c1c);--hub-danger-strong:#b0202a;--hub-danger-text:#e5484d;--hub-danger-tint:#e5484d14;--hub-danger-tint-weak:#e5484d0d;--hub-danger-border:#e5484d59;--hub-danger-border-soft:#e5484d47;--hub-danger-soft:#d1242f14}body[data-ds-dark-theme]{--hub-bg-btn:#ffffff1f}";
2533
+ const css = ":root,body[data-ds-dark-theme]{--hub-text-primary:var(--dsw-alias-label-primary,#1f2328);--hub-text-secondary:var(--dsw-alias-label-secondary,#6b7280);--hub-text-tertiary:var(--dsw-alias-label-tertiary,#8b93a1);--hub-text-disabled:var(--dsw-alias-label-disabled,#aab1bd);--hub-text-on-fill:var(--dsw-alias-label-primary-foreground,#fff);--hub-bg-1:var(--dsw-alias-bg-layer-1,#fff);--hub-bg-2:var(--dsw-alias-bg-layer-2,#80808014);--hub-bg-3:#8080801a;--hub-bg-btn:#8080801f;--hub-bg-hover:var(--dsw-alias-interactive-bg-hover,#80808029);--hub-bg-on-fill:#80808038;--hub-border-1:var(--dsw-alias-border-l1,#eceef1);--hub-border-2:var(--dsw-alias-border-l2,#e5e7eb);--hub-border-ghost:var(--dsw-alias-button-ghost-active-border,#4f6ef740);--hub-border-input:var(--dsw-alias-input-border,#6b728040);--hub-brand:var(--dsw-alias-state-business-primary,#4f6ef7);--hub-brand-hover:#3b5bdb;--hub-brand-tint:#4f6ef70f;--hub-brand-tint-strong:#4f6ef71f;--hub-brand-border:#4f6ef759;--hub-brand-border-soft:#4f6ef738;--hub-purple-1:#4f46e5;--hub-purple-2:#7c3aed;--hub-purple-border:#8b5cf68c;--hub-purple-tint:#4f46e514;--hub-purple-shadow:#4f46e547;--hub-purple-shadow-strong:#7c3aed6b;--hub-btn-fill:var(--dsw-alias-button-primary-fill,#1f2328);--hub-btn-hover:var(--dsw-alias-button-primary-hover,#43454a);--hub-success:#16a34a;--hub-success-tint:#16a34a1f;--hub-success-border:#16a34a4d;--hub-warn:var(--dsw-alias-state-warn-primary,#b8860b);--hub-warn-tint:#b8860b14;--hub-warn-border:#b8860b59;--hub-warn-strong:#b8860bd9;--hub-warning:var(--dsw-alias-state-warning-primary,#b45309);--hub-warning-tint:#b4530914;--hub-warning-border:#b453094d;--hub-danger:var(--dsw-alias-state-danger-primary,#d1242f);--hub-danger-hover:var(--dsw-alias-state-danger-hover,#b91c1c);--hub-danger-strong:#b0202a;--hub-danger-text:#e5484d;--hub-danger-tint:#e5484d14;--hub-danger-tint-weak:#e5484d0d;--hub-danger-border:#e5484d59;--hub-danger-border-soft:#e5484d47;--hub-danger-soft:#d1242f14}body[data-ds-dark-theme]{--hub-bg-btn:#ffffff1f;--hub-success:#22c55e;--hub-success-tint:#22c55e29;--hub-success-border:#22c55e59}";
2401
2534
  const tagId = "dsh-plugin/tokens.module.css";
2402
2535
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
2403
2536
  const tag = document.createElement("style");