dsh-agy-link 0.4.57 → 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
@@ -105,6 +105,7 @@ window.__ModuleLoader__.load({
105
105
  "quota.fiveHour": "5 小时额度",
106
106
  "quota.weekly": "周额度",
107
107
  "quota.refreshed": "额度已刷新",
108
+ "quota.windowReset": "已重置 · 可用",
108
109
  "proxy.button": "代理",
109
110
  "proxy.placeholder": "专属代理 URL(如:http://127.0.0.1:7890;留空则使用全局)",
110
111
  "proxy.save": "保存",
@@ -244,6 +245,7 @@ window.__ModuleLoader__.load({
244
245
  "quota.fiveHour": "5-hour quota",
245
246
  "quota.weekly": "Weekly quota",
246
247
  "quota.refreshed": "Quota refreshed",
248
+ "quota.windowReset": "Reset · available",
247
249
  "proxy.button": "Proxy",
248
250
  "proxy.placeholder": "Dedicated proxy URL (for example: http://127.0.0.1:7890; leave blank to use the global proxy)",
249
251
  "proxy.save": "Save",
@@ -383,6 +385,7 @@ window.__ModuleLoader__.load({
383
385
  "quota.fiveHour": "Cota de 5 horas",
384
386
  "quota.weekly": "Cota semanal",
385
387
  "quota.refreshed": "Cota atualizada",
388
+ "quota.windowReset": "Redefinida · disponível",
386
389
  "proxy.button": "Proxy",
387
390
  "proxy.placeholder": "URL do proxy exclusivo (por exemplo: http://127.0.0.1:7890; deixe vazio para usar o proxy global)",
388
391
  "proxy.save": "Salvar",
@@ -522,6 +525,7 @@ window.__ModuleLoader__.load({
522
525
  "quota.fiveHour": "Cuota de 5 horas",
523
526
  "quota.weekly": "Cuota semanal",
524
527
  "quota.refreshed": "Cuota actualizada",
528
+ "quota.windowReset": "Reiniciada · disponible",
525
529
  "proxy.button": "Proxy",
526
530
  "proxy.placeholder": "URL de proxy exclusivo (por ejemplo: http://127.0.0.1:7890; déjelo vacío para usar el proxy global)",
527
531
  "proxy.save": "Guardar",
@@ -3002,7 +3006,7 @@ body > [id^="iagy-mmd"] .error-icon {
3002
3006
  const dataLang = (code?.getAttribute("data-language") ?? block.getAttribute("data-language") ?? "").trim().toLowerCase();
3003
3007
  if (dataLang !== "") return dataLang;
3004
3008
  const text = ((block.querySelector("[data-code-block-banner] [class*=\"infostring\"]") ?? block.querySelector("[data-code-block-banner] [class*=\"language\"]"))?.textContent ?? "").trim().toLowerCase();
3005
- if (text !== "") return text.split(/\s+/)[0] ?? "";
3009
+ if (text !== "" && text !== "代码块" && text !== "code" && text !== "code block") return text.split(/\s+/)[0] ?? "";
3006
3010
  const bannerText = (block.querySelector("[data-code-block-banner]")?.textContent ?? "").trim().toLowerCase();
3007
3011
  if (bannerText !== "" && bannerText !== "代码块" && bannerText !== "code" && bannerText !== "code block") return bannerText.split(/\s+/)[0] ?? "";
3008
3012
  return "";
@@ -3072,12 +3076,18 @@ body > [id^="iagy-mmd"] .error-icon {
3072
3076
  function cleanupTempElements(id) {
3073
3077
  if (typeof document === "undefined") return;
3074
3078
  if (id) {
3075
- document.getElementById("d" + id)?.remove();
3076
- document.getElementById("i" + id)?.remove();
3077
- 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();
3078
3085
  }
3079
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-\"]");
3080
- 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
+ }
3081
3091
  }
3082
3092
  function repairMermaidSource(source) {
3083
3093
  if (!/^\s*(?:flowchart|graph)\b/i.test(source)) return source;
@@ -3592,11 +3602,17 @@ div[data-variant="think"] [class*="thinkBody"] {
3592
3602
  * Format reset timestamp into readable date/time + relative countdown.
3593
3603
  */
3594
3604
  function formatQuotaWindow(t, resetTimeStr) {
3595
- if (!resetTimeStr) return { resetText: "" };
3605
+ if (!resetTimeStr) return {
3606
+ resetText: "",
3607
+ expired: false
3608
+ };
3596
3609
  try {
3597
3610
  const d = new Date(resetTimeStr);
3598
3611
  const diffMs = d.getTime() - Date.now();
3599
- if (diffMs <= 0) return { resetText: "" };
3612
+ if (Number.isNaN(d.getTime()) || diffMs <= 0) return {
3613
+ resetText: "",
3614
+ expired: true
3615
+ };
3600
3616
  const totalMins = Math.ceil(diffMs / 6e4);
3601
3617
  const days = Math.floor(totalMins / 1440);
3602
3618
  const hours = Math.floor(totalMins % 1440 / 60);
@@ -3605,9 +3621,15 @@ div[data-variant="think"] [class*="thinkBody"] {
3605
3621
  const countdown = days > 0 ? `${days}${t("duration.day")} ${hours}${t("duration.hour")}` : hours > 0 ? `${hours}${t("duration.hour")} ${mins}${t("duration.minute")}` : `${mins}${t("duration.minute")}`;
3606
3622
  const hh = d.getHours().toString().padStart(2, "0");
3607
3623
  const mm = d.getMinutes().toString().padStart(2, "0");
3608
- return { resetText: isWeekly ? `${d.getMonth() + 1}/${d.getDate()} ${hh}:${mm} (${countdown})` : `${hh}:${mm} (${countdown})` };
3624
+ return {
3625
+ resetText: isWeekly ? `${d.getMonth() + 1}/${d.getDate()} ${hh}:${mm} (${countdown})` : `${hh}:${mm} (${countdown})`,
3626
+ expired: false
3627
+ };
3609
3628
  } catch {
3610
- return { resetText: "" };
3629
+ return {
3630
+ resetText: "",
3631
+ expired: true
3632
+ };
3611
3633
  }
3612
3634
  }
3613
3635
  /** Inline brand logo (Gemini / Claude / OpenAI) as a crisp SVG mark. */
@@ -3656,47 +3678,322 @@ div[data-variant="think"] [class*="thinkBody"] {
3656
3678
  anthropic: "claude",
3657
3679
  openai: "openai"
3658
3680
  };
3659
- /** Antigravity mark: gradient orb with an orbit ring (product has no public simple-icon). */
3660
- function agyIcon(size = 14) {
3661
- 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";
3662
3687
  return h("svg", {
3663
- viewBox: "0 0 24 24",
3688
+ viewBox: "0 0 36 36",
3664
3689
  width: size,
3665
3690
  height: size,
3691
+ fill: "none",
3666
3692
  "aria-hidden": true,
3667
3693
  style: {
3668
3694
  display: "inline-block",
3669
- verticalAlign: "-2px",
3695
+ verticalAlign: "-2.5px",
3670
3696
  flexShrink: 0
3671
3697
  }
3672
3698
  }, h("defs", null, h("linearGradient", {
3673
- id: gid,
3674
- x1: "0",
3675
- y1: "0",
3676
- x2: "1",
3677
- y2: "1"
3699
+ id: `${uid}-orb`,
3700
+ x1: "12",
3701
+ y1: "11",
3702
+ x2: "25",
3703
+ y2: "25",
3704
+ gradientUnits: "userSpaceOnUse"
3678
3705
  }, h("stop", {
3679
- offset: "0",
3680
- "stop-color": "#4C8DFF"
3706
+ offset: "0%",
3707
+ "stop-color": "#38BDF8"
3681
3708
  }), h("stop", {
3682
- offset: "1",
3683
- "stop-color": "#A96BFF"
3684
- }))), h("circle", {
3685
- cx: 12,
3686
- cy: 12,
3687
- r: 6,
3688
- fill: `url(#${gid})`
3689
- }), h("ellipse", {
3690
- cx: 12,
3691
- cy: 12,
3692
- rx: 10.4,
3693
- ry: 3.9,
3694
- fill: "none",
3695
- stroke: `url(#${gid})`,
3696
- "stroke-width": 1.4,
3697
- 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"
3698
3804
  }));
3699
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
+ }
3700
3997
  const GLOBAL_CSS = `
3701
3998
  @keyframes agy-spin {
3702
3999
  0% { transform: rotate(0deg); }
@@ -3983,6 +4280,22 @@ body.dark,
3983
4280
  .agy-progress-fill {
3984
4281
  transition: width 0.4s cubic-bezier(0.16, 1, 0.3, 1);
3985
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
+ }
3986
4299
  .agy-modal-backdrop {
3987
4300
  position: fixed;
3988
4301
  inset: 0;
@@ -4308,6 +4621,7 @@ body.dark,
4308
4621
  const [toast, setToast] = useState(null);
4309
4622
  const [expandedModels, setExpandedModels] = useState({});
4310
4623
  const [addProxyInput, setAddProxyInput] = useState("");
4624
+ const [optimisticActiveId, setOptimisticActiveId] = useState(null);
4311
4625
  const [, setTimeTick] = useState(0);
4312
4626
  useEffect(() => {
4313
4627
  const timer = setInterval(() => setTimeTick((n) => n + 1), 3e4);
@@ -4443,13 +4757,24 @@ body.dark,
4443
4757
  }
4444
4758
  };
4445
4759
  const setActiveAccount = async (id) => {
4760
+ setOptimisticActiveId(id);
4446
4761
  setLoadingAction(`active:${id}`);
4447
- const res = await postJson("/plugins/agy-link/pool/set-active", { id });
4448
- setLoadingAction(null);
4449
- if (res && res.ok) {
4450
- await refresh();
4451
- showToast(t("account.activeSet"), "success");
4452
- } 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
+ }
4453
4778
  };
4454
4779
  const removeAccount = async (id, alias) => {
4455
4780
  setLoadingAction(`remove:${id}`);
@@ -4595,103 +4920,10 @@ body.dark,
4595
4920
  "aria-label": t("aria.closeToast")
4596
4921
  }, uiIcon("x", 12)));
4597
4922
  };
4598
- const renderQuotaBar = (label, familyKey, acc) => {
4599
- const info = acc.quotas[familyKey];
4600
- const cd = acc.cooldowns[familyKey];
4601
- const inCooldown = cd && cd.cooldownUntil > Date.now();
4602
- const has5h = typeof info?.remainingFraction === "number" && Number.isFinite(info.remainingFraction);
4603
- const pct5h = has5h ? Math.max(0, Math.min(100, Math.round(info.remainingFraction * 100))) : -1;
4604
- const cdNote = inCooldown ? t("account.localCooldown") : "";
4605
- const w5h = formatQuotaWindow(t, info?.resetTime);
4606
- const pctWeekly = typeof info?.weeklyFraction === "number" && Number.isFinite(info.weeklyFraction) ? Math.max(0, Math.min(100, Math.round(info.weeklyFraction * 100))) : -1;
4607
- const wWeekly = formatQuotaWindow(t, info?.weeklyResetTime);
4608
- const getColors = (pct) => {
4609
- if (pct < 0) return {
4610
- bar: "var(--agy-quota-none-border)",
4611
- text: "var(--agy-quota-none-text)",
4612
- bg: "var(--agy-quota-none-bg)",
4613
- border: "var(--agy-quota-none-border)"
4614
- };
4615
- if (pct <= 20) return {
4616
- bar: "linear-gradient(90deg, #dc2626, #ef4444)",
4617
- text: "var(--agy-quota-low-text)",
4618
- bg: "var(--agy-quota-low-bg)",
4619
- border: "var(--agy-quota-low-border)"
4620
- };
4621
- if (pct <= 50) return {
4622
- bar: "linear-gradient(90deg, #d97706, #f59e0b)",
4623
- text: "var(--agy-quota-med-text)",
4624
- bg: "var(--agy-quota-med-bg)",
4625
- border: "var(--agy-quota-med-border)"
4626
- };
4627
- return {
4628
- bar: "linear-gradient(90deg, #059669, #10b981)",
4629
- text: "var(--agy-quota-high-text)",
4630
- bg: "var(--agy-quota-high-bg)",
4631
- border: "var(--agy-quota-high-border)"
4632
- };
4633
- };
4634
- const c5h = getColors(pct5h);
4635
- const cWeekly = getColors(pctWeekly);
4636
- const renderLine = (windowName, percent, c, resetStr) => {
4637
- return h("div", { style: {
4638
- display: "flex",
4639
- alignItems: "center",
4640
- fontSize: "11.5px",
4641
- margin: "4px 0"
4642
- } }, h("span", { style: {
4643
- width: "52px",
4644
- color: "var(--agy-text-window-label)",
4645
- fontSize: "11px",
4646
- fontWeight: 700,
4647
- flexShrink: 0
4648
- } }, windowName), h("div", { style: S.progressBarBg }, h("div", {
4649
- className: "agy-progress-fill",
4650
- style: {
4651
- width: `${percent < 0 ? 100 : percent}%`,
4652
- height: "100%",
4653
- background: c.bar,
4654
- borderRadius: "3px"
4655
- }
4656
- })), h("div", { style: {
4657
- display: "inline-flex",
4658
- alignItems: "center",
4659
- gap: "8px",
4660
- minWidth: "140px",
4661
- justifyContent: "flex-end",
4662
- flexShrink: 0
4663
- } }, h("span", { style: {
4664
- padding: "2px 7px",
4665
- borderRadius: "4px",
4666
- background: c.bg,
4667
- color: c.text,
4668
- border: `1px solid ${c.border}`,
4669
- fontWeight: 700,
4670
- fontSize: "11.5px",
4671
- lineHeight: 1.2
4672
- } }, percent < 0 ? "—" : `${percent}%`), resetStr ? h("span", { style: {
4673
- color: "var(--agy-text-secondary)",
4674
- fontSize: "11px",
4675
- fontWeight: 500
4676
- } }, `↻ ${resetStr}`) : null));
4677
- };
4678
- return h("div", { style: {
4679
- margin: "6px 0",
4680
- padding: "8px 10px",
4681
- background: "var(--agy-bg-subbox)",
4682
- borderRadius: "7px",
4683
- border: "1px solid var(--agy-border-box)"
4684
- } }, h("div", { style: {
4685
- display: "flex",
4686
- alignItems: "center",
4687
- gap: "6px",
4688
- fontWeight: 700,
4689
- fontSize: "12.5px",
4690
- marginBottom: "5px",
4691
- color: "var(--agy-text-primary)"
4692
- } }, brandIcon(FAMILY_BRAND[familyKey], 14), h("span", null, label)), familyKey !== "argon" || has5h ? renderLine(t("quota.fiveHour"), pct5h, c5h, w5h.resetText ? w5h.resetText + cdNote : cdNote.replace(/^ · /, "")) : null, renderLine(t("quota.weekly"), pctWeekly, cWeekly, wWeekly.resetText));
4693
- };
4694
- 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;
4695
4927
  const renderedAccountCards = accounts.map((acc) => {
4696
4928
  const isPrimary = acc.id === pool?.primaryAccountId;
4697
4929
  const hasCooldown = Object.entries(acc.cooldowns).some(([, cd]) => cd && cd.cooldownUntil > Date.now());
@@ -4854,15 +5086,21 @@ body.dark,
4854
5086
  fontWeight: 700
4855
5087
  },
4856
5088
  title: t("status.inUse")
4857
- }, uiIcon("zap", 10, "#10b981"), t("status.inUse")) : null, acc.proxyUrl ? h("span", { style: {
4858
- ...S.badgeTag,
4859
- background: "var(--agy-badge-proxy-bg)",
4860
- color: "var(--agy-badge-proxy-text)",
4861
- borderColor: "var(--agy-badge-proxy-border)",
4862
- gap: "4px",
4863
- fontSize: "10px",
4864
- padding: "1px 5px"
4865
- } }, 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", {
4866
5104
  style: {
4867
5105
  ...S.badgeTag,
4868
5106
  background: "var(--agy-bg-subbox)",
@@ -5052,7 +5290,7 @@ body.dark,
5052
5290
  } }, h("input", {
5053
5291
  style: S.input,
5054
5292
  value: proxyInputs[acc.id] !== void 0 ? proxyInputs[acc.id] : acc.proxyUrl ?? "",
5055
- placeholder: t("proxy.placeholder"),
5293
+ placeholder: pool?.systemProxy ? `${t("proxy.placeholder")} (${pool.systemProxy})` : t("proxy.placeholder"),
5056
5294
  "aria-label": t("aria.proxyInput"),
5057
5295
  onChange: (e) => setProxyInputs({
5058
5296
  ...proxyInputs,
@@ -5106,7 +5344,7 @@ body.dark,
5106
5344
  }), h("input", {
5107
5345
  style: S.input,
5108
5346
  value: addProxyInput,
5109
- placeholder: t("account.proxyPlaceholder"),
5347
+ placeholder: pool?.systemProxy ? `${t("account.proxyPlaceholder")} (${pool.systemProxy})` : t("account.proxyPlaceholder"),
5110
5348
  "aria-label": t("aria.proxyInput"),
5111
5349
  onChange: (e) => setAddProxyInput(e.target.value)
5112
5350
  })), h("div", { style: {
@@ -5193,7 +5431,7 @@ body.dark,
5193
5431
  display: "flex",
5194
5432
  alignItems: "center",
5195
5433
  gap: "8px"
5196
- } }, agyIcon(16), h("span", { style: {
5434
+ } }, agyIcon(18), h("span", { style: {
5197
5435
  fontWeight: 700,
5198
5436
  fontSize: "14px",
5199
5437
  color: "var(--agy-text-primary)"
@@ -5487,11 +5725,32 @@ body.dark,
5487
5725
  locale: NS
5488
5726
  }, AgySettingsSection);
5489
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
+ });
5490
5748
  installAgyToolView(ctx);
5491
5749
  ctx.effect(() => installAutoExpandReasoning());
5492
5750
  ctx.effect(() => installMermaidRendering());
5493
5751
  ctx.effect(() => installImageEnhancer());
5494
5752
  ctx.effect(() => installDecisionChips());
5753
+ ctx.effect(() => installSettingsNavIcon(ctx, () => locale.bind(NS)("section.label")));
5495
5754
  }
5496
5755
  //#endregion
5497
5756
  exports.apply = apply;