@xrxs-ai/dsh-xrxs-plugins-store 0.2.2 → 0.2.4

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/lib/client.js CHANGED
@@ -30,7 +30,7 @@ __export(index_exports, {
30
30
  inject: () => inject
31
31
  });
32
32
  module.exports = __toCommonJS(index_exports);
33
- var import_react11 = require("react");
33
+ var import_react12 = require("react");
34
34
 
35
35
  // src/client/MarketplaceApp.tsx
36
36
  var import_react9 = require("react");
@@ -140,6 +140,12 @@ function installPlugin(name, version, sourceType) {
140
140
  function uninstallPlugin(name) {
141
141
  return hostPost("/api/uninstall", { name });
142
142
  }
143
+ function checkSelfUpdate() {
144
+ return hostGet("/api/self-update");
145
+ }
146
+ function applySelfUpdate(version) {
147
+ return hostPost("/api/self-update/apply", { version });
148
+ }
143
149
 
144
150
  // src/client/data/developer-api.ts
145
151
  var BASE = "/api/developer/plugins";
@@ -2202,7 +2208,7 @@ function runInstallOnce(args, retried) {
2202
2208
  }
2203
2209
  args.onToast(
2204
2210
  "success",
2205
- `${args.name}@${args.version} \u5B89\u88C5\u5B8C\u6210,\u5B8C\u5168\u9000\u51FA\u5E76\u91CD\u542F\u5E94\u7528\u540E\u751F\u6548`
2211
+ `${args.name}@${args.version} ${args.verb ?? "\u5B89\u88C5"}\u5B8C\u6210,\u5B8C\u5168\u9000\u51FA\u5E76\u91CD\u542F\u5E94\u7528\u540E\u751F\u6548`
2206
2212
  );
2207
2213
  return { applied: true };
2208
2214
  }).catch(async (error) => {
@@ -2210,7 +2216,7 @@ function runInstallOnce(args, retried) {
2210
2216
  const approved = await args.onBuildBlocked(error.pendingBuilds ?? []);
2211
2217
  if (approved) return runInstallOnce(args, true);
2212
2218
  }
2213
- notice({ title: `\u5B89\u88C5\u5931\u8D25:${args.name}@${args.version}`, body: messageOf(error) });
2219
+ notice({ title: `${args.verb ?? "\u5B89\u88C5"}\u5931\u8D25:${args.name}@${args.version}`, body: messageOf(error) });
2214
2220
  return { applied: false };
2215
2221
  });
2216
2222
  }
@@ -2550,15 +2556,20 @@ function InstallButton(props) {
2550
2556
  const [buildConfirm, setBuildConfirm] = (0, import_react6.useState)(null);
2551
2557
  const [approving, setApproving] = (0, import_react6.useState)(false);
2552
2558
  const compat = checkCompat(props.compatRange, props.dshVersion);
2559
+ const verb = props.installed?.updateAvailable === true ? "\u66F4\u65B0" : "\u5B89\u88C5";
2560
+ const variant = verb === "\u66F4\u65B0" ? "update" : "primary";
2561
+ if (props.installed !== void 0 && !props.installed.updateAvailable) {
2562
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "xps-mk-install", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Button, { size: props.size ?? "medium", variant: "primary", disabled: true, title: "\u5DF2\u5B89\u88C5\u6700\u65B0\u7248\u672C,\u91CD\u88C5\u540C\u7248\u672C\u4E0D\u4F1A\u5237\u65B0", children: "\u5DF2\u5B89\u88C5" }) });
2563
+ }
2553
2564
  if (compat.ok === false) {
2554
2565
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "xps-mk-install", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2555
2566
  Button,
2556
2567
  {
2557
2568
  size: props.size ?? "medium",
2558
- variant: "primary",
2569
+ variant,
2559
2570
  disabled: true,
2560
2571
  title: compat.reason ?? "\u4E0E\u672C\u673A dsh \u7248\u672C\u4E0D\u517C\u5BB9",
2561
- children: "\u5B89\u88C5"
2572
+ children: verb
2562
2573
  }
2563
2574
  ) });
2564
2575
  }
@@ -2568,9 +2579,12 @@ function InstallButton(props) {
2568
2579
  name: props.pluginName,
2569
2580
  version: props.version,
2570
2581
  sourceType: props.sourceType,
2582
+ verb,
2571
2583
  onToast: props.onToast,
2572
2584
  onNotice: setNotice,
2573
2585
  onBuildBlocked: (packages) => new Promise((resolve) => setBuildConfirm({ packages, resolve }))
2586
+ }).then((result) => {
2587
+ if (result.applied) props.onInstalled?.();
2574
2588
  }).finally(() => setPhase("idle"));
2575
2589
  };
2576
2590
  const handleBuildApprove = () => {
@@ -2589,15 +2603,18 @@ function InstallButton(props) {
2589
2603
  };
2590
2604
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
2591
2605
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "xps-mk-install", onClick: (e) => e.stopPropagation(), children: phase === "confirm" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "xps-mk-confirm", children: [
2592
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Button, { size: "small", variant: "primary", onClick: doInstall, title: `\u786E\u8BA4\u5B89\u88C5 ${props.pluginName}@${props.version}`, children: "\u786E\u8BA4\u5B89\u88C5" }),
2593
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Button, { size: "small", variant: "ghost", onClick: () => setPhase("idle"), title: "\u53D6\u6D88\u5B89\u88C5", children: "\u53D6\u6D88" })
2606
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Button, { size: "small", variant, onClick: doInstall, title: `\u786E\u8BA4${verb} ${props.pluginName}@${props.version}`, children: [
2607
+ "\u786E\u8BA4",
2608
+ verb
2609
+ ] }),
2610
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Button, { size: "small", variant: "ghost", onClick: () => setPhase("idle"), title: `\u53D6\u6D88${verb}`, children: "\u53D6\u6D88" })
2594
2611
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2595
2612
  Button,
2596
2613
  {
2597
2614
  size: props.size ?? "medium",
2598
- variant: "primary",
2615
+ variant,
2599
2616
  disabled: phase === "installing",
2600
- title: phase === "installing" ? "\u5B89\u88C5\u4E2D\u2026" : compat.ok === null ? "\u517C\u5BB9\u6027\u672A\u77E5:\u65E0\u6CD5\u8BFB\u53D6\u672C\u673A dsh \u7248\u672C" : `\u5B89\u88C5 ${props.pluginName}@${props.version}`,
2617
+ title: phase === "installing" ? `${verb}\u4E2D\u2026` : compat.ok === null ? "\u517C\u5BB9\u6027\u672A\u77E5:\u65E0\u6CD5\u8BFB\u53D6\u672C\u673A dsh \u7248\u672C" : `${verb} ${props.pluginName}@${props.version}`,
2601
2618
  onClick: () => {
2602
2619
  if (compat.ok === null) {
2603
2620
  props.onToast("info", "\u65E0\u6CD5\u786E\u8BA4\u4E0E\u672C\u673A dsh \u7248\u672C\u7684\u517C\u5BB9\u6027");
@@ -2605,7 +2622,7 @@ function InstallButton(props) {
2605
2622
  }
2606
2623
  setPhase("confirm");
2607
2624
  },
2608
- children: phase === "installing" ? "\u5B89\u88C5\u4E2D\u2026" : "\u5B89\u88C5"
2625
+ children: phase === "installing" ? `${verb}\u4E2D\u2026` : verb
2609
2626
  }
2610
2627
  ) }),
2611
2628
  notice !== null && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
@@ -2722,6 +2739,8 @@ function PluginRow(props) {
2722
2739
  compatRange: p.compatRange,
2723
2740
  sourceType: p.sourceType,
2724
2741
  dshVersion: props.dshVersion,
2742
+ installed,
2743
+ onInstalled: props.onInstalled,
2725
2744
  size: "small",
2726
2745
  onToast: props.onToast
2727
2746
  }
@@ -2960,6 +2979,7 @@ function MarketPage(props) {
2960
2979
  plugin: p,
2961
2980
  dshVersion,
2962
2981
  installed: installedMap.get(p.name),
2982
+ onInstalled: () => setReloadFlag((flag) => flag + 1),
2963
2983
  onOpen: props.onOpenDetail ?? (() => {
2964
2984
  }),
2965
2985
  onToast: toasts.push
@@ -3211,7 +3231,14 @@ function PluginDetailPage(props) {
3211
3231
  const [selectedVersion, setSelectedVersion] = (0, import_react8.useState)(null);
3212
3232
  const [reloadFlag, setReloadFlag] = (0, import_react8.useState)(0);
3213
3233
  const [dshVersion, setDshVersion] = (0, import_react8.useState)(null);
3234
+ const [installed, setInstalled] = (0, import_react8.useState)(null);
3214
3235
  const toasts = useToasts();
3236
+ const loadInstalled = (0, import_react8.useCallback)(
3237
+ (name) => {
3238
+ getInstalled().then((list) => setInstalled(list.find((item) => item.name === name) ?? null)).catch(() => setInstalled(null));
3239
+ },
3240
+ []
3241
+ );
3215
3242
  (0, import_react8.useEffect)(() => {
3216
3243
  let alive = true;
3217
3244
  getHostInfo().then((info) => {
@@ -3227,6 +3254,8 @@ function PluginDetailPage(props) {
3227
3254
  setStatus("loading");
3228
3255
  setDetail(null);
3229
3256
  setSelectedVersion(null);
3257
+ setInstalled(null);
3258
+ if (pluginId !== "") loadInstalled(pluginId);
3230
3259
  getPluginDetail(pluginId).then((d) => {
3231
3260
  if (!alive) return;
3232
3261
  if (d === null) {
@@ -3242,7 +3271,7 @@ function PluginDetailPage(props) {
3242
3271
  return () => {
3243
3272
  alive = false;
3244
3273
  };
3245
- }, [pluginId, reloadFlag]);
3274
+ }, [pluginId, reloadFlag, loadInstalled]);
3246
3275
  const backButton = /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "xps-mk-back", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Button, { size: "small", variant: "ghost", onClick: () => props.onBack?.(), title: "\u8FD4\u56DE\u5E02\u573A\u5217\u8868", children: "\u2190 \u8FD4\u56DE\u5E02\u573A" }) });
3247
3276
  if (status === "loading") {
3248
3277
  return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "xps-mk-detail", children: [
@@ -3321,6 +3350,8 @@ function PluginDetailPage(props) {
3321
3350
  compatRange: displayCompatRange,
3322
3351
  sourceType: detail.sourceType,
3323
3352
  dshVersion,
3353
+ installed: installed ?? void 0,
3354
+ onInstalled: () => loadInstalled(detail.name),
3324
3355
  onToast: toasts.push
3325
3356
  }
3326
3357
  )
@@ -3374,7 +3405,7 @@ function PluginDetailPage(props) {
3374
3405
  }
3375
3406
 
3376
3407
  // src/client/theme.css
3377
- var theme_default = "/* \u85AA\u4EBA\u85AA\u4E8B\u5E02\u573A client \u4E3B\u9898:\u5BF9\u6807\u5BBF\u4E3B\u5B98\u65B9\u63D2\u4EF6\u7BA1\u7406\u5668(PluginManagerPage.module.css)\u89C6\u89C9\u8BED\u8A00,\n * \u5168\u90E8\u8D70\u5BBF\u4E3B --dsw-alias-* token(\u5E26\u515C\u5E95\u503C,token \u7F3A\u5931\u65F6\u53EF\u72EC\u7ACB\u9884\u89C8)\u3002 */\n\n/* ---------- \u9875\u9762\u9AA8\u67B6 ---------- */\n\n.xps-app {\n display: flex;\n width: 100%;\n height: 100%;\n background: var(--dsw-alias-bg-layer-1, #ffffff);\n color: var(--dsw-alias-label-primary, #1f2329);\n font-family: inherit;\n}\n\n/* \u5DE6\u4FA7\u4E8C\u7EA7\u5BFC\u822A(B \xB7 \u56FE\u6807\u5C45\u4E0A\u84DD\u8C03\u7EC6\u7EBF\u98CE:\u5706\u89D2\u5757 r10,\u9009\u4E2D\u6D45\u84DD\u5E95+\u54C1\u724C\u84DD\u5B57) */\n.xps-nav {\n flex: none;\n width: 92px;\n box-sizing: border-box;\n padding: 16px 10px;\n display: flex;\n flex-direction: column;\n gap: 3px;\n border-right: 0.5px solid var(--dsw-alias-border-l2, #dee0e3);\n}\n\n.xps-nav-item {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 3px;\n padding: 9px 0 7px;\n border: none;\n border-radius: 10px;\n background: transparent;\n cursor: pointer;\n color: var(--dsw-alias-label-secondary, #646a73);\n font-family: inherit;\n font-size: 12px;\n line-height: 18px;\n}\n\n.xps-nav-item:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, 0.04));\n}\n\n.xps-nav-item-active,\n.xps-nav-item-active:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 10%, var(--dsw-alias-bg-layer-1, #ffffff));\n color: var(--dsw-alias-brand-primary, #3370ff);\n font-weight: 600;\n}\n\n.xps-nav-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n line-height: 0;\n}\n\n.xps-nav-label {\n white-space: nowrap;\n}\n\n/* \u5185\u5BB9\u533A:\u5B98\u65B9\u9875\u540C\u6B3E\u5C45\u4E2D\u5217(28px \u9876 / clamp \u4FA7 / 48px \u5E95,960 \u4E0A\u9650) */\n.xps-content {\n flex: 1;\n min-width: 0;\n overflow: auto;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 28px clamp(24px, 4vw, 48px) 48px;\n}\n\n.xps-content > * {\n width: 100%;\n max-width: 960px;\n box-sizing: border-box;\n}\n\n/* \u9875\u5934:flex space-between,\u6807\u9898 20/28/500,\u526F\u9898 13/20 secondary */\n.xps-page-head {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 16px;\n margin-bottom: 20px;\n}\n\n.xps-page-title {\n margin: 0;\n font-size: 20px;\n line-height: 28px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n/* \u6807\u9898\u884C\u5185\u6302\u5FBD\u6807(\u8BA1\u6570\u7B49\u72B6\u6001\u4FE1\u606F\u8DDF\u968F\u6807\u9898,\u4E0D\u6DF7\u8FDB\u53F3\u4E0A\u89D2\u64CD\u4F5C\u533A) */\n.xps-title-with-badges {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.xps-page-intro {\n margin: 4px 0 0;\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary, #646a73);\n}\n\n.xps-page-actions {\n flex: none;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n/* \u533A\u5757\u9898 14/22/500 */\n.xps-section-title {\n margin: 0;\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n/* ---------- \u6587\u5B57\u8272\u9636\u5DE5\u5177\u7C7B ---------- */\n\n.xps-text-secondary {\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary, #646a73);\n}\n\n/* \u8BF4\u660E/\u8BA1\u6570:12/18 tertiary */\n.xps-text-caption {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary, #8f959e);\n}\n\n/* \u5305\u540D/\u7248\u672C\u53F7\u7B49 mono */\n.xps-mono {\n font-family: var(--dsw-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);\n}\n\n/* ---------- \u6309\u94AE(\u80F6\u56CA) ---------- */\n\n.xps-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n height: 32px;\n box-sizing: border-box;\n padding: 0 14px;\n border-radius: 16px;\n border: 0.5px solid var(--dsw-alias-border-l3, #d0d3d9);\n background: transparent;\n color: var(--dsw-alias-label-primary, #1f2329);\n font-family: inherit;\n font-size: 13px;\n line-height: 20px;\n cursor: pointer;\n white-space: nowrap;\n}\n\n.xps-btn:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, rgba(31, 35, 41, 0.06));\n}\n\n.xps-btn:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n/* \u4E3B\u6309\u94AE(B \u65B9\u5411\u8BC6\u522B\u8272):\u5B9E\u5FC3\u54C1\u724C\u84DD + \u767D\u5B57,hover \u52A0\u6DF1 */\n.xps-btn-primary {\n background: var(--dsw-alias-brand-primary, #3370ff);\n border-color: transparent;\n color: var(--dsw-alias-label-primary-foreground, #ffffff);\n}\n\n.xps-btn-primary:hover:not(:disabled) {\n background: var(--dsw-alias-button-primary-hover, color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 85%, #000000));\n}\n\n/* \u63CF\u8FB9\u4E3B\u6309\u94AE(\u5DF2\u5B89\u88C5/\u66F4\u65B0\u6001):\u54C1\u724C\u84DD\u63CF\u8FB9 + \u84DD\u5B57\u900F\u660E\u5E95 */\n.xps-btn-outline {\n border: 1px solid var(--dsw-alias-brand-primary, #3370ff);\n background: transparent;\n color: var(--dsw-alias-brand-primary, #3370ff);\n}\n\n.xps-btn-outline:hover:not(:disabled) {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 8%, transparent);\n}\n\n/* \u5371\u9669\u6309\u94AE:\u590D\u7528\u6B21\u6309\u94AE,\u7EA2\u5B57 + 30% \u7EA2\u6846,hover \u6362\u7EA2 wash */\n.xps-btn-danger {\n color: var(--dsw-alias-state-error-primary, #d83931);\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d83931) 30%, transparent);\n}\n\n.xps-btn-danger:hover:not(:disabled) {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d83931) 8%, transparent);\n}\n\n.xps-btn-ghost {\n border-color: transparent;\n background: transparent;\n color: var(--dsw-alias-label-secondary, #646a73);\n}\n\n.xps-btn-ghost:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n.xps-btn-sm {\n height: 26px;\n padding: 0 10px;\n font-size: 12px;\n line-height: 18px;\n border-radius: 13px;\n}\n\n/* \u56FE\u6807\u6309\u94AE:28\xD728 \u5168\u5706 */\n/* \u56FE\u6807\u6309\u94AE:\u4E0E .xps-btn \u540C\u9AD8(32px)\u3001\u540C 0.5px \u8FB9\u6846,\u73AF\u5F62\u5237\u65B0\u7B49\u56FE\u6807\u6309\u94AE\u4E0E\u6587\u5B57\u6309\u94AE\u5E76\u6392\u65F6\u6BD4\u4F8B\u4E00\u81F4 */\n.xps-icon-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n flex: none;\n padding: 0;\n border: 0.5px solid var(--dsw-alias-border-l3, #d0d3d9);\n border-radius: 999px;\n background: transparent;\n color: var(--dsw-alias-label-secondary, #646a73);\n cursor: pointer;\n font-family: inherit;\n font-size: 14px;\n transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease,\n opacity 0.15s ease;\n}\n\n.xps-icon-btn:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, rgba(31, 35, 41, 0.06));\n border-color: var(--dsw-alias-border-l4, #a8abb2);\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n.xps-icon-btn:active:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-active, rgba(38, 49, 72, 0.1));\n transform: scale(0.96);\n}\n\n.xps-icon-btn:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n/* ---------- \u8F93\u5165\u6846 ---------- */\n\n.xps-input {\n width: 100%;\n box-sizing: border-box;\n height: 32px;\n padding: 0 10px;\n border-radius: 8px;\n border: 0.5px solid var(--dsw-alias-border-l4, #c9cdd4);\n background: var(--dsw-alias-bg-layer-1, #ffffff);\n color: var(--dsw-alias-label-primary, #1f2329);\n font-family: inherit;\n font-size: 13px;\n line-height: 20px;\n outline: none;\n}\n\n.xps-input::placeholder {\n color: var(--dsw-alias-label-tertiary, #8f959e);\n}\n\n/* \u8F93\u5165\u6846 hover:\u8FB9\u6846\u8F7B\u62AC\u4E00\u6863,\u4E0E focus \u7684\u54C1\u724C\u84DD\u533A\u5206 */\n.xps-input:hover:not(:disabled):not(:focus) {\n border-color: var(--dsw-alias-border-l4, #a8abb2);\n}\n\n.xps-input:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.xps-input:focus {\n border-color: var(--dsw-alias-brand-primary, #3370ff);\n box-shadow: inset 0 0 0 0.5px var(--dsw-alias-brand-primary, #3370ff);\n}\n\n/* ---------- \u5FBD\u6807(\u80F6\u56CA 11/17/500) ---------- */\n\n.xps-badge {\n display: inline-flex;\n align-items: center;\n padding: 1px 8px;\n border-radius: 999px;\n border: 0.5px solid var(--dsw-alias-border-l3, #dee0e3);\n font-size: 11px;\n line-height: 17px;\n font-weight: 500;\n white-space: nowrap;\n background: var(--dsw-alias-bg-layer-2, #f5f6f7);\n color: var(--dsw-alias-label-secondary, #646a73);\n}\n\n.xps-badge-success {\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary, #1f9d55) 10%, var(--dsw-alias-bg-layer-1, #ffffff));\n border-color: color-mix(in srgb, var(--dsw-alias-state-success-primary, #1f9d55) 30%, transparent);\n color: var(--dsw-alias-state-success-primary, #1f9d55);\n}\n\n.xps-badge-warning {\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary, #d98708) 10%, var(--dsw-alias-bg-layer-1, #ffffff));\n border-color: color-mix(in srgb, var(--dsw-alias-state-warn-primary, #d98708) 30%, transparent);\n color: var(--dsw-alias-state-warn-primary, #d98708);\n}\n\n.xps-badge-error {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d83931) 10%, var(--dsw-alias-bg-layer-1, #ffffff));\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d83931) 30%, transparent);\n color: var(--dsw-alias-state-error-primary, #d83931);\n}\n\n.xps-badge-info {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 10%, var(--dsw-alias-bg-layer-1, #ffffff));\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 30%, transparent);\n color: var(--dsw-alias-brand-primary, #3370ff);\n}\n\n/* ---------- \u5217\u8868\u884C(\u53D1\u4E1D\u7EBF\u6E05\u5355\u5F0F:\u4E0E\u5E02\u573A\u884C .xps-mk-row\u3001\u5F00\u53D1\u8005\u884C .xps-dev-item \u540C\u8303\u5F0F) ---------- */\n\n.xps-row-list {\n display: flex;\n flex-direction: column;\n}\n\n.xps-row {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 8px;\n border-bottom: 0.5px solid var(--dsw-alias-border-l2, #dee0e3);\n border-radius: 0;\n background: transparent;\n cursor: pointer;\n min-width: 0;\n transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease,\n opacity 0.15s ease;\n}\n\n/* \u6E05\u5355\u672B\u884C\u53BB\u53D1\u4E1D\u7EBF(\u4E0E .xps-dev-item:last-child \u540C\u505A\u6CD5) */\n.xps-row-list > .xps-row:last-child {\n border-bottom: none;\n}\n\n/* \u884C hover:\u6574\u884C\u80CC\u666F\u8F7B\u62AC,\u4E0E\u5E02\u573A\u884C\u540C\u5C42\u7EA7 */\n.xps-row:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(31, 35, 41, 0.06));\n}\n\n/* \u56FE\u6807\u6846 40\xD740\u30010.5px hairline\u3001r10 */\n.xps-row-icon {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n border: 0.5px solid var(--dsw-alias-border-l3, #d0d3d9);\n border-radius: 10px;\n color: var(--dsw-alias-label-secondary, #646a73);\n font-size: 18px;\n line-height: 1;\n}\n\n.xps-row-main {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.xps-row-title {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n/* \u884C\u9898 14/20/500(\u5B98\u65B9\u884C\u6807\u9898\u89C4\u683C)\u3002\u5C55\u793A\u540D\u4E0E\u300C\u56DE\u9000\u7684\u5305\u540D\u300D\u90FD\u7528\u666E\u901A\u5B57\u4F53:\n * \u6807\u8BC6\u7B26\u53EA\u5728\u540E\u9762\u7684 .xps-row-pkg \u91CC\u8D70\u7B49\u5BBD,\u4E0E\u5E02\u573A/\u5F00\u53D1\u8005\u9875\u540C\u4E00\u89C4\u5219\u3002 */\n.xps-row-name {\n font-size: 14px;\n line-height: 20px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* \u5C55\u793A\u540D\u4E4B\u540E\u7684\u5305\u540D(\u6807\u8BC6\u7B26,\u7B49\u5BBD\u5C0F\u5B57 11px;\u4E0E .xps-mk-row-pkg / .xps-dev-pkg \u540C\u89C4\u683C) */\n.xps-row-pkg {\n flex: none;\n font-size: 11px;\n line-height: 17px;\n color: var(--dsw-alias-label-tertiary, #8f959e);\n}\n\n/* \u884C\u63CF\u8FF0 13/18 tertiary + \u5355\u884C\u622A\u65AD */\n.xps-row-desc {\n font-size: 13px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary, #8f959e);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.xps-row-end {\n flex: none;\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n\n/* ---------- \u6A2A\u5E45/\u63D0\u793A\u6761 ---------- */\n\n.xps-banner {\n margin: 0 0 12px;\n padding: 8px 12px;\n border-radius: 10px;\n font-size: 12px;\n line-height: 18px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary, #d98708) 12%, var(--dsw-alias-bg-layer-1, #ffffff));\n border: 0.5px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary, #d98708) 30%, transparent);\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n.xps-banner-error {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d83931) 10%, var(--dsw-alias-bg-layer-1, #ffffff));\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d83931) 30%, transparent);\n color: var(--dsw-alias-state-error-primary, #d83931);\n}\n\n/* ---------- \u7A7A\u6001(dashed 0.5px l2 + r8 + pad 18 \u5C45\u4E2D 13 tertiary) ---------- */\n\n.xps-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n /* \u56FE\u6807 / \u6807\u9898 / \u63CF\u8FF0\u7EDF\u4E00 8px \u8282\u594F */\n gap: 8px;\n padding: 18px;\n border: 0.5px dashed var(--dsw-alias-border-l2, #dee0e3);\n border-radius: 8px;\n color: var(--dsw-alias-label-tertiary, #8f959e);\n font-size: 13px;\n line-height: 20px;\n text-align: center;\n}\n\n.xps-empty-icon {\n font-size: 24px;\n line-height: 1;\n}\n\n.xps-empty-title {\n font-size: 13px;\n line-height: 20px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n/* \u6309\u94AE\u4E0E\u4E0A\u65B9\u6587\u6848\u5408\u8BA1 12px(\u7236\u7EA7 gap 8 + \u8FD9\u91CC 4) */\n.xps-empty-action {\n margin-top: 4px;\n}\n\n/* \u300C\u6211\u7684\u300D\u9875\u672A\u767B\u5F55\u5F15\u5BFC\u5361:\u6D41\u7A0B\u8BF4\u660E + \u524D\u5F80\u5F00\u53D1\u8005\u5E73\u53F0(\u65E0\u4EE4\u724C\u8F93\u5165\u5165\u53E3,\u767B\u5F55\u53EA\u5728\u8BBE\u7F6E\u91CC) */\n.xps-guide {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 20px 24px;\n border: 0.5px dashed var(--dsw-alias-border-l2, #dee0e3);\n border-radius: 8px;\n}\n\n.xps-guide-title {\n font-size: 14px;\n line-height: 20px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n.xps-guide-desc {\n margin: 0;\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary, #646a73);\n}\n\n.xps-guide-steps {\n margin: 0;\n padding-left: 20px;\n display: flex;\n flex-direction: column;\n gap: 6px;\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary, #646a73);\n}\n\n.xps-guide-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 4px;\n}\n\n.xps-guide-url {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary, #8f959e);\n word-break: break-all;\n}\n\n/* ---------- \u4E0A\u4F20\u8868\u5355(\u6253\u5305\u63D0\u4EA4) ---------- */\n\n/* \u62D6\u5165 / \u9009\u62E9\u533A:dashed \u5927\u9776\u533A;\u62D6\u60AC\u65F6\u6574\u533A\u54C1\u724C\u84DD\u63CF\u8FB9 + \u6D45\u84DD wash(.xps-up-drop-over) */\n.xps-up-drop {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n padding: 28px 16px;\n margin-bottom: 12px;\n text-align: center;\n border: 0.5px dashed var(--dsw-alias-border-l4, #c9cdd4);\n border-radius: 12px;\n cursor: pointer;\n transition: background-color 0.15s ease, border-color 0.15s ease;\n}\n\n.xps-up-drop:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(31, 35, 41, 0.04));\n}\n\n.xps-up-drop-over,\n.xps-up-drop-over:hover {\n border-color: var(--dsw-alias-brand-primary, #3370ff);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 8%, transparent);\n}\n\n.xps-up-drop-icon {\n font-size: 28px;\n line-height: 1;\n}\n\n.xps-up-drop-title {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n.xps-up-drop-actions {\n display: flex;\n gap: 8px;\n margin-top: 8px;\n}\n\n/* \u5206\u7EC4\u5361\u7247:\u8BC6\u522B\u7ED3\u679C / \u63D2\u4EF6\u4FE1\u606F\u5404\u4E00\u5F20,\u66FF\u4EE3\u6563\u843D\u7684\u884C\u5185\u8FB9\u8DDD */\n.xps-up-card {\n padding: 14px 16px;\n margin-bottom: 12px;\n border: 0.5px solid var(--dsw-alias-border-l2, #dee0e3);\n border-radius: 10px;\n}\n\n.xps-up-card-actions {\n margin-left: auto;\n display: flex;\n gap: 4px;\n}\n\n/* \u4E0A\u4F20\u9875\u53CC\u680F:\u5DE6\u300C\u9009\u62E9\u5185\u5BB9 + \u8BC6\u522B\u7ED3\u679C\u300D\u53F3\u300C\u63D2\u4EF6\u4FE1\u606F + \u63D0\u4EA4\u300D,\u4E0E\u5176\u4ED6\u9875\u5171\u7528\u6807\u51C6 960 \u5217\u3002\n * \u5B50\u5143\u7D20\u76F4\u63A5\u505A grid item \u5E76\u663E\u5F0F\u5B9A\u4F4D:\u5DE6\u680F 1 \u5217\u4E09\u4E2A\u5757,\u53F3\u680F 2 \u5217\u4E24\u4E2A\u5757(r2-5 \u62C9\u4F38),\n * \u4E24\u680F\u5E95\u8FB9\u5929\u7136\u5BF9\u9F50;\u7A84\u5C4F(<880px)\u9000\u5316\u4E3A\u5355\u5217\u3001\u6309 DOM \u987A\u5E8F\u5806\u53E0 */\n.xps-up-layout {\n display: grid;\n grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);\n gap: 16px 16px;\n align-items: stretch;\n}\n\n/* \u76F4\u63A5\u5B50\u5143\u7D20\u5373\u7F51\u683C\u9879:\u5757\u81EA\u8EAB\u7684\u5916\u8FB9\u8DDD\u5F52\u96F6,\u95F4\u8DDD\u7EDF\u4E00\u4EA4\u7ED9 grid gap */\n.xps-up-side-drop,\n.xps-up-side-notice,\n.xps-up-side-scan,\n.xps-up-main-form {\n margin-bottom: 0;\n}\n\n.xps-up-layout > * {\n min-width: 0;\n min-height: 0;\n}\n\n.xps-up-side-drop { grid-column: 1; grid-row: 1; }\n.xps-up-side-notice { grid-column: 1; grid-row: 2; }\n.xps-up-side-scan { grid-column: 1; grid-row: 3 / 6; }\n.xps-up-main-form { grid-column: 2; grid-row: 1 / 6; }\n.xps-up-main-submit { grid-column: 2; grid-row: 6; }\n\n/* \u7A84\u5C4F:\u53CC\u680F\u5148\u4E8E\u8868\u5355\u6805\u683C\u584C\u6210\u5355\u5217,\u907F\u514D\u5B57\u6BB5\u88AB\u538B\u5230\u6362\u884C\u96BE\u8BFB */\n@media (max-width: 1120px) {\n .xps-up-grid {\n grid-template-columns: 1fr;\n }\n}\n\n@media (max-width: 1024px) {\n .xps-up-layout {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .xps-up-layout > [class^='xps-up-'],\n .xps-up-layout > [class*=' xps-up-'] {\n grid-column: auto;\n grid-row: auto;\n }\n}\n\n/* \u53F3\u680F\u7A7A\u6001:\u4E0E\u5DE6\u4FA7\u62D6\u5165\u533A\u540C\u6B3E\u865A\u7EBF\u5361\u7247,\u7B49\u9AD8\u5C45\u4E2D;\u70B9\u51FB\u7B49\u540C\u300C\u9009\u62E9\u76EE\u5F55\u300D\u3002\n * \u62C9\u4F38\u7531 grid item \u81EA\u8EAB\u5B8C\u6210(display: flex \u6491\u6EE1\u5206\u914D\u5230\u7684\u884C),\u4E0D\u4F9D\u8D56\u767E\u5206\u6BD4\u9AD8\u5EA6 */\n.xps-up-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n box-sizing: border-box;\n align-self: stretch;\n height: 100%;\n min-height: 200px;\n padding: 28px 16px;\n text-align: center;\n border: 0.5px dashed var(--dsw-alias-border-l2, #dee0e3);\n border-radius: 12px;\n cursor: pointer;\n transition: background-color 0.15s ease, border-color 0.15s ease;\n}\n\n.xps-up-empty:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(31, 35, 41, 0.04));\n}\n\n/* \u7A7A\u6001\u53CC\u5361:\u5DE6\u62D6\u5165\u533A + \u53F3\u6D41\u7A0B\u8BF4\u660E,\u5355\u884C\u7F51\u683C\u5929\u7136\u7B49\u9AD8(\u5404\u81EA stretch) */\n.xps-up-empty-grid {\n display: grid;\n grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);\n gap: 16px;\n align-items: stretch;\n}\n\n.xps-up-empty-grid .xps-up-drop {\n justify-content: center;\n margin-bottom: 0;\n}\n\n/* \u6D41\u7A0B\u8BF4\u660E\u5361\u53EA\u505A\u5C55\u793A:\u53BB\u6389\u624B\u578B\u4E0E\u60AC\u505C\u53CD\u9988 */\n.xps-up-empty-static,\n.xps-up-empty-static:hover {\n justify-content: center;\n cursor: default;\n background: transparent;\n}\n\n@media (max-width: 1024px) {\n .xps-up-empty-grid {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n/* \u7B2C 1 \u6B65\u5361\u91CC\u300C\u8FD8\u5DEE\u4EE3\u7801\u76EE\u5F55\u300D\u7684\u5C31\u5730\u63D0\u793A\u6761 */\n.xps-up-source-missing {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 10px;\n padding: 8px 10px;\n border-radius: 8px;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-warning-primary, #b25e09);\n background: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #dc6803) 8%, transparent);\n}\n\n/* \u7A7A\u6001\u53F3\u680F\u7684\u53D1\u5E03\u6D41\u7A0B:\u586B\u5145\u539F\u672C\u7684\u6B7B\u7A7A\u95F4,\u517C\u505A\u5F15\u5BFC(\u5DE6\u5BF9\u9F50\u6E05\u5355,\u5C45\u4E2D\u653E\u7F6E) */\n.xps-up-flow {\n display: flex;\n flex-direction: column;\n gap: 12px;\n width: 100%;\n max-width: 380px;\n padding: 8px 4px;\n}\n\n.xps-up-flow-title {\n font-size: 13px;\n line-height: 20px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n.xps-up-flow-item {\n display: flex;\n gap: 10px;\n text-align: left;\n}\n\n.xps-up-flow-no {\n flex: none;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n margin-top: 1px;\n border-radius: 50%;\n font-size: 11px;\n font-weight: 500;\n color: var(--dsw-alias-brand-primary, #3370ff);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 10%, transparent);\n}\n\n.xps-up-flow-main {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.xps-up-flow-item-title {\n font-size: 13px;\n line-height: 20px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n.xps-up-flow-item-desc {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary, #8f959e);\n}\n\n/* \u5361\u7247\u6807\u9898\u4E0A\u7684\u6B65\u9AA4\u5FBD\u6807(\u7B2C 1 \u6B65 / \u7B2C 2 \u6B65),\u5EFA\u7ACB\u300C\u9009\u5185\u5BB9 \u2192 \u586B\u4FE1\u606F\u300D\u7684\u6D41\u7A0B\u611F */\n.xps-up-step-chip {\n flex: none;\n padding: 1px 8px;\n border-radius: 999px;\n font-size: 11px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-brand-primary, #3370ff);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 10%, transparent);\n}\n\n/* \u9875\u811A\u300C\u53D1\u5E03\u8BF4\u660E\u300D:\u5E38\u9A7B\u5168\u6587\u8BF4\u660E\u5361 */\n.xps-up-guide {\n margin-top: 20px;\n padding: 16px 20px;\n border: 0.5px solid var(--dsw-alias-border-l2, #dee0e3);\n border-radius: 10px;\n}\n\n.xps-up-guide-title {\n margin-bottom: 10px;\n font-size: 13px;\n line-height: 20px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n.xps-up-guide ol {\n margin: 0;\n padding-left: 20px;\n display: grid;\n gap: 8px;\n}\n\n.xps-up-guide li {\n font-size: 12px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary, #4e5460);\n}\n\n.xps-up-guide li::marker {\n color: var(--dsw-alias-label-tertiary, #8f959e);\n}\n\n.xps-up-guide b {\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n/* \u8BC6\u522B\u7ED3\u679C\u5361\u6807\u9898:\u957F\u6587\u6848\u5141\u8BB8\u6362\u884C,\u8865\u9009\u6309\u94AE\u56FA\u5B9A\u53F3\u4FA7\u4E0D\u53C2\u4E0E\u6362\u884C\u6324\u538B */\n.xps-up-card-title {\n display: flex;\n align-items: baseline;\n gap: 8px;\n margin-bottom: 10px;\n font-size: 13px;\n line-height: 20px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n/* \u8865\u9009\u6309\u94AE\u56FA\u5B9A\u53F3\u4FA7;\u6807\u9898\u8BCD\u4E0D\u6362\u884C(\u53EA\u6709\u6807\u9898\u5355\u9879\u65F6\u4E0D\u53D7 margin-left:auto \u8BEF\u4F24) */\n.xps-up-card-title > .xps-up-card-actions {\n flex: none;\n margin-left: auto;\n}\n\n.xps-up-card-title > span:first-child {\n flex: none;\n}\n\n/* \u8868\u5355\u6805\u683C:\u4E24\u5217\u4E00\u884C(\u5355\u9879\u7528 .xps-up-grid-single \u6536\u6210\u6574\u884C)\u3002\n * align-items: end:\u5DE6\u53F3\u5B57\u6BB5\u6807\u7B7E\u884C\u6570\u4E0D\u540C\u65F6\u8F93\u5165\u6846\u5E95\u8FB9\u5BF9\u9F50,\u6807\u7B7E\u5404\u81EA\u5411\u4E0A\u751F\u957F */\n.xps-up-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 10px 12px;\n margin-bottom: 10px;\n align-items: end;\n}\n\n.xps-up-grid-single {\n grid-template-columns: 1fr;\n}\n\n/* \u4EA7\u7269 / \u6E90\u7801\u5019\u9009\u884C:radio + \u56FE\u6807 + \u540D\u79F0(\u4E00\u884C) + \u76F8\u5BF9\u8DEF\u5F84(\u5C0F\u5B57\u4E00\u884C,\u8D85\u957F\u622A\u65AD);\n * \u9009\u4E2D\u6001\u54C1\u724C\u84DD\u63CF\u8FB9 */\n.xps-up-candidate {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 10px;\n margin-bottom: 4px;\n border: 0.5px solid var(--dsw-alias-border-l2, #dee0e3);\n border-radius: 8px;\n font-size: 13px;\n line-height: 20px;\n cursor: pointer;\n min-width: 0;\n transition: background-color 0.15s ease, border-color 0.15s ease;\n}\n\n.xps-up-candidate:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(31, 35, 41, 0.06));\n}\n\n.xps-up-candidate-active,\n.xps-up-candidate-active:hover {\n border-color: var(--dsw-alias-brand-primary, #3370ff);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 6%, transparent);\n}\n\n/* radio / \u56FE\u6807\u4E0D\u53C2\u4E0E\u6536\u7F29 */\n.xps-up-candidate > input,\n.xps-up-candidate > span:first-of-type {\n flex: none;\n}\n\n/* \u540D\u79F0 + \u8DEF\u5F84\u4E24\u884C\u5757:\u5360\u6EE1\u5269\u4F59\u5BBD\u5EA6,\u5185\u90E8\u5404\u81EA\u622A\u65AD */\n.xps-up-candidate-main {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 1px;\n}\n\n.xps-up-candidate-name {\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.xps-up-candidate-path {\n font-size: 12px;\n line-height: 17px;\n color: var(--dsw-alias-label-tertiary, #8f959e);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n direction: rtl;\n text-align: left;\n}\n\n.xps-up-candidate-path > bdi {\n direction: ltr;\n unicode-bidi: isolate;\n}\n\n/* ---------- \u9AA8\u67B6\u5C4F ---------- */\n\n.xps-skeleton-group {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.xps-skeleton {\n height: 56px;\n border-radius: 12px;\n background: linear-gradient(\n 90deg,\n var(--dsw-alias-interactive-bg-hover, rgba(31, 35, 41, 0.05)) 25%,\n var(--dsw-alias-border-l2, rgba(31, 35, 41, 0.1)) 37%,\n var(--dsw-alias-interactive-bg-hover, rgba(31, 35, 41, 0.05)) 63%\n );\n background-size: 400% 100%;\n animation: xps-skeleton-loading 1.4s ease infinite;\n}\n\n@keyframes xps-skeleton-loading {\n 0% {\n background-position: 100% 50%;\n }\n 100% {\n background-position: 0 50%;\n }\n}\n\n/* ---------- Toast ---------- */\n\n.xps-toast-host {\n position: fixed;\n top: 16px;\n left: 50%;\n transform: translateX(-50%);\n display: flex;\n flex-direction: column;\n gap: 8px;\n z-index: 9999;\n}\n\n.xps-toast {\n padding: 8px 14px;\n border-radius: 10px;\n font-size: 13px;\n line-height: 20px;\n /* \u591A\u884C\u63D0\u793A\u4E0D\u88AB\u6298\u53E0\u6210\u4E00\u6BB5(\u957F\u6587\u6848\u6539\u8D70 .xps-dialog-pre,\u8FD9\u91CC\u515C\u4F4F\u77ED\u7684\u591A\u884C\u63D0\u793A) */\n white-space: pre-wrap;\n background: var(--dsw-alias-bg-layer-3, #f0f1f2);\n color: var(--dsw-alias-label-primary, #1f2329);\n border: 0.5px solid var(--dsw-alias-border-l2, #dee0e3);\n box-shadow: 0 4px 16px var(--dsw-alias-bg-mask-1, rgba(0, 0, 0, 0.12));\n cursor: pointer;\n /* \u5165\u573A:\u6DE1\u5165 + \u8F7B\u5FAE\u4E0A\u79FB(\u79BB\u573A\u7531 useToasts \u76F4\u63A5\u4ECE\u5217\u8868\u79FB\u9664,\u4E0D\u505A\u5EF6\u8FDF\u5378\u8F7D) */\n animation: xps-fade-slide-in 0.15s ease-out;\n}\n\n@keyframes xps-fade-slide-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.xps-toast-success {\n border-color: color-mix(in srgb, var(--dsw-alias-state-success-primary, #1f9d55) 30%, transparent);\n}\n\n.xps-toast-error {\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d83931) 30%, transparent);\n}\n\n/* ---------- \u5BF9\u8BDD\u6846 ---------- */\n\n.xps-overlay {\n position: fixed;\n inset: 0;\n z-index: 9998;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--dsw-alias-bg-mask-2, rgba(0, 0, 0, 0.45));\n animation: xps-fade-in 0.15s ease-out;\n}\n\n@keyframes xps-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.xps-dialog {\n width: 360px;\n padding: 16px 20px;\n border-radius: 12px;\n border: 0.5px solid var(--dsw-alias-border-l2, #dee0e3);\n background: var(--dsw-alias-bg-layer-3, #ffffff);\n box-shadow: 0 8px 32px var(--dsw-alias-bg-mask-1, rgba(0, 0, 0, 0.18));\n /* \u5165\u573A:\u6DE1\u5165 + 0.98 \u2192 1 \u8F7B\u5FAE\u653E\u5927 */\n animation: xps-dialog-in 0.15s ease-out;\n}\n\n@keyframes xps-dialog-in {\n from { opacity: 0; transform: scale(0.98); }\n to { opacity: 1; transform: scale(1); }\n}\n\n.xps-dialog-title {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n margin-bottom: 8px;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n.xps-dialog-body {\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary, #646a73);\n margin-bottom: 16px;\n}\n\n.xps-dialog-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n}\n\n/* \u957F\u6587\u672C\u5BF9\u8BDD\u6846(\u5B89\u88C5\u5931\u8D25\u7684\u591A\u884C\u65E5\u5FD7\u3001\u5F85\u624B\u52A8\u6267\u884C\u7684\u547D\u4EE4):\u6BD4\u901A\u7528\u5BF9\u8BDD\u6846\u5BBD,\u7A84\u5C4F\u81EA\u52A8\u6536\u7A84 */\n.xps-dialog.xps-dialog-wide {\n width: 520px;\n max-width: calc(100vw - 32px);\n box-sizing: border-box;\n}\n\n/* \u6B63\u6587\u539F\u6587\u5757:\u4FDD\u7559\u6362\u884C\u4E0E\u7F29\u8FDB,\u8FC7\u957F\u65F6\u5185\u90E8\u6EDA\u52A8,\u4E0D\u628A\u7A97\u53E3\u6491\u7206;\u53EF\u624B\u52A8\u9009\u4E2D\u590D\u5236 */\n.xps-dialog-pre {\n white-space: pre-wrap;\n max-height: 320px;\n overflow: auto;\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-2, #f5f6f7);\n border: 0.5px solid var(--dsw-alias-border-l2, #dee0e3);\n font-family: var(--dsw-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary, #1f2329);\n text-align: left;\n word-break: break-word;\n user-select: text;\n}\n\n/* ---------- \u9875\u9762\u5360\u4F4D(\u9AA8\u67B6\u671F) ---------- */\n\n.xps-page-placeholder {\n padding: 18px;\n border: 0.5px dashed var(--dsw-alias-border-l2, #dee0e3);\n border-radius: 8px;\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-tertiary, #8f959e);\n}\n\n/* ---------- \u4EA4\u4E92\u72B6\u6001(\u5168\u7AD9\u7EDF\u4E00:\u8FC7\u6E21 / \u6309\u538B / \u7126\u70B9\u73AF) ----------\n * \u53EA\u8FC7\u6E21\u989C\u8272\u4E0E\u900F\u660E\u5EA6,\u4E0D\u505A\u4F4D\u79FB\u7F29\u653E\u52A8\u753B;\u6309\u538B\u7528\u4E00\u6863\u66F4\u6DF1\u7684 active \u5E95\u8272 + \u6781\u8F7B\u5FAE\u4E0B\u538B\u3002\n * \u9875\u9762\u79C1\u6709\u6837\u5F0F(market / admin)\u5728\u672C\u6587\u4EF6\u4E4B\u540E\u6CE8\u5165,\u5404\u81EA\u7684\u8FC7\u6E21\u4E0E\u6309\u538B\u6001\u5199\u5728\u5404\u81EA\u6A21\u5757\u91CC\u3002\n */\n\n/* .xps-row \u7684\u8FC7\u6E21\u5199\u5728\u81EA\u5DF1\u7684\u57FA\u7840\u89C4\u5219\u91CC(\u89C1\u4E0A),\u6B64\u5904\u4E0D\u518D\u91CD\u590D\u58F0\u660E */\n.xps-btn,\n.xps-icon-btn,\n.xps-nav-item,\n.xps-input {\n transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease,\n opacity 0.15s ease;\n}\n\n/* \u6309\u538B:\u80CC\u666F\u518D\u6DF1\u4E00\u6863(interactive-bg-active);\u4E3B/\u63CF\u8FB9/\u5371\u9669\u6309\u94AE\u6309\u5404\u81EA\u8272\u7CFB\u52A0\u6DF1 */\n.xps-btn:active:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-active, rgba(38, 49, 72, 0.1));\n transform: scale(0.98);\n}\n\n.xps-btn-primary:active:not(:disabled) {\n /* \u4E3B\u6309\u94AE\u6CA1\u6709 -active token(\u53EA\u6709 -fill / -hover),\u6309\u538B\u76F4\u63A5\u6309\u54C1\u724C\u8272\u52A0\u6DF1 */\n background: color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 78%, #000000);\n}\n\n.xps-btn-outline:active:not(:disabled) {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 16%, transparent);\n}\n\n.xps-btn-danger:active:not(:disabled) {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d83931) 16%, transparent);\n}\n\n.xps-btn-ghost:active:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-active, rgba(38, 49, 72, 0.1));\n}\n\n.xps-icon-btn:active:not(:disabled),\n.xps-nav-item:active {\n background: var(--dsw-alias-interactive-bg-active, rgba(38, 49, 72, 0.1));\n}\n\n.xps-row:active {\n background: var(--dsw-alias-interactive-bg-active, rgba(38, 49, 72, 0.1));\n}\n\n/* \u7126\u70B9\u73AF:\u53EA\u5728\u952E\u76D8\u5BFC\u822A\u65F6\u51FA\u73B0(:focus-visible),\u9F20\u6807\u70B9\u51FB\u4E0D\u753B\u73AF */\n.xps-btn:focus-visible,\n.xps-icon-btn:focus-visible,\n.xps-nav-item:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #3370ff);\n outline-offset: 2px;\n}\n\n/* \u6574\u884C\u5361\u7247\u7528\u5185\u63CF\u8FB9,\u907F\u514D\u8D34\u5230\u5185\u5BB9\u533A\u8FB9\u7F18\u88AB\u88C1\u6389 */\n.xps-row:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #3370ff);\n outline-offset: -2px;\n}\n\n/* \u7981\u7528\u6001:\u9664\u5404\u7EC4\u4EF6\u81EA\u5DF1\u7684 opacity \u5916,\u6E38\u6807\u7EDF\u4E00\u515C\u5E95 */\n.xps-app :disabled {\n cursor: not-allowed;\n}\n\n/* \u52A8\u6548\u504F\u597D:reduce \u65F6\u5173\u6389\u8FC7\u6E21\u4E0E\u5165\u573A\u52A8\u753B(\u6309\u538B\u7684\u7F29\u653E\u4E5F\u4E00\u5E76\u53D6\u6D88) */\n@media (prefers-reduced-motion: reduce) {\n .xps-btn,\n .xps-icon-btn,\n .xps-nav-item,\n .xps-input,\n .xps-row,\n .xps-toast,\n .xps-overlay,\n .xps-dialog {\n transition: none;\n animation: none;\n }\n\n .xps-btn:active:not(:disabled) {\n transform: none;\n }\n}\n";
3408
+ var theme_default = "/* \u85AA\u4EBA\u85AA\u4E8B\u5E02\u573A client \u4E3B\u9898:\u5BF9\u6807\u5BBF\u4E3B\u5B98\u65B9\u63D2\u4EF6\u7BA1\u7406\u5668(PluginManagerPage.module.css)\u89C6\u89C9\u8BED\u8A00,\n * \u5168\u90E8\u8D70\u5BBF\u4E3B --dsw-alias-* token(\u5E26\u515C\u5E95\u503C,token \u7F3A\u5931\u65F6\u53EF\u72EC\u7ACB\u9884\u89C8)\u3002 */\n\n/* ---------- \u9875\u9762\u9AA8\u67B6 ---------- */\n\n.xps-app {\n display: flex;\n width: 100%;\n height: 100%;\n background: var(--dsw-alias-bg-layer-1, #ffffff);\n color: var(--dsw-alias-label-primary, #1f2329);\n font-family: inherit;\n}\n\n/* \u5DE6\u4FA7\u4E8C\u7EA7\u5BFC\u822A(B \xB7 \u56FE\u6807\u5C45\u4E0A\u84DD\u8C03\u7EC6\u7EBF\u98CE:\u5706\u89D2\u5757 r10,\u9009\u4E2D\u6D45\u84DD\u5E95+\u54C1\u724C\u84DD\u5B57) */\n.xps-nav {\n flex: none;\n width: 92px;\n box-sizing: border-box;\n padding: 16px 10px;\n display: flex;\n flex-direction: column;\n gap: 3px;\n border-right: 0.5px solid var(--dsw-alias-border-l2, #dee0e3);\n}\n\n.xps-nav-item {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 3px;\n padding: 9px 0 7px;\n border: none;\n border-radius: 10px;\n background: transparent;\n cursor: pointer;\n color: var(--dsw-alias-label-secondary, #646a73);\n font-family: inherit;\n font-size: 12px;\n line-height: 18px;\n}\n\n.xps-nav-item:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, 0.04));\n}\n\n.xps-nav-item-active,\n.xps-nav-item-active:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 10%, var(--dsw-alias-bg-layer-1, #ffffff));\n color: var(--dsw-alias-brand-primary, #3370ff);\n font-weight: 600;\n}\n\n.xps-nav-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n line-height: 0;\n}\n\n.xps-nav-label {\n white-space: nowrap;\n}\n\n/* \u5185\u5BB9\u533A:\u5B98\u65B9\u9875\u540C\u6B3E\u5C45\u4E2D\u5217(28px \u9876 / clamp \u4FA7 / 48px \u5E95,960 \u4E0A\u9650) */\n.xps-content {\n flex: 1;\n min-width: 0;\n overflow: auto;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 28px clamp(24px, 4vw, 48px) 48px;\n}\n\n.xps-content > * {\n width: 100%;\n max-width: 960px;\n box-sizing: border-box;\n}\n\n/* \u9875\u5934:flex space-between,\u6807\u9898 20/28/500,\u526F\u9898 13/20 secondary */\n.xps-page-head {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 16px;\n margin-bottom: 20px;\n}\n\n.xps-page-title {\n margin: 0;\n font-size: 20px;\n line-height: 28px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n/* \u6807\u9898\u884C\u5185\u6302\u5FBD\u6807(\u8BA1\u6570\u7B49\u72B6\u6001\u4FE1\u606F\u8DDF\u968F\u6807\u9898,\u4E0D\u6DF7\u8FDB\u53F3\u4E0A\u89D2\u64CD\u4F5C\u533A) */\n.xps-title-with-badges {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.xps-page-intro {\n margin: 4px 0 0;\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary, #646a73);\n}\n\n.xps-page-actions {\n flex: none;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n/* \u533A\u5757\u9898 14/22/500 */\n.xps-section-title {\n margin: 0;\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n/* ---------- \u6587\u5B57\u8272\u9636\u5DE5\u5177\u7C7B ---------- */\n\n.xps-text-secondary {\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary, #646a73);\n}\n\n/* \u8BF4\u660E/\u8BA1\u6570:12/18 tertiary */\n.xps-text-caption {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary, #8f959e);\n}\n\n/* \u5305\u540D/\u7248\u672C\u53F7\u7B49 mono */\n.xps-mono {\n font-family: var(--dsw-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);\n}\n\n/* ---------- \u6309\u94AE(\u80F6\u56CA) ---------- */\n\n.xps-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n height: 32px;\n box-sizing: border-box;\n padding: 0 14px;\n border-radius: 16px;\n border: 0.5px solid var(--dsw-alias-border-l3, #d0d3d9);\n background: transparent;\n color: var(--dsw-alias-label-primary, #1f2329);\n font-family: inherit;\n font-size: 13px;\n line-height: 20px;\n cursor: pointer;\n white-space: nowrap;\n}\n\n.xps-btn:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, rgba(31, 35, 41, 0.06));\n}\n\n.xps-btn:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n/* \u4E3B\u6309\u94AE(B \u65B9\u5411\u8BC6\u522B\u8272):\u5B9E\u5FC3\u54C1\u724C\u84DD + \u767D\u5B57,hover \u52A0\u6DF1 */\n.xps-btn-primary {\n background: var(--dsw-alias-brand-primary, #3370ff);\n border-color: transparent;\n color: var(--dsw-alias-label-primary-foreground, #ffffff);\n}\n\n.xps-btn-primary:hover:not(:disabled) {\n background: var(--dsw-alias-button-primary-hover, color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 85%, #000000));\n}\n\n/* \u63CF\u8FB9\u4E3B\u6309\u94AE(\u5DF2\u5B89\u88C5/\u66F4\u65B0\u6001):\u54C1\u724C\u84DD\u63CF\u8FB9 + \u84DD\u5B57\u900F\u660E\u5E95 */\n.xps-btn-outline {\n border: 1px solid var(--dsw-alias-brand-primary, #3370ff);\n background: transparent;\n color: var(--dsw-alias-brand-primary, #3370ff);\n}\n\n.xps-btn-outline:hover:not(:disabled) {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 8%, transparent);\n}\n\n/* \u66F4\u65B0\u6309\u94AE:\u4E0E\u300C\u2191 \u53EF\u66F4\u65B0\u300D\u5FBD\u6807\u540C\u6E90\u7684\u6A59\u8272\u63CF\u8FB9(\u4E0D\u8DDF\u4E3B\u9898 primary \u8D70,\u9ED1\u8272\u4E3B\u9898\u4E0B\u4E5F\u80FD\u548C\u5B89\u88C5\u62C9\u5F00) */\n.xps-btn-update {\n border: 1px solid var(--dsw-alias-state-warn-primary, #d98708);\n background: transparent;\n color: var(--dsw-alias-state-warn-primary, #d98708);\n}\n\n.xps-btn-update:hover:not(:disabled) {\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary, #d98708) 10%, transparent);\n}\n\n/* \u5371\u9669\u6309\u94AE:\u590D\u7528\u6B21\u6309\u94AE,\u7EA2\u5B57 + 30% \u7EA2\u6846,hover \u6362\u7EA2 wash */\n.xps-btn-danger {\n color: var(--dsw-alias-state-error-primary, #d83931);\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d83931) 30%, transparent);\n}\n\n.xps-btn-danger:hover:not(:disabled) {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d83931) 8%, transparent);\n}\n\n.xps-btn-ghost {\n border-color: transparent;\n background: transparent;\n color: var(--dsw-alias-label-secondary, #646a73);\n}\n\n.xps-btn-ghost:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n.xps-btn-sm {\n height: 26px;\n padding: 0 10px;\n font-size: 12px;\n line-height: 18px;\n border-radius: 13px;\n}\n\n/* \u56FE\u6807\u6309\u94AE:28\xD728 \u5168\u5706 */\n/* \u56FE\u6807\u6309\u94AE:\u4E0E .xps-btn \u540C\u9AD8(32px)\u3001\u540C 0.5px \u8FB9\u6846,\u73AF\u5F62\u5237\u65B0\u7B49\u56FE\u6807\u6309\u94AE\u4E0E\u6587\u5B57\u6309\u94AE\u5E76\u6392\u65F6\u6BD4\u4F8B\u4E00\u81F4 */\n.xps-icon-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n flex: none;\n padding: 0;\n border: 0.5px solid var(--dsw-alias-border-l3, #d0d3d9);\n border-radius: 999px;\n background: transparent;\n color: var(--dsw-alias-label-secondary, #646a73);\n cursor: pointer;\n font-family: inherit;\n font-size: 14px;\n transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease,\n opacity 0.15s ease;\n}\n\n.xps-icon-btn:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, rgba(31, 35, 41, 0.06));\n border-color: var(--dsw-alias-border-l4, #a8abb2);\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n.xps-icon-btn:active:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-active, rgba(38, 49, 72, 0.1));\n transform: scale(0.96);\n}\n\n.xps-icon-btn:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n/* ---------- \u8F93\u5165\u6846 ---------- */\n\n.xps-input {\n width: 100%;\n box-sizing: border-box;\n height: 32px;\n padding: 0 10px;\n border-radius: 8px;\n border: 0.5px solid var(--dsw-alias-border-l4, #c9cdd4);\n background: var(--dsw-alias-bg-layer-1, #ffffff);\n color: var(--dsw-alias-label-primary, #1f2329);\n font-family: inherit;\n font-size: 13px;\n line-height: 20px;\n outline: none;\n}\n\n.xps-input::placeholder {\n color: var(--dsw-alias-label-tertiary, #8f959e);\n}\n\n/* \u8F93\u5165\u6846 hover:\u8FB9\u6846\u8F7B\u62AC\u4E00\u6863,\u4E0E focus \u7684\u54C1\u724C\u84DD\u533A\u5206 */\n.xps-input:hover:not(:disabled):not(:focus) {\n border-color: var(--dsw-alias-border-l4, #a8abb2);\n}\n\n.xps-input:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.xps-input:focus {\n border-color: var(--dsw-alias-brand-primary, #3370ff);\n box-shadow: inset 0 0 0 0.5px var(--dsw-alias-brand-primary, #3370ff);\n}\n\n/* ---------- \u5FBD\u6807(\u80F6\u56CA 11/17/500) ---------- */\n\n.xps-badge {\n display: inline-flex;\n align-items: center;\n padding: 1px 8px;\n border-radius: 999px;\n border: 0.5px solid var(--dsw-alias-border-l3, #dee0e3);\n font-size: 11px;\n line-height: 17px;\n font-weight: 500;\n white-space: nowrap;\n background: var(--dsw-alias-bg-layer-2, #f5f6f7);\n color: var(--dsw-alias-label-secondary, #646a73);\n}\n\n.xps-badge-success {\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary, #1f9d55) 10%, var(--dsw-alias-bg-layer-1, #ffffff));\n border-color: color-mix(in srgb, var(--dsw-alias-state-success-primary, #1f9d55) 30%, transparent);\n color: var(--dsw-alias-state-success-primary, #1f9d55);\n}\n\n.xps-badge-warning {\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary, #d98708) 10%, var(--dsw-alias-bg-layer-1, #ffffff));\n border-color: color-mix(in srgb, var(--dsw-alias-state-warn-primary, #d98708) 30%, transparent);\n color: var(--dsw-alias-state-warn-primary, #d98708);\n}\n\n.xps-badge-error {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d83931) 10%, var(--dsw-alias-bg-layer-1, #ffffff));\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d83931) 30%, transparent);\n color: var(--dsw-alias-state-error-primary, #d83931);\n}\n\n.xps-badge-info {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 10%, var(--dsw-alias-bg-layer-1, #ffffff));\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 30%, transparent);\n color: var(--dsw-alias-brand-primary, #3370ff);\n}\n\n/* ---------- \u5217\u8868\u884C(\u53D1\u4E1D\u7EBF\u6E05\u5355\u5F0F:\u4E0E\u5E02\u573A\u884C .xps-mk-row\u3001\u5F00\u53D1\u8005\u884C .xps-dev-item \u540C\u8303\u5F0F) ---------- */\n\n.xps-row-list {\n display: flex;\n flex-direction: column;\n}\n\n.xps-row {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 8px;\n border-bottom: 0.5px solid var(--dsw-alias-border-l2, #dee0e3);\n border-radius: 0;\n background: transparent;\n cursor: pointer;\n min-width: 0;\n transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease,\n opacity 0.15s ease;\n}\n\n/* \u6E05\u5355\u672B\u884C\u53BB\u53D1\u4E1D\u7EBF(\u4E0E .xps-dev-item:last-child \u540C\u505A\u6CD5) */\n.xps-row-list > .xps-row:last-child {\n border-bottom: none;\n}\n\n/* \u884C hover:\u6574\u884C\u80CC\u666F\u8F7B\u62AC,\u4E0E\u5E02\u573A\u884C\u540C\u5C42\u7EA7 */\n.xps-row:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(31, 35, 41, 0.06));\n}\n\n/* \u56FE\u6807\u6846 40\xD740\u30010.5px hairline\u3001r10 */\n.xps-row-icon {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n border: 0.5px solid var(--dsw-alias-border-l3, #d0d3d9);\n border-radius: 10px;\n color: var(--dsw-alias-label-secondary, #646a73);\n font-size: 18px;\n line-height: 1;\n}\n\n.xps-row-main {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.xps-row-title {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n/* \u884C\u9898 14/20/500(\u5B98\u65B9\u884C\u6807\u9898\u89C4\u683C)\u3002\u5C55\u793A\u540D\u4E0E\u300C\u56DE\u9000\u7684\u5305\u540D\u300D\u90FD\u7528\u666E\u901A\u5B57\u4F53:\n * \u6807\u8BC6\u7B26\u53EA\u5728\u540E\u9762\u7684 .xps-row-pkg \u91CC\u8D70\u7B49\u5BBD,\u4E0E\u5E02\u573A/\u5F00\u53D1\u8005\u9875\u540C\u4E00\u89C4\u5219\u3002 */\n.xps-row-name {\n font-size: 14px;\n line-height: 20px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* \u5C55\u793A\u540D\u4E4B\u540E\u7684\u5305\u540D(\u6807\u8BC6\u7B26,\u7B49\u5BBD\u5C0F\u5B57 11px;\u4E0E .xps-mk-row-pkg / .xps-dev-pkg \u540C\u89C4\u683C) */\n.xps-row-pkg {\n flex: none;\n font-size: 11px;\n line-height: 17px;\n color: var(--dsw-alias-label-tertiary, #8f959e);\n}\n\n/* \u884C\u63CF\u8FF0 13/18 tertiary + \u5355\u884C\u622A\u65AD */\n.xps-row-desc {\n font-size: 13px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary, #8f959e);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.xps-row-end {\n flex: none;\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n\n/* ---------- \u6A2A\u5E45/\u63D0\u793A\u6761 ---------- */\n\n.xps-banner {\n margin: 0 0 12px;\n padding: 8px 12px;\n border-radius: 10px;\n font-size: 12px;\n line-height: 18px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary, #d98708) 12%, var(--dsw-alias-bg-layer-1, #ffffff));\n border: 0.5px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary, #d98708) 30%, transparent);\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n.xps-banner-error {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d83931) 10%, var(--dsw-alias-bg-layer-1, #ffffff));\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d83931) 30%, transparent);\n color: var(--dsw-alias-state-error-primary, #d83931);\n}\n\n/* ---------- \u7A7A\u6001(dashed 0.5px l2 + r8 + pad 18 \u5C45\u4E2D 13 tertiary) ---------- */\n\n.xps-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n /* \u56FE\u6807 / \u6807\u9898 / \u63CF\u8FF0\u7EDF\u4E00 8px \u8282\u594F */\n gap: 8px;\n padding: 18px;\n border: 0.5px dashed var(--dsw-alias-border-l2, #dee0e3);\n border-radius: 8px;\n color: var(--dsw-alias-label-tertiary, #8f959e);\n font-size: 13px;\n line-height: 20px;\n text-align: center;\n}\n\n.xps-empty-icon {\n font-size: 24px;\n line-height: 1;\n}\n\n.xps-empty-title {\n font-size: 13px;\n line-height: 20px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n/* \u6309\u94AE\u4E0E\u4E0A\u65B9\u6587\u6848\u5408\u8BA1 12px(\u7236\u7EA7 gap 8 + \u8FD9\u91CC 4) */\n.xps-empty-action {\n margin-top: 4px;\n}\n\n/* \u300C\u6211\u7684\u300D\u9875\u672A\u767B\u5F55\u5F15\u5BFC\u5361:\u6D41\u7A0B\u8BF4\u660E + \u524D\u5F80\u5F00\u53D1\u8005\u5E73\u53F0(\u65E0\u4EE4\u724C\u8F93\u5165\u5165\u53E3,\u767B\u5F55\u53EA\u5728\u8BBE\u7F6E\u91CC) */\n.xps-guide {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 20px 24px;\n border: 0.5px dashed var(--dsw-alias-border-l2, #dee0e3);\n border-radius: 8px;\n}\n\n.xps-guide-title {\n font-size: 14px;\n line-height: 20px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n.xps-guide-desc {\n margin: 0;\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary, #646a73);\n}\n\n.xps-guide-steps {\n margin: 0;\n padding-left: 20px;\n display: flex;\n flex-direction: column;\n gap: 6px;\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary, #646a73);\n}\n\n.xps-guide-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 4px;\n}\n\n.xps-guide-url {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary, #8f959e);\n word-break: break-all;\n}\n\n/* ---------- \u4E0A\u4F20\u8868\u5355(\u6253\u5305\u63D0\u4EA4) ---------- */\n\n/* \u62D6\u5165 / \u9009\u62E9\u533A:dashed \u5927\u9776\u533A;\u62D6\u60AC\u65F6\u6574\u533A\u54C1\u724C\u84DD\u63CF\u8FB9 + \u6D45\u84DD wash(.xps-up-drop-over) */\n.xps-up-drop {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n padding: 28px 16px;\n margin-bottom: 12px;\n text-align: center;\n border: 0.5px dashed var(--dsw-alias-border-l4, #c9cdd4);\n border-radius: 12px;\n cursor: pointer;\n transition: background-color 0.15s ease, border-color 0.15s ease;\n}\n\n.xps-up-drop:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(31, 35, 41, 0.04));\n}\n\n.xps-up-drop-over,\n.xps-up-drop-over:hover {\n border-color: var(--dsw-alias-brand-primary, #3370ff);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 8%, transparent);\n}\n\n.xps-up-drop-icon {\n font-size: 28px;\n line-height: 1;\n}\n\n.xps-up-drop-title {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n.xps-up-drop-actions {\n display: flex;\n gap: 8px;\n margin-top: 8px;\n}\n\n/* \u5206\u7EC4\u5361\u7247:\u8BC6\u522B\u7ED3\u679C / \u63D2\u4EF6\u4FE1\u606F\u5404\u4E00\u5F20,\u66FF\u4EE3\u6563\u843D\u7684\u884C\u5185\u8FB9\u8DDD */\n.xps-up-card {\n padding: 14px 16px;\n margin-bottom: 12px;\n border: 0.5px solid var(--dsw-alias-border-l2, #dee0e3);\n border-radius: 10px;\n}\n\n.xps-up-card-actions {\n margin-left: auto;\n display: flex;\n gap: 4px;\n}\n\n/* \u4E0A\u4F20\u9875\u53CC\u680F:\u5DE6\u300C\u9009\u62E9\u5185\u5BB9 + \u8BC6\u522B\u7ED3\u679C\u300D\u53F3\u300C\u63D2\u4EF6\u4FE1\u606F + \u63D0\u4EA4\u300D,\u4E0E\u5176\u4ED6\u9875\u5171\u7528\u6807\u51C6 960 \u5217\u3002\n * \u5B50\u5143\u7D20\u76F4\u63A5\u505A grid item \u5E76\u663E\u5F0F\u5B9A\u4F4D:\u5DE6\u680F 1 \u5217\u4E09\u4E2A\u5757,\u53F3\u680F 2 \u5217\u4E24\u4E2A\u5757(r2-5 \u62C9\u4F38),\n * \u4E24\u680F\u5E95\u8FB9\u5929\u7136\u5BF9\u9F50;\u7A84\u5C4F(<880px)\u9000\u5316\u4E3A\u5355\u5217\u3001\u6309 DOM \u987A\u5E8F\u5806\u53E0 */\n.xps-up-layout {\n display: grid;\n grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);\n gap: 16px 16px;\n align-items: stretch;\n}\n\n/* \u76F4\u63A5\u5B50\u5143\u7D20\u5373\u7F51\u683C\u9879:\u5757\u81EA\u8EAB\u7684\u5916\u8FB9\u8DDD\u5F52\u96F6,\u95F4\u8DDD\u7EDF\u4E00\u4EA4\u7ED9 grid gap */\n.xps-up-side-drop,\n.xps-up-side-notice,\n.xps-up-side-scan,\n.xps-up-main-form {\n margin-bottom: 0;\n}\n\n.xps-up-layout > * {\n min-width: 0;\n min-height: 0;\n}\n\n.xps-up-side-drop { grid-column: 1; grid-row: 1; }\n.xps-up-side-notice { grid-column: 1; grid-row: 2; }\n.xps-up-side-scan { grid-column: 1; grid-row: 3 / 6; }\n.xps-up-main-form { grid-column: 2; grid-row: 1 / 6; }\n.xps-up-main-submit { grid-column: 2; grid-row: 6; }\n\n/* \u7A84\u5C4F:\u53CC\u680F\u5148\u4E8E\u8868\u5355\u6805\u683C\u584C\u6210\u5355\u5217,\u907F\u514D\u5B57\u6BB5\u88AB\u538B\u5230\u6362\u884C\u96BE\u8BFB */\n@media (max-width: 1120px) {\n .xps-up-grid {\n grid-template-columns: 1fr;\n }\n}\n\n@media (max-width: 1024px) {\n .xps-up-layout {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .xps-up-layout > [class^='xps-up-'],\n .xps-up-layout > [class*=' xps-up-'] {\n grid-column: auto;\n grid-row: auto;\n }\n}\n\n/* \u53F3\u680F\u7A7A\u6001:\u4E0E\u5DE6\u4FA7\u62D6\u5165\u533A\u540C\u6B3E\u865A\u7EBF\u5361\u7247,\u7B49\u9AD8\u5C45\u4E2D;\u70B9\u51FB\u7B49\u540C\u300C\u9009\u62E9\u76EE\u5F55\u300D\u3002\n * \u62C9\u4F38\u7531 grid item \u81EA\u8EAB\u5B8C\u6210(display: flex \u6491\u6EE1\u5206\u914D\u5230\u7684\u884C),\u4E0D\u4F9D\u8D56\u767E\u5206\u6BD4\u9AD8\u5EA6 */\n.xps-up-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n box-sizing: border-box;\n align-self: stretch;\n height: 100%;\n min-height: 200px;\n padding: 28px 16px;\n text-align: center;\n border: 0.5px dashed var(--dsw-alias-border-l2, #dee0e3);\n border-radius: 12px;\n cursor: pointer;\n transition: background-color 0.15s ease, border-color 0.15s ease;\n}\n\n.xps-up-empty:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(31, 35, 41, 0.04));\n}\n\n/* \u7A7A\u6001\u53CC\u5361:\u5DE6\u62D6\u5165\u533A + \u53F3\u6D41\u7A0B\u8BF4\u660E,\u5355\u884C\u7F51\u683C\u5929\u7136\u7B49\u9AD8(\u5404\u81EA stretch) */\n.xps-up-empty-grid {\n display: grid;\n grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);\n gap: 16px;\n align-items: stretch;\n}\n\n.xps-up-empty-grid .xps-up-drop {\n justify-content: center;\n margin-bottom: 0;\n}\n\n/* \u6D41\u7A0B\u8BF4\u660E\u5361\u53EA\u505A\u5C55\u793A:\u53BB\u6389\u624B\u578B\u4E0E\u60AC\u505C\u53CD\u9988 */\n.xps-up-empty-static,\n.xps-up-empty-static:hover {\n justify-content: center;\n cursor: default;\n background: transparent;\n}\n\n@media (max-width: 1024px) {\n .xps-up-empty-grid {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n/* \u7B2C 1 \u6B65\u5361\u91CC\u300C\u8FD8\u5DEE\u4EE3\u7801\u76EE\u5F55\u300D\u7684\u5C31\u5730\u63D0\u793A\u6761 */\n.xps-up-source-missing {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 10px;\n padding: 8px 10px;\n border-radius: 8px;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-warning-primary, #b25e09);\n background: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #dc6803) 8%, transparent);\n}\n\n/* \u7A7A\u6001\u53F3\u680F\u7684\u53D1\u5E03\u6D41\u7A0B:\u586B\u5145\u539F\u672C\u7684\u6B7B\u7A7A\u95F4,\u517C\u505A\u5F15\u5BFC(\u5DE6\u5BF9\u9F50\u6E05\u5355,\u5C45\u4E2D\u653E\u7F6E) */\n.xps-up-flow {\n display: flex;\n flex-direction: column;\n gap: 12px;\n width: 100%;\n max-width: 380px;\n padding: 8px 4px;\n}\n\n.xps-up-flow-title {\n font-size: 13px;\n line-height: 20px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n.xps-up-flow-item {\n display: flex;\n gap: 10px;\n text-align: left;\n}\n\n.xps-up-flow-no {\n flex: none;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n margin-top: 1px;\n border-radius: 50%;\n font-size: 11px;\n font-weight: 500;\n color: var(--dsw-alias-brand-primary, #3370ff);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 10%, transparent);\n}\n\n.xps-up-flow-main {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.xps-up-flow-item-title {\n font-size: 13px;\n line-height: 20px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n.xps-up-flow-item-desc {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary, #8f959e);\n}\n\n/* \u5361\u7247\u6807\u9898\u4E0A\u7684\u6B65\u9AA4\u5FBD\u6807(\u7B2C 1 \u6B65 / \u7B2C 2 \u6B65),\u5EFA\u7ACB\u300C\u9009\u5185\u5BB9 \u2192 \u586B\u4FE1\u606F\u300D\u7684\u6D41\u7A0B\u611F */\n.xps-up-step-chip {\n flex: none;\n padding: 1px 8px;\n border-radius: 999px;\n font-size: 11px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-brand-primary, #3370ff);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 10%, transparent);\n}\n\n/* \u9875\u811A\u300C\u53D1\u5E03\u8BF4\u660E\u300D:\u5E38\u9A7B\u5168\u6587\u8BF4\u660E\u5361 */\n.xps-up-guide {\n margin-top: 20px;\n padding: 16px 20px;\n border: 0.5px solid var(--dsw-alias-border-l2, #dee0e3);\n border-radius: 10px;\n}\n\n.xps-up-guide-title {\n margin-bottom: 10px;\n font-size: 13px;\n line-height: 20px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n.xps-up-guide ol {\n margin: 0;\n padding-left: 20px;\n display: grid;\n gap: 8px;\n}\n\n.xps-up-guide li {\n font-size: 12px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary, #4e5460);\n}\n\n.xps-up-guide li::marker {\n color: var(--dsw-alias-label-tertiary, #8f959e);\n}\n\n.xps-up-guide b {\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n/* \u8BC6\u522B\u7ED3\u679C\u5361\u6807\u9898:\u957F\u6587\u6848\u5141\u8BB8\u6362\u884C,\u8865\u9009\u6309\u94AE\u56FA\u5B9A\u53F3\u4FA7\u4E0D\u53C2\u4E0E\u6362\u884C\u6324\u538B */\n.xps-up-card-title {\n display: flex;\n align-items: baseline;\n gap: 8px;\n margin-bottom: 10px;\n font-size: 13px;\n line-height: 20px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n/* \u8865\u9009\u6309\u94AE\u56FA\u5B9A\u53F3\u4FA7;\u6807\u9898\u8BCD\u4E0D\u6362\u884C(\u53EA\u6709\u6807\u9898\u5355\u9879\u65F6\u4E0D\u53D7 margin-left:auto \u8BEF\u4F24) */\n.xps-up-card-title > .xps-up-card-actions {\n flex: none;\n margin-left: auto;\n}\n\n.xps-up-card-title > span:first-child {\n flex: none;\n}\n\n/* \u8868\u5355\u6805\u683C:\u4E24\u5217\u4E00\u884C(\u5355\u9879\u7528 .xps-up-grid-single \u6536\u6210\u6574\u884C)\u3002\n * align-items: end:\u5DE6\u53F3\u5B57\u6BB5\u6807\u7B7E\u884C\u6570\u4E0D\u540C\u65F6\u8F93\u5165\u6846\u5E95\u8FB9\u5BF9\u9F50,\u6807\u7B7E\u5404\u81EA\u5411\u4E0A\u751F\u957F */\n.xps-up-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 10px 12px;\n margin-bottom: 10px;\n align-items: end;\n}\n\n.xps-up-grid-single {\n grid-template-columns: 1fr;\n}\n\n/* \u4EA7\u7269 / \u6E90\u7801\u5019\u9009\u884C:radio + \u56FE\u6807 + \u540D\u79F0(\u4E00\u884C) + \u76F8\u5BF9\u8DEF\u5F84(\u5C0F\u5B57\u4E00\u884C,\u8D85\u957F\u622A\u65AD);\n * \u9009\u4E2D\u6001\u54C1\u724C\u84DD\u63CF\u8FB9 */\n.xps-up-candidate {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 10px;\n margin-bottom: 4px;\n border: 0.5px solid var(--dsw-alias-border-l2, #dee0e3);\n border-radius: 8px;\n font-size: 13px;\n line-height: 20px;\n cursor: pointer;\n min-width: 0;\n transition: background-color 0.15s ease, border-color 0.15s ease;\n}\n\n.xps-up-candidate:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(31, 35, 41, 0.06));\n}\n\n.xps-up-candidate-active,\n.xps-up-candidate-active:hover {\n border-color: var(--dsw-alias-brand-primary, #3370ff);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 6%, transparent);\n}\n\n/* radio / \u56FE\u6807\u4E0D\u53C2\u4E0E\u6536\u7F29 */\n.xps-up-candidate > input,\n.xps-up-candidate > span:first-of-type {\n flex: none;\n}\n\n/* \u540D\u79F0 + \u8DEF\u5F84\u4E24\u884C\u5757:\u5360\u6EE1\u5269\u4F59\u5BBD\u5EA6,\u5185\u90E8\u5404\u81EA\u622A\u65AD */\n.xps-up-candidate-main {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 1px;\n}\n\n.xps-up-candidate-name {\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #1f2329);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.xps-up-candidate-path {\n font-size: 12px;\n line-height: 17px;\n color: var(--dsw-alias-label-tertiary, #8f959e);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n direction: rtl;\n text-align: left;\n}\n\n.xps-up-candidate-path > bdi {\n direction: ltr;\n unicode-bidi: isolate;\n}\n\n/* ---------- \u9AA8\u67B6\u5C4F ---------- */\n\n.xps-skeleton-group {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.xps-skeleton {\n height: 56px;\n border-radius: 12px;\n background: linear-gradient(\n 90deg,\n var(--dsw-alias-interactive-bg-hover, rgba(31, 35, 41, 0.05)) 25%,\n var(--dsw-alias-border-l2, rgba(31, 35, 41, 0.1)) 37%,\n var(--dsw-alias-interactive-bg-hover, rgba(31, 35, 41, 0.05)) 63%\n );\n background-size: 400% 100%;\n animation: xps-skeleton-loading 1.4s ease infinite;\n}\n\n@keyframes xps-skeleton-loading {\n 0% {\n background-position: 100% 50%;\n }\n 100% {\n background-position: 0 50%;\n }\n}\n\n/* ---------- Toast ---------- */\n\n.xps-toast-host {\n position: fixed;\n top: 16px;\n left: 50%;\n transform: translateX(-50%);\n display: flex;\n flex-direction: column;\n gap: 8px;\n z-index: 9999;\n}\n\n.xps-toast {\n padding: 8px 14px;\n border-radius: 10px;\n font-size: 13px;\n line-height: 20px;\n /* \u591A\u884C\u63D0\u793A\u4E0D\u88AB\u6298\u53E0\u6210\u4E00\u6BB5(\u957F\u6587\u6848\u6539\u8D70 .xps-dialog-pre,\u8FD9\u91CC\u515C\u4F4F\u77ED\u7684\u591A\u884C\u63D0\u793A) */\n white-space: pre-wrap;\n background: var(--dsw-alias-bg-layer-3, #f0f1f2);\n color: var(--dsw-alias-label-primary, #1f2329);\n border: 0.5px solid var(--dsw-alias-border-l2, #dee0e3);\n box-shadow: 0 4px 16px var(--dsw-alias-bg-mask-1, rgba(0, 0, 0, 0.12));\n cursor: pointer;\n /* \u5165\u573A:\u6DE1\u5165 + \u8F7B\u5FAE\u4E0A\u79FB(\u79BB\u573A\u7531 useToasts \u76F4\u63A5\u4ECE\u5217\u8868\u79FB\u9664,\u4E0D\u505A\u5EF6\u8FDF\u5378\u8F7D) */\n animation: xps-fade-slide-in 0.15s ease-out;\n}\n\n@keyframes xps-fade-slide-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.xps-toast-success {\n border-color: color-mix(in srgb, var(--dsw-alias-state-success-primary, #1f9d55) 30%, transparent);\n}\n\n.xps-toast-error {\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d83931) 30%, transparent);\n}\n\n/* ---------- \u5BF9\u8BDD\u6846 ---------- */\n\n.xps-overlay {\n position: fixed;\n inset: 0;\n z-index: 9998;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--dsw-alias-bg-mask-2, rgba(0, 0, 0, 0.45));\n animation: xps-fade-in 0.15s ease-out;\n}\n\n@keyframes xps-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.xps-dialog {\n width: 360px;\n padding: 16px 20px;\n border-radius: 12px;\n border: 0.5px solid var(--dsw-alias-border-l2, #dee0e3);\n background: var(--dsw-alias-bg-layer-3, #ffffff);\n box-shadow: 0 8px 32px var(--dsw-alias-bg-mask-1, rgba(0, 0, 0, 0.18));\n /* \u5165\u573A:\u6DE1\u5165 + 0.98 \u2192 1 \u8F7B\u5FAE\u653E\u5927 */\n animation: xps-dialog-in 0.15s ease-out;\n}\n\n@keyframes xps-dialog-in {\n from { opacity: 0; transform: scale(0.98); }\n to { opacity: 1; transform: scale(1); }\n}\n\n.xps-dialog-title {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n margin-bottom: 8px;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n\n.xps-dialog-body {\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary, #646a73);\n margin-bottom: 16px;\n}\n\n.xps-dialog-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n}\n\n/* \u957F\u6587\u672C\u5BF9\u8BDD\u6846(\u5B89\u88C5\u5931\u8D25\u7684\u591A\u884C\u65E5\u5FD7\u3001\u5F85\u624B\u52A8\u6267\u884C\u7684\u547D\u4EE4):\u6BD4\u901A\u7528\u5BF9\u8BDD\u6846\u5BBD,\u7A84\u5C4F\u81EA\u52A8\u6536\u7A84 */\n.xps-dialog.xps-dialog-wide {\n width: 520px;\n max-width: calc(100vw - 32px);\n box-sizing: border-box;\n}\n\n/* \u6B63\u6587\u539F\u6587\u5757:\u4FDD\u7559\u6362\u884C\u4E0E\u7F29\u8FDB,\u8FC7\u957F\u65F6\u5185\u90E8\u6EDA\u52A8,\u4E0D\u628A\u7A97\u53E3\u6491\u7206;\u53EF\u624B\u52A8\u9009\u4E2D\u590D\u5236 */\n.xps-dialog-pre {\n white-space: pre-wrap;\n max-height: 320px;\n overflow: auto;\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-2, #f5f6f7);\n border: 0.5px solid var(--dsw-alias-border-l2, #dee0e3);\n font-family: var(--dsw-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary, #1f2329);\n text-align: left;\n word-break: break-word;\n user-select: text;\n}\n\n/* ---------- \u9875\u9762\u5360\u4F4D(\u9AA8\u67B6\u671F) ---------- */\n\n.xps-page-placeholder {\n padding: 18px;\n border: 0.5px dashed var(--dsw-alias-border-l2, #dee0e3);\n border-radius: 8px;\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-tertiary, #8f959e);\n}\n\n/* ---------- \u4EA4\u4E92\u72B6\u6001(\u5168\u7AD9\u7EDF\u4E00:\u8FC7\u6E21 / \u6309\u538B / \u7126\u70B9\u73AF) ----------\n * \u53EA\u8FC7\u6E21\u989C\u8272\u4E0E\u900F\u660E\u5EA6,\u4E0D\u505A\u4F4D\u79FB\u7F29\u653E\u52A8\u753B;\u6309\u538B\u7528\u4E00\u6863\u66F4\u6DF1\u7684 active \u5E95\u8272 + \u6781\u8F7B\u5FAE\u4E0B\u538B\u3002\n * \u9875\u9762\u79C1\u6709\u6837\u5F0F(market / admin)\u5728\u672C\u6587\u4EF6\u4E4B\u540E\u6CE8\u5165,\u5404\u81EA\u7684\u8FC7\u6E21\u4E0E\u6309\u538B\u6001\u5199\u5728\u5404\u81EA\u6A21\u5757\u91CC\u3002\n */\n\n/* .xps-row \u7684\u8FC7\u6E21\u5199\u5728\u81EA\u5DF1\u7684\u57FA\u7840\u89C4\u5219\u91CC(\u89C1\u4E0A),\u6B64\u5904\u4E0D\u518D\u91CD\u590D\u58F0\u660E */\n.xps-btn,\n.xps-icon-btn,\n.xps-nav-item,\n.xps-input {\n transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease,\n opacity 0.15s ease;\n}\n\n/* \u6309\u538B:\u80CC\u666F\u518D\u6DF1\u4E00\u6863(interactive-bg-active);\u4E3B/\u63CF\u8FB9/\u5371\u9669\u6309\u94AE\u6309\u5404\u81EA\u8272\u7CFB\u52A0\u6DF1 */\n.xps-btn:active:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-active, rgba(38, 49, 72, 0.1));\n transform: scale(0.98);\n}\n\n.xps-btn-primary:active:not(:disabled) {\n /* \u4E3B\u6309\u94AE\u6CA1\u6709 -active token(\u53EA\u6709 -fill / -hover),\u6309\u538B\u76F4\u63A5\u6309\u54C1\u724C\u8272\u52A0\u6DF1 */\n background: color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 78%, #000000);\n}\n\n.xps-btn-outline:active:not(:disabled) {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary, #3370ff) 16%, transparent);\n}\n\n.xps-btn-danger:active:not(:disabled) {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d83931) 16%, transparent);\n}\n\n.xps-btn-ghost:active:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-active, rgba(38, 49, 72, 0.1));\n}\n\n.xps-icon-btn:active:not(:disabled),\n.xps-nav-item:active {\n background: var(--dsw-alias-interactive-bg-active, rgba(38, 49, 72, 0.1));\n}\n\n.xps-row:active {\n background: var(--dsw-alias-interactive-bg-active, rgba(38, 49, 72, 0.1));\n}\n\n/* \u7126\u70B9\u73AF:\u53EA\u5728\u952E\u76D8\u5BFC\u822A\u65F6\u51FA\u73B0(:focus-visible),\u9F20\u6807\u70B9\u51FB\u4E0D\u753B\u73AF */\n.xps-btn:focus-visible,\n.xps-icon-btn:focus-visible,\n.xps-nav-item:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #3370ff);\n outline-offset: 2px;\n}\n\n/* \u6574\u884C\u5361\u7247\u7528\u5185\u63CF\u8FB9,\u907F\u514D\u8D34\u5230\u5185\u5BB9\u533A\u8FB9\u7F18\u88AB\u88C1\u6389 */\n.xps-row:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #3370ff);\n outline-offset: -2px;\n}\n\n/* \u7981\u7528\u6001:\u9664\u5404\u7EC4\u4EF6\u81EA\u5DF1\u7684 opacity \u5916,\u6E38\u6807\u7EDF\u4E00\u515C\u5E95 */\n.xps-app :disabled {\n cursor: not-allowed;\n}\n\n/* \u52A8\u6548\u504F\u597D:reduce \u65F6\u5173\u6389\u8FC7\u6E21\u4E0E\u5165\u573A\u52A8\u753B(\u6309\u538B\u7684\u7F29\u653E\u4E5F\u4E00\u5E76\u53D6\u6D88) */\n@media (prefers-reduced-motion: reduce) {\n .xps-btn,\n .xps-icon-btn,\n .xps-nav-item,\n .xps-input,\n .xps-row,\n .xps-toast,\n .xps-overlay,\n .xps-dialog {\n transition: none;\n animation: none;\n }\n\n .xps-btn:active:not(:disabled) {\n transform: none;\n }\n}\n";
3378
3409
 
3379
3410
  // src/client/theme-inject.ts
3380
3411
  function ensureThemeStyles() {
@@ -3576,6 +3607,126 @@ function GeneralTokenRow() {
3576
3607
  ] });
3577
3608
  }
3578
3609
 
3610
+ // src/client/settings/GeneralUpdateRow.tsx
3611
+ var import_react11 = require("react");
3612
+ var import_jsx_runtime22 = require("react/jsx-runtime");
3613
+ var rowStyle2 = {
3614
+ display: "flex",
3615
+ justifyContent: "space-between",
3616
+ alignItems: "center",
3617
+ gap: 24,
3618
+ padding: "16px 0",
3619
+ borderBottom: "0.5px solid var(--dsw-alias-border-l2, #dee0e3)"
3620
+ };
3621
+ var leftStyle2 = { minWidth: 0 };
3622
+ var titleStyle2 = {
3623
+ fontSize: 14,
3624
+ lineHeight: "20px",
3625
+ color: "var(--dsw-alias-label-primary, #1f2329)"
3626
+ };
3627
+ var descStyle2 = {
3628
+ marginTop: 4,
3629
+ fontSize: 12,
3630
+ lineHeight: "18px",
3631
+ color: "var(--dsw-alias-label-secondary, #646a73)"
3632
+ };
3633
+ var valueStyle2 = {
3634
+ fontSize: 13,
3635
+ lineHeight: "20px",
3636
+ color: "var(--dsw-alias-label-primary, #1f2329)"
3637
+ };
3638
+ var hintStyle2 = {
3639
+ fontSize: 12,
3640
+ lineHeight: "18px",
3641
+ color: "var(--dsw-alias-label-tertiary, #8f959e)"
3642
+ };
3643
+ var errorStyle2 = {
3644
+ ...hintStyle2,
3645
+ color: "var(--dsw-alias-state-error-primary, #d83931)",
3646
+ whiteSpace: "pre-line"
3647
+ };
3648
+ var rightStyle2 = {
3649
+ flexShrink: 0,
3650
+ display: "flex",
3651
+ flexDirection: "column",
3652
+ alignItems: "flex-end",
3653
+ gap: 4
3654
+ };
3655
+ function messageOf3(error, fallback) {
3656
+ return error instanceof Error && error.message !== "" ? error.message : fallback;
3657
+ }
3658
+ function GeneralUpdateRow() {
3659
+ const [phase, setPhase] = (0, import_react11.useState)({ kind: "checking" });
3660
+ const [error, setError] = (0, import_react11.useState)("");
3661
+ const check = () => {
3662
+ setPhase({ kind: "checking" });
3663
+ setError("");
3664
+ void checkSelfUpdate().then((result) => setPhase({ kind: "checked", check: result })).catch((err) => {
3665
+ setPhase({ kind: "checked", check: { current: null, latest: null, updateAvailable: false } });
3666
+ setError(messageOf3(err, "\u68C0\u67E5\u66F4\u65B0\u5931\u8D25"));
3667
+ });
3668
+ };
3669
+ (0, import_react11.useEffect)(check, []);
3670
+ const handleUpdate = (target, check0) => {
3671
+ setPhase({ kind: "updating", check: check0 });
3672
+ setError("");
3673
+ void applySelfUpdate(target).then((result) => {
3674
+ if (result.command !== void 0 && result.command !== "") {
3675
+ setPhase({ kind: "degraded", command: result.command, version: target });
3676
+ return;
3677
+ }
3678
+ setPhase({ kind: "updated", version: target });
3679
+ }).catch((err) => {
3680
+ setPhase({ kind: "checked", check: check0 });
3681
+ setError(messageOf3(err, "\u66F4\u65B0\u5931\u8D25"));
3682
+ });
3683
+ };
3684
+ const checking = phase.kind === "checking";
3685
+ const updating = phase.kind === "updating";
3686
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: rowStyle2, children: [
3687
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: leftStyle2, children: [
3688
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: titleStyle2, children: "\u85AA\u4EBA\u85AA\u4E8B\u5E02\u573A \xB7 \u63D2\u4EF6\u66F4\u65B0" }),
3689
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: descStyle2, children: phase.kind === "checked" && phase.check.current !== null ? `\u5F53\u524D\u7248\u672C v${phase.check.current}` : "\u81EA\u52A8\u68C0\u6D4B npm \u4E0A\u7684\u65B0\u7248\u672C,\u4E00\u952E\u66F4\u65B0(\u66F4\u65B0\u540E\u9700\u91CD\u542F\u5E94\u7528\u751F\u6548)" })
3690
+ ] }),
3691
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: rightStyle2, children: [
3692
+ phase.kind === "checking" && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: hintStyle2, children: "\u6B63\u5728\u68C0\u67E5\u66F4\u65B0\u2026" }),
3693
+ phase.kind === "checked" && (phase.check.updateAvailable && phase.check.latest !== null ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
3694
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: valueStyle2, children: [
3695
+ "\u53D1\u73B0\u65B0\u7248\u672C v",
3696
+ phase.check.latest
3697
+ ] }),
3698
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3699
+ Button,
3700
+ {
3701
+ variant: "primary",
3702
+ size: "small",
3703
+ onClick: () => handleUpdate(phase.check.latest ?? "", phase.check),
3704
+ title: `\u66F4\u65B0\u5230 v${phase.check.latest}`,
3705
+ children: "\u4E00\u952E\u66F4\u65B0"
3706
+ }
3707
+ )
3708
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
3709
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: hintStyle2, children: phase.check.latest === null ? "\u65E0\u6CD5\u83B7\u53D6\u6700\u65B0\u7248\u672C\u4FE1\u606F" : "\u5DF2\u662F\u6700\u65B0\u7248\u672C" }),
3710
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Button, { size: "small", variant: "ghost", onClick: check, title: "\u91CD\u65B0\u68C0\u67E5 npm \u4E0A\u7684\u6700\u65B0\u7248\u672C", children: "\u91CD\u65B0\u68C0\u67E5" })
3711
+ ] })),
3712
+ updating && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: hintStyle2, children: "\u6B63\u5728\u66F4\u65B0,\u8BF7\u7A0D\u5019\u2026" }),
3713
+ phase.kind === "updated" && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: valueStyle2, children: [
3714
+ "\u5DF2\u66F4\u65B0\u5230 v",
3715
+ phase.version,
3716
+ ",\u5B8C\u5168\u9000\u51FA\u5E76\u91CD\u542F\u5E94\u7528\u540E\u751F\u6548"
3717
+ ] }),
3718
+ phase.kind === "degraded" && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { maxWidth: 420, textAlign: "right" }, children: [
3719
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: errorStyle2, children: "\u5BBF\u4E3B\u547D\u4EE4\u884C\u4E0D\u53EF\u7528,\u8BF7\u624B\u52A8\u6267\u884C\u4EE5\u4E0B\u547D\u4EE4\u540E\u91CD\u542F\u5E94\u7528:" }),
3720
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { ...hintStyle2, whiteSpace: "pre-wrap", wordBreak: "break-all" }, children: phase.command })
3721
+ ] }),
3722
+ error !== "" && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
3723
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: errorStyle2, children: error }),
3724
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Button, { size: "small", variant: "ghost", onClick: check, disabled: checking, children: "\u91CD\u8BD5" })
3725
+ ] })
3726
+ ] })
3727
+ ] });
3728
+ }
3729
+
3579
3730
  // src/client/index.ts
3580
3731
  var inject = ["slots"];
3581
3732
  function injectTheme() {
@@ -3588,7 +3739,7 @@ function injectTheme() {
3588
3739
  function StoreIcon(props) {
3589
3740
  const active = props.active === true;
3590
3741
  const size = typeof props.size === "number" ? props.size : 20;
3591
- return (0, import_react11.createElement)(
3742
+ return (0, import_react12.createElement)(
3592
3743
  "svg",
3593
3744
  {
3594
3745
  width: size,
@@ -3599,13 +3750,13 @@ function StoreIcon(props) {
3599
3750
  color: active ? "var(--dsw-alias-brand-primary, #3861fb)" : "var(--dsw-alias-label-secondary, #646a73)"
3600
3751
  }
3601
3752
  },
3602
- (0, import_react11.createElement)("path", {
3753
+ (0, import_react12.createElement)("path", {
3603
3754
  d: "M4 7h16l-1.2-3.2A1 1 0 0 0 17.85 3H6.15a1 1 0 0 0-.95.8L4 7Zm0 0v12a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1V7",
3604
3755
  stroke: "currentColor",
3605
3756
  strokeWidth: 1.6,
3606
3757
  strokeLinejoin: "round"
3607
3758
  }),
3608
- (0, import_react11.createElement)("path", {
3759
+ (0, import_react12.createElement)("path", {
3609
3760
  d: "M9 11a3 3 0 0 0 6 0",
3610
3761
  stroke: "currentColor",
3611
3762
  strokeWidth: 1.6,
@@ -3615,13 +3766,13 @@ function StoreIcon(props) {
3615
3766
  }
3616
3767
  function BundleConfigSeat(props) {
3617
3768
  if (props.view === "page") {
3618
- return (0, import_react11.createElement)(
3769
+ return (0, import_react12.createElement)(
3619
3770
  "div",
3620
3771
  { className: "xps-page-placeholder" },
3621
3772
  "\u85AA\u4EBA\u85AA\u4E8B\u5E02\u573A\u914D\u7F6E(\u5360\u4F4D):serviceBaseUrl / cacheDir / requestTimeout / cachePolicy"
3622
3773
  );
3623
3774
  }
3624
- return (0, import_react11.createElement)("div", null, "\u85AA\u4EBA\u85AA\u4E8B\u5E02\u573A:\u79C1\u6709\u63D2\u4EF6\u6D4F\u89C8\u3001\u5B89\u88C5\u4E0E\u5F00\u53D1\u8005\u4E0A\u4F20");
3775
+ return (0, import_react12.createElement)("div", null, "\u85AA\u4EBA\u85AA\u4E8B\u5E02\u573A:\u79C1\u6709\u63D2\u4EF6\u6D4F\u89C8\u3001\u5B89\u88C5\u4E0E\u5F00\u53D1\u8005\u4E0A\u4F20");
3625
3776
  }
3626
3777
  function apply(ctx) {
3627
3778
  const slots = ctx.get("slots");
@@ -3654,7 +3805,7 @@ function apply(ctx) {
3654
3805
  "main",
3655
3806
  () => safe(
3656
3807
  "main",
3657
- () => slots.register({ name: "main", key: "xrxs-plugins-store" }, () => (0, import_react11.createElement)(MarketplaceApp))
3808
+ () => slots.register({ name: "main", key: "xrxs-plugins-store" }, () => (0, import_react12.createElement)(MarketplaceApp))
3658
3809
  )
3659
3810
  ),
3660
3811
  "xrxs-plugins-store.main"
@@ -3666,12 +3817,25 @@ function apply(ctx) {
3666
3817
  "settings.general.item",
3667
3818
  () => slots.register(
3668
3819
  { name: "settings.general.item", id: "xrxs-plugins-store-token", order: 50 },
3669
- () => (0, import_react11.createElement)(GeneralTokenRow)
3820
+ () => (0, import_react12.createElement)(GeneralTokenRow)
3670
3821
  )
3671
3822
  )
3672
3823
  ),
3673
3824
  "xrxs-plugins-store.settings.general-item"
3674
3825
  );
3826
+ ctx.effect(
3827
+ () => slots.inject(
3828
+ "settings.general.item",
3829
+ () => safe(
3830
+ "settings.general.item",
3831
+ () => slots.register(
3832
+ { name: "settings.general.item", id: "xrxs-plugins-store-update", order: 51 },
3833
+ () => (0, import_react12.createElement)(GeneralUpdateRow)
3834
+ )
3835
+ )
3836
+ ),
3837
+ "xrxs-plugins-store.settings.general-update"
3838
+ );
3675
3839
  ctx.effect(
3676
3840
  () => slots.inject(
3677
3841
  "plugins.bundle.config",
@@ -3679,7 +3843,7 @@ function apply(ctx) {
3679
3843
  "plugins.bundle.config",
3680
3844
  () => slots.register(
3681
3845
  { name: "plugins.bundle.config", key: "@xrxs-ai/dsh-xrxs-plugins-store" },
3682
- (props) => (0, import_react11.createElement)(BundleConfigSeat, props)
3846
+ (props) => (0, import_react12.createElement)(BundleConfigSeat, props)
3683
3847
  )
3684
3848
  )
3685
3849
  ),
@@ -64,7 +64,9 @@ export type KnownInstallErrorKind = 'minimum-release-age' | 'version-incompatibl
64
64
  /** 整个包在 registry 上不存在(404)。 */
65
65
  | 'package-not-found'
66
66
  /** 依赖的安装脚本被 pnpm 10+ 默认拦截(ERR_PNPM_IGNORED_BUILDS),需用户批准构建。 */
67
- | 'build-scripts-ignored';
67
+ | 'build-scripts-ignored'
68
+ /** desktop profile 由 Electron 应用独占管理,外部 CLI 被拒。 */
69
+ | 'desktop-profile-locked';
68
70
  export interface KnownInstallError {
69
71
  kind: KnownInstallErrorKind;
70
72
  hint: string;
@@ -3,7 +3,7 @@ import { spawn } from 'node:child_process';
3
3
  import { existsSync, readdirSync, statSync } from 'node:fs';
4
4
  import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
5
5
  import { homedir } from 'node:os';
6
- import { delimiter, dirname, join } from 'node:path';
6
+ import { basename, delimiter, dirname, join } from 'node:path';
7
7
  import { ApiError } from "./api-client.js";
8
8
  import { FATAL_TGZ_DEFECTS, inspectTgz } from "./tgz-inspect.js";
9
9
  /** shim 探测超时:只判「活不活」,5s 足够。 */
@@ -82,13 +82,26 @@ function appCliRelativePath(platform) {
82
82
  function runAsNodeFromCurrentProcess(execPath, platform) {
83
83
  if (execPath === '')
84
84
  return null;
85
- const execDir = dirname(execPath);
86
- const candidates = platform === 'darwin'
87
- ? [join(dirname(execDir), 'Resources', 'app', 'lib', 'desktop-cli.js')]
88
- : [join(execDir, 'resources', 'app', 'lib', 'desktop-cli.js')];
89
- for (const cliJs of candidates) {
90
- if (isRunnableFile(execPath, platform) && existsSync(cliJs))
91
- return { executable: execPath, cliJs };
85
+ // 沿 execPath 向上逐级找 Resources/resources 下的 app/lib/desktop-cli.js,锁定「安装本体」:
86
+ // 主进程(execPath = <App>.app/Contents/MacOS/<bin>)一层就命中;helper/utility 进程
87
+ // (路径更深,如 Contents/Frameworks/… Helper.app/Contents/MacOS/…)多级也能命中。
88
+ // 本体自带的 CLI 与本插件同宿主,peer 校验版本天然一致 —— 这是所有通道里最可靠的一条。
89
+ let dir = dirname(execPath);
90
+ for (let depth = 0; depth < 6; depth += 1) {
91
+ const cliJs = platform === 'darwin'
92
+ ? join(dir, 'Resources', 'app', 'lib', 'desktop-cli.js')
93
+ : join(dir, 'resources', 'app', 'lib', 'desktop-cli.js');
94
+ if (isRunnableFile(execPath, platform) && existsSync(cliJs)) {
95
+ const appRoot = dirname(dir);
96
+ const candidate = { executable: execPath, cliJs };
97
+ if (appRoot.endsWith('.app'))
98
+ candidate.appName = basename(appRoot).replace(/\.app$/i, '');
99
+ return candidate;
100
+ }
101
+ const parent = dirname(dir);
102
+ if (parent === dir)
103
+ break;
104
+ dir = parent;
92
105
  }
93
106
  return null;
94
107
  }
@@ -197,6 +210,14 @@ export async function resolveDshCli(env = process.env, execPath = process.execPa
197
210
  const home = env.HOME ?? env.USERPROFILE ?? homedir();
198
211
  const rejected = [];
199
212
  const notes = [];
213
+ // 本体 CLI 永远优先,shim 只作兜底:应用内入口(desktop-cli.js,manageDesktopProfile=true)
214
+ // 与本插件同宿主 —— peer 校验版本天然一致,不受 desktop profile 独占限制,也不吃外部 shim
215
+ // 的历史顽疾(缺 --profile、版本错位、陈旧 shim)。插件必然装在某个宿主应用里,所以这条
216
+ // 路几乎总能命中;只有应用不在标准位置 / desktop-cli.js 缺失时才轮到外部 shim。
217
+ const runAsNode = findRunAsNode(platform, env, home, execPath, notes, kind, appRoots);
218
+ if (runAsNode !== null)
219
+ return { cli: runAsNode, rejected, notes };
220
+ notes.push('未找到宿主应用内的 CLI 入口(desktop-cli.js),回落外部 dsh shim');
200
221
  const candidates = [
201
222
  ...findShimsIn((env.PATH ?? '').split(delimiter), platform),
202
223
  ...findShimsIn(commonShimDirs(platform, home), platform),
@@ -207,8 +228,7 @@ export async function resolveDshCli(env = process.env, execPath = process.execPa
207
228
  return { cli: { kind: 'shim', path: shimPath }, rejected, notes };
208
229
  rejected.push({ kind: 'shim', path: shimPath, reason: probe.reason });
209
230
  }
210
- const runAsNode = findRunAsNode(platform, env, home, execPath, notes, kind, appRoots);
211
- return { cli: runAsNode, rejected, notes };
231
+ return { cli: null, rejected, notes };
212
232
  }
213
233
  /** 只要通道(兼容旧调用形态)。 */
214
234
  export async function discoverDshCli(env = process.env, execPath = process.execPath) {
@@ -316,6 +336,12 @@ export function parseKnownInstallError(stderr, packageName, version, profile) {
316
336
  }
317
337
  // pnpm 10+ 默认不执行依赖的安装脚本(供应链防护):插件依赖带 postinstall 的包会触发。
318
338
  // 这不是包坏了,是「需要用户显式批准」—— 给出批准入口,不替用户做供应链决定。
339
+ if (/managed exclusively by the Electron application/i.test(stderr)) {
340
+ return {
341
+ kind: 'desktop-profile-locked',
342
+ hint: 'desktop profile 由桌面应用独占管理,外部 dsh 命令行不能直接操作它。请把「薪人薪事市场」插件更新到 0.2.4 或更高版本(新版会自动改用应用内 CLI 入口),或在桌面应用的插件管理器中操作。',
343
+ };
344
+ }
319
345
  if (/ERR_PNPM_IGNORED_BUILDS|Ignored build scripts/i.test(stderr)) {
320
346
  const packages = parseIgnoredBuildPackages(stderr);
321
347
  return {
@@ -1,5 +1,6 @@
1
1
  import { ApiError } from "./api-client.js";
2
2
  import { approveProfileBuilds } from "./build-approval.js";
3
+ import { applySelfUpdate, checkSelfUpdate } from "./self-update.js";
3
4
  import { submitPackage } from "./package-submit.js";
4
5
  import { installPlugin, listInstalledFromProfile, rawOutputOf, reportInstall, scrubCredentials, uninstallPlugin, InstallFailure, } from "./installer.js";
5
6
  /**
@@ -393,6 +394,18 @@ async function handleUninstall(rc) {
393
394
  throw new HttpError(400, '缺少参数 name');
394
395
  writeInstallOutcome(rc, await uninstallPlugin(name, rc.deps.installer));
395
396
  }
397
+ /** GET /api/self-update:当前版本 vs npm latest(公开端点,无鉴权;失败 latest=null,UI 显示检查失败)。 */
398
+ async function handleSelfUpdateCheck(rc) {
399
+ writeOk(rc, await checkSelfUpdate());
400
+ }
401
+ /** POST /api/self-update/apply:一键自我更新(复用安装链路装 npm 确切版本),成功后提示重启。 */
402
+ async function handleSelfUpdateApply(rc) {
403
+ const body = await readJsonBody(rc.req);
404
+ const version = requiredString(body.version);
405
+ if (version === null)
406
+ throw new HttpError(400, '缺少参数 version(要更新到的确切版本)');
407
+ writeInstallOutcome(rc, await applySelfUpdate(version, rc.deps.installer));
408
+ }
396
409
  /** POST /api/approve-builds:批准 pnpm 拦下的依赖构建脚本(allowBuilds 占位 → true),批准后 client 重试安装。 */
397
410
  async function handleApproveBuilds(rc) {
398
411
  const body = await readJsonBody(rc.req);
@@ -510,6 +523,8 @@ const ROUTES = [
510
523
  { method: 'POST', pattern: '/api/uninstall', handler: handleUninstall },
511
524
  { method: 'POST', pattern: '/api/install-report', handler: handleInstallReport },
512
525
  { method: 'POST', pattern: '/api/approve-builds', handler: handleApproveBuilds },
526
+ { method: 'GET', pattern: '/api/self-update', handler: handleSelfUpdateCheck },
527
+ { method: 'POST', pattern: '/api/self-update/apply', handler: handleSelfUpdateApply },
513
528
  {
514
529
  method: 'POST',
515
530
  pattern: '/api/developer/plugins',
@@ -0,0 +1,30 @@
1
+ import { type InstallOutcome, type InstallerDeps } from './installer.ts';
2
+ /**
3
+ * 市场插件自我更新(设计文档外新增,入口:设置 → 通用 → 薪人薪事市场 下方):
4
+ * - 当前版本:读插件包根的 package.json(运行实例的 version,重启后即新版本);
5
+ * - 最新版本:查 npm registry 的 dist-tag latest(公开端点,无鉴权、零凭据);
6
+ * - 一键更新:复用安装链路 `dsh plugin --profile <n> add @xrxs-ai/dsh-xrxs-plugins-store@<版本>`
7
+ * (installPlugin 白名单 + --profile + 老 CLI 回退全继承)。
8
+ * 覆盖安装运行中的自身目录是安全的:文件句柄仍指向旧 inode,重启后加载新版本 ——
9
+ * 与市场里更新其他插件走的是同一条路。
10
+ */
11
+ /** npm 包名(自我更新的目标就是本插件)。 */
12
+ export declare const SELF_PACKAGE_NAME = "@xrxs-ai/dsh-xrxs-plugins-store";
13
+ /** 当前运行实例的版本(包根 package.json);读不到为 null(极端情况:裸文件运行)。
14
+ * 依次尝试:模块相对层级(tsc 产物 lib/host/ 与源码 src/host/ 都是上一级的上一级)、
15
+ * 按包名 resolve(profile 安装布局变化时的兜底);读到的包名必须匹配,防止层级猜错读成别的包。 */
16
+ export declare function currentSelfVersion(): string | null;
17
+ export interface SelfUpdateCheck {
18
+ /** 当前运行实例版本;读不到为 null(无法比较,不可更新) */
19
+ current: string | null;
20
+ /** npm 上 latest 的版本;查询失败为 null */
21
+ latest: string | null;
22
+ updateAvailable: boolean;
23
+ }
24
+ /** 查 npm latest 并与当前版本比较;registry 查询失败时 latest 为 null(不抛,便于 UI 展示「检查失败」)。 */
25
+ export declare function checkSelfUpdate(): Promise<SelfUpdateCheck>;
26
+ /** 应用更新:复用安装链路装确切版本(不装 latest tag,避免「检查到装的」漂移)。 */
27
+ export declare function applySelfUpdate(version: string, deps: InstallerDeps): Promise<InstallOutcome>;
28
+ /** 简易 semver 比较(本插件只用 x.y.z;逐段数值比较,长度不齐补 0):
29
+ * a>b → 1,a<b → -1,相等 → 0;不可解析的段当 0。 */
30
+ export declare function compareVersions(a: string, b: string): number;
@@ -0,0 +1,97 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { createRequire } from 'node:module';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { installPlugin } from "./installer.js";
5
+ /**
6
+ * 市场插件自我更新(设计文档外新增,入口:设置 → 通用 → 薪人薪事市场 下方):
7
+ * - 当前版本:读插件包根的 package.json(运行实例的 version,重启后即新版本);
8
+ * - 最新版本:查 npm registry 的 dist-tag latest(公开端点,无鉴权、零凭据);
9
+ * - 一键更新:复用安装链路 `dsh plugin --profile <n> add @xrxs-ai/dsh-xrxs-plugins-store@<版本>`
10
+ * (installPlugin 白名单 + --profile + 老 CLI 回退全继承)。
11
+ * 覆盖安装运行中的自身目录是安全的:文件句柄仍指向旧 inode,重启后加载新版本 ——
12
+ * 与市场里更新其他插件走的是同一条路。
13
+ */
14
+ /** npm 包名(自我更新的目标就是本插件)。 */
15
+ export const SELF_PACKAGE_NAME = '@xrxs-ai/dsh-xrxs-plugins-store';
16
+ /** 查 latest 的 registry(源头以 npmjs 为准;镜像站有分钟级同步延迟,可能查到旧 latest)。 */
17
+ const NPM_REGISTRY_LATEST = 'https://registry.npmjs.org/@xrxs-ai%2Fdsh-xrxs-plugins-store/latest';
18
+ /** registry 查询超时:公开端点,给短超时,失败让用户重试而不是干等。 */
19
+ const LATEST_TIMEOUT_MS = 10_000;
20
+ let cachedVersion = null;
21
+ /** 当前运行实例的版本(包根 package.json);读不到为 null(极端情况:裸文件运行)。
22
+ * 依次尝试:模块相对层级(tsc 产物 lib/host/ 与源码 src/host/ 都是上一级的上一级)、
23
+ * 按包名 resolve(profile 安装布局变化时的兜底);读到的包名必须匹配,防止层级猜错读成别的包。 */
24
+ export function currentSelfVersion() {
25
+ if (cachedVersion !== null)
26
+ return cachedVersion;
27
+ const tryRead = (path) => {
28
+ try {
29
+ const pkg = JSON.parse(readFileSync(path, 'utf8'));
30
+ return typeof pkg.version === 'string' && pkg.name === SELF_PACKAGE_NAME ? pkg.version : null;
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ };
36
+ try {
37
+ const pkgPath = fileURLToPath(new URL('../../package.json', import.meta.url));
38
+ cachedVersion = tryRead(pkgPath);
39
+ }
40
+ catch {
41
+ cachedVersion = null;
42
+ }
43
+ if (cachedVersion === null) {
44
+ try {
45
+ cachedVersion = tryRead(createRequire(import.meta.url).resolve(`${SELF_PACKAGE_NAME}/package.json`));
46
+ }
47
+ catch {
48
+ cachedVersion = null;
49
+ }
50
+ }
51
+ return cachedVersion;
52
+ }
53
+ /** 查 npm latest 并与当前版本比较;registry 查询失败时 latest 为 null(不抛,便于 UI 展示「检查失败」)。 */
54
+ export async function checkSelfUpdate() {
55
+ const current = currentSelfVersion();
56
+ let latest = null;
57
+ try {
58
+ const response = await fetch(NPM_REGISTRY_LATEST, {
59
+ signal: AbortSignal.timeout(LATEST_TIMEOUT_MS),
60
+ headers: { accept: 'application/json' },
61
+ });
62
+ if (response.ok) {
63
+ const data = (await response.json());
64
+ if (typeof data.version === 'string' && data.version !== '')
65
+ latest = data.version;
66
+ }
67
+ }
68
+ catch {
69
+ // 网络失败/超时:latest 保持 null
70
+ }
71
+ return { current, latest, updateAvailable: current !== null && latest !== null && compareVersions(latest, current) > 0 };
72
+ }
73
+ /** 应用更新:复用安装链路装确切版本(不装 latest tag,避免「检查到装的」漂移)。 */
74
+ export async function applySelfUpdate(version, deps) {
75
+ return installPlugin({ name: SELF_PACKAGE_NAME, version, sourceType: 'npm' }, deps);
76
+ }
77
+ /** 简易 semver 比较(本插件只用 x.y.z;逐段数值比较,长度不齐补 0):
78
+ * a>b → 1,a<b → -1,相等 → 0;不可解析的段当 0。 */
79
+ export function compareVersions(a, b) {
80
+ const parse = (text) => text
81
+ .trim()
82
+ .replace(/^v/, '')
83
+ .split('.')
84
+ .map((part) => {
85
+ const numeric = /^\d+/.exec(part);
86
+ return numeric === null ? 0 : Number(numeric[0]);
87
+ });
88
+ const left = parse(a);
89
+ const right = parse(b);
90
+ const length = Math.max(left.length, right.length);
91
+ for (let index = 0; index < length; index += 1) {
92
+ const diff = (left[index] ?? 0) - (right[index] ?? 0);
93
+ if (diff !== 0)
94
+ return diff > 0 ? 1 : -1;
95
+ }
96
+ return 0;
97
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xrxs-ai/dsh-xrxs-plugins-store",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "DSH 私有插件市场插件(静态持久 bundle,双 face)",
5
5
  "type": "module",
6
6
  "license": "MIT",