dsh-agy-link 0.4.59 → 0.4.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.js CHANGED
@@ -3006,7 +3006,7 @@ body > [id^="iagy-mmd"] .error-icon {
3006
3006
  const dataLang = (code?.getAttribute("data-language") ?? block.getAttribute("data-language") ?? "").trim().toLowerCase();
3007
3007
  if (dataLang !== "") return dataLang;
3008
3008
  const text = ((block.querySelector("[data-code-block-banner] [class*=\"infostring\"]") ?? block.querySelector("[data-code-block-banner] [class*=\"language\"]"))?.textContent ?? "").trim().toLowerCase();
3009
- if (text !== "") return text.split(/\s+/)[0] ?? "";
3009
+ if (text !== "" && text !== "代码块" && text !== "code" && text !== "code block") return text.split(/\s+/)[0] ?? "";
3010
3010
  const bannerText = (block.querySelector("[data-code-block-banner]")?.textContent ?? "").trim().toLowerCase();
3011
3011
  if (bannerText !== "" && bannerText !== "代码块" && bannerText !== "code" && bannerText !== "code block") return bannerText.split(/\s+/)[0] ?? "";
3012
3012
  return "";
@@ -3076,12 +3076,18 @@ body > [id^="iagy-mmd"] .error-icon {
3076
3076
  function cleanupTempElements(id) {
3077
3077
  if (typeof document === "undefined") return;
3078
3078
  if (id) {
3079
- document.getElementById("d" + id)?.remove();
3080
- document.getElementById("i" + id)?.remove();
3081
- document.getElementById(id)?.remove();
3079
+ const delD = document.getElementById("d" + id);
3080
+ if (delD && (typeof delD.closest !== "function" || !delD.closest("[data-agy-mermaid-svg]"))) delD.remove();
3081
+ const delI = document.getElementById("i" + id);
3082
+ if (delI && (typeof delI.closest !== "function" || !delI.closest("[data-agy-mermaid-svg]"))) delI.remove();
3083
+ const el = document.getElementById(id);
3084
+ if (el && (typeof el.closest !== "function" || !el.closest("[data-agy-mermaid-svg]"))) el.remove();
3082
3085
  }
3083
3086
  const stray = document.querySelectorAll("body > [id^=\"dagy-mmd\"], body > [id^=\"iagy-mmd\"], body > [id^=\"d_agy-mmd\"], body > [id^=\"i_agy-mmd\"], body > [id^=\"agy-mmd-\"]");
3084
- for (let i = 0; i < stray.length; i++) stray[i]?.remove();
3087
+ for (let i = 0; i < stray.length; i++) {
3088
+ const s = stray[i];
3089
+ if (s && (typeof s.closest !== "function" || !s.closest("[data-agy-mermaid-svg]"))) s.remove();
3090
+ }
3085
3091
  }
3086
3092
  function repairMermaidSource(source) {
3087
3093
  if (!/^\s*(?:flowchart|graph)\b/i.test(source)) return source;
@@ -3672,47 +3678,322 @@ div[data-variant="think"] [class*="thinkBody"] {
3672
3678
  anthropic: "claude",
3673
3679
  openai: "openai"
3674
3680
  };
3675
- /** Antigravity mark: gradient orb with an orbit ring (product has no public simple-icon). */
3676
- function agyIcon(size = 14) {
3677
- const gid = "agy-icon-linear-gradient";
3681
+ /**
3682
+ * Antigravity logo mark: 3D orbit sphere with specular highlight, luminous front/back rings
3683
+ * and twin satellite nodes matching the official assets/icon.svg.
3684
+ */
3685
+ function agyIcon(size = 16) {
3686
+ const uid = "agy-logo";
3678
3687
  return h("svg", {
3679
- viewBox: "0 0 24 24",
3688
+ viewBox: "0 0 36 36",
3680
3689
  width: size,
3681
3690
  height: size,
3691
+ fill: "none",
3682
3692
  "aria-hidden": true,
3683
3693
  style: {
3684
3694
  display: "inline-block",
3685
- verticalAlign: "-2px",
3695
+ verticalAlign: "-2.5px",
3686
3696
  flexShrink: 0
3687
3697
  }
3688
3698
  }, h("defs", null, h("linearGradient", {
3689
- id: gid,
3690
- x1: "0",
3691
- y1: "0",
3692
- x2: "1",
3693
- y2: "1"
3699
+ id: `${uid}-orb`,
3700
+ x1: "12",
3701
+ y1: "11",
3702
+ x2: "25",
3703
+ y2: "25",
3704
+ gradientUnits: "userSpaceOnUse"
3694
3705
  }, h("stop", {
3695
- offset: "0",
3696
- "stop-color": "#4C8DFF"
3706
+ offset: "0%",
3707
+ "stop-color": "#38BDF8"
3697
3708
  }), h("stop", {
3698
- offset: "1",
3699
- "stop-color": "#A96BFF"
3700
- }))), h("circle", {
3701
- cx: 12,
3702
- cy: 12,
3703
- r: 6,
3704
- fill: `url(#${gid})`
3705
- }), h("ellipse", {
3706
- cx: 12,
3707
- cy: 12,
3708
- rx: 10.4,
3709
- ry: 3.9,
3710
- fill: "none",
3711
- stroke: `url(#${gid})`,
3712
- "stroke-width": 1.4,
3713
- transform: "rotate(-18 12 12)"
3709
+ offset: "45%",
3710
+ "stop-color": "#6366F1"
3711
+ }), h("stop", {
3712
+ offset: "85%",
3713
+ "stop-color": "#9333EA"
3714
+ }), h("stop", {
3715
+ offset: "100%",
3716
+ "stop-color": "#C026D3"
3717
+ })), h("linearGradient", {
3718
+ id: `${uid}-rf`,
3719
+ x1: "6",
3720
+ y1: "24",
3721
+ x2: "31",
3722
+ y2: "12",
3723
+ gradientUnits: "userSpaceOnUse"
3724
+ }, h("stop", {
3725
+ offset: "0%",
3726
+ "stop-color": "#00D2FF"
3727
+ }), h("stop", {
3728
+ offset: "40%",
3729
+ "stop-color": "#38BDF8"
3730
+ }), h("stop", {
3731
+ offset: "70%",
3732
+ "stop-color": "#818CF8"
3733
+ }), h("stop", {
3734
+ offset: "100%",
3735
+ "stop-color": "#F43F5E"
3736
+ })), h("linearGradient", {
3737
+ id: `${uid}-rb`,
3738
+ x1: "7",
3739
+ y1: "12",
3740
+ x2: "29",
3741
+ y2: "24",
3742
+ gradientUnits: "userSpaceOnUse"
3743
+ }, h("stop", {
3744
+ offset: "0%",
3745
+ "stop-color": "#38BDF8",
3746
+ "stop-opacity": "0.4"
3747
+ }), h("stop", {
3748
+ offset: "100%",
3749
+ "stop-color": "#A855F7",
3750
+ "stop-opacity": "0.4"
3751
+ })), h("linearGradient", {
3752
+ id: `${uid}-hl`,
3753
+ x1: "14",
3754
+ y1: "12",
3755
+ x2: "19",
3756
+ y2: "18",
3757
+ gradientUnits: "userSpaceOnUse"
3758
+ }, h("stop", {
3759
+ offset: "0%",
3760
+ "stop-color": "#FFFFFF",
3761
+ "stop-opacity": "0.65"
3762
+ }), h("stop", {
3763
+ offset: "100%",
3764
+ "stop-color": "#FFFFFF",
3765
+ "stop-opacity": "0.05"
3766
+ }))), h("path", {
3767
+ d: "M 6.8 14.2 C 8.2 9.6 17.8 7.2 26.2 10.8 C 28.0 11.6 29.3 12.6 30.2 13.8",
3768
+ stroke: `url(#${uid}-rb)`,
3769
+ "stroke-width": "2.4",
3770
+ "stroke-linecap": "round"
3771
+ }), h("circle", {
3772
+ cx: 18,
3773
+ cy: 18,
3774
+ r: 7.5,
3775
+ fill: `url(#${uid}-orb)`
3776
+ }), h("path", {
3777
+ d: "M 13.2 15.2 A 5.5 5.5 0 0 1 21.0 13.0 A 6.2 6.2 0 0 0 14.0 18.0 Z",
3778
+ fill: `url(#${uid}-hl)`
3779
+ }), h("path", {
3780
+ d: "M 30.2 13.8 C 31.4 18.2 21.8 26.2 12.8 24.2 C 9.4 23.4 7.4 21.8 6.6 19.6",
3781
+ stroke: `url(#${uid}-rf)`,
3782
+ "stroke-width": "2.6",
3783
+ "stroke-linecap": "round"
3784
+ }), h("circle", {
3785
+ cx: 8.2,
3786
+ cy: 18.2,
3787
+ r: 2.2,
3788
+ fill: "#00D2FF"
3789
+ }), h("circle", {
3790
+ cx: 8.2,
3791
+ cy: 18.2,
3792
+ r: 1,
3793
+ fill: "#FFFFFF"
3794
+ }), h("circle", {
3795
+ cx: 28.4,
3796
+ cy: 20.4,
3797
+ r: 1.8,
3798
+ fill: "#F43F5E"
3799
+ }), h("circle", {
3800
+ cx: 28.4,
3801
+ cy: 20.4,
3802
+ r: .8,
3803
+ fill: "#FFFFFF"
3714
3804
  }));
3715
3805
  }
3806
+ /**
3807
+ * Settings dialog navigation icon replacement for Antigravity.
3808
+ * DSH settings shell projects nav glyphs from a closed list and falls back to a generic gear
3809
+ * for third-party sections. We dynamically inject a stylesheet matching Antigravity's section
3810
+ * row to display the custom Antigravity brand logo.
3811
+ */
3812
+ const NAV_ICON_MARKER = "data-dsh-agy-nav-icon";
3813
+ const NAV_ROW_SELECTOR = "[role=\"dialog\"] nav button, [role=\"dialog\"] nav a, [role=\"dialog\"] aside button, .dsh-settings-nav button";
3814
+ const AGY_NAV_LOGO_SVG = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 36 36\" fill=\"none\"><defs><linearGradient id=\"an-orb\" x1=\"12\" y1=\"11\" x2=\"25\" y2=\"25\" gradientUnits=\"userSpaceOnUse\"><stop offset=\"0%\" stop-color=\"#38BDF8\"/><stop offset=\"45%\" stop-color=\"#6366F1\"/><stop offset=\"85%\" stop-color=\"#9333EA\"/><stop offset=\"100%\" stop-color=\"#C026D3\"/></linearGradient><linearGradient id=\"an-rf\" x1=\"6\" y1=\"24\" x2=\"31\" y2=\"12\" gradientUnits=\"userSpaceOnUse\"><stop offset=\"0%\" stop-color=\"#00D2FF\"/><stop offset=\"40%\" stop-color=\"#38BDF8\"/><stop offset=\"70%\" stop-color=\"#818CF8\"/><stop offset=\"100%\" stop-color=\"#F43F5E\"/></linearGradient><linearGradient id=\"an-rb\" x1=\"7\" y1=\"12\" x2=\"29\" y2=\"24\" gradientUnits=\"userSpaceOnUse\"><stop offset=\"0%\" stop-color=\"#38BDF8\" stop-opacity=\"0.4\"/><stop offset=\"100%\" stop-color=\"#A855F7\" stop-opacity=\"0.4\"/></linearGradient><linearGradient id=\"an-hl\" x1=\"14\" y1=\"12\" x2=\"19\" y2=\"18\" gradientUnits=\"userSpaceOnUse\"><stop offset=\"0%\" stop-color=\"#FFFFFF\" stop-opacity=\"0.65\"/><stop offset=\"100%\" stop-color=\"#FFFFFF\" stop-opacity=\"0.05\"/></linearGradient></defs><path d=\"M 6.8 14.2 C 8.2 9.6 17.8 7.2 26.2 10.8 C 28.0 11.6 29.3 12.6 30.2 13.8\" stroke=\"url(#an-rb)\" stroke-width=\"2.4\" stroke-linecap=\"round\"/><circle cx=\"18\" cy=\"18\" r=\"7.5\" fill=\"url(#an-orb)\"/><path d=\"M 13.2 15.2 A 5.5 5.5 0 0 1 21.0 13.0 A 6.2 6.2 0 0 0 14.0 18.0 Z\" fill=\"url(#an-hl)\"/><path d=\"M 30.2 13.8 C 31.4 18.2 21.8 26.2 12.8 24.2 C 9.4 23.4 7.4 21.8 6.6 19.6\" stroke=\"url(#an-rf)\" stroke-width=\"2.6\" stroke-linecap=\"round\"/><circle cx=\"8.2\" cy=\"18.2\" r=\"2.2\" fill=\"#00D2FF\"/><circle cx=\"8.2\" cy=\"18.2\" r=\"1.0\" fill=\"#FFFFFF\"/><circle cx=\"28.4\" cy=\"20.4\" r=\"1.8\" fill=\"#F43F5E\"/><circle cx=\"28.4\" cy=\"20.4\" r=\"0.8\" fill=\"#FFFFFF\"/></svg>";
3815
+ function agyNavLogoUrl() {
3816
+ return `data:image/svg+xml,${encodeURIComponent(AGY_NAV_LOGO_SVG)}`;
3817
+ }
3818
+ function isOwnNavRow(rowText, wantedLabel) {
3819
+ const wanted = String(wantedLabel ?? "").trim().toLowerCase();
3820
+ const text = String(rowText ?? "").trim().toLowerCase();
3821
+ if (!wanted && !text) return false;
3822
+ return text === wanted || text.includes("antigravity");
3823
+ }
3824
+ function navIconCss(logoUrl) {
3825
+ return [
3826
+ `[${NAV_ICON_MARKER}] > svg { display: none !important; }`,
3827
+ `[${NAV_ICON_MARKER}] > [class*="icon"] > svg { display: none !important; }`,
3828
+ `[${NAV_ICON_MARKER}]::before {`,
3829
+ ` content: '';`,
3830
+ ` flex: none;`,
3831
+ ` width: 16px;`,
3832
+ ` height: 16px;`,
3833
+ ` background-image: url("${logoUrl}");`,
3834
+ ` background-repeat: no-repeat;`,
3835
+ ` background-position: center;`,
3836
+ ` background-size: 16px 16px;`,
3837
+ ` opacity: 0.92;`,
3838
+ ` transition: opacity 0.15s ease, transform 0.15s ease;`,
3839
+ `}`,
3840
+ `[${NAV_ICON_MARKER}]:hover::before,`,
3841
+ `[${NAV_ICON_MARKER}][aria-selected="true"]::before,`,
3842
+ `[${NAV_ICON_MARKER}].active::before,`,
3843
+ `[${NAV_ICON_MARKER}][data-state="active"]::before {`,
3844
+ ` opacity: 1;`,
3845
+ ` transform: scale(1.08);`,
3846
+ `}`
3847
+ ].join("\n");
3848
+ }
3849
+ function installSettingsNavIcon(ctx, resolveLabel) {
3850
+ if (typeof document === "undefined") return () => {};
3851
+ const tag = document.createElement("style");
3852
+ tag.dataset.plugin = "dsh-agy-link";
3853
+ tag.dataset.pluginCss = "dsh-agy-link/settings-nav-icon";
3854
+ tag.textContent = navIconCss(agyNavLogoUrl());
3855
+ document.head.appendChild(tag);
3856
+ let disposed = false;
3857
+ let scheduled = false;
3858
+ const sync = () => {
3859
+ scheduled = false;
3860
+ if (disposed) return;
3861
+ const wanted = resolveLabel();
3862
+ for (const row of Array.from(document.querySelectorAll(NAV_ROW_SELECTOR))) if (isOwnNavRow(row.textContent, wanted)) row.setAttribute(NAV_ICON_MARKER, "");
3863
+ else row.removeAttribute(NAV_ICON_MARKER);
3864
+ };
3865
+ const schedule = () => {
3866
+ if (scheduled || disposed) return;
3867
+ scheduled = true;
3868
+ queueMicrotask(sync);
3869
+ };
3870
+ sync();
3871
+ const observer = new MutationObserver(schedule);
3872
+ observer.observe(document.body, {
3873
+ childList: true,
3874
+ subtree: true,
3875
+ characterData: true
3876
+ });
3877
+ return () => {
3878
+ disposed = true;
3879
+ observer.disconnect();
3880
+ for (const row of Array.from(document.querySelectorAll(`[${NAV_ICON_MARKER}]`))) row.removeAttribute(NAV_ICON_MARKER);
3881
+ tag.remove();
3882
+ };
3883
+ }
3884
+ /**
3885
+ * One family's quota block: brand mark + 5h/weekly bars with reset countdowns
3886
+ * and cooldown notes. Module-level so the settings section and the Plugins-page
3887
+ * dashboard render IDENTICAL quota visuals from one implementation.
3888
+ */
3889
+ function renderFamilyQuotaBar(t, label, familyKey, acc, isRefreshing = false) {
3890
+ const info = acc.quotas[familyKey];
3891
+ const cd = acc.cooldowns[familyKey];
3892
+ const inCooldown = cd && cd.cooldownUntil > Date.now();
3893
+ const has5h = typeof info?.remainingFraction === "number" && Number.isFinite(info.remainingFraction);
3894
+ const pct5h = has5h ? Math.max(0, Math.min(100, Math.round(info.remainingFraction * 100))) : -1;
3895
+ const cdNote = inCooldown ? t("account.localCooldown") : "";
3896
+ const w5h = formatQuotaWindow(t, info?.resetTime);
3897
+ const expiredFull5h = w5h.expired && has5h && pct5h >= 100;
3898
+ const hasWeekly = typeof info?.weeklyFraction === "number" && Number.isFinite(info.weeklyFraction);
3899
+ const pctWeekly = hasWeekly ? Math.max(0, Math.min(100, Math.round(info.weeklyFraction * 100))) : -1;
3900
+ const wWeekly = formatQuotaWindow(t, info?.weeklyResetTime);
3901
+ const expiredFullWeekly = wWeekly.expired && hasWeekly && pctWeekly >= 100;
3902
+ const getColors = (pct) => {
3903
+ if (pct < 0) return {
3904
+ bar: "var(--agy-quota-none-border)",
3905
+ text: "var(--agy-quota-none-text)",
3906
+ bg: "var(--agy-quota-none-bg)",
3907
+ border: "var(--agy-quota-none-border)"
3908
+ };
3909
+ if (pct <= 20) return {
3910
+ bar: "linear-gradient(90deg, #dc2626, #ef4444)",
3911
+ text: "var(--agy-quota-low-text)",
3912
+ bg: "var(--agy-quota-low-bg)",
3913
+ border: "var(--agy-quota-low-border)"
3914
+ };
3915
+ if (pct <= 50) return {
3916
+ bar: "linear-gradient(90deg, #d97706, #f59e0b)",
3917
+ text: "var(--agy-quota-med-text)",
3918
+ bg: "var(--agy-quota-med-bg)",
3919
+ border: "var(--agy-quota-med-border)"
3920
+ };
3921
+ return {
3922
+ bar: "linear-gradient(90deg, #059669, #10b981)",
3923
+ text: "var(--agy-quota-high-text)",
3924
+ bg: "var(--agy-quota-high-bg)",
3925
+ border: "var(--agy-quota-high-border)"
3926
+ };
3927
+ };
3928
+ const c5h = getColors(pct5h);
3929
+ const cWeekly = getColors(pctWeekly);
3930
+ const renderLine = (windowName, percent, c, resetStr, rawFraction, rawReset) => {
3931
+ const isShimmer = percent < 0 || isRefreshing;
3932
+ const tooltipText = typeof rawFraction === "number" ? `${(rawFraction * 100).toFixed(1)}% (raw: ${rawFraction})${rawReset ? ` · reset: ${rawReset}` : ""}` : resetStr ? `↻ ${resetStr}` : void 0;
3933
+ return h("div", { style: {
3934
+ display: "flex",
3935
+ alignItems: "center",
3936
+ fontSize: "11.5px",
3937
+ margin: "4px 0"
3938
+ } }, h("span", { style: {
3939
+ width: "52px",
3940
+ color: "var(--agy-text-window-label)",
3941
+ fontSize: "11px",
3942
+ fontWeight: 700,
3943
+ flexShrink: 0
3944
+ } }, windowName), h("div", {
3945
+ className: isShimmer ? "agy-shimmer-track" : "",
3946
+ style: S.progressBarBg
3947
+ }, h("div", {
3948
+ className: "agy-progress-fill",
3949
+ style: {
3950
+ width: `${percent < 0 ? 100 : percent}%`,
3951
+ height: "100%",
3952
+ background: c.bar,
3953
+ borderRadius: "3px"
3954
+ }
3955
+ })), h("div", { style: {
3956
+ display: "inline-flex",
3957
+ alignItems: "center",
3958
+ gap: "8px",
3959
+ minWidth: "140px",
3960
+ justifyContent: "flex-end",
3961
+ flexShrink: 0
3962
+ } }, h("span", {
3963
+ title: tooltipText,
3964
+ style: {
3965
+ padding: "2px 7px",
3966
+ borderRadius: "4px",
3967
+ background: c.bg,
3968
+ color: c.text,
3969
+ border: `1px solid ${c.border}`,
3970
+ fontWeight: 700,
3971
+ fontSize: "11.5px",
3972
+ lineHeight: 1.2,
3973
+ cursor: tooltipText ? "help" : "default"
3974
+ }
3975
+ }, percent < 0 ? "—" : `${percent}%`), resetStr ? h("span", { style: {
3976
+ color: "var(--agy-text-secondary)",
3977
+ fontSize: "11px",
3978
+ fontWeight: 500
3979
+ } }, `↻ ${resetStr}`) : null));
3980
+ };
3981
+ return h("div", { style: {
3982
+ margin: "6px 0",
3983
+ padding: "8px 10px",
3984
+ background: "var(--agy-bg-subbox)",
3985
+ borderRadius: "7px",
3986
+ border: "1px solid var(--agy-border-box)"
3987
+ } }, h("div", { style: {
3988
+ display: "flex",
3989
+ alignItems: "center",
3990
+ gap: "6px",
3991
+ fontWeight: 700,
3992
+ fontSize: "12.5px",
3993
+ marginBottom: "5px",
3994
+ color: "var(--agy-text-primary)"
3995
+ } }, brandIcon(FAMILY_BRAND[familyKey], 14), h("span", null, label)), familyKey !== "argon" || has5h ? renderLine(t("quota.fiveHour"), pct5h, c5h, w5h.resetText ? w5h.resetText + cdNote : expiredFull5h ? t("quota.windowReset") + cdNote : cdNote.replace(/^ · /, ""), info?.remainingFraction, info?.resetTime) : null, renderLine(t("quota.weekly"), pctWeekly, cWeekly, wWeekly.resetText ? wWeekly.resetText : expiredFullWeekly ? t("quota.windowReset") : "", info?.weeklyFraction, info?.weeklyResetTime));
3996
+ }
3716
3997
  const GLOBAL_CSS = `
3717
3998
  @keyframes agy-spin {
3718
3999
  0% { transform: rotate(0deg); }
@@ -3999,6 +4280,22 @@ body.dark,
3999
4280
  .agy-progress-fill {
4000
4281
  transition: width 0.4s cubic-bezier(0.16, 1, 0.3, 1);
4001
4282
  }
4283
+ @keyframes agy-shimmer {
4284
+ 0% { transform: translateX(-100%); }
4285
+ 100% { transform: translateX(100%); }
4286
+ }
4287
+ .agy-shimmer-track {
4288
+ position: relative;
4289
+ overflow: hidden;
4290
+ }
4291
+ .agy-shimmer-track::after {
4292
+ content: '';
4293
+ position: absolute;
4294
+ top: 0; left: 0; right: 0; bottom: 0;
4295
+ background: linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.22) 50%, transparent 100%);
4296
+ animation: agy-shimmer 1.8s infinite ease-in-out;
4297
+ pointer-events: none;
4298
+ }
4002
4299
  .agy-modal-backdrop {
4003
4300
  position: fixed;
4004
4301
  inset: 0;
@@ -4324,6 +4621,7 @@ body.dark,
4324
4621
  const [toast, setToast] = useState(null);
4325
4622
  const [expandedModels, setExpandedModels] = useState({});
4326
4623
  const [addProxyInput, setAddProxyInput] = useState("");
4624
+ const [optimisticActiveId, setOptimisticActiveId] = useState(null);
4327
4625
  const [, setTimeTick] = useState(0);
4328
4626
  useEffect(() => {
4329
4627
  const timer = setInterval(() => setTimeTick((n) => n + 1), 3e4);
@@ -4459,13 +4757,24 @@ body.dark,
4459
4757
  }
4460
4758
  };
4461
4759
  const setActiveAccount = async (id) => {
4760
+ setOptimisticActiveId(id);
4462
4761
  setLoadingAction(`active:${id}`);
4463
- const res = await postJson("/plugins/agy-link/pool/set-active", { id });
4464
- setLoadingAction(null);
4465
- if (res && res.ok) {
4466
- await refresh();
4467
- showToast(t("account.activeSet"), "success");
4468
- } else showToast(res?.error || t("account.activeSetFailed"), "error");
4762
+ try {
4763
+ const res = await postJson("/plugins/agy-link/pool/set-active", { id });
4764
+ if (res && res.ok) {
4765
+ await refresh();
4766
+ showToast(t("account.activeSet"), "success");
4767
+ } else {
4768
+ setOptimisticActiveId(null);
4769
+ showToast(res?.error || t("account.activeSetFailed"), "error");
4770
+ }
4771
+ } catch {
4772
+ setOptimisticActiveId(null);
4773
+ showToast(t("account.activeSetFailed"), "error");
4774
+ } finally {
4775
+ setOptimisticActiveId(null);
4776
+ setLoadingAction(null);
4777
+ }
4469
4778
  };
4470
4779
  const removeAccount = async (id, alias) => {
4471
4780
  setLoadingAction(`remove:${id}`);
@@ -4611,106 +4920,10 @@ body.dark,
4611
4920
  "aria-label": t("aria.closeToast")
4612
4921
  }, uiIcon("x", 12)));
4613
4922
  };
4614
- const renderQuotaBar = (label, familyKey, acc) => {
4615
- const info = acc.quotas[familyKey];
4616
- const cd = acc.cooldowns[familyKey];
4617
- const inCooldown = cd && cd.cooldownUntil > Date.now();
4618
- const has5h = typeof info?.remainingFraction === "number" && Number.isFinite(info.remainingFraction);
4619
- const pct5h = has5h ? Math.max(0, Math.min(100, Math.round(info.remainingFraction * 100))) : -1;
4620
- const cdNote = inCooldown ? t("account.localCooldown") : "";
4621
- const w5h = formatQuotaWindow(t, info?.resetTime);
4622
- const expiredFull5h = w5h.expired && has5h && pct5h >= 100;
4623
- const hasWeekly = typeof info?.weeklyFraction === "number" && Number.isFinite(info.weeklyFraction);
4624
- const pctWeekly = hasWeekly ? Math.max(0, Math.min(100, Math.round(info.weeklyFraction * 100))) : -1;
4625
- const wWeekly = formatQuotaWindow(t, info?.weeklyResetTime);
4626
- const expiredFullWeekly = wWeekly.expired && hasWeekly && pctWeekly >= 100;
4627
- const getColors = (pct) => {
4628
- if (pct < 0) return {
4629
- bar: "var(--agy-quota-none-border)",
4630
- text: "var(--agy-quota-none-text)",
4631
- bg: "var(--agy-quota-none-bg)",
4632
- border: "var(--agy-quota-none-border)"
4633
- };
4634
- if (pct <= 20) return {
4635
- bar: "linear-gradient(90deg, #dc2626, #ef4444)",
4636
- text: "var(--agy-quota-low-text)",
4637
- bg: "var(--agy-quota-low-bg)",
4638
- border: "var(--agy-quota-low-border)"
4639
- };
4640
- if (pct <= 50) return {
4641
- bar: "linear-gradient(90deg, #d97706, #f59e0b)",
4642
- text: "var(--agy-quota-med-text)",
4643
- bg: "var(--agy-quota-med-bg)",
4644
- border: "var(--agy-quota-med-border)"
4645
- };
4646
- return {
4647
- bar: "linear-gradient(90deg, #059669, #10b981)",
4648
- text: "var(--agy-quota-high-text)",
4649
- bg: "var(--agy-quota-high-bg)",
4650
- border: "var(--agy-quota-high-border)"
4651
- };
4652
- };
4653
- const c5h = getColors(pct5h);
4654
- const cWeekly = getColors(pctWeekly);
4655
- const renderLine = (windowName, percent, c, resetStr) => {
4656
- return h("div", { style: {
4657
- display: "flex",
4658
- alignItems: "center",
4659
- fontSize: "11.5px",
4660
- margin: "4px 0"
4661
- } }, h("span", { style: {
4662
- width: "52px",
4663
- color: "var(--agy-text-window-label)",
4664
- fontSize: "11px",
4665
- fontWeight: 700,
4666
- flexShrink: 0
4667
- } }, windowName), h("div", { style: S.progressBarBg }, h("div", {
4668
- className: "agy-progress-fill",
4669
- style: {
4670
- width: `${percent < 0 ? 100 : percent}%`,
4671
- height: "100%",
4672
- background: c.bar,
4673
- borderRadius: "3px"
4674
- }
4675
- })), h("div", { style: {
4676
- display: "inline-flex",
4677
- alignItems: "center",
4678
- gap: "8px",
4679
- minWidth: "140px",
4680
- justifyContent: "flex-end",
4681
- flexShrink: 0
4682
- } }, h("span", { style: {
4683
- padding: "2px 7px",
4684
- borderRadius: "4px",
4685
- background: c.bg,
4686
- color: c.text,
4687
- border: `1px solid ${c.border}`,
4688
- fontWeight: 700,
4689
- fontSize: "11.5px",
4690
- lineHeight: 1.2
4691
- } }, percent < 0 ? "—" : `${percent}%`), resetStr ? h("span", { style: {
4692
- color: "var(--agy-text-secondary)",
4693
- fontSize: "11px",
4694
- fontWeight: 500
4695
- } }, `↻ ${resetStr}`) : null));
4696
- };
4697
- return h("div", { style: {
4698
- margin: "6px 0",
4699
- padding: "8px 10px",
4700
- background: "var(--agy-bg-subbox)",
4701
- borderRadius: "7px",
4702
- border: "1px solid var(--agy-border-box)"
4703
- } }, h("div", { style: {
4704
- display: "flex",
4705
- alignItems: "center",
4706
- gap: "6px",
4707
- fontWeight: 700,
4708
- fontSize: "12.5px",
4709
- marginBottom: "5px",
4710
- color: "var(--agy-text-primary)"
4711
- } }, brandIcon(FAMILY_BRAND[familyKey], 14), h("span", null, label)), familyKey !== "argon" || has5h ? renderLine(t("quota.fiveHour"), pct5h, c5h, w5h.resetText ? w5h.resetText + cdNote : expiredFull5h ? t("quota.windowReset") + cdNote : cdNote.replace(/^ · /, "")) : null, renderLine(t("quota.weekly"), pctWeekly, cWeekly, wWeekly.resetText ? wWeekly.resetText : expiredFullWeekly ? t("quota.windowReset") : ""));
4712
- };
4713
- const activeAccountId = pool?.activeAccountId ?? pool?.lastActiveAccountId ?? pool?.activeAccountIds?.google ?? pool?.primaryAccountId;
4923
+ const isRefreshingQuota = loadingAction === "refresh-quota";
4924
+ const renderQuotaBar = (label, familyKey, acc) => renderFamilyQuotaBar(t, label, familyKey, acc, isRefreshingQuota);
4925
+ const authoritativeActiveId = pool?.activeAccountId ?? pool?.lastActiveAccountId ?? pool?.activeAccountIds?.google ?? pool?.primaryAccountId;
4926
+ const activeAccountId = optimisticActiveId ?? authoritativeActiveId;
4714
4927
  const renderedAccountCards = accounts.map((acc) => {
4715
4928
  const isPrimary = acc.id === pool?.primaryAccountId;
4716
4929
  const hasCooldown = Object.entries(acc.cooldowns).some(([, cd]) => cd && cd.cooldownUntil > Date.now());
@@ -4873,15 +5086,21 @@ body.dark,
4873
5086
  fontWeight: 700
4874
5087
  },
4875
5088
  title: t("status.inUse")
4876
- }, uiIcon("zap", 10, "#10b981"), t("status.inUse")) : null, acc.proxyUrl ? h("span", { style: {
4877
- ...S.badgeTag,
4878
- background: "var(--agy-badge-proxy-bg)",
4879
- color: "var(--agy-badge-proxy-text)",
4880
- borderColor: "var(--agy-badge-proxy-border)",
4881
- gap: "4px",
4882
- fontSize: "10px",
4883
- padding: "1px 5px"
4884
- } }, uiIcon("globe", 10, "var(--agy-badge-proxy-text)"), t("status.proxy")) : null, !acc.enabled ? h("span", {
5089
+ }, uiIcon("zap", 10, "#10b981"), t("status.inUse")) : null, (() => {
5090
+ const effectiveProxy = acc.proxyUrl || pool?.systemProxy;
5091
+ return effectiveProxy ? h("span", {
5092
+ style: {
5093
+ ...S.badgeTag,
5094
+ background: "var(--agy-badge-proxy-bg)",
5095
+ color: "var(--agy-badge-proxy-text)",
5096
+ borderColor: "var(--agy-badge-proxy-border)",
5097
+ gap: "4px",
5098
+ fontSize: "10px",
5099
+ padding: "1px 5px"
5100
+ },
5101
+ title: effectiveProxy
5102
+ }, uiIcon("globe", 10, "var(--agy-badge-proxy-text)"), t("status.proxy")) : null;
5103
+ })(), !acc.enabled ? h("span", {
4885
5104
  style: {
4886
5105
  ...S.badgeTag,
4887
5106
  background: "var(--agy-bg-subbox)",
@@ -5071,7 +5290,7 @@ body.dark,
5071
5290
  } }, h("input", {
5072
5291
  style: S.input,
5073
5292
  value: proxyInputs[acc.id] !== void 0 ? proxyInputs[acc.id] : acc.proxyUrl ?? "",
5074
- placeholder: t("proxy.placeholder"),
5293
+ placeholder: pool?.systemProxy ? `${t("proxy.placeholder")} (${pool.systemProxy})` : t("proxy.placeholder"),
5075
5294
  "aria-label": t("aria.proxyInput"),
5076
5295
  onChange: (e) => setProxyInputs({
5077
5296
  ...proxyInputs,
@@ -5125,7 +5344,7 @@ body.dark,
5125
5344
  }), h("input", {
5126
5345
  style: S.input,
5127
5346
  value: addProxyInput,
5128
- placeholder: t("account.proxyPlaceholder"),
5347
+ placeholder: pool?.systemProxy ? `${t("account.proxyPlaceholder")} (${pool.systemProxy})` : t("account.proxyPlaceholder"),
5129
5348
  "aria-label": t("aria.proxyInput"),
5130
5349
  onChange: (e) => setAddProxyInput(e.target.value)
5131
5350
  })), h("div", { style: {
@@ -5212,7 +5431,7 @@ body.dark,
5212
5431
  display: "flex",
5213
5432
  alignItems: "center",
5214
5433
  gap: "8px"
5215
- } }, agyIcon(16), h("span", { style: {
5434
+ } }, agyIcon(18), h("span", { style: {
5216
5435
  fontWeight: 700,
5217
5436
  fontSize: "14px",
5218
5437
  color: "var(--agy-text-primary)"
@@ -5506,11 +5725,32 @@ body.dark,
5506
5725
  locale: NS
5507
5726
  }, AgySettingsSection);
5508
5727
  });
5728
+ ctx.slots.inject("plugins.bundle.config", () => {
5729
+ return ctx.slots.register({
5730
+ name: "plugins.bundle.config",
5731
+ key: "dsh-agy-link",
5732
+ locale: NS
5733
+ }, (ownerProps) => {
5734
+ if (ownerProps?.view === "summary") return null;
5735
+ return h(AgySettingsSection, { isModal: false });
5736
+ });
5737
+ });
5738
+ ctx.slots.inject("plugins.row.config", () => {
5739
+ return ctx.slots.register({
5740
+ name: "plugins.row.config",
5741
+ key: "dsh-agy-link#agy-link",
5742
+ locale: NS
5743
+ }, (ownerProps) => {
5744
+ if (ownerProps?.view === "summary") return null;
5745
+ return h(AgySettingsSection, { isModal: false });
5746
+ });
5747
+ });
5509
5748
  installAgyToolView(ctx);
5510
5749
  ctx.effect(() => installAutoExpandReasoning());
5511
5750
  ctx.effect(() => installMermaidRendering());
5512
5751
  ctx.effect(() => installImageEnhancer());
5513
5752
  ctx.effect(() => installDecisionChips());
5753
+ ctx.effect(() => installSettingsNavIcon(ctx, () => locale.bind(NS)("section.label")));
5514
5754
  }
5515
5755
  //#endregion
5516
5756
  exports.apply = apply;