dsh-agy-link 0.4.70 → 0.4.74
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/CHANGELOG.md +124 -0
- package/README.md +4 -0
- package/dist/bridge.mjs +6 -2
- package/dist/client.js +254 -48
- package/dist/index.js +784 -84
- package/docs/KNOWN-GAPS.md +26 -3
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -36,7 +36,8 @@ window.__ModuleLoader__.load({
|
|
|
36
36
|
move: "M9 5h.01M9 12h.01M9 19h.01M15 5h.01M15 12h.01M15 19h.01",
|
|
37
37
|
arrowUp: "M12 19V5M5 12l7-7 7 7",
|
|
38
38
|
arrowDown: "M12 5v14M19 12l-7 7-7-7",
|
|
39
|
-
power: "M18.36 6.64a9 9 0 1 1-12.73 0M12 2v10"
|
|
39
|
+
power: "M18.36 6.64a9 9 0 1 1-12.73 0M12 2v10",
|
|
40
|
+
flame: "M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z"
|
|
40
41
|
};
|
|
41
42
|
//#endregion
|
|
42
43
|
//#region src/client/locales.ts
|
|
@@ -181,7 +182,17 @@ window.__ModuleLoader__.load({
|
|
|
181
182
|
"account.disableTitle": "停用此账号(切号与调度时跳过)",
|
|
182
183
|
"account.enabledToast": "已启用账号:{alias}",
|
|
183
184
|
"account.disabledToast": "已停用账号:{alias}",
|
|
184
|
-
"status.disabled": "已停用"
|
|
185
|
+
"status.disabled": "已停用",
|
|
186
|
+
"header.warmup": "一键预热",
|
|
187
|
+
"header.warmingUp": "预热中",
|
|
188
|
+
"account.warmup": "预热",
|
|
189
|
+
"account.warmingUp": "预热中",
|
|
190
|
+
"account.warmupTitle": "预热该账号(向 Google 发送极小探活请求,提前激活 7 天周配额计时器)",
|
|
191
|
+
"warmup.success": "账号预热成功",
|
|
192
|
+
"warmup.allSuccess": "一键预热任务已完成",
|
|
193
|
+
"warmup.skipped": "当前账号或模型处于冷却中,无需预热",
|
|
194
|
+
"config.autoWarmup": "7天周配额自动预热",
|
|
195
|
+
"config.autoWarmupDesc": "周配额到达重置时间或冷启动时自动唤醒 1 次启动新周期"
|
|
185
196
|
};
|
|
186
197
|
const en = {
|
|
187
198
|
"section.label": "Antigravity",
|
|
@@ -321,7 +332,17 @@ window.__ModuleLoader__.load({
|
|
|
321
332
|
"account.disableTitle": "Disable this account (skip in rotation)",
|
|
322
333
|
"account.enabledToast": "Account enabled: {alias}",
|
|
323
334
|
"account.disabledToast": "Account disabled: {alias}",
|
|
324
|
-
"status.disabled": "Disabled"
|
|
335
|
+
"status.disabled": "Disabled",
|
|
336
|
+
"header.warmup": "Auto Warmup",
|
|
337
|
+
"header.warmingUp": "Warming up...",
|
|
338
|
+
"account.warmup": "Warmup",
|
|
339
|
+
"account.warmingUp": "Warming up...",
|
|
340
|
+
"account.warmupTitle": "Warm up this account (trigger 7-day weekly reset timer)",
|
|
341
|
+
"warmup.success": "Account warmed up successfully",
|
|
342
|
+
"warmup.allSuccess": "Warmup completed for all accounts",
|
|
343
|
+
"warmup.skipped": "Account or model is in cooldown, no warmup needed",
|
|
344
|
+
"config.autoWarmup": "7-Day Quota Auto-Warmup",
|
|
345
|
+
"config.autoWarmupDesc": "Automatically trigger a 1-token probe when weekly reset time is reached"
|
|
325
346
|
};
|
|
326
347
|
const ptBR = {
|
|
327
348
|
"section.label": "Antigravity",
|
|
@@ -461,7 +482,17 @@ window.__ModuleLoader__.load({
|
|
|
461
482
|
"account.disableTitle": "Desativar esta conta (ignorar na rotação)",
|
|
462
483
|
"account.enabledToast": "Conta ativada: {alias}",
|
|
463
484
|
"account.disabledToast": "Conta desativada: {alias}",
|
|
464
|
-
"status.disabled": "Desativado"
|
|
485
|
+
"status.disabled": "Desativado",
|
|
486
|
+
"header.warmup": "Pré-aquecimento",
|
|
487
|
+
"header.warmingUp": "Aquecendo...",
|
|
488
|
+
"account.warmup": "Aquecer",
|
|
489
|
+
"account.warmingUp": "Aquecendo...",
|
|
490
|
+
"account.warmupTitle": "Aquecer esta conta (ativar cronômetro semanal de 7 dias)",
|
|
491
|
+
"warmup.success": "Conta aquecida com sucesso",
|
|
492
|
+
"warmup.allSuccess": "Pré-aquecimento concluído",
|
|
493
|
+
"warmup.skipped": "Conta em espera, sem necessidade de aquecimento",
|
|
494
|
+
"config.autoWarmup": "Pré-aquecimento automático de 7 dias",
|
|
495
|
+
"config.autoWarmupDesc": "Ativa automaticamente um ciclo quando o tempo de redefinição semanal é atingido"
|
|
465
496
|
};
|
|
466
497
|
const es = {
|
|
467
498
|
"section.label": "Antigravity",
|
|
@@ -601,7 +632,17 @@ window.__ModuleLoader__.load({
|
|
|
601
632
|
"account.disableTitle": "Deshabilitar esta cuenta (ignorar en rotación)",
|
|
602
633
|
"account.enabledToast": "Cuenta habilitada: {alias}",
|
|
603
634
|
"account.disabledToast": "Cuenta deshabilitada: {alias}",
|
|
604
|
-
"status.disabled": "Deshabilitado"
|
|
635
|
+
"status.disabled": "Deshabilitado",
|
|
636
|
+
"header.warmup": "Precalentamiento",
|
|
637
|
+
"header.warmingUp": "Calentando...",
|
|
638
|
+
"account.warmup": "Calentar",
|
|
639
|
+
"account.warmingUp": "Calentando...",
|
|
640
|
+
"account.warmupTitle": "Calentar esta cuenta (activar temporizador semanal de 7 días)",
|
|
641
|
+
"warmup.success": "Cuenta calentada con éxito",
|
|
642
|
+
"warmup.allSuccess": "Precalentamiento completado",
|
|
643
|
+
"warmup.skipped": "Cuenta en espera, sin necesidad de calentar",
|
|
644
|
+
"config.autoWarmup": "Precalentamiento automático de 7 días",
|
|
645
|
+
"config.autoWarmupDesc": "Activa automáticamente un ciclo cuando se alcanza el tiempo de reinicio semanal"
|
|
605
646
|
};
|
|
606
647
|
//#endregion
|
|
607
648
|
//#region src/client/scroll-guard.ts
|
|
@@ -609,6 +650,7 @@ window.__ModuleLoader__.load({
|
|
|
609
650
|
let scrollTimer = null;
|
|
610
651
|
let listenerAttached = false;
|
|
611
652
|
const settleListeners = /* @__PURE__ */ new Set();
|
|
653
|
+
let overlaySuspended = false;
|
|
612
654
|
function onScrollActivity() {
|
|
613
655
|
isScrolling = true;
|
|
614
656
|
if (scrollTimer !== null) clearTimeout(scrollTimer);
|
|
@@ -620,8 +662,29 @@ window.__ModuleLoader__.load({
|
|
|
620
662
|
} catch {}
|
|
621
663
|
}, 150);
|
|
622
664
|
}
|
|
623
|
-
|
|
624
|
-
|
|
665
|
+
/**
|
|
666
|
+
* Suspend every overlay scanner while a modal/overlay owns the screen.
|
|
667
|
+
*
|
|
668
|
+
* Opening the Antigravity console must freeze the conversation behind it: any
|
|
669
|
+
* DOM the scanners inject while the panel composites on top becomes visible
|
|
670
|
+
* flashing, and the modal's own periodic re-renders keep waking the global
|
|
671
|
+
* observers. On resume we fire the settle listeners once so scanners catch up
|
|
672
|
+
* on anything that changed while they were held back.
|
|
673
|
+
*/
|
|
674
|
+
function setOverlaySuspended(active) {
|
|
675
|
+
if (overlaySuspended === active) return;
|
|
676
|
+
overlaySuspended = active;
|
|
677
|
+
if (!active) for (const fn of settleListeners) try {
|
|
678
|
+
fn();
|
|
679
|
+
} catch {}
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* The one predicate every overlay scanner should gate on: may I mutate the DOM
|
|
683
|
+
* right now? False during an active scroll gesture AND while an overlay owns
|
|
684
|
+
* the screen. Scanners must not act while this is true.
|
|
685
|
+
*/
|
|
686
|
+
function isInteractionLocked() {
|
|
687
|
+
return isScrolling || overlaySuspended;
|
|
625
688
|
}
|
|
626
689
|
/** Register a callback to run once scrolling has settled. Returns an unregister function. */
|
|
627
690
|
function onScrollSettle(fn) {
|
|
@@ -654,6 +717,7 @@ window.__ModuleLoader__.load({
|
|
|
654
717
|
}
|
|
655
718
|
settleListeners.clear();
|
|
656
719
|
isScrolling = false;
|
|
720
|
+
overlaySuspended = false;
|
|
657
721
|
}
|
|
658
722
|
//#endregion
|
|
659
723
|
//#region src/client/decisions.ts
|
|
@@ -810,7 +874,7 @@ window.__ModuleLoader__.load({
|
|
|
810
874
|
*/
|
|
811
875
|
function scanAndEnhanceDecisions() {
|
|
812
876
|
if (typeof document === "undefined") return;
|
|
813
|
-
if (
|
|
877
|
+
if (isInteractionLocked()) return;
|
|
814
878
|
const markdownContainers = document.querySelectorAll("div[class*=\"_markdown_\"], [data-markdown-variant]");
|
|
815
879
|
for (let i = 0; i < markdownContainers.length; i++) {
|
|
816
880
|
const container = markdownContainers[i];
|
|
@@ -879,11 +943,11 @@ window.__ModuleLoader__.load({
|
|
|
879
943
|
let decisionScanTimer = null;
|
|
880
944
|
let unbindDecisionSettle = null;
|
|
881
945
|
function scheduleDecisionScan() {
|
|
882
|
-
if (
|
|
946
|
+
if (isInteractionLocked()) return;
|
|
883
947
|
if (decisionScanTimer !== null) return;
|
|
884
948
|
decisionScanTimer = setTimeout(() => {
|
|
885
949
|
decisionScanTimer = null;
|
|
886
|
-
if (
|
|
950
|
+
if (isInteractionLocked()) return;
|
|
887
951
|
scanAndEnhanceDecisions();
|
|
888
952
|
}, 100);
|
|
889
953
|
}
|
|
@@ -1018,8 +1082,10 @@ window.__ModuleLoader__.load({
|
|
|
1018
1082
|
position: fixed;
|
|
1019
1083
|
inset: 0;
|
|
1020
1084
|
z-index: 999999;
|
|
1021
|
-
background: rgba(0, 0, 0, 0.
|
|
1022
|
-
backdrop
|
|
1085
|
+
background: rgba(0, 0, 0, 0.9);
|
|
1086
|
+
/* No full-viewport backdrop blur: same flicker class as the console overlay.
|
|
1087
|
+
The image viewer is already near-opaque; a solid alpha is stable. */
|
|
1088
|
+
overscroll-behavior: contain;
|
|
1023
1089
|
display: flex;
|
|
1024
1090
|
flex-direction: column;
|
|
1025
1091
|
user-select: none;
|
|
@@ -1288,7 +1354,7 @@ window.__ModuleLoader__.load({
|
|
|
1288
1354
|
*/
|
|
1289
1355
|
function scanAndEnhanceImages() {
|
|
1290
1356
|
if (typeof document === "undefined") return;
|
|
1291
|
-
if (
|
|
1357
|
+
if (isInteractionLocked()) return;
|
|
1292
1358
|
const origin = getOrigin();
|
|
1293
1359
|
if (origin && !origin.includes("127.0.0.1") && !origin.includes("localhost")) {
|
|
1294
1360
|
const images = document.querySelectorAll("img[src*=\"/plugins/agy-link/media\"]");
|
|
@@ -1381,11 +1447,11 @@ window.__ModuleLoader__.load({
|
|
|
1381
1447
|
let imageScanTimer = null;
|
|
1382
1448
|
let unbindImageSettle = null;
|
|
1383
1449
|
function scheduleImageScan() {
|
|
1384
|
-
if (
|
|
1450
|
+
if (isInteractionLocked()) return;
|
|
1385
1451
|
if (imageScanTimer !== null) return;
|
|
1386
1452
|
imageScanTimer = setTimeout(() => {
|
|
1387
1453
|
imageScanTimer = null;
|
|
1388
|
-
if (
|
|
1454
|
+
if (isInteractionLocked()) return;
|
|
1389
1455
|
scanAndEnhanceImages();
|
|
1390
1456
|
}, 100);
|
|
1391
1457
|
}
|
|
@@ -3006,6 +3072,12 @@ div[data-agy-mermaid-svg] svg {
|
|
|
3006
3072
|
min-width: 280px;
|
|
3007
3073
|
height: auto;
|
|
3008
3074
|
}
|
|
3075
|
+
.agy-mermaid-body {
|
|
3076
|
+
display: flex;
|
|
3077
|
+
justify-content: center;
|
|
3078
|
+
width: 100%;
|
|
3079
|
+
overflow-x: auto;
|
|
3080
|
+
}
|
|
3009
3081
|
.agy-mermaid-toolbar {
|
|
3010
3082
|
display: flex;
|
|
3011
3083
|
justify-content: flex-end;
|
|
@@ -3261,6 +3333,12 @@ body > [id^="iagy-mmd"] .error-icon {
|
|
|
3261
3333
|
return l;
|
|
3262
3334
|
}).join("\n");
|
|
3263
3335
|
}
|
|
3336
|
+
function isInvalidOrCollapsedSvg(svg) {
|
|
3337
|
+
if (!svg || svg.trim() === "") return true;
|
|
3338
|
+
if (svg.includes("class=\"error-icon\"") || svg.includes("class=\"error-text\"") || svg.includes("aria-roledescription=\"error\"")) return true;
|
|
3339
|
+
if (svg.includes("viewBox=\"0 0 0 0\"") || svg.includes("viewBox=\"-8 -8 16 16\"") || svg.includes("max-width: 16px") || svg.includes("max-width: 0px")) return true;
|
|
3340
|
+
return false;
|
|
3341
|
+
}
|
|
3264
3342
|
async function renderInto(block, source, lang = "") {
|
|
3265
3343
|
block.querySelector("[data-agy-mermaid-svg]")?.remove();
|
|
3266
3344
|
const mount = document.createElement("div");
|
|
@@ -3293,8 +3371,8 @@ body > [id^="iagy-mmd"] .error-icon {
|
|
|
3293
3371
|
else throw parseErr;
|
|
3294
3372
|
}
|
|
3295
3373
|
if (!parseValidated && typeof api.parse !== "function") targetSource = repairMermaidSource(targetSource);
|
|
3296
|
-
const { svg } = await api.render(id, targetSource
|
|
3297
|
-
if (
|
|
3374
|
+
const { svg } = await api.render(id, targetSource);
|
|
3375
|
+
if (isInvalidOrCollapsedSvg(svg)) throw new Error("Mermaid returned an empty or invalid diagram");
|
|
3298
3376
|
mount.innerHTML = "";
|
|
3299
3377
|
const toolbar = document.createElement("div");
|
|
3300
3378
|
toolbar.className = "agy-mermaid-toolbar";
|
|
@@ -3335,17 +3413,17 @@ body > [id^="iagy-mmd"] .error-icon {
|
|
|
3335
3413
|
}
|
|
3336
3414
|
let scanTimer$1 = null;
|
|
3337
3415
|
function scheduleScan$1() {
|
|
3338
|
-
if (
|
|
3416
|
+
if (isInteractionLocked()) return;
|
|
3339
3417
|
if (scanTimer$1 !== null) return;
|
|
3340
3418
|
scanTimer$1 = setTimeout(() => {
|
|
3341
3419
|
scanTimer$1 = null;
|
|
3342
|
-
if (
|
|
3420
|
+
if (isInteractionLocked()) return;
|
|
3343
3421
|
scan();
|
|
3344
3422
|
}, 150);
|
|
3345
3423
|
}
|
|
3346
3424
|
function scan() {
|
|
3347
3425
|
if (typeof document === "undefined") return;
|
|
3348
|
-
if (
|
|
3426
|
+
if (isInteractionLocked()) return;
|
|
3349
3427
|
cleanupTempElements();
|
|
3350
3428
|
const blocks = document.querySelectorAll(".md-code-block");
|
|
3351
3429
|
for (let i = 0; i < blocks.length; i++) {
|
|
@@ -3509,7 +3587,7 @@ div[data-variant="think"] [class*="thinkBody"] {
|
|
|
3509
3587
|
passive: true
|
|
3510
3588
|
});
|
|
3511
3589
|
}
|
|
3512
|
-
if (
|
|
3590
|
+
if (isInteractionLocked()) return;
|
|
3513
3591
|
if (body.clientHeight > 8) {
|
|
3514
3592
|
handledTurns.add(turnKey);
|
|
3515
3593
|
root.dataset.agyExpanded = "true";
|
|
@@ -3523,7 +3601,7 @@ div[data-variant="think"] [class*="thinkBody"] {
|
|
|
3523
3601
|
}
|
|
3524
3602
|
function scanThinkingRows() {
|
|
3525
3603
|
if (typeof document === "undefined") return;
|
|
3526
|
-
if (
|
|
3604
|
+
if (isInteractionLocked()) return;
|
|
3527
3605
|
const rows = document.querySelectorAll("div[data-variant=\"think\"]");
|
|
3528
3606
|
for (let i = 0; i < rows.length; i++) {
|
|
3529
3607
|
const row = rows[i];
|
|
@@ -3532,11 +3610,11 @@ div[data-variant="think"] [class*="thinkBody"] {
|
|
|
3532
3610
|
}
|
|
3533
3611
|
let scanTimer = null;
|
|
3534
3612
|
function scheduleScan() {
|
|
3535
|
-
if (
|
|
3613
|
+
if (isInteractionLocked()) return;
|
|
3536
3614
|
if (scanTimer !== null) return;
|
|
3537
3615
|
scanTimer = setTimeout(() => {
|
|
3538
3616
|
scanTimer = null;
|
|
3539
|
-
if (
|
|
3617
|
+
if (isInteractionLocked()) return;
|
|
3540
3618
|
scanThinkingRows();
|
|
3541
3619
|
}, 150);
|
|
3542
3620
|
}
|
|
@@ -3653,6 +3731,7 @@ div[data-variant="think"] [class*="thinkBody"] {
|
|
|
3653
3731
|
}
|
|
3654
3732
|
const statusListeners = /* @__PURE__ */ new Set();
|
|
3655
3733
|
let statusPollTimer = null;
|
|
3734
|
+
let statusPollInterval = 3e3;
|
|
3656
3735
|
let statusFetchSeq = 0;
|
|
3657
3736
|
function isStatusEqual(a, b) {
|
|
3658
3737
|
if (a === b) return true;
|
|
@@ -3680,16 +3759,25 @@ div[data-variant="think"] [class*="thinkBody"] {
|
|
|
3680
3759
|
}
|
|
3681
3760
|
}
|
|
3682
3761
|
function ensureStatusPolling() {
|
|
3683
|
-
if (statusPollTimer !== null)
|
|
3762
|
+
if (statusPollTimer !== null) {
|
|
3763
|
+
if (statusPollInterval !== 3e3) {
|
|
3764
|
+
clearInterval(statusPollTimer);
|
|
3765
|
+
statusPollTimer = null;
|
|
3766
|
+
} else return;
|
|
3767
|
+
}
|
|
3768
|
+
statusPollInterval = 3e3;
|
|
3684
3769
|
statusPollTick();
|
|
3685
3770
|
statusPollTimer = setInterval(() => {
|
|
3686
3771
|
statusPollTick();
|
|
3687
3772
|
}, 3e3);
|
|
3688
3773
|
}
|
|
3689
3774
|
function stopStatusPollingIfIdle() {
|
|
3690
|
-
if (statusListeners.size === 0 && statusPollTimer !== null) {
|
|
3775
|
+
if (statusListeners.size === 0 && statusPollTimer !== null && statusPollInterval === 3e3) {
|
|
3691
3776
|
clearInterval(statusPollTimer);
|
|
3692
|
-
|
|
3777
|
+
statusPollInterval = 15e3;
|
|
3778
|
+
statusPollTimer = setInterval(() => {
|
|
3779
|
+
statusPollTick();
|
|
3780
|
+
}, 15e3);
|
|
3693
3781
|
}
|
|
3694
3782
|
}
|
|
3695
3783
|
/**
|
|
@@ -3710,7 +3798,7 @@ div[data-variant="think"] [class*="thinkBody"] {
|
|
|
3710
3798
|
}, []);
|
|
3711
3799
|
const refresh = async () => {
|
|
3712
3800
|
const st = await getStatus();
|
|
3713
|
-
if (st !== null) notifyStatus(st);
|
|
3801
|
+
if (st !== null && !isStatusEqual(statusCache, st)) notifyStatus(st);
|
|
3714
3802
|
};
|
|
3715
3803
|
return {
|
|
3716
3804
|
status,
|
|
@@ -3722,7 +3810,10 @@ div[data-variant="think"] [class*="thinkBody"] {
|
|
|
3722
3810
|
open: false,
|
|
3723
3811
|
listeners: /* @__PURE__ */ new Set(),
|
|
3724
3812
|
setOpen(v) {
|
|
3813
|
+
if (agyModalStore.open === v) return;
|
|
3725
3814
|
agyModalStore.open = v;
|
|
3815
|
+
setOverlaySuspended(v);
|
|
3816
|
+
if (typeof document !== "undefined" && document.documentElement) document.documentElement.classList.toggle("agy-modal-open", v);
|
|
3726
3817
|
agyModalStore.listeners.forEach((fn) => fn());
|
|
3727
3818
|
},
|
|
3728
3819
|
subscribe(fn) {
|
|
@@ -3734,8 +3825,9 @@ div[data-variant="think"] [class*="thinkBody"] {
|
|
|
3734
3825
|
};
|
|
3735
3826
|
/**
|
|
3736
3827
|
* Global modal host manager: ensures exactly one mounted session header
|
|
3737
|
-
* hosts the modal dialog portal reactively.
|
|
3738
|
-
*
|
|
3828
|
+
* hosts the modal dialog portal reactively. The most recently focused or mounted
|
|
3829
|
+
* header is prioritized immediately to prevent host handoff flicker when opened.
|
|
3830
|
+
* If the primary header unmounts, the next available header is seamlessly notified.
|
|
3739
3831
|
*/
|
|
3740
3832
|
const modalHostManager = {
|
|
3741
3833
|
listeners: /* @__PURE__ */ new Map(),
|
|
@@ -3749,7 +3841,9 @@ div[data-variant="think"] [class*="thinkBody"] {
|
|
|
3749
3841
|
if (modalHostManager.activeId === id) {
|
|
3750
3842
|
const next = modalHostManager.listeners.keys().next().value ?? null;
|
|
3751
3843
|
modalHostManager.activeId = next;
|
|
3752
|
-
if (next)
|
|
3844
|
+
if (next) try {
|
|
3845
|
+
modalHostManager.listeners.get(next)?.(true);
|
|
3846
|
+
} catch {}
|
|
3753
3847
|
}
|
|
3754
3848
|
};
|
|
3755
3849
|
},
|
|
@@ -3757,8 +3851,12 @@ div[data-variant="think"] [class*="thinkBody"] {
|
|
|
3757
3851
|
if (modalHostManager.activeId !== id) {
|
|
3758
3852
|
const prev = modalHostManager.activeId;
|
|
3759
3853
|
modalHostManager.activeId = id;
|
|
3760
|
-
if (prev
|
|
3761
|
-
|
|
3854
|
+
if (prev && prev !== id) try {
|
|
3855
|
+
modalHostManager.listeners.get(prev)?.(false);
|
|
3856
|
+
} catch {}
|
|
3857
|
+
try {
|
|
3858
|
+
modalHostManager.listeners.get(id)?.(true);
|
|
3859
|
+
} catch {}
|
|
3762
3860
|
}
|
|
3763
3861
|
}
|
|
3764
3862
|
};
|
|
@@ -4435,7 +4533,7 @@ body.dark,
|
|
|
4435
4533
|
}
|
|
4436
4534
|
|
|
4437
4535
|
.agy-btn {
|
|
4438
|
-
transition:
|
|
4536
|
+
transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease, filter 0.15s ease, transform 0.15s ease;
|
|
4439
4537
|
user-select: none;
|
|
4440
4538
|
}
|
|
4441
4539
|
.agy-btn:hover:not(:disabled) {
|
|
@@ -4455,12 +4553,17 @@ body.dark,
|
|
|
4455
4553
|
.agy-shimmer-track {
|
|
4456
4554
|
position: relative;
|
|
4457
4555
|
overflow: hidden;
|
|
4556
|
+
contain: paint;
|
|
4557
|
+
transform: translateZ(0);
|
|
4558
|
+
isolation: isolate;
|
|
4458
4559
|
}
|
|
4459
4560
|
.agy-shimmer-track::after {
|
|
4460
4561
|
content: '';
|
|
4461
4562
|
position: absolute;
|
|
4462
4563
|
top: 0; left: 0; right: 0; bottom: 0;
|
|
4463
4564
|
background: linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.22) 50%, transparent 100%);
|
|
4565
|
+
transform: translateX(-100%) translateZ(0);
|
|
4566
|
+
will-change: transform;
|
|
4464
4567
|
animation: agy-shimmer 1.8s infinite ease-in-out;
|
|
4465
4568
|
pointer-events: none;
|
|
4466
4569
|
}
|
|
@@ -4469,13 +4572,24 @@ body.dark,
|
|
|
4469
4572
|
inset: 0;
|
|
4470
4573
|
z-index: 9999;
|
|
4471
4574
|
background: var(--agy-modal-backdrop);
|
|
4472
|
-
|
|
4575
|
+
/* NO full-screen backdrop blur here. Filtering the whole viewport forces
|
|
4576
|
+
Chromium/Electron to re-sample the page every frame while anything behind
|
|
4577
|
+
it moves (scroll, streaming, animations) — the recurring "打开控制台后滚动
|
|
4578
|
+
闪屏" root cause. The rgba dim below is stable and flicker-free. */
|
|
4579
|
+
overscroll-behavior: contain;
|
|
4473
4580
|
display: flex;
|
|
4474
4581
|
align-items: center;
|
|
4475
4582
|
justify-content: center;
|
|
4476
4583
|
padding: 16px;
|
|
4477
4584
|
box-sizing: border-box;
|
|
4478
4585
|
}
|
|
4586
|
+
/* While the console is open, freeze the conversation scroller behind it so
|
|
4587
|
+
nothing moves/reflows under the fixed overlay. scrollbar-gutter:stable on the
|
|
4588
|
+
host scroller keeps the width from jumping when overflow flips to hidden. */
|
|
4589
|
+
html.agy-modal-open [data-conversation-scroll] {
|
|
4590
|
+
overflow: hidden !important;
|
|
4591
|
+
overscroll-behavior: contain;
|
|
4592
|
+
}
|
|
4479
4593
|
.agy-modal-panel {
|
|
4480
4594
|
position: relative;
|
|
4481
4595
|
width: 100%;
|
|
@@ -4490,6 +4604,8 @@ body.dark,
|
|
|
4490
4604
|
overflow: hidden;
|
|
4491
4605
|
color: var(--agy-text-primary);
|
|
4492
4606
|
font-family: var(--agy-font-family);
|
|
4607
|
+
transform: translateZ(0);
|
|
4608
|
+
contain: content;
|
|
4493
4609
|
}
|
|
4494
4610
|
.agy-submodel-row {
|
|
4495
4611
|
display: flex;
|
|
@@ -4747,6 +4863,15 @@ body.dark,
|
|
|
4747
4863
|
};
|
|
4748
4864
|
function apply(ctx) {
|
|
4749
4865
|
injectGlobalStyles();
|
|
4866
|
+
ctx.effect(() => {
|
|
4867
|
+
ensureStatusPolling();
|
|
4868
|
+
return () => {
|
|
4869
|
+
if (statusPollTimer !== null) {
|
|
4870
|
+
clearInterval(statusPollTimer);
|
|
4871
|
+
statusPollTimer = null;
|
|
4872
|
+
}
|
|
4873
|
+
};
|
|
4874
|
+
}, "agy-link: status polling");
|
|
4750
4875
|
const locale = ctx.locale;
|
|
4751
4876
|
ctx.effect(() => {
|
|
4752
4877
|
const disposePtBR = locale.addLanguage({
|
|
@@ -4976,15 +5101,41 @@ body.dark,
|
|
|
4976
5101
|
};
|
|
4977
5102
|
const refreshQuota = async (id) => {
|
|
4978
5103
|
setLoadingAction(id ? `refresh:${id}` : "refresh:all");
|
|
4979
|
-
|
|
4980
|
-
|
|
5104
|
+
try {
|
|
5105
|
+
const res = await postJson("/plugins/agy-link/pool/refresh-quota", { id });
|
|
5106
|
+
if (res === null || res?.ok === false) {
|
|
5107
|
+
actionFailed();
|
|
5108
|
+
return;
|
|
5109
|
+
}
|
|
5110
|
+
await refresh();
|
|
5111
|
+
showToast(t("quota.refreshed"), "success");
|
|
5112
|
+
} finally {
|
|
5113
|
+
setLoadingAction(null);
|
|
5114
|
+
}
|
|
5115
|
+
};
|
|
5116
|
+
const warmupAccount = async (id) => {
|
|
5117
|
+
setLoadingAction(id ? `warmup:${id}` : "warmup:all");
|
|
5118
|
+
try {
|
|
5119
|
+
const res = await postJson("/plugins/agy-link/pool/warmup", {
|
|
5120
|
+
id,
|
|
5121
|
+
force: true,
|
|
5122
|
+
...id ? {} : { all: true }
|
|
5123
|
+
});
|
|
5124
|
+
if (res === null || res?.ok === false) {
|
|
5125
|
+
actionFailed();
|
|
5126
|
+
return;
|
|
5127
|
+
}
|
|
5128
|
+
await refresh();
|
|
5129
|
+
const results = Array.isArray(res.results) ? res.results : [];
|
|
5130
|
+
const skippedCount = results.filter((r) => r.skipped).length;
|
|
5131
|
+
const successCount = results.filter((r) => r.success && !r.skipped).length;
|
|
5132
|
+
const failedCount = results.length - skippedCount - successCount;
|
|
5133
|
+
if (successCount > 0) showToast(id ? t("warmup.success") : t("warmup.allSuccess"), "success");
|
|
5134
|
+
else if (skippedCount > 0 && failedCount === 0) showToast(t("warmup.skipped"), "info");
|
|
5135
|
+
else actionFailed();
|
|
5136
|
+
} finally {
|
|
4981
5137
|
setLoadingAction(null);
|
|
4982
|
-
actionFailed();
|
|
4983
|
-
return;
|
|
4984
5138
|
}
|
|
4985
|
-
await refresh();
|
|
4986
|
-
setLoadingAction(null);
|
|
4987
|
-
showToast(t("quota.refreshed"), "success");
|
|
4988
5139
|
};
|
|
4989
5140
|
const saveProxy = async (id) => {
|
|
4990
5141
|
setLoadingAction(`proxy:${id}`);
|
|
@@ -5091,7 +5242,7 @@ body.dark,
|
|
|
5091
5242
|
"aria-label": t("aria.closeToast")
|
|
5092
5243
|
}, uiIcon("x", 12)));
|
|
5093
5244
|
};
|
|
5094
|
-
const renderQuotaBar = (label, familyKey, acc) => renderFamilyQuotaBar(t, label, familyKey, acc, loadingAction === "refresh
|
|
5245
|
+
const renderQuotaBar = (label, familyKey, acc) => renderFamilyQuotaBar(t, label, familyKey, acc, loadingAction === "refresh:all" || loadingAction === `refresh:${acc.id}`);
|
|
5095
5246
|
const authoritativeActiveId = pool?.activeAccountId ?? pool?.lastActiveAccountId ?? pool?.activeAccountIds?.google ?? pool?.primaryAccountId;
|
|
5096
5247
|
const activeAccountId = optimisticActiveId ?? authoritativeActiveId;
|
|
5097
5248
|
const renderedAccountCards = accounts.map((acc) => {
|
|
@@ -5311,12 +5462,28 @@ body.dark,
|
|
|
5311
5462
|
...S.btnSm,
|
|
5312
5463
|
gap: "3px",
|
|
5313
5464
|
fontSize: "11px",
|
|
5314
|
-
padding: "2px 6px"
|
|
5465
|
+
padding: "2px 6px",
|
|
5466
|
+
minWidth: "58px",
|
|
5467
|
+
justifyContent: "center"
|
|
5315
5468
|
},
|
|
5316
5469
|
title: t("account.syncTitle"),
|
|
5317
5470
|
disabled: accountActionBusy(acc, "refresh"),
|
|
5318
5471
|
onClick: () => void refreshQuota(acc.id)
|
|
5319
|
-
}, loadingAction === `refresh:${acc.id}` ? [renderSpinner(), t("account.syncing")] : [uiIcon("refresh", 10), ` ${t("account.sync")}`]), acc.enabled && !
|
|
5472
|
+
}, loadingAction === `refresh:${acc.id}` ? [renderSpinner(), t("account.syncing")] : [uiIcon("refresh", 10), ` ${t("account.sync")}`]), acc.enabled && !acc.authRequired ? h("button", {
|
|
5473
|
+
type: "button",
|
|
5474
|
+
className: "agy-btn",
|
|
5475
|
+
style: {
|
|
5476
|
+
...S.btnSm,
|
|
5477
|
+
gap: "3px",
|
|
5478
|
+
fontSize: "11px",
|
|
5479
|
+
padding: "2px 6px",
|
|
5480
|
+
minWidth: "58px",
|
|
5481
|
+
justifyContent: "center"
|
|
5482
|
+
},
|
|
5483
|
+
title: t("account.warmupTitle"),
|
|
5484
|
+
disabled: accountActionBusy(acc, "warmup"),
|
|
5485
|
+
onClick: () => void warmupAccount(acc.id)
|
|
5486
|
+
}, loadingAction === `warmup:${acc.id}` ? [renderSpinner(), t("account.warmingUp")] : [uiIcon("flame", 10, "#f97316"), ` ${t("account.warmup")}`]) : null, acc.enabled && !isInUse ? h("button", {
|
|
5320
5487
|
type: "button",
|
|
5321
5488
|
className: "agy-btn",
|
|
5322
5489
|
style: {
|
|
@@ -5618,6 +5785,15 @@ body.dark,
|
|
|
5618
5785
|
},
|
|
5619
5786
|
onClick: () => setAddingAccount(true)
|
|
5620
5787
|
}, [uiIcon("plus", 12, "#ffffff"), ` ${t("account.add")}`]) : null, h("button", {
|
|
5788
|
+
type: "button",
|
|
5789
|
+
className: "agy-btn",
|
|
5790
|
+
style: {
|
|
5791
|
+
...S.btn,
|
|
5792
|
+
gap: "4px"
|
|
5793
|
+
},
|
|
5794
|
+
disabled: isBusy,
|
|
5795
|
+
onClick: () => void warmupAccount()
|
|
5796
|
+
}, loadingAction === "warmup:all" ? [renderSpinner(), t("header.warmingUp")] : [uiIcon("flame", 12, "#f97316"), ` ${t("header.warmup")}`]), h("button", {
|
|
5621
5797
|
type: "button",
|
|
5622
5798
|
className: "agy-btn",
|
|
5623
5799
|
style: {
|
|
@@ -5714,6 +5890,22 @@ body.dark,
|
|
|
5714
5890
|
style: pool?.mode === "round-robin" ? S.segBtnActive : S.segBtn,
|
|
5715
5891
|
onClick: () => void setMode("round-robin")
|
|
5716
5892
|
}, t("pool.roundRobin")))), h("div", { style: {
|
|
5893
|
+
display: "flex",
|
|
5894
|
+
alignItems: "center",
|
|
5895
|
+
justifyContent: "space-between"
|
|
5896
|
+
} }, h("div", { style: {
|
|
5897
|
+
display: "flex",
|
|
5898
|
+
flexDirection: "column"
|
|
5899
|
+
} }, h("span", { style: {
|
|
5900
|
+
color: "var(--agy-text-primary)",
|
|
5901
|
+
fontWeight: 600,
|
|
5902
|
+
fontSize: "12.5px"
|
|
5903
|
+
} }, t("config.autoWarmup")), h("span", { style: S.muted }, t("config.autoWarmupDesc"))), h("button", {
|
|
5904
|
+
type: "button",
|
|
5905
|
+
style: status?.autoWarmup !== false ? S.segBtnActive : S.segBtn,
|
|
5906
|
+
disabled: loadingAction === "config:autoWarmup",
|
|
5907
|
+
onClick: () => void setCfg("autoWarmup", status?.autoWarmup === false)
|
|
5908
|
+
}, status?.autoWarmup !== false ? t("account.disable") : t("account.enable"))), h("div", { style: {
|
|
5717
5909
|
display: "flex",
|
|
5718
5910
|
flexDirection: "column",
|
|
5719
5911
|
gap: "6px"
|
|
@@ -5800,6 +5992,7 @@ body.dark,
|
|
|
5800
5992
|
onClick: () => agyModalStore.setOpen(false)
|
|
5801
5993
|
}, uiIcon("x", 14, "var(--agy-text-btn)"))), h("div", { style: {
|
|
5802
5994
|
overflowY: "auto",
|
|
5995
|
+
overscrollBehavior: "contain",
|
|
5803
5996
|
padding: "18px",
|
|
5804
5997
|
flex: "1",
|
|
5805
5998
|
background: "var(--agy-bg-panel)"
|
|
@@ -5813,7 +6006,13 @@ body.dark,
|
|
|
5813
6006
|
const hostIdRef = useRef(null);
|
|
5814
6007
|
if (hostIdRef.current === null) hostIdRef.current = "host_" + Math.random().toString(36).slice(2);
|
|
5815
6008
|
const hostId = hostIdRef.current;
|
|
5816
|
-
const [isPrimaryHost, setIsPrimaryHost] = useState(
|
|
6009
|
+
const [isPrimaryHost, setIsPrimaryHost] = useState(() => {
|
|
6010
|
+
if (modalHostManager.activeId === null) {
|
|
6011
|
+
modalHostManager.activeId = hostId;
|
|
6012
|
+
return true;
|
|
6013
|
+
}
|
|
6014
|
+
return modalHostManager.activeId === hostId;
|
|
6015
|
+
});
|
|
5817
6016
|
useEffect(() => {
|
|
5818
6017
|
return modalHostManager.register(hostId, setIsPrimaryHost);
|
|
5819
6018
|
}, [hostId]);
|
|
@@ -5866,7 +6065,9 @@ body.dark,
|
|
|
5866
6065
|
display: "inline-flex",
|
|
5867
6066
|
alignItems: "center",
|
|
5868
6067
|
gap: "6px",
|
|
5869
|
-
boxShadow: "var(--agy-shadow-card)"
|
|
6068
|
+
boxShadow: "var(--agy-shadow-card)",
|
|
6069
|
+
flexShrink: 0,
|
|
6070
|
+
whiteSpace: "nowrap"
|
|
5870
6071
|
}
|
|
5871
6072
|
}, h("span", { style: {
|
|
5872
6073
|
display: "inline-block",
|
|
@@ -5917,7 +6118,12 @@ body.dark,
|
|
|
5917
6118
|
});
|
|
5918
6119
|
ctx.effect(() => {
|
|
5919
6120
|
ensureScrollListener();
|
|
5920
|
-
return
|
|
6121
|
+
return () => {
|
|
6122
|
+
disposeScrollListener();
|
|
6123
|
+
agyModalStore.open = false;
|
|
6124
|
+
setOverlaySuspended(false);
|
|
6125
|
+
if (typeof document !== "undefined" && document.documentElement) document.documentElement.classList.remove("agy-modal-open");
|
|
6126
|
+
};
|
|
5921
6127
|
});
|
|
5922
6128
|
installAgyToolView(ctx);
|
|
5923
6129
|
ctx.effect(() => installAutoExpandReasoning());
|