dsh-agy-link 0.4.50 → 0.4.53
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 +50 -0
- package/dist/client.js +153 -84
- package/dist/index.js +573 -76
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,55 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.53 (2026-10-15)
|
|
4
|
+
|
|
5
|
+
### English
|
|
6
|
+
|
|
7
|
+
- **Fix: a NUL byte in a tool result can no longer kill the turn before agy starts.** Tool output that quoted binary content (an agent listing or reading a `.git` directory, a packed object, an image) carried U+0000 into the assembled prompt; because the prompt travels as an `-p` argv element, `spawn()` rejected it with `TypeError [ERR_INVALID_ARG_VALUE]: The argument 'args[16]' must be a string without null bytes` and the turn failed as "failed to spawn agy" before agy was ever launched — the retry re-sent the same history and failed identically, so the session could not make progress. `stripNulBytes()` now removes U+0000 from the rolling digest (per message text), from the final prompt on its single path into `buildArgs` — covering both the argv transport and the `--input-format stream-json` stdin transport — and from the one-shot/compaction prompt after file inlining. Every other control character is legal in argv and is left untouched.
|
|
8
|
+
|
|
9
|
+
### 中文 (Chinese)
|
|
10
|
+
|
|
11
|
+
- **修复:工具结果里的 NUL 字节不再让整个轮次在 agy 启动前就崩溃。** 当工具输出引用了二进制内容(agent 列出或读取 `.git` 目录、packed object、图片等)时,U+0000 会被带进拼装好的提示词;提示词以 `-p` 参数进入 argv,`spawn()` 因此抛 `TypeError [ERR_INVALID_ARG_VALUE]: The argument 'args[16]' must be a string without null bytes`,整轮以「failed to spawn agy」失败——重试会重发同一段历史,于是同样失败,会话彻底卡死。现在 `stripNulBytes()` 会从三处移除 U+0000:滚动摘要中每条消息的文本、进入 `buildArgs` 前的最终提示词(同时覆盖 argv 与 `--input-format stream-json` 的 stdin 两种传输)、以及一次性/压缩任务内联文件后的提示词。其余控制字符在 argv 中合法,保持原样。
|
|
12
|
+
|
|
13
|
+
## 0.4.52 (2026-10-15)
|
|
14
|
+
|
|
15
|
+
### English
|
|
16
|
+
|
|
17
|
+
- **Fix: DSH `/goal` infinite continuation loop resolved.** In DSH, `/goal` runs a multi-round state machine (up to 256 rounds) that keeps injecting `<goal_round>` until the agent explicitly invokes `update_goal(action='complete')`. Because `agy` CLI uses its own native tools and terminates after finishing, DSH treated the goal as perpetually active (running up to 93+ rounds). The bridge now intercepts the completion event in goal mode and emits a synthetic `update_goal(complete)` tool-call, properly closing the goal state machine.
|
|
18
|
+
- **Feature: DSH `/plan` mode support.** When running in plan mode (prompt containing "You are in plan mode"), the bridge automatically emits the `exit_plan_mode` tool-call carrying the generated plan markdown for user interactive review and approval.
|
|
19
|
+
- **Feature: /agy goal command family.** Added `/agy goal [status|complete|pause|resume|clear]` allowing users to inspect the current goal state (ID, revision, objective, round count) or manually control/complete/clear the active goal.
|
|
20
|
+
- **Feature: /agy session command family.** Added `/agy session [info|clear]` for inspecting session workspace CWD, bound agy conversation ID, event counts, and safely dropping session bindings without guessing. `/agy clear` is also upgraded to prioritize the current session.
|
|
21
|
+
- **Feature: Intelligent quota-expiry-first rotation (Weekly & 5h).** Refactored pool candidate selection: when switching accounts, the pool prioritizes accounts whose weekly quota is expiring soonest (Priority 1: preventing irreversible weekly quota loss), followed by accounts whose 5-hour quota is expiring soonest (Priority 2). Execution maintains seamless sticky sequential drain, continuing on the current account until its quota is exhausted before cleanly advancing to the next optimal candidate.
|
|
22
|
+
- **UI: Simplified thinking turn banner.** Replaced verbose `[agy thinking turn · N thinking tokens]` chip with concise `[agy · N tokens]` (or `[agy]` when no count is present), avoiding long headers crowding out the collapsed reasoning summary in DSH.
|
|
23
|
+
- **UI: Removed redundant "Set as primary" action.** Dropped the confusing "Set as primary" button from the account cards across all locales. Manual account activation is cleanly handled via the existing "Set as in use" action.
|
|
24
|
+
|
|
25
|
+
### 中文 (Chinese)
|
|
26
|
+
|
|
27
|
+
- **修复:彻底解决 DSH `/goal` 目标空转死循环问题。** DSH 的 `/goal` 状态机在模型未调用宿主原生 `update_goal(action='complete')` 前,会在每轮结束后自动注入 `<goal_round>` 启动下一轮(最多 256 轮,曾导致 93+ 轮空转)。由于 agy 是自闭环 Agent 引擎,完成任务后正常退出但不会直接调用 DSH 宿主工具。桥接层新增 `dsh-goal` 协议转换模块,在检测到目标轮次执行完毕后,自动向 DSH 发射 `update_goal(complete)` 工具调用块,使 DSH 目标状态机正常流转至完成态并停止重试。
|
|
28
|
+
- **功能:支持 DSH `/plan` 规划模式适配。** 当检测到会话处于规划模式(上下文携带 "You are in plan mode")时,桥接层在模型生成规划后自动发射 `exit_plan_mode` 工具调用块,将规划 Markdown 提交给 DSH 宿主渲染审核弹窗供用户审批。
|
|
29
|
+
- **功能:新增 `/agy goal` 目标管理命令。** 支持 `/agy goal [status|complete|pause|resume|clear]`,可实时查看当前会话的目标状态(目标 ID、版本号、目标描述、已执行轮次/上限),或手动完成、暂停、恢复、清除卡住的目标。
|
|
30
|
+
- **功能:新增 `/agy session` 会话管理命令。** 支持 `/agy session [info|clear]`,可精确查看当前 DSH 会话绑定的工作区 CWD、agy 会话 ID、事件总数等信息,或一键清除当前会话的 agy 绑定;同时增强 `/agy clear` 优先清理当前活动会话的绑定。
|
|
31
|
+
- **功能:按配额临期优先度智能轮换账号(周额度优先,5小时次优)。** 重构账号轮换调度算法:在切号时,第一优先级优先选取周额度剩余时间最少(最先到期)的账号(避免周硬额度清零浪费),第二优先级选取 5 小时窗口最先到期的账号;同时严格遵循无感黏性消耗原则(只要当前账号的 5 小时或周额度未耗尽绝不切号,耗尽后自动无缝切换下一个最优账号),最大化利用全部账号配额。
|
|
32
|
+
- **体验:精简思考过程标签(thinking banner)。** 将冗长的 `[agy thinking turn · N thinking tokens]` 简化为精炼的 `[agy · N tokens]`(无计数时为 `[agy]`),大幅缩减括号内字符宽度,让 DSH 折叠思考栏能够更完整展现具体的思维链与工具摘要。
|
|
33
|
+
- **体验:移除冗余的“设为主用”按钮。** 从前端控制台卡片操作栏和各语言包中彻底移除“设为主用”按钮,手动切换账号统一由“设为当前使用”负责,简化界面操作。
|
|
34
|
+
|
|
35
|
+
## 0.4.51 (2026-10-15)
|
|
36
|
+
|
|
37
|
+
### English
|
|
38
|
+
|
|
39
|
+
- **Feature: Per-account Enable / Disable toggles.** Added dedicated Enable / Disable buttons and status badges to each account card in the WebUI console and CLI (`/agy enable-account <id>`, `/agy disable-account <id>`). Disabled accounts are dimmed with a gray "Disabled" badge.
|
|
40
|
+
- **Fix: Account rotation and selection strictly skips disabled accounts.** Rotation algorithms (`selectAccount`, `advanceAccount`, sticky sequential drain, round-robin, and fallback model degradation) skip disabled accounts completely.
|
|
41
|
+
- **Fix: Cooldown & quota reset fallback never returns a disabled account.** `getActiveAccountId` previously fell back to `primaryAccountId` or the first account without checking `enabled`, which could surface a disabled slot as active; it now only falls back to eligible enabled accounts (or `undefined` if all accounts are disabled).
|
|
42
|
+
- **Fix: Background auth reverification skips disabled accounts.** `needsAuthReverify` now checks `account.enabled`, preventing the background quota poller from probing disabled slots.
|
|
43
|
+
- **Fix: Detailed error diagnostics when accounts are disabled.** When all or remaining accounts cannot serve a model family, the error message explicitly enumerates disabled slots and informs the user to re-enable them in the console or CLI rather than reporting misleading 0 cooldown/auth counts.
|
|
44
|
+
|
|
45
|
+
### 中文 (Chinese)
|
|
46
|
+
|
|
47
|
+
- **功能:每个账号增加启用 / 停用按钮。** 在 WebUI 控制台的每个账号卡片上以及 CLI 命令中增加了启用/停用按钮与操作(`/agy enable-account <id>`、`/agy disable-account <id>`)。停用账号卡片以半透明呈现并标记灰色“已停用”徽章。
|
|
48
|
+
- **修复:切号与调度严格跳过停用账号。** 顺次耗尽(sequential)、轮询(round-robin)、主动切号(advanceAccount)、跨家族自动降级(autoFallbackModel)等调度算法在选号时全部严格跳过已停用账号。
|
|
49
|
+
- **修复:号池活动指针降级不再回退到已停用账号。** 修复了 `getActiveAccountId` 在全部账号限流时无条件 fallback 到主账号或首个账号导致停用账号被当作当前在用账号的缺陷;现在严格仅回退到已启用的账号(若全部账号均被停用则返回 `undefined`)。
|
|
50
|
+
- **修复:后台静默身份复验跳过已停用账号。** `needsAuthReverify` 增加了 `account.enabled` 检查,彻底杜绝后台轮询向 Google 请求复验已停用账号。
|
|
51
|
+
- **修复:账号不可用时清晰提示停用状态。** 当全部或部分账号不可用时,错误提示中会明确指出有几个账号处于“已停用”状态,并提示用户在控制台或通过 CLI 重新启用,不再报出误导性的 0 冷却/0 登录错误。
|
|
52
|
+
|
|
3
53
|
## 0.4.50 (2026-10-14)
|
|
4
54
|
|
|
5
55
|
### English
|
package/dist/client.js
CHANGED
|
@@ -35,7 +35,8 @@ window.__ModuleLoader__.load({
|
|
|
35
35
|
alert: "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0zM12 9v4M12 17h.01",
|
|
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
|
-
arrowDown: "M12 5v14M19 12l-7 7-7-7"
|
|
38
|
+
arrowDown: "M12 5v14M19 12l-7 7-7-7",
|
|
39
|
+
power: "M18.36 6.64a9 9 0 1 1-12.73 0M12 2v10"
|
|
39
40
|
};
|
|
40
41
|
//#endregion
|
|
41
42
|
//#region src/client/locales.ts
|
|
@@ -72,7 +73,10 @@ window.__ModuleLoader__.load({
|
|
|
72
73
|
"status.needsAuth": "待认证",
|
|
73
74
|
"status.loading": "正在加载 Antigravity 状态...",
|
|
74
75
|
"status.authRequired": "需重新登录",
|
|
75
|
-
"
|
|
76
|
+
"account.setActive": "设为当前使用",
|
|
77
|
+
"account.settingActive": "切换中",
|
|
78
|
+
"account.activeSet": "已切换当前使用账号",
|
|
79
|
+
"account.activeSetFailed": "该账号当前不可用(冷却或需重新登录)",
|
|
76
80
|
"status.proxy": "代理",
|
|
77
81
|
"status.inUse": "当前使用",
|
|
78
82
|
"account.add": "添加 Google 账号",
|
|
@@ -85,8 +89,6 @@ window.__ModuleLoader__.load({
|
|
|
85
89
|
"aria.proxyInput": "专属代理 URL",
|
|
86
90
|
"aria.authCodeInput": "授权码或回调 URL",
|
|
87
91
|
"aria.closeToast": "关闭提示",
|
|
88
|
-
"account.setPrimary": "设为主用",
|
|
89
|
-
"account.settingPrimary": "设置中",
|
|
90
92
|
"account.details": "明细",
|
|
91
93
|
"account.collapse": "收起",
|
|
92
94
|
"account.expandOthers": "展开查看 Claude & GPT-OSS 模型额度",
|
|
@@ -171,7 +173,14 @@ window.__ModuleLoader__.load({
|
|
|
171
173
|
"account.cardExpand": "展开详情",
|
|
172
174
|
"account.draggingTarget": "放置至此成为优先级 #{num}",
|
|
173
175
|
"account.dragBanner": "正在调整优先级:将【{alias}】移动至 #{num}",
|
|
174
|
-
"account.dragHint": "拖拽卡片可实时调整调度优先级"
|
|
176
|
+
"account.dragHint": "拖拽卡片可实时调整调度优先级",
|
|
177
|
+
"account.enable": "启用",
|
|
178
|
+
"account.disable": "停用",
|
|
179
|
+
"account.enableTitle": "启用此账号(加入自动切号与调度)",
|
|
180
|
+
"account.disableTitle": "停用此账号(切号与调度时跳过)",
|
|
181
|
+
"account.enabledToast": "已启用账号:{alias}",
|
|
182
|
+
"account.disabledToast": "已停用账号:{alias}",
|
|
183
|
+
"status.disabled": "已停用"
|
|
175
184
|
};
|
|
176
185
|
const en = {
|
|
177
186
|
"section.label": "Antigravity",
|
|
@@ -203,7 +212,10 @@ window.__ModuleLoader__.load({
|
|
|
203
212
|
"status.needsAuth": "Authentication required",
|
|
204
213
|
"status.loading": "Loading Antigravity status...",
|
|
205
214
|
"status.authRequired": "Sign in again required",
|
|
206
|
-
"
|
|
215
|
+
"account.setActive": "Set as in use",
|
|
216
|
+
"account.settingActive": "Switching...",
|
|
217
|
+
"account.activeSet": "Active account switched",
|
|
218
|
+
"account.activeSetFailed": "Account not currently eligible (cooldown or auth required)",
|
|
207
219
|
"status.proxy": "Proxy",
|
|
208
220
|
"status.inUse": "In use",
|
|
209
221
|
"account.add": "Add Google account",
|
|
@@ -216,8 +228,6 @@ window.__ModuleLoader__.load({
|
|
|
216
228
|
"aria.proxyInput": "Dedicated proxy URL",
|
|
217
229
|
"aria.authCodeInput": "Authorization code or callback URL",
|
|
218
230
|
"aria.closeToast": "Dismiss notification",
|
|
219
|
-
"account.setPrimary": "Set as primary",
|
|
220
|
-
"account.settingPrimary": "Setting...",
|
|
221
231
|
"account.details": "Details",
|
|
222
232
|
"account.collapse": "Collapse",
|
|
223
233
|
"account.expandOthers": "Expand Claude & GPT-OSS quotas",
|
|
@@ -302,7 +312,14 @@ window.__ModuleLoader__.load({
|
|
|
302
312
|
"account.cardExpand": "Expand details",
|
|
303
313
|
"account.draggingTarget": "Drop here to set priority #{num}",
|
|
304
314
|
"account.dragBanner": "Reordering: moving [{alias}] to priority #{num}",
|
|
305
|
-
"account.dragHint": "Drag cards to reorder scheduling priority in real time"
|
|
315
|
+
"account.dragHint": "Drag cards to reorder scheduling priority in real time",
|
|
316
|
+
"account.enable": "Enable",
|
|
317
|
+
"account.disable": "Disable",
|
|
318
|
+
"account.enableTitle": "Enable this account (include in rotation)",
|
|
319
|
+
"account.disableTitle": "Disable this account (skip in rotation)",
|
|
320
|
+
"account.enabledToast": "Account enabled: {alias}",
|
|
321
|
+
"account.disabledToast": "Account disabled: {alias}",
|
|
322
|
+
"status.disabled": "Disabled"
|
|
306
323
|
};
|
|
307
324
|
const ptBR = {
|
|
308
325
|
"section.label": "Antigravity",
|
|
@@ -334,7 +351,10 @@ window.__ModuleLoader__.load({
|
|
|
334
351
|
"status.needsAuth": "Autenticação necessária",
|
|
335
352
|
"status.loading": "Carregando o status do Antigravity...",
|
|
336
353
|
"status.authRequired": "É necessário entrar novamente",
|
|
337
|
-
"
|
|
354
|
+
"account.setActive": "Definir como em uso",
|
|
355
|
+
"account.settingActive": "Alternando...",
|
|
356
|
+
"account.activeSet": "Conta em uso alterada",
|
|
357
|
+
"account.activeSetFailed": "Conta não elegível no momento (cooldown ou login necessário)",
|
|
338
358
|
"status.proxy": "Proxy",
|
|
339
359
|
"status.inUse": "Em uso",
|
|
340
360
|
"account.add": "Adicionar conta Google",
|
|
@@ -347,8 +367,6 @@ window.__ModuleLoader__.load({
|
|
|
347
367
|
"aria.proxyInput": "URL do proxy exclusivo",
|
|
348
368
|
"aria.authCodeInput": "Código de autorização ou URL de retorno",
|
|
349
369
|
"aria.closeToast": "Fechar notificação",
|
|
350
|
-
"account.setPrimary": "Definir como principal",
|
|
351
|
-
"account.settingPrimary": "Definindo...",
|
|
352
370
|
"account.details": "Detalhes",
|
|
353
371
|
"account.collapse": "Recolher",
|
|
354
372
|
"account.expandOthers": "Expandir cotas Claude e GPT-OSS",
|
|
@@ -433,7 +451,14 @@ window.__ModuleLoader__.load({
|
|
|
433
451
|
"account.cardExpand": "Expandir detalhes",
|
|
434
452
|
"account.draggingTarget": "Soltar aqui para prioridade #{num}",
|
|
435
453
|
"account.dragBanner": "Reordenando: movendo [{alias}] para #{num}",
|
|
436
|
-
"account.dragHint": "Arraste os cartões para reordenar a prioridade em tempo real"
|
|
454
|
+
"account.dragHint": "Arraste os cartões para reordenar a prioridade em tempo real",
|
|
455
|
+
"account.enable": "Ativar",
|
|
456
|
+
"account.disable": "Desativar",
|
|
457
|
+
"account.enableTitle": "Ativar esta conta (incluir na rotação)",
|
|
458
|
+
"account.disableTitle": "Desativar esta conta (ignorar na rotação)",
|
|
459
|
+
"account.enabledToast": "Conta ativada: {alias}",
|
|
460
|
+
"account.disabledToast": "Conta desativada: {alias}",
|
|
461
|
+
"status.disabled": "Desativado"
|
|
437
462
|
};
|
|
438
463
|
const es = {
|
|
439
464
|
"section.label": "Antigravity",
|
|
@@ -465,7 +490,10 @@ window.__ModuleLoader__.load({
|
|
|
465
490
|
"status.needsAuth": "Se requiere autenticación",
|
|
466
491
|
"status.loading": "Cargando el estado de Antigravity...",
|
|
467
492
|
"status.authRequired": "Debe iniciar sesión de nuevo",
|
|
468
|
-
"
|
|
493
|
+
"account.setActive": "Establecer como en uso",
|
|
494
|
+
"account.settingActive": "Cambiando...",
|
|
495
|
+
"account.activeSet": "Cuenta en uso cambiada",
|
|
496
|
+
"account.activeSetFailed": "Cuenta no elegible ahora (enfriamiento o requiere login)",
|
|
469
497
|
"status.proxy": "Proxy",
|
|
470
498
|
"status.inUse": "En uso",
|
|
471
499
|
"account.add": "Añadir cuenta de Google",
|
|
@@ -478,8 +506,6 @@ window.__ModuleLoader__.load({
|
|
|
478
506
|
"aria.proxyInput": "URL de proxy exclusivo",
|
|
479
507
|
"aria.authCodeInput": "Código de autorización o URL de devolución",
|
|
480
508
|
"aria.closeToast": "Cerrar notificación",
|
|
481
|
-
"account.setPrimary": "Establecer como principal",
|
|
482
|
-
"account.settingPrimary": "Configurando...",
|
|
483
509
|
"account.details": "Detalles",
|
|
484
510
|
"account.collapse": "Contraer",
|
|
485
511
|
"account.expandOthers": "Expandir cuotas Claude y GPT-OSS",
|
|
@@ -564,7 +590,14 @@ window.__ModuleLoader__.load({
|
|
|
564
590
|
"account.cardExpand": "Expandir detalles",
|
|
565
591
|
"account.draggingTarget": "Soltar aquí para prioridad #{num}",
|
|
566
592
|
"account.dragBanner": "Reordenando: moviendo [{alias}] a #{num}",
|
|
567
|
-
"account.dragHint": "Arrastre las tarjetas para reordenar la prioridad en tiempo real"
|
|
593
|
+
"account.dragHint": "Arrastre las tarjetas para reordenar la prioridad en tiempo real",
|
|
594
|
+
"account.enable": "Habilitar",
|
|
595
|
+
"account.disable": "Deshabilitar",
|
|
596
|
+
"account.enableTitle": "Habilitar esta cuenta (incluir en rotación)",
|
|
597
|
+
"account.disableTitle": "Deshabilitar esta cuenta (ignorar en rotación)",
|
|
598
|
+
"account.enabledToast": "Cuenta habilitada: {alias}",
|
|
599
|
+
"account.disabledToast": "Cuenta deshabilitada: {alias}",
|
|
600
|
+
"status.disabled": "Deshabilitado"
|
|
568
601
|
};
|
|
569
602
|
//#endregion
|
|
570
603
|
//#region src/client/decisions.ts
|
|
@@ -3174,7 +3207,7 @@ div[data-variant="think"] [class*="thinkBody"] {
|
|
|
3174
3207
|
if (!body) return;
|
|
3175
3208
|
const text = (body.textContent ?? "").trim();
|
|
3176
3209
|
if (text === "") return;
|
|
3177
|
-
if (/^\[agy thinking turn(?: · \d+ thinking tokens)?\]\s*$/.test(text)) return;
|
|
3210
|
+
if (/^\[agy(?: thinking turn)?(?: · \d+ (?:thinking )?tokens)?\]\s*$/.test(text)) return;
|
|
3178
3211
|
const style = typeof getComputedStyle === "function" ? getComputedStyle(body) : null;
|
|
3179
3212
|
if (style && style.display !== "none" && body.clientHeight > 8) {
|
|
3180
3213
|
root.dataset.agyExpanded = "true";
|
|
@@ -3283,9 +3316,7 @@ div[data-variant="think"] [class*="thinkBody"] {
|
|
|
3283
3316
|
if (typeof AbortSignal !== "undefined" && typeof AbortSignal.timeout === "function") init.signal = AbortSignal.timeout(5e3);
|
|
3284
3317
|
const res = await win.fetch?.(base + "/plugins/agy-link/status", init);
|
|
3285
3318
|
if (!res || !res.ok) return null;
|
|
3286
|
-
|
|
3287
|
-
statusCache = payload;
|
|
3288
|
-
return payload;
|
|
3319
|
+
return await res.json();
|
|
3289
3320
|
} catch {
|
|
3290
3321
|
return null;
|
|
3291
3322
|
}
|
|
@@ -3394,20 +3425,35 @@ div[data-variant="think"] [class*="thinkBody"] {
|
|
|
3394
3425
|
}
|
|
3395
3426
|
};
|
|
3396
3427
|
/**
|
|
3397
|
-
*
|
|
3398
|
-
*
|
|
3428
|
+
* Global modal host manager: ensures exactly one mounted session header
|
|
3429
|
+
* hosts the modal dialog portal reactively. If the primary header unmounts,
|
|
3430
|
+
* the next available header is immediately notified and seamlessly takes over.
|
|
3399
3431
|
*/
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3432
|
+
const modalHostManager = {
|
|
3433
|
+
listeners: /* @__PURE__ */ new Map(),
|
|
3434
|
+
activeId: null,
|
|
3435
|
+
register(id, onChange) {
|
|
3436
|
+
modalHostManager.listeners.set(id, onChange);
|
|
3437
|
+
if (modalHostManager.activeId === null) modalHostManager.activeId = id;
|
|
3438
|
+
onChange(modalHostManager.activeId === id);
|
|
3439
|
+
return () => {
|
|
3440
|
+
modalHostManager.listeners.delete(id);
|
|
3441
|
+
if (modalHostManager.activeId === id) {
|
|
3442
|
+
const next = modalHostManager.listeners.keys().next().value ?? null;
|
|
3443
|
+
modalHostManager.activeId = next;
|
|
3444
|
+
if (next) modalHostManager.listeners.get(next)?.(true);
|
|
3445
|
+
}
|
|
3446
|
+
};
|
|
3447
|
+
},
|
|
3448
|
+
claim(id) {
|
|
3449
|
+
if (modalHostManager.activeId !== id) {
|
|
3450
|
+
const prev = modalHostManager.activeId;
|
|
3451
|
+
modalHostManager.activeId = id;
|
|
3452
|
+
if (prev) modalHostManager.listeners.get(prev)?.(false);
|
|
3453
|
+
modalHostManager.listeners.get(id)?.(true);
|
|
3454
|
+
}
|
|
3455
|
+
}
|
|
3456
|
+
};
|
|
3411
3457
|
/**
|
|
3412
3458
|
* Format reset timestamp into readable date/time + relative countdown.
|
|
3413
3459
|
*/
|
|
@@ -3475,10 +3521,9 @@ div[data-variant="think"] [class*="thinkBody"] {
|
|
|
3475
3521
|
anthropic: "claude",
|
|
3476
3522
|
openai: "openai"
|
|
3477
3523
|
};
|
|
3478
|
-
let agyIconSeq = 0;
|
|
3479
3524
|
/** Antigravity mark: gradient orb with an orbit ring (product has no public simple-icon). */
|
|
3480
3525
|
function agyIcon(size = 14) {
|
|
3481
|
-
const gid =
|
|
3526
|
+
const gid = "agy-icon-linear-gradient";
|
|
3482
3527
|
return h("svg", {
|
|
3483
3528
|
viewBox: "0 0 24 24",
|
|
3484
3529
|
width: size,
|
|
@@ -3929,7 +3974,7 @@ body.dark,
|
|
|
3929
3974
|
marginBottom: "8px",
|
|
3930
3975
|
color: "var(--agy-text-primary)",
|
|
3931
3976
|
boxShadow: "var(--agy-shadow-card)",
|
|
3932
|
-
transition: "
|
|
3977
|
+
transition: "border-color 0.18s ease, box-shadow 0.18s ease, opacity 0.18s ease"
|
|
3933
3978
|
},
|
|
3934
3979
|
cardPrimary: {
|
|
3935
3980
|
background: "var(--agy-bg-card)",
|
|
@@ -3939,7 +3984,7 @@ body.dark,
|
|
|
3939
3984
|
marginBottom: "8px",
|
|
3940
3985
|
color: "var(--agy-text-primary)",
|
|
3941
3986
|
boxShadow: "var(--agy-shadow-card)",
|
|
3942
|
-
transition: "
|
|
3987
|
+
transition: "border-color 0.18s ease, box-shadow 0.18s ease, opacity 0.18s ease"
|
|
3943
3988
|
},
|
|
3944
3989
|
quotaBox: {
|
|
3945
3990
|
background: "var(--agy-bg-box)",
|
|
@@ -4085,6 +4130,7 @@ body.dark,
|
|
|
4085
4130
|
}
|
|
4086
4131
|
};
|
|
4087
4132
|
function apply(ctx) {
|
|
4133
|
+
injectGlobalStyles();
|
|
4088
4134
|
const locale = ctx.locale;
|
|
4089
4135
|
ctx.effect(() => {
|
|
4090
4136
|
const disposePtBR = locale.addLanguage({
|
|
@@ -4116,7 +4162,6 @@ body.dark,
|
|
|
4116
4162
|
return locale.bind(NS);
|
|
4117
4163
|
};
|
|
4118
4164
|
const AgySettingsSection = (props) => {
|
|
4119
|
-
injectGlobalStyles();
|
|
4120
4165
|
const t = useAgyTranslation();
|
|
4121
4166
|
const { status, refresh } = useAgyStatus();
|
|
4122
4167
|
const [aliasInput, setAliasInput] = useState("");
|
|
@@ -4262,9 +4307,18 @@ body.dark,
|
|
|
4262
4307
|
if (hiddenPendingRef.current === next) hiddenPendingRef.current = null;
|
|
4263
4308
|
}
|
|
4264
4309
|
};
|
|
4265
|
-
const
|
|
4266
|
-
setLoadingAction(`
|
|
4267
|
-
const res = await postJson("/plugins/agy-link/pool/
|
|
4310
|
+
const setActiveAccount = async (id) => {
|
|
4311
|
+
setLoadingAction(`active:${id}`);
|
|
4312
|
+
const res = await postJson("/plugins/agy-link/pool/set-active", { id });
|
|
4313
|
+
setLoadingAction(null);
|
|
4314
|
+
if (res && res.ok) {
|
|
4315
|
+
await refresh();
|
|
4316
|
+
showToast(t("account.activeSet"), "success");
|
|
4317
|
+
} else showToast(res?.error || t("account.activeSetFailed"), "error");
|
|
4318
|
+
};
|
|
4319
|
+
const removeAccount = async (id, alias) => {
|
|
4320
|
+
setLoadingAction(`remove:${id}`);
|
|
4321
|
+
const res = await postJson("/plugins/agy-link/pool/remove", { id });
|
|
4268
4322
|
if (res === null || res?.ok === false) {
|
|
4269
4323
|
setLoadingAction(null);
|
|
4270
4324
|
actionFailed();
|
|
@@ -4272,11 +4326,15 @@ body.dark,
|
|
|
4272
4326
|
}
|
|
4273
4327
|
await refresh();
|
|
4274
4328
|
setLoadingAction(null);
|
|
4275
|
-
showToast(t("account.
|
|
4329
|
+
showToast(t("account.removed", { alias }), "info");
|
|
4276
4330
|
};
|
|
4277
|
-
const
|
|
4278
|
-
|
|
4279
|
-
|
|
4331
|
+
const toggleAccountEnabled = async (acc) => {
|
|
4332
|
+
const nextState = !acc.enabled;
|
|
4333
|
+
setLoadingAction(`enable:${acc.id}`);
|
|
4334
|
+
const res = await postJson("/plugins/agy-link/pool/enable", {
|
|
4335
|
+
id: acc.id,
|
|
4336
|
+
enabled: nextState
|
|
4337
|
+
});
|
|
4280
4338
|
if (res === null || res?.ok === false) {
|
|
4281
4339
|
setLoadingAction(null);
|
|
4282
4340
|
actionFailed();
|
|
@@ -4284,7 +4342,9 @@ body.dark,
|
|
|
4284
4342
|
}
|
|
4285
4343
|
await refresh();
|
|
4286
4344
|
setLoadingAction(null);
|
|
4287
|
-
|
|
4345
|
+
const legacyDefault = acc.defaultAlias === void 0 && acc.systemHome && acc.alias === "主账号 (系统登录)";
|
|
4346
|
+
const displayAlias = acc.defaultAlias || legacyDefault ? acc.systemHome ? t("account.defaultAlias") : acc.alias : acc.alias;
|
|
4347
|
+
showToast(t(nextState ? "account.enabledToast" : "account.disabledToast", { alias: displayAlias }), "success");
|
|
4288
4348
|
};
|
|
4289
4349
|
const refreshQuota = async (id) => {
|
|
4290
4350
|
setLoadingAction(id ? `refresh:${id}` : "refresh:all");
|
|
@@ -4509,7 +4569,8 @@ body.dark,
|
|
|
4509
4569
|
...S.card,
|
|
4510
4570
|
cursor: "default",
|
|
4511
4571
|
padding: "10px 14px",
|
|
4512
|
-
marginBottom: "8px"
|
|
4572
|
+
marginBottom: "8px",
|
|
4573
|
+
...!acc.enabled ? { opacity: .72 } : {}
|
|
4513
4574
|
};
|
|
4514
4575
|
const legacyDefault = acc.defaultAlias === void 0 && acc.systemHome && acc.alias === "主账号 (系统登录)";
|
|
4515
4576
|
const displayAlias = acc.defaultAlias || legacyDefault ? acc.systemHome ? t("account.defaultAlias") : t("account.aliasDefault", { number: accIndex + 1 }) : acc.alias;
|
|
@@ -4640,12 +4701,7 @@ body.dark,
|
|
|
4640
4701
|
whiteSpace: "nowrap"
|
|
4641
4702
|
},
|
|
4642
4703
|
title: acc.email
|
|
4643
|
-
}, uiIcon("mail", 10, "var(--agy-badge-email-text)"), acc.email) : null,
|
|
4644
|
-
...S.badgePrimary,
|
|
4645
|
-
gap: "3px",
|
|
4646
|
-
fontSize: "10.5px",
|
|
4647
|
-
padding: "1px 5px"
|
|
4648
|
-
} }, uiIcon("star", 10, "var(--agy-badge-primary-text)"), t("status.primary")) : null, isInUse ? h("span", {
|
|
4704
|
+
}, uiIcon("mail", 10, "var(--agy-badge-email-text)"), acc.email) : null, isInUse ? h("span", {
|
|
4649
4705
|
style: {
|
|
4650
4706
|
...S.badgeTag,
|
|
4651
4707
|
background: "rgba(16, 185, 129, 0.12)",
|
|
@@ -4665,7 +4721,19 @@ body.dark,
|
|
|
4665
4721
|
gap: "4px",
|
|
4666
4722
|
fontSize: "10px",
|
|
4667
4723
|
padding: "1px 5px"
|
|
4668
|
-
} }, uiIcon("globe", 10, "var(--agy-badge-proxy-text)"), t("status.proxy")) : null
|
|
4724
|
+
} }, uiIcon("globe", 10, "var(--agy-badge-proxy-text)"), t("status.proxy")) : null, !acc.enabled ? h("span", {
|
|
4725
|
+
style: {
|
|
4726
|
+
...S.badgeTag,
|
|
4727
|
+
background: "var(--agy-bg-subbox)",
|
|
4728
|
+
color: "var(--agy-text-secondary)",
|
|
4729
|
+
borderColor: "var(--agy-border-subbox)",
|
|
4730
|
+
gap: "3px",
|
|
4731
|
+
fontSize: "10px",
|
|
4732
|
+
padding: "1px 5px",
|
|
4733
|
+
fontWeight: 700
|
|
4734
|
+
},
|
|
4735
|
+
title: t("status.disabled")
|
|
4736
|
+
}, uiIcon("power", 10, "#64748b"), t("status.disabled")) : null), h("div", { style: {
|
|
4669
4737
|
display: "flex",
|
|
4670
4738
|
gap: "4px",
|
|
4671
4739
|
alignItems: "center",
|
|
@@ -4673,19 +4741,21 @@ body.dark,
|
|
|
4673
4741
|
} }, h("button", {
|
|
4674
4742
|
type: "button",
|
|
4675
4743
|
className: "agy-btn",
|
|
4676
|
-
style:
|
|
4677
|
-
...S.
|
|
4744
|
+
style: acc.enabled ? {
|
|
4745
|
+
...S.btnSm,
|
|
4678
4746
|
gap: "3px",
|
|
4679
4747
|
fontSize: "11px",
|
|
4680
4748
|
padding: "2px 6px"
|
|
4681
4749
|
} : {
|
|
4682
|
-
...S.
|
|
4750
|
+
...S.btnSmPrimary,
|
|
4683
4751
|
gap: "3px",
|
|
4684
4752
|
fontSize: "11px",
|
|
4685
4753
|
padding: "2px 6px"
|
|
4686
4754
|
},
|
|
4687
|
-
|
|
4688
|
-
|
|
4755
|
+
title: acc.enabled ? t("account.disableTitle") : t("account.enableTitle"),
|
|
4756
|
+
disabled: isBusy,
|
|
4757
|
+
onClick: () => void toggleAccountEnabled(acc)
|
|
4758
|
+
}, loadingAction === `enable:${acc.id}` ? [renderSpinner(), acc.enabled ? t("account.disable") : t("account.enable")] : [uiIcon("power", 10, acc.enabled ? "var(--agy-text-secondary)" : "#ffffff"), ` ${acc.enabled ? t("account.disable") : t("account.enable")}`]), h("button", {
|
|
4689
4759
|
type: "button",
|
|
4690
4760
|
className: "agy-btn",
|
|
4691
4761
|
style: {
|
|
@@ -4697,7 +4767,7 @@ body.dark,
|
|
|
4697
4767
|
title: t("account.syncTitle"),
|
|
4698
4768
|
disabled: isBusy,
|
|
4699
4769
|
onClick: () => void refreshQuota(acc.id)
|
|
4700
|
-
}, loadingAction === `refresh:${acc.id}` ? [renderSpinner(), t("account.syncing")] : [uiIcon("refresh", 10), ` ${t("account.sync")}`]), !
|
|
4770
|
+
}, loadingAction === `refresh:${acc.id}` ? [renderSpinner(), t("account.syncing")] : [uiIcon("refresh", 10), ` ${t("account.sync")}`]), acc.enabled && !isInUse ? h("button", {
|
|
4701
4771
|
type: "button",
|
|
4702
4772
|
className: "agy-btn",
|
|
4703
4773
|
style: {
|
|
@@ -4706,9 +4776,10 @@ body.dark,
|
|
|
4706
4776
|
fontSize: "11px",
|
|
4707
4777
|
padding: "2px 6px"
|
|
4708
4778
|
},
|
|
4779
|
+
title: t("account.setActive"),
|
|
4709
4780
|
disabled: isBusy,
|
|
4710
|
-
onClick: () => void
|
|
4711
|
-
}, loadingAction === `
|
|
4781
|
+
onClick: () => void setActiveAccount(acc.id)
|
|
4782
|
+
}, loadingAction === `active:${acc.id}` ? [renderSpinner(), t("account.settingActive")] : [uiIcon("zap", 10), ` ${t("account.setActive")}`]) : null, h("button", {
|
|
4712
4783
|
type: "button",
|
|
4713
4784
|
className: "agy-btn",
|
|
4714
4785
|
style: isEditingProxy ? {
|
|
@@ -5123,25 +5194,8 @@ body.dark,
|
|
|
5123
5194
|
};
|
|
5124
5195
|
/** Modal dialog container rendered into document.body */
|
|
5125
5196
|
const AgyModalDialog = () => {
|
|
5126
|
-
const instanceIdRef = useRef(null);
|
|
5127
|
-
if (instanceIdRef.current === null) instanceIdRef.current = "modal_" + Math.random().toString(36).slice(2);
|
|
5128
|
-
const isPrimary = registerModalInstance(instanceIdRef.current);
|
|
5129
|
-
useEffect(() => {
|
|
5130
|
-
const id = instanceIdRef.current;
|
|
5131
|
-
return () => {
|
|
5132
|
-
unregisterModalInstance(id);
|
|
5133
|
-
};
|
|
5134
|
-
}, []);
|
|
5135
5197
|
const t = useAgyTranslation();
|
|
5136
|
-
const [isOpen, setIsOpen] = useState(agyModalStore.open);
|
|
5137
5198
|
useEffect(() => {
|
|
5138
|
-
injectGlobalStyles();
|
|
5139
|
-
return agyModalStore.subscribe(() => {
|
|
5140
|
-
setIsOpen(agyModalStore.open);
|
|
5141
|
-
});
|
|
5142
|
-
}, []);
|
|
5143
|
-
useEffect(() => {
|
|
5144
|
-
if (!isOpen) return;
|
|
5145
5199
|
const onKey = (e) => {
|
|
5146
5200
|
if (e.key === "Escape") {
|
|
5147
5201
|
e.stopPropagation();
|
|
@@ -5150,8 +5204,7 @@ body.dark,
|
|
|
5150
5204
|
};
|
|
5151
5205
|
win.addEventListener?.("keydown", onKey, true);
|
|
5152
5206
|
return () => win.removeEventListener?.("keydown", onKey, true);
|
|
5153
|
-
}, [
|
|
5154
|
-
if (!isOpen || !isPrimary) return null;
|
|
5207
|
+
}, []);
|
|
5155
5208
|
return h("div", {
|
|
5156
5209
|
className: "agy-modal-backdrop",
|
|
5157
5210
|
onClick: (e) => {
|
|
@@ -5208,6 +5261,19 @@ body.dark,
|
|
|
5208
5261
|
};
|
|
5209
5262
|
/** Session Header badge in chat toolbar */
|
|
5210
5263
|
const AgySessionStatus = () => {
|
|
5264
|
+
const hostIdRef = useRef(null);
|
|
5265
|
+
if (hostIdRef.current === null) hostIdRef.current = "host_" + Math.random().toString(36).slice(2);
|
|
5266
|
+
const hostId = hostIdRef.current;
|
|
5267
|
+
const [isPrimaryHost, setIsPrimaryHost] = useState(false);
|
|
5268
|
+
useEffect(() => {
|
|
5269
|
+
return modalHostManager.register(hostId, setIsPrimaryHost);
|
|
5270
|
+
}, [hostId]);
|
|
5271
|
+
const [isModalOpen, setIsModalOpen] = useState(agyModalStore.open);
|
|
5272
|
+
useEffect(() => {
|
|
5273
|
+
return agyModalStore.subscribe(() => {
|
|
5274
|
+
setIsModalOpen(agyModalStore.open);
|
|
5275
|
+
});
|
|
5276
|
+
}, []);
|
|
5211
5277
|
const t = useAgyTranslation();
|
|
5212
5278
|
const { status } = useAgyStatus();
|
|
5213
5279
|
const [, setTimeTick] = useState(0);
|
|
@@ -5234,7 +5300,10 @@ body.dark,
|
|
|
5234
5300
|
type: "button",
|
|
5235
5301
|
title: badgeTitle,
|
|
5236
5302
|
className: "agy-btn",
|
|
5237
|
-
onClick: () =>
|
|
5303
|
+
onClick: () => {
|
|
5304
|
+
modalHostManager.claim(hostId);
|
|
5305
|
+
agyModalStore.setOpen(true);
|
|
5306
|
+
},
|
|
5238
5307
|
style: {
|
|
5239
5308
|
background: "var(--agy-bg-header)",
|
|
5240
5309
|
border: "1px solid var(--agy-border-card)",
|
|
@@ -5257,7 +5326,7 @@ body.dark,
|
|
|
5257
5326
|
borderRadius: "50%",
|
|
5258
5327
|
background: color
|
|
5259
5328
|
} }), buttonLabel);
|
|
5260
|
-
return h("div", { style: { display: "inline-block" } }, badge, portalToBody(h(AgyModalDialog, null)));
|
|
5329
|
+
return h("div", { style: { display: "inline-block" } }, badge, isPrimaryHost && isModalOpen ? portalToBody(h(AgyModalDialog, null)) : null);
|
|
5261
5330
|
};
|
|
5262
5331
|
ctx.slots.inject("conversation.session.header.actions", () => {
|
|
5263
5332
|
return ctx.slots.register({
|