dsh-agy-link 0.4.46 → 0.4.49

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
@@ -8,12 +8,16 @@ window.__ModuleLoader__.load({
8
8
  const BRAND_PATHS = {
9
9
  gemini: "M11.04 19.32Q12 21.51 12 24q0-2.49.93-4.68.96-2.19 2.58-3.81t3.81-2.55Q21.51 12 24 12q-2.49 0-4.68-.93a12.3 12.3 0 0 1-3.81-2.58 12.3 12.3 0 0 1-2.58-3.81Q12 2.49 12 0q0 2.49-.96 4.68-.93 2.19-2.55 3.81a12.3 12.3 0 0 1-3.81 2.58Q2.49 12 0 12q2.49 0 4.68.96 2.19.93 3.81 2.55t2.55 3.81",
10
10
  claude: "m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z",
11
- openai: "M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z"
11
+ openai: "M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z",
12
+ chrome: "M12 0C8.21 0 4.831 1.757 2.632 4.501l3.953 6.848A5.454 5.454 0 0 1 12 6.545h10.73c-.911-3.794-4.321-6.545-8.384-6.545zM1.986 6.368A11.95 11.95 0 0 0 0 12c0 6.096 4.542 11.134 10.428 11.89l3.953-6.848a5.454 5.454 0 0 1-5.836-2.585L1.986 6.368zm14.569 5.632a5.454 5.454 0 0 1-1.127 3.327l-5.365 9.293C10.784 24.873 11.385 25 12 25c6.627 0 12-5.373 12-12 0-.341-.014-.679-.042-1.013H12v.013h4.555z",
13
+ edge: "M23.95 13.91c-.13-1.68-.78-3.23-1.83-4.47-.98-1.16-2.29-1.99-3.76-2.4-.64-.18-1.3-.28-1.97-.29-2.09-.03-4.08.74-5.63 2.16-1.57 1.44-2.48 3.44-2.55 5.56.08 1.47.66 2.87 1.66 3.96.99 1.09 2.37 1.76 3.86 1.88 1.34.1 2.69-.26 3.82-1.02.44-.3.84-.66 1.18-1.07l2.87 2.87c-1.35 1.44-3.04 2.51-4.92 3.12-1.89.6-3.9.7-5.84.28-2.67-.58-5.06-2.06-6.75-4.17-1.68-2.12-2.59-4.78-2.57-7.51.02-2.85 1.04-5.6 2.89-7.77C6.88 4.31 9.53 2.85 12.44 2.38c2.19-.35 4.43-.2 6.55.45 2.13.65 4.04 1.83 5.58 3.44l-2.9 2.9c-1.12-1.19-2.52-2.06-4.07-2.54-1.55-.47-3.19-.57-4.78-.3-2.14.36-4.08 1.45-5.46 3.06-1.38 1.62-2.13 3.69-2.13 5.84 0 2.05.69 4.04 1.98 5.62 1.28 1.58 3.1 2.64 5.12 3.01 1.47.27 2.99.17 4.42-.31 1.43-.48 2.7-1.33 3.69-2.46l-4.13-4.13c-.37.28-.8.48-1.26.58-.46.1-.94.09-1.4-.02-.57-.14-1.08-.47-1.46-.93-.38-.46-.59-1.04-.59-1.64.03-.84.4-1.63 1.03-2.2.63-.57 1.45-.88 2.3-.87.87.01 1.7.35 2.32.95.62.61.98 1.43 1 2.3h4.67z"
12
14
  };
13
15
  const BRAND_COLORS = {
14
16
  gemini: "#8E75B2",
15
17
  claude: "#D97757",
16
- openai: "#10a37f"
18
+ openai: "#10a37f",
19
+ chrome: "#4285F4",
20
+ edge: "#0078D7"
17
21
  };
18
22
  const UI_PATHS = {
19
23
  trash: "M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M10 11v6M14 11v6",
@@ -28,7 +32,10 @@ window.__ModuleLoader__.load({
28
32
  check: "M20 6L9 17l-5-5",
29
33
  x: "M18 6L6 18M6 6l12 12",
30
34
  externalLink: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6M15 3h6v6M10 14L21 3",
31
- 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"
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
+ move: "M9 5h.01M9 12h.01M9 19h.01M15 5h.01M15 12h.01M15 19h.01",
37
+ arrowUp: "M12 19V5M5 12l7-7 7 7",
38
+ arrowDown: "M12 5v14M19 12l-7 7-7-7"
32
39
  };
33
40
  //#endregion
34
41
  //#region src/client/locales.ts
@@ -71,6 +78,7 @@ window.__ModuleLoader__.load({
71
78
  "account.add": "添加 Google 账号",
72
79
  "account.aliasDefault": "备用 Google 账号 {number}",
73
80
  "account.defaultAlias": "主账号(系统登录)",
81
+ "account.proxyPlaceholder": "专属代理 URL(如 http://127.0.0.1:7890,留空则继承全局)",
74
82
  "account.aliasPlaceholder": "账号别名(例如:备用账号 2)",
75
83
  "account.removeTitle": "移除此账号",
76
84
  "aria.aliasInput": "账号别名",
@@ -81,6 +89,9 @@ window.__ModuleLoader__.load({
81
89
  "account.settingPrimary": "设置中",
82
90
  "account.details": "明细",
83
91
  "account.collapse": "收起",
92
+ "account.expandOthers": "展开查看 Claude & GPT-OSS 模型额度",
93
+ "account.collapseOthers": "收起 Claude & GPT-OSS 模型额度",
94
+ "account.otherModels": "Claude / GPT 额度",
84
95
  "account.sync": "同步",
85
96
  "account.syncing": "同步中",
86
97
  "account.syncTitle": "刷新此账号(换号后立即同步 email / 额度 / 模型)",
@@ -93,7 +104,6 @@ window.__ModuleLoader__.load({
93
104
  "quota.weekly": "周额度",
94
105
  "quota.refreshed": "额度已刷新",
95
106
  "proxy.button": "代理",
96
- "pool.winIsolationWarn": "Windows 提示:agy 的登录凭据存在系统级 Credential Manager(单槽位),多账号池无法隔离凭据——轮巡只切换工作目录,实际仍消耗系统登录账号(issue #45)。",
97
107
  "proxy.placeholder": "专属代理 URL(如:http://127.0.0.1:7890;留空则使用全局)",
98
108
  "proxy.save": "保存",
99
109
  "proxy.saved": "代理已保存",
@@ -147,7 +157,21 @@ window.__ModuleLoader__.load({
147
157
  "header.refreshQuota": "刷新额度",
148
158
  "header.refreshing": "刷新中",
149
159
  "console.close": "关闭(Esc)",
150
- "header.badgeTitle": "Antigravity:{count} 个账号已就绪 · 点击打开控制台"
160
+ "header.badgeTitle": "Antigravity:{count} 个账号已就绪 · 点击打开控制台",
161
+ "header.badgeLoading": "Antigravity · 点击打开控制台",
162
+ "account.type.agy": "Google Antigravity (CLI / OAuth)",
163
+ "account.loginType": "登录方式:",
164
+ "account.dragHandle": "拖拽调整优先级",
165
+ "account.moveUp": "上移优先级",
166
+ "account.moveDown": "下移优先级",
167
+ "account.reordered": "账号优先级顺序已更新",
168
+ "account.collapseAll": "全部折叠",
169
+ "account.expandAll": "全部展开",
170
+ "account.cardCollapse": "收起详情",
171
+ "account.cardExpand": "展开详情",
172
+ "account.draggingTarget": "放置至此成为优先级 #{num}",
173
+ "account.dragBanner": "正在调整优先级:将【{alias}】移动至 #{num}",
174
+ "account.dragHint": "拖拽卡片可实时调整调度优先级"
151
175
  };
152
176
  const en = {
153
177
  "section.label": "Antigravity",
@@ -185,6 +209,7 @@ window.__ModuleLoader__.load({
185
209
  "account.add": "Add Google account",
186
210
  "account.aliasDefault": "Backup Google account {number}",
187
211
  "account.defaultAlias": "Primary account (system sign-in)",
212
+ "account.proxyPlaceholder": "Dedicated proxy URL (e.g. http://127.0.0.1:7890; leave blank to inherit global)",
188
213
  "account.aliasPlaceholder": "Account alias (for example: Backup account 2)",
189
214
  "account.removeTitle": "Remove this account",
190
215
  "aria.aliasInput": "Account alias",
@@ -195,6 +220,9 @@ window.__ModuleLoader__.load({
195
220
  "account.settingPrimary": "Setting...",
196
221
  "account.details": "Details",
197
222
  "account.collapse": "Collapse",
223
+ "account.expandOthers": "Expand Claude & GPT-OSS quotas",
224
+ "account.collapseOthers": "Collapse Claude & GPT-OSS quotas",
225
+ "account.otherModels": "Claude / GPT quotas",
198
226
  "account.sync": "Sync",
199
227
  "account.syncing": "Syncing...",
200
228
  "account.syncTitle": "Refresh this account (sync email, quota, and models after switching accounts)",
@@ -207,7 +235,6 @@ window.__ModuleLoader__.load({
207
235
  "quota.weekly": "Weekly quota",
208
236
  "quota.refreshed": "Quota refreshed",
209
237
  "proxy.button": "Proxy",
210
- "pool.winIsolationWarn": "Windows: agy keeps its login in the system-wide Credential Manager (single slot), so the account pool cannot isolate credentials — rotation switches workspaces only, and generation still bills the system login (issue #45).",
211
238
  "proxy.placeholder": "Dedicated proxy URL (for example: http://127.0.0.1:7890; leave blank to use the global proxy)",
212
239
  "proxy.save": "Save",
213
240
  "proxy.saved": "Proxy saved",
@@ -261,7 +288,21 @@ window.__ModuleLoader__.load({
261
288
  "header.refreshQuota": "Refresh quota",
262
289
  "header.refreshing": "Refreshing...",
263
290
  "console.close": "Close (Esc)",
264
- "header.badgeTitle": "Antigravity: {count} accounts ready · click to open the console"
291
+ "header.badgeTitle": "Antigravity: {count} accounts ready · click to open the console",
292
+ "header.badgeLoading": "Antigravity · click to open the console",
293
+ "account.type.agy": "Google Antigravity (CLI / OAuth)",
294
+ "account.loginType": "Login Method:",
295
+ "account.dragHandle": "Drag to reorder priority",
296
+ "account.moveUp": "Move up priority",
297
+ "account.moveDown": "Move down priority",
298
+ "account.reordered": "Account priorities reordered successfully",
299
+ "account.collapseAll": "Collapse all",
300
+ "account.expandAll": "Expand all",
301
+ "account.cardCollapse": "Collapse",
302
+ "account.cardExpand": "Expand details",
303
+ "account.draggingTarget": "Drop here to set priority #{num}",
304
+ "account.dragBanner": "Reordering: moving [{alias}] to priority #{num}",
305
+ "account.dragHint": "Drag cards to reorder scheduling priority in real time"
265
306
  };
266
307
  const ptBR = {
267
308
  "section.label": "Antigravity",
@@ -299,6 +340,7 @@ window.__ModuleLoader__.load({
299
340
  "account.add": "Adicionar conta Google",
300
341
  "account.aliasDefault": "Conta Google reserva {number}",
301
342
  "account.defaultAlias": "Conta principal (login do sistema)",
343
+ "account.proxyPlaceholder": "URL de proxy dedicada (ex.: http://127.0.0.1:7890; deixe vazio para herdar a global)",
302
344
  "account.aliasPlaceholder": "Apelido da conta (por exemplo: Conta reserva 2)",
303
345
  "account.removeTitle": "Remover esta conta",
304
346
  "aria.aliasInput": "Apelido da conta",
@@ -309,6 +351,9 @@ window.__ModuleLoader__.load({
309
351
  "account.settingPrimary": "Definindo...",
310
352
  "account.details": "Detalhes",
311
353
  "account.collapse": "Recolher",
354
+ "account.expandOthers": "Expandir cotas Claude e GPT-OSS",
355
+ "account.collapseOthers": "Recolher cotas Claude e GPT-OSS",
356
+ "account.otherModels": "Cotas Claude / GPT",
312
357
  "account.sync": "Sincronizar",
313
358
  "account.syncing": "Sincronizando...",
314
359
  "account.syncTitle": "Atualizar esta conta (sincroniza e-mail, cota e modelos depois de trocar de conta)",
@@ -321,7 +366,6 @@ window.__ModuleLoader__.load({
321
366
  "quota.weekly": "Cota semanal",
322
367
  "quota.refreshed": "Cota atualizada",
323
368
  "proxy.button": "Proxy",
324
- "pool.winIsolationWarn": "Windows: o agy guarda o login no Credential Manager do sistema (um único slot), então o pool de contas não isola credenciais — a rotação troca apenas os diretórios e o consumo continua na conta do sistema (issue #45).",
325
369
  "proxy.placeholder": "URL do proxy exclusivo (por exemplo: http://127.0.0.1:7890; deixe vazio para usar o proxy global)",
326
370
  "proxy.save": "Salvar",
327
371
  "proxy.saved": "Proxy salvo",
@@ -375,7 +419,21 @@ window.__ModuleLoader__.load({
375
419
  "header.refreshQuota": "Atualizar cota",
376
420
  "header.refreshing": "Atualizando...",
377
421
  "console.close": "Fechar (Esc)",
378
- "header.badgeTitle": "Antigravity: {count} contas prontas · clique para abrir o console"
422
+ "header.badgeTitle": "Antigravity: {count} contas prontas · clique para abrir o console",
423
+ "header.badgeLoading": "Antigravity · clique para abrir o console",
424
+ "account.type.agy": "Google Antigravity (CLI / OAuth)",
425
+ "account.loginType": "Tipo de login:",
426
+ "account.dragHandle": "Arrastar para reordenar prioridade",
427
+ "account.moveUp": "Subir prioridade",
428
+ "account.moveDown": "Descer prioridade",
429
+ "account.reordered": "Prioridade das contas reordenada com sucesso",
430
+ "account.collapseAll": "Recolher todos",
431
+ "account.expandAll": "Expandir todos",
432
+ "account.cardCollapse": "Recolher",
433
+ "account.cardExpand": "Expandir detalhes",
434
+ "account.draggingTarget": "Soltar aqui para prioridade #{num}",
435
+ "account.dragBanner": "Reordenando: movendo [{alias}] para #{num}",
436
+ "account.dragHint": "Arraste os cartões para reordenar a prioridade em tempo real"
379
437
  };
380
438
  const es = {
381
439
  "section.label": "Antigravity",
@@ -413,6 +471,7 @@ window.__ModuleLoader__.load({
413
471
  "account.add": "Añadir cuenta de Google",
414
472
  "account.aliasDefault": "Cuenta de Google de respaldo {number}",
415
473
  "account.defaultAlias": "Cuenta principal (inicio de sesión del sistema)",
474
+ "account.proxyPlaceholder": "URL de proxy dedicada (p. ej., http://127.0.0.1:7890; déjalo vacío para heredar la global)",
416
475
  "account.aliasPlaceholder": "Alias de la cuenta (por ejemplo: Cuenta de respaldo 2)",
417
476
  "account.removeTitle": "Eliminar esta cuenta",
418
477
  "aria.aliasInput": "Alias de la cuenta",
@@ -423,6 +482,9 @@ window.__ModuleLoader__.load({
423
482
  "account.settingPrimary": "Configurando...",
424
483
  "account.details": "Detalles",
425
484
  "account.collapse": "Contraer",
485
+ "account.expandOthers": "Expandir cuotas Claude y GPT-OSS",
486
+ "account.collapseOthers": "Contraer cuotas Claude y GPT-OSS",
487
+ "account.otherModels": "Cuotas Claude / GPT",
426
488
  "account.sync": "Sincronizar",
427
489
  "account.syncing": "Sincronizando...",
428
490
  "account.syncTitle": "Actualizar esta cuenta (sincroniza correo, cuota y modelos tras cambiar de cuenta)",
@@ -435,7 +497,6 @@ window.__ModuleLoader__.load({
435
497
  "quota.weekly": "Cuota semanal",
436
498
  "quota.refreshed": "Cuota actualizada",
437
499
  "proxy.button": "Proxy",
438
- "pool.winIsolationWarn": "Windows: agy guarda el inicio de sesión en el Credential Manager del sistema (un único espacio), por lo que el pool de cuentas no puede aislar credenciales — la rotación solo cambia de directorio y el consumo sigue en la cuenta del sistema (issue #45).",
439
500
  "proxy.placeholder": "URL de proxy exclusivo (por ejemplo: http://127.0.0.1:7890; déjelo vacío para usar el proxy global)",
440
501
  "proxy.save": "Guardar",
441
502
  "proxy.saved": "Proxy guardado",
@@ -489,9 +550,729 @@ window.__ModuleLoader__.load({
489
550
  "header.refreshQuota": "Actualizar cuota",
490
551
  "header.refreshing": "Actualizando...",
491
552
  "console.close": "Cerrar (Esc)",
492
- "header.badgeTitle": "Antigravity: {count} cuentas listas · haga clic para abrir la consola"
553
+ "header.badgeTitle": "Antigravity: {count} cuentas listas · haga clic para abrir la consola",
554
+ "header.badgeLoading": "Antigravity · haga clic para abrir la consola",
555
+ "account.type.agy": "Google Antigravity (CLI / OAuth)",
556
+ "account.loginType": "Tipo de inicio de sesión:",
557
+ "account.dragHandle": "Arrastrar para reordenar prioridad",
558
+ "account.moveUp": "Subir prioridad",
559
+ "account.moveDown": "Bajar prioridad",
560
+ "account.reordered": "Prioridad de cuentas reordenada con éxito",
561
+ "account.collapseAll": "Contraer todo",
562
+ "account.expandAll": "Expandir todo",
563
+ "account.cardCollapse": "Contraer",
564
+ "account.cardExpand": "Expandir detalles",
565
+ "account.draggingTarget": "Soltar aquí para prioridad #{num}",
566
+ "account.dragBanner": "Reordenando: moviendo [{alias}] a #{num}",
567
+ "account.dragHint": "Arrastre las tarjetas para reordenar la prioridad en tiempo real"
493
568
  };
494
569
  //#endregion
570
+ //#region src/client/decisions.ts
571
+ const DECISION_CSS = `
572
+ .agy-decision-container {
573
+ margin: 10px 0 6px 0;
574
+ padding: 10px 12px;
575
+ border-radius: 8px;
576
+ background: var(--dsw-alias-bg-l2, rgba(127, 127, 127, 0.07));
577
+ border: 1px dashed var(--dsw-alias-border-l3, rgba(127, 127, 127, 0.3));
578
+ }
579
+
580
+ .agy-decision-header {
581
+ font-size: 12px;
582
+ font-weight: 600;
583
+ color: var(--dsw-alias-label-secondary, #aaa);
584
+ margin-bottom: 8px;
585
+ display: flex;
586
+ align-items: center;
587
+ gap: 6px;
588
+ }
589
+
590
+ .agy-decision-chips {
591
+ display: flex;
592
+ flex-wrap: wrap;
593
+ gap: 8px;
594
+ }
595
+
596
+ .agy-decision-chip {
597
+ background: var(--dsw-alias-bg-l1, rgba(255, 255, 255, 0.05));
598
+ border: 1px solid var(--dsw-alias-border-l2, rgba(127, 127, 127, 0.25));
599
+ color: var(--dsw-alias-label-primary, #eee);
600
+ padding: 5px 12px;
601
+ border-radius: 999px;
602
+ cursor: pointer;
603
+ font-size: 12px;
604
+ font-weight: 500;
605
+ display: inline-flex;
606
+ align-items: center;
607
+ gap: 6px;
608
+ transition: all 0.15s ease;
609
+ user-select: none;
610
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
611
+ text-align: left;
612
+ max-width: 100%;
613
+ }
614
+
615
+ .agy-decision-chip:hover {
616
+ background: var(--dsw-alias-bg-hover, rgba(127, 127, 127, 0.18));
617
+ border-color: var(--dsw-alias-border-l4, rgba(127, 127, 127, 0.5));
618
+ transform: translateY(-1px);
619
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.18);
620
+ }
621
+
622
+ .agy-decision-chip:active {
623
+ transform: translateY(0);
624
+ }
625
+
626
+ .agy-decision-chip.selected {
627
+ background: rgba(16, 185, 129, 0.15);
628
+ border-color: #10b981;
629
+ color: #10b981;
630
+ }
631
+
632
+ .agy-decision-chip-num {
633
+ font-weight: 700;
634
+ opacity: 0.8;
635
+ }
636
+
637
+ .agy-decision-chip-text {
638
+ overflow: hidden;
639
+ text-overflow: ellipsis;
640
+ white-space: nowrap;
641
+ }
642
+ `;
643
+ function injectStyles$3() {
644
+ if (typeof document === "undefined") return;
645
+ const styleId = "dsh-agy-link-decisions-css";
646
+ if (document.getElementById(styleId) === null) {
647
+ const st = document.createElement("style");
648
+ st.id = styleId;
649
+ st.textContent = DECISION_CSS;
650
+ const host = document.head ?? document.documentElement;
651
+ if (host) host.appendChild(st);
652
+ }
653
+ }
654
+ /**
655
+ * Insert text directly into DSH's chat composer
656
+ */
657
+ function insertTextIntoChatComposer(text) {
658
+ if (typeof document === "undefined" || !text) return false;
659
+ const inputEl = document.querySelector("[data-composer-input]") ?? document.querySelector("[role=\"textbox\"][contenteditable=\"true\"]") ?? document.querySelector("textarea");
660
+ if (!inputEl) return false;
661
+ inputEl.focus();
662
+ if (inputEl instanceof HTMLTextAreaElement || inputEl instanceof HTMLInputElement) {
663
+ const start = inputEl.selectionStart ?? inputEl.value.length;
664
+ const end = inputEl.selectionEnd ?? inputEl.value.length;
665
+ inputEl.setRangeText(text, start, end, "end");
666
+ inputEl.dispatchEvent(new Event("input", { bubbles: true }));
667
+ inputEl.dispatchEvent(new Event("change", { bubbles: true }));
668
+ return true;
669
+ }
670
+ try {
671
+ if (document.execCommand("insertText", false, text)) return true;
672
+ } catch {}
673
+ const existing = inputEl.textContent?.trim() ?? "";
674
+ inputEl.textContent = existing ? `${existing} ${text}` : text;
675
+ inputEl.dispatchEvent(new InputEvent("input", {
676
+ bubbles: true,
677
+ inputType: "insertText",
678
+ data: text
679
+ }));
680
+ return true;
681
+ }
682
+ /** Check if text header suggests an actionable decision or choice prompt */
683
+ const DECISION_HEADER_REGEX = /(?:请(?:您)?(?:拍板|指示|决定|选择|决策)|decision|next\s+step|choose|拍板|选择方案)/i;
684
+ /** Extract numbered options or choice items from a decision list */
685
+ function extractOptionsFromList(container) {
686
+ const options = [];
687
+ const listItems = container.querySelectorAll("li");
688
+ if (listItems.length > 0) for (let i = 0; i < listItems.length; i++) {
689
+ const li = listItems[i];
690
+ if (!li) continue;
691
+ const text = (li.textContent ?? "").trim();
692
+ if (!text) continue;
693
+ const m = text.match(/^([0-9]+[、..:]\s*)?(.*?)(?:[::—\-·]|\n|$)/);
694
+ const num = m?.[1]?.trim() ?? `${i + 1}.`;
695
+ let title = m?.[2]?.trim() || text.slice(0, 50);
696
+ if (title.length > 40) title = title.slice(0, 40) + "…";
697
+ options.push({
698
+ num,
699
+ title,
700
+ fullText: text
701
+ });
702
+ }
703
+ return options;
704
+ }
705
+ /**
706
+ * Scan DOM for decision prompts and mount interactive choice chips
707
+ */
708
+ function scanAndEnhanceDecisions() {
709
+ if (typeof document === "undefined") return;
710
+ const markdownContainers = document.querySelectorAll("div[class*=\"_markdown_\"], [data-markdown-variant]");
711
+ for (let i = 0; i < markdownContainers.length; i++) {
712
+ const container = markdownContainers[i];
713
+ if (!container || container.dataset.agyDecisionsScanned === "true") continue;
714
+ const headings = container.querySelectorAll("h2, h3, h4, p > strong");
715
+ for (let j = 0; j < headings.length; j++) {
716
+ const heading = headings[j];
717
+ if (!heading || heading.dataset.agyDecisionAttached === "true") continue;
718
+ const headingText = (heading.textContent ?? "").trim();
719
+ if (!DECISION_HEADER_REGEX.test(headingText)) continue;
720
+ let sibling = heading.nextElementSibling;
721
+ let targetList = null;
722
+ while (sibling) {
723
+ if (sibling.tagName === "OL" || sibling.tagName === "UL") {
724
+ targetList = sibling;
725
+ break;
726
+ }
727
+ if (/^H[1-4]$/.test(sibling.tagName)) break;
728
+ sibling = sibling.nextElementSibling;
729
+ }
730
+ if (!targetList) continue;
731
+ const options = extractOptionsFromList(targetList);
732
+ if (options.length === 0) continue;
733
+ heading.dataset.agyDecisionAttached = "true";
734
+ const box = document.createElement("div");
735
+ box.className = "agy-decision-container";
736
+ const header = document.createElement("div");
737
+ header.className = "agy-decision-header";
738
+ header.innerHTML = "<span>💬 点击选项快速填入:</span>";
739
+ box.appendChild(header);
740
+ const chips = document.createElement("div");
741
+ chips.className = "agy-decision-chips";
742
+ for (const opt of options) {
743
+ const chip = document.createElement("button");
744
+ chip.type = "button";
745
+ chip.className = "agy-decision-chip";
746
+ chip.title = `点击填入: ${opt.fullText}`;
747
+ const numSpan = document.createElement("span");
748
+ numSpan.className = "agy-decision-chip-num";
749
+ numSpan.textContent = opt.num ?? "👉";
750
+ const textSpan = document.createElement("span");
751
+ textSpan.className = "agy-decision-chip-text";
752
+ textSpan.textContent = opt.title;
753
+ chip.appendChild(numSpan);
754
+ chip.appendChild(textSpan);
755
+ chip.onclick = (e) => {
756
+ e.stopPropagation();
757
+ const cleanText = opt.fullText.replace(/^[0-9]+[、..:]\s*/, "").trim();
758
+ insertTextIntoChatComposer(`我选择 ${opt.num ? opt.num + " " : ""}${cleanText}`);
759
+ chip.classList.add("selected");
760
+ setTimeout(() => chip.classList.remove("selected"), 1200);
761
+ };
762
+ chips.appendChild(chip);
763
+ }
764
+ box.appendChild(chips);
765
+ targetList.parentNode?.insertBefore(box, targetList.nextSibling);
766
+ }
767
+ }
768
+ }
769
+ let decisionChipsDispose = null;
770
+ function installDecisionChips() {
771
+ if (typeof window === "undefined" || typeof document === "undefined") return () => {};
772
+ decisionChipsDispose?.();
773
+ injectStyles$3();
774
+ const observer = new MutationObserver(() => {
775
+ scanAndEnhanceDecisions();
776
+ });
777
+ const setup = () => {
778
+ if (document.body) {
779
+ observer.observe(document.body, {
780
+ childList: true,
781
+ subtree: true
782
+ });
783
+ scanAndEnhanceDecisions();
784
+ }
785
+ };
786
+ if (document.readyState === "loading") window.addEventListener("DOMContentLoaded", setup, { once: true });
787
+ else setup();
788
+ const dispose = () => {
789
+ observer.disconnect();
790
+ window.removeEventListener("DOMContentLoaded", setup);
791
+ if (decisionChipsDispose === dispose) decisionChipsDispose = null;
792
+ };
793
+ decisionChipsDispose = dispose;
794
+ return dispose;
795
+ }
796
+ //#endregion
797
+ //#region src/client/images.ts
798
+ let lightboxOverlay = null;
799
+ let lightboxScale = 1;
800
+ let lightboxTranslateX = 0;
801
+ let lightboxTranslateY = 0;
802
+ let isDraggingLightbox = false;
803
+ let dragStartX = 0;
804
+ let dragStartY = 0;
805
+ const IMAGE_CSS = `
806
+ .agy-image-card {
807
+ display: inline-flex;
808
+ flex-direction: column;
809
+ margin: 6px 0;
810
+ max-width: 100%;
811
+ border-radius: 8px;
812
+ overflow: hidden;
813
+ border: 1px solid var(--dsw-alias-border-l2, rgba(127, 127, 127, 0.25));
814
+ background: var(--dsw-alias-bg-l1, rgba(255, 255, 255, 0.03));
815
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
816
+ transition: transform 0.15s ease, box-shadow 0.15s ease;
817
+ vertical-align: middle;
818
+ }
819
+
820
+ .agy-image-card:hover {
821
+ border-color: var(--dsw-alias-border-l3, rgba(127, 127, 127, 0.45));
822
+ box-shadow: 0 4px 14px rgba(0, 0, 0, 0.25);
823
+ }
824
+
825
+ .agy-image-thumb-wrap {
826
+ position: relative;
827
+ overflow: hidden;
828
+ max-height: 480px;
829
+ cursor: zoom-in;
830
+ display: flex;
831
+ align-items: center;
832
+ justify-content: center;
833
+ background: repeating-conic-gradient(rgba(127,127,127,0.08) 0% 25%, transparent 0% 50%) 50% / 16px 16px;
834
+ }
835
+
836
+ .agy-image-thumb {
837
+ display: block;
838
+ max-width: 100%;
839
+ max-height: 480px;
840
+ height: auto;
841
+ object-fit: contain;
842
+ transition: transform 0.2s ease;
843
+ }
844
+
845
+ .agy-image-card:hover .agy-image-thumb {
846
+ transform: scale(1.015);
847
+ }
848
+
849
+ .agy-image-caption {
850
+ padding: 6px 10px;
851
+ font-size: 11.5px;
852
+ color: var(--dsw-alias-label-secondary, #aaa);
853
+ background: var(--dsw-alias-bg-l2, rgba(127, 127, 127, 0.08));
854
+ border-top: 1px solid var(--dsw-alias-border-l2, rgba(127, 127, 127, 0.15));
855
+ display: flex;
856
+ align-items: center;
857
+ justify-content: space-between;
858
+ gap: 8px;
859
+ overflow: hidden;
860
+ text-overflow: ellipsis;
861
+ white-space: nowrap;
862
+ }
863
+
864
+ .agy-image-link-chip {
865
+ display: inline-flex;
866
+ align-items: center;
867
+ gap: 4px;
868
+ padding: 2px 6px;
869
+ margin: 0 2px;
870
+ border-radius: 4px;
871
+ font-size: 12px;
872
+ background: var(--dsw-alias-bg-l2, rgba(127, 127, 127, 0.1));
873
+ border: 1px solid var(--dsw-alias-border-l2, rgba(127, 127, 127, 0.2));
874
+ color: var(--dsw-alias-label-primary, #ddd);
875
+ cursor: pointer;
876
+ text-decoration: none;
877
+ transition: all 0.15s ease;
878
+ }
879
+
880
+ .agy-image-link-chip:hover {
881
+ background: var(--dsw-alias-bg-hover, rgba(127, 127, 127, 0.2));
882
+ border-color: var(--dsw-alias-border-l3, rgba(127, 127, 127, 0.35));
883
+ }
884
+
885
+ /* Lightbox Modal */
886
+ .agy-lightbox-backdrop {
887
+ position: fixed;
888
+ inset: 0;
889
+ z-index: 999999;
890
+ background: rgba(0, 0, 0, 0.85);
891
+ backdrop-filter: blur(8px);
892
+ display: flex;
893
+ flex-direction: column;
894
+ user-select: none;
895
+ opacity: 0;
896
+ transition: opacity 0.2s ease;
897
+ }
898
+
899
+ .agy-lightbox-backdrop.open {
900
+ opacity: 1;
901
+ }
902
+
903
+ .agy-lightbox-header {
904
+ height: 48px;
905
+ display: flex;
906
+ align-items: center;
907
+ justify-content: space-between;
908
+ padding: 0 16px;
909
+ background: rgba(20, 20, 20, 0.65);
910
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
911
+ color: #fff;
912
+ font-size: 13px;
913
+ }
914
+
915
+ .agy-lightbox-title {
916
+ font-weight: 500;
917
+ overflow: hidden;
918
+ text-overflow: ellipsis;
919
+ white-space: nowrap;
920
+ max-width: 60%;
921
+ }
922
+
923
+ .agy-lightbox-actions {
924
+ display: flex;
925
+ align-items: center;
926
+ gap: 8px;
927
+ }
928
+
929
+ .agy-lightbox-btn {
930
+ background: rgba(255, 255, 255, 0.1);
931
+ border: 1px solid rgba(255, 255, 255, 0.15);
932
+ color: #fff;
933
+ border-radius: 6px;
934
+ padding: 4px 10px;
935
+ cursor: pointer;
936
+ font-size: 12px;
937
+ display: inline-flex;
938
+ align-items: center;
939
+ gap: 4px;
940
+ transition: all 0.15s ease;
941
+ }
942
+
943
+ .agy-lightbox-btn:hover {
944
+ background: rgba(255, 255, 255, 0.2);
945
+ }
946
+
947
+ .agy-lightbox-btn-close {
948
+ background: rgba(239, 68, 68, 0.25);
949
+ border-color: rgba(239, 68, 68, 0.4);
950
+ }
951
+
952
+ .agy-lightbox-btn-close:hover {
953
+ background: rgba(239, 68, 68, 0.45);
954
+ }
955
+
956
+ .agy-lightbox-body {
957
+ flex: 1;
958
+ position: relative;
959
+ overflow: hidden;
960
+ display: flex;
961
+ align-items: center;
962
+ justify-content: center;
963
+ cursor: grab;
964
+ }
965
+
966
+ .agy-lightbox-body.grabbing {
967
+ cursor: grabbing;
968
+ }
969
+
970
+ .agy-lightbox-img-wrap {
971
+ transform-origin: center center;
972
+ transition: transform 0.05s ease-out;
973
+ display: inline-block;
974
+ }
975
+
976
+ .agy-lightbox-img {
977
+ max-width: 90vw;
978
+ max-height: 85vh;
979
+ object-fit: contain;
980
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
981
+ border-radius: 4px;
982
+ pointer-events: none;
983
+ }
984
+ `;
985
+ function injectStyles$2() {
986
+ if (typeof document === "undefined") return;
987
+ const styleId = "dsh-agy-link-images-css";
988
+ if (document.getElementById(styleId) === null) {
989
+ const st = document.createElement("style");
990
+ st.id = styleId;
991
+ st.textContent = IMAGE_CSS;
992
+ const host = document.head ?? document.documentElement;
993
+ if (host) host.appendChild(st);
994
+ }
995
+ }
996
+ function getOrigin() {
997
+ if (typeof window !== "undefined" && window.location?.origin) return window.location.origin;
998
+ return "";
999
+ }
1000
+ /** Build media URL from path */
1001
+ function buildMediaUrl(rawPath) {
1002
+ return `${getOrigin()}/plugins/agy-link/media?path=${encodeURIComponent(rawPath.trim())}`;
1003
+ }
1004
+ /**
1005
+ * Open fullscreen Lightbox modal
1006
+ */
1007
+ function openLightbox(src, title = "Image Preview", rawPath) {
1008
+ if (typeof document === "undefined") return;
1009
+ injectStyles$2();
1010
+ if (lightboxOverlay) {
1011
+ lightboxOverlay.remove();
1012
+ lightboxOverlay = null;
1013
+ }
1014
+ lightboxScale = 1;
1015
+ lightboxTranslateX = 0;
1016
+ lightboxTranslateY = 0;
1017
+ const overlay = document.createElement("div");
1018
+ overlay.className = "agy-lightbox-backdrop";
1019
+ const header = document.createElement("div");
1020
+ header.className = "agy-lightbox-header";
1021
+ const titleEl = document.createElement("div");
1022
+ titleEl.className = "agy-lightbox-title";
1023
+ titleEl.textContent = title;
1024
+ header.appendChild(titleEl);
1025
+ const actions = document.createElement("div");
1026
+ actions.className = "agy-lightbox-actions";
1027
+ const btnZoomIn = document.createElement("button");
1028
+ btnZoomIn.className = "agy-lightbox-btn";
1029
+ btnZoomIn.textContent = "🔍+";
1030
+ btnZoomIn.title = "放大 / Zoom In";
1031
+ const btnZoomOut = document.createElement("button");
1032
+ btnZoomOut.className = "agy-lightbox-btn";
1033
+ btnZoomOut.textContent = "🔍-";
1034
+ btnZoomOut.title = "缩小 / Zoom Out";
1035
+ const btnReset = document.createElement("button");
1036
+ btnReset.className = "agy-lightbox-btn";
1037
+ btnReset.textContent = "1:1";
1038
+ btnReset.title = "实际大小 / Reset";
1039
+ actions.appendChild(btnZoomIn);
1040
+ actions.appendChild(btnZoomOut);
1041
+ actions.appendChild(btnReset);
1042
+ if (rawPath) {
1043
+ const btnCopyPath = document.createElement("button");
1044
+ btnCopyPath.className = "agy-lightbox-btn";
1045
+ btnCopyPath.textContent = "📋 复制路径";
1046
+ btnCopyPath.onclick = (e) => {
1047
+ e.stopPropagation();
1048
+ if (navigator.clipboard) navigator.clipboard.writeText(rawPath).then(() => {
1049
+ btnCopyPath.textContent = "✓ 已复制";
1050
+ setTimeout(() => {
1051
+ btnCopyPath.textContent = "📋 复制路径";
1052
+ }, 1500);
1053
+ }).catch(() => {});
1054
+ };
1055
+ actions.appendChild(btnCopyPath);
1056
+ }
1057
+ const btnClose = document.createElement("button");
1058
+ btnClose.className = "agy-lightbox-btn agy-lightbox-btn-close";
1059
+ btnClose.textContent = "✕ 关闭";
1060
+ actions.appendChild(btnClose);
1061
+ header.appendChild(actions);
1062
+ overlay.appendChild(header);
1063
+ const body = document.createElement("div");
1064
+ body.className = "agy-lightbox-body";
1065
+ const imgWrap = document.createElement("div");
1066
+ imgWrap.className = "agy-lightbox-img-wrap";
1067
+ const img = document.createElement("img");
1068
+ img.className = "agy-lightbox-img";
1069
+ img.src = src;
1070
+ img.alt = title;
1071
+ imgWrap.appendChild(img);
1072
+ body.appendChild(imgWrap);
1073
+ overlay.appendChild(body);
1074
+ const updateTransform = () => {
1075
+ imgWrap.style.transform = `translate(${lightboxTranslateX}px, ${lightboxTranslateY}px) scale(${lightboxScale})`;
1076
+ };
1077
+ btnZoomIn.onclick = (e) => {
1078
+ e.stopPropagation();
1079
+ lightboxScale = Math.min(lightboxScale * 1.3, 5);
1080
+ updateTransform();
1081
+ };
1082
+ btnZoomOut.onclick = (e) => {
1083
+ e.stopPropagation();
1084
+ lightboxScale = Math.max(lightboxScale / 1.3, .2);
1085
+ updateTransform();
1086
+ };
1087
+ btnReset.onclick = (e) => {
1088
+ e.stopPropagation();
1089
+ lightboxScale = 1;
1090
+ lightboxTranslateX = 0;
1091
+ lightboxTranslateY = 0;
1092
+ updateTransform();
1093
+ };
1094
+ const closeLightbox = () => {
1095
+ window.removeEventListener("keydown", onKeyDown);
1096
+ overlay.classList.remove("open");
1097
+ setTimeout(() => {
1098
+ overlay.remove();
1099
+ if (lightboxOverlay === overlay) lightboxOverlay = null;
1100
+ }, 200);
1101
+ };
1102
+ btnClose.onclick = (e) => {
1103
+ e.stopPropagation();
1104
+ closeLightbox();
1105
+ };
1106
+ overlay.onclick = (e) => {
1107
+ if (e.target === overlay || e.target === body) closeLightbox();
1108
+ };
1109
+ const onKeyDown = (e) => {
1110
+ if (e.key === "Escape") closeLightbox();
1111
+ };
1112
+ window.addEventListener("keydown", onKeyDown);
1113
+ body.onmousedown = (e) => {
1114
+ isDraggingLightbox = true;
1115
+ dragStartX = e.clientX - lightboxTranslateX;
1116
+ dragStartY = e.clientY - lightboxTranslateY;
1117
+ body.classList.add("grabbing");
1118
+ };
1119
+ const onMouseMove = (e) => {
1120
+ if (!isDraggingLightbox) return;
1121
+ lightboxTranslateX = e.clientX - dragStartX;
1122
+ lightboxTranslateY = e.clientY - dragStartY;
1123
+ updateTransform();
1124
+ };
1125
+ const onMouseUp = () => {
1126
+ if (isDraggingLightbox) {
1127
+ isDraggingLightbox = false;
1128
+ body.classList.remove("grabbing");
1129
+ }
1130
+ };
1131
+ window.addEventListener("mousemove", onMouseMove);
1132
+ window.addEventListener("mouseup", onMouseUp);
1133
+ body.onwheel = (e) => {
1134
+ e.preventDefault();
1135
+ const factor = e.deltaY < 0 ? 1.15 : .87;
1136
+ lightboxScale = Math.max(.2, Math.min(lightboxScale * factor, 5));
1137
+ updateTransform();
1138
+ };
1139
+ document.body.appendChild(overlay);
1140
+ lightboxOverlay = overlay;
1141
+ requestAnimationFrame(() => overlay.classList.add("open"));
1142
+ }
1143
+ /** Check if a URL or path is an image */
1144
+ function isImageFile(pathOrUrl) {
1145
+ if (!pathOrUrl || typeof pathOrUrl !== "string") return false;
1146
+ const clean = pathOrUrl.split(/[?#]/)[0] ?? "";
1147
+ return /\.(png|jpe?g|webp|gif|svg|bmp|ico|avif)$/i.test(clean);
1148
+ }
1149
+ /** Get React props of a DOM element */
1150
+ function getReactProps(el) {
1151
+ const key = Object.keys(el).find((k) => k.startsWith("__reactProps"));
1152
+ if (!key) return null;
1153
+ return el[key];
1154
+ }
1155
+ /**
1156
+ * Scan DOM for imageAlt spans and enhance them with live rendered images
1157
+ */
1158
+ function scanAndEnhanceImages() {
1159
+ if (typeof document === "undefined") return;
1160
+ const origin = getOrigin();
1161
+ if (origin && !origin.includes("127.0.0.1") && !origin.includes("localhost")) {
1162
+ const images = document.querySelectorAll("img[src*=\"/plugins/agy-link/media\"]");
1163
+ for (let i = 0; i < images.length; i++) {
1164
+ const img = images[i];
1165
+ if (img && img.src.includes("127.0.0.1")) {
1166
+ const u = new URL(img.src);
1167
+ img.src = `${origin}${u.pathname}${u.search}`;
1168
+ }
1169
+ }
1170
+ }
1171
+ const markdownContainers = document.querySelectorAll("div[class*=\"_markdown_\"], [data-markdown-variant]");
1172
+ for (let i = 0; i < markdownContainers.length; i++) {
1173
+ const container = markdownContainers[i];
1174
+ if (!container) continue;
1175
+ const altSpans = container.querySelectorAll("span[class*=\"imageAlt\"], span[class*=\"_imageAlt_\"]");
1176
+ if (altSpans.length === 0) continue;
1177
+ const props = getReactProps(container);
1178
+ const mdText = typeof props?.text === "string" ? props.text : "";
1179
+ if (!mdText) continue;
1180
+ const imgMatches = [];
1181
+ const re = /!\[(.*?)\]\((file:\/\/\/[^\s)]+|file:\/\/[^\s)]+|[A-Za-z]:[\\/][^\s)]+|\/home\/[^\s)]+|\/mnt\/[a-zA-Z]\/[^\s)]+|\\\\wsl\.localhost\\[^\s)]+)\)/g;
1182
+ let m;
1183
+ while ((m = re.exec(mdText)) !== null) imgMatches.push({
1184
+ alt: m[1] ?? "",
1185
+ target: m[2] ?? ""
1186
+ });
1187
+ if (imgMatches.length === 0) continue;
1188
+ for (let j = 0; j < altSpans.length; j++) {
1189
+ const span = altSpans[j];
1190
+ if (!span || span.dataset.agyEnhanced === "true") continue;
1191
+ const altText = (span.textContent ?? "").trim();
1192
+ const match = imgMatches.find((im) => im.alt.trim() === altText) ?? imgMatches[j];
1193
+ if (!match) continue;
1194
+ span.dataset.agyEnhanced = "true";
1195
+ const mediaUrl = buildMediaUrl(match.target);
1196
+ const card = document.createElement("div");
1197
+ card.className = "agy-image-card";
1198
+ const thumbWrap = document.createElement("div");
1199
+ thumbWrap.className = "agy-image-thumb-wrap";
1200
+ thumbWrap.title = `${altText || "Image"} (点击全屏放大)`;
1201
+ const img = document.createElement("img");
1202
+ img.className = "agy-image-thumb";
1203
+ img.src = mediaUrl;
1204
+ img.alt = altText || "Preview";
1205
+ img.loading = "lazy";
1206
+ img.onerror = () => {
1207
+ card.style.display = "none";
1208
+ span.style.display = "";
1209
+ };
1210
+ thumbWrap.appendChild(img);
1211
+ card.appendChild(thumbWrap);
1212
+ if (altText) {
1213
+ const caption = document.createElement("div");
1214
+ caption.className = "agy-image-caption";
1215
+ caption.textContent = altText;
1216
+ card.appendChild(caption);
1217
+ }
1218
+ thumbWrap.onclick = (e) => {
1219
+ e.stopPropagation();
1220
+ openLightbox(mediaUrl, altText || "Image Preview", match.target);
1221
+ };
1222
+ span.style.display = "none";
1223
+ span.parentNode?.insertBefore(card, span);
1224
+ }
1225
+ }
1226
+ const links = document.querySelectorAll("a[href^=\"file://\"]");
1227
+ for (let i = 0; i < links.length; i++) {
1228
+ const link = links[i];
1229
+ if (!link || link.dataset.agyLinkEnhanced === "true") continue;
1230
+ const href = link.href ?? "";
1231
+ if (!isImageFile(href)) continue;
1232
+ link.dataset.agyLinkEnhanced = "true";
1233
+ const mediaUrl = buildMediaUrl(href);
1234
+ const linkText = link.textContent ?? "Image";
1235
+ link.onclick = (e) => {
1236
+ e.preventDefault();
1237
+ e.stopPropagation();
1238
+ openLightbox(mediaUrl, linkText, href);
1239
+ };
1240
+ if (!link.querySelector(".agy-image-link-icon")) {
1241
+ const badge = document.createElement("span");
1242
+ badge.className = "agy-image-link-chip agy-image-link-icon";
1243
+ badge.textContent = "🖼️ 预览";
1244
+ link.appendChild(badge);
1245
+ }
1246
+ }
1247
+ }
1248
+ let imageEnhancerDispose = null;
1249
+ function installImageEnhancer() {
1250
+ if (typeof window === "undefined" || typeof document === "undefined") return () => {};
1251
+ imageEnhancerDispose?.();
1252
+ injectStyles$2();
1253
+ const observer = new MutationObserver(() => {
1254
+ scanAndEnhanceImages();
1255
+ });
1256
+ const setup = () => {
1257
+ if (document.body) {
1258
+ observer.observe(document.body, {
1259
+ childList: true,
1260
+ subtree: true
1261
+ });
1262
+ scanAndEnhanceImages();
1263
+ }
1264
+ };
1265
+ if (document.readyState === "loading") window.addEventListener("DOMContentLoaded", setup, { once: true });
1266
+ else setup();
1267
+ const dispose = () => {
1268
+ observer.disconnect();
1269
+ window.removeEventListener("DOMContentLoaded", setup);
1270
+ if (imageEnhancerDispose === dispose) imageEnhancerDispose = null;
1271
+ };
1272
+ imageEnhancerDispose = dispose;
1273
+ return dispose;
1274
+ }
1275
+ //#endregion
495
1276
  //#region src/client/toolview.ts
496
1277
  function react() {
497
1278
  const mod = require("react");
@@ -684,6 +1465,40 @@ window.__ModuleLoader__.load({
684
1465
  fill: "currentColor"
685
1466
  }));
686
1467
  }
1468
+ function IconQuestionOutline16(size = 14, className = "") {
1469
+ return hx("svg", {
1470
+ width: size,
1471
+ height: size,
1472
+ className: className || void 0,
1473
+ viewBox: "0 0 16 16",
1474
+ fill: "none",
1475
+ style: {
1476
+ display: "block",
1477
+ flexShrink: 0
1478
+ },
1479
+ "aria-hidden": true
1480
+ }, hx("path", {
1481
+ d: "M8 1C4.134 1 1 3.91 1 7.5c0 1.547.575 2.973 1.559 4.093L1.13 14.54a.5.5 0 00.627.63l3.238-1.079C5.875 14.316 6.91 14.5 8 14.5c3.866 0 7-2.91 7-6.5S11.866 1 8 1zm0 10.5a.75.75 0 110-1.5.75.75 0 010 1.5zm1.09-3.41c-.42.34-.59.54-.59.91H7.5v-.5c0-.66.36-1.12.82-1.48.44-.35.68-.61.68-1.02 0-.55-.45-1-1-1s-1 .45-1 1H6c0-1.1.9-2 2-2s2 .9 2 2c0 .73-.39 1.25-.91 1.67z",
1482
+ fill: "currentColor"
1483
+ }));
1484
+ }
1485
+ function IconImageOutline16(size = 14, className = "") {
1486
+ return hx("svg", {
1487
+ width: size,
1488
+ height: size,
1489
+ className: className || void 0,
1490
+ viewBox: "0 0 16 16",
1491
+ fill: "none",
1492
+ style: {
1493
+ display: "block",
1494
+ flexShrink: 0
1495
+ },
1496
+ "aria-hidden": true
1497
+ }, hx("path", {
1498
+ d: "M14 3H2a1 1 0 00-1 1v8a1 1 0 001 1h12a1 1 0 001-1V4a1 1 0 00-1-1zm-1 8H3l2.5-3.2 1.8 2.3 2.7-3.5L13 11zM5.5 6a1.5 1.5 0 110-3 1.5 1.5 0 010 3z",
1499
+ fill: "currentColor"
1500
+ }));
1501
+ }
687
1502
  function toolIconFor(kind, size = 14) {
688
1503
  switch (kind) {
689
1504
  case "terminal": return IconApiOutline14(size);
@@ -692,6 +1507,8 @@ window.__ModuleLoader__.load({
692
1507
  case "read": return IconBrowseOutline16(size);
693
1508
  case "search":
694
1509
  case "list": return IconSearchOutline16(size);
1510
+ case "question": return IconQuestionOutline16(size);
1511
+ case "image": return IconImageOutline16(size);
695
1512
  default: return IconCodeOutline16(size);
696
1513
  }
697
1514
  }
@@ -795,6 +1612,16 @@ window.__ModuleLoader__.load({
795
1612
  "remove_file",
796
1613
  "rm"
797
1614
  ]);
1615
+ const QUESTION_TOOLS = /* @__PURE__ */ new Set([
1616
+ "ask_question",
1617
+ "ask",
1618
+ "question"
1619
+ ]);
1620
+ const IMAGE_TOOLS = /* @__PURE__ */ new Set([
1621
+ "generate_image",
1622
+ "create_image",
1623
+ "render_image"
1624
+ ]);
798
1625
  function mirrorCardModel(block, cwd, home) {
799
1626
  const info = mirrorInfo(block);
800
1627
  const out = resultText(block);
@@ -806,6 +1633,33 @@ window.__ModuleLoader__.load({
806
1633
  };
807
1634
  const { tool, input } = info;
808
1635
  const desc = pick(input, "Description", "description", "toolAction", "toolSummary", "Instruction", "instruction");
1636
+ if (QUESTION_TOOLS.has(tool)) {
1637
+ const questionsRaw = input.questions ?? input.Questions;
1638
+ const questions = Array.isArray(questionsRaw) ? questionsRaw : [];
1639
+ return {
1640
+ kind: "question",
1641
+ tool,
1642
+ title: questions[0]?.question ?? desc ?? "Ask Question",
1643
+ output: out,
1644
+ questions,
1645
+ raw: parsedArgsRaw(block)
1646
+ };
1647
+ }
1648
+ if (IMAGE_TOOLS.has(tool)) {
1649
+ const prompt = pick(input, "Prompt", "prompt") ?? "";
1650
+ const name = pick(input, "ImageName", "image_name", "name") ?? "image";
1651
+ const ratio = pick(input, "AspectRatio", "aspect_ratio") ?? "1:1";
1652
+ return {
1653
+ kind: "image",
1654
+ tool,
1655
+ title: desc ?? `Generate Image · ${name}`,
1656
+ prompt,
1657
+ imageName: name,
1658
+ aspectRatio: ratio,
1659
+ output: out,
1660
+ raw: parsedArgsRaw(block)
1661
+ };
1662
+ }
809
1663
  if (TERMINAL_TOOLS.has(tool)) {
810
1664
  const command = pick(input, "CommandLine", "command_line", "command", "cmd", "Cmd") ?? JSON.stringify(input);
811
1665
  const cwdVal = pick(input, "Cwd", "cwd", "WorkingDirectory", "working_directory") ?? cwd;
@@ -839,12 +1693,17 @@ window.__ModuleLoader__.load({
839
1693
  const path = pick(input, "AbsolutePath", "absolute_path", "TargetFile", "target_file", "path", "file_path", "filename", "Path", "FilePath", "FileName", "targetFile") ?? "";
840
1694
  const offset = num(input, "offset", "Offset") ?? num(input, "StartLine", "start_line");
841
1695
  const line = offset !== void 0 ? offset > 0 && (tool === "view_file" || tool === "read_file") ? offset : offset + 1 : void 0;
1696
+ const isImg = isImageFile(path);
842
1697
  return {
843
- kind: "read",
1698
+ kind: isImg ? "image" : "read",
844
1699
  tool,
845
1700
  title: desc ? `${desc} · ${path}` : path !== "" ? "Read " + path : "Read",
846
1701
  path,
847
1702
  output: out,
1703
+ isImage: isImg,
1704
+ imagePath: isImg ? path : void 0,
1705
+ prompt: desc,
1706
+ imageName: path.split(/[/\\]/).pop() || "image",
848
1707
  ...path !== "" ? { location: {
849
1708
  path,
850
1709
  ...line !== void 0 ? { line } : {}
@@ -938,6 +1797,8 @@ window.__ModuleLoader__.load({
938
1797
  case "search": return model.tool === "search_web" || model.tool === "web_search" ? tr(t, "tv.webSearch", "Web Search") : tr(t, "tv.search", "Search");
939
1798
  case "list": return tr(t, "tv.list", "List");
940
1799
  case "delete": return tr(t, "tv.delete", "Delete");
1800
+ case "question": return tr(t, "tv.question", "Question");
1801
+ case "image": return tr(t, "tv.image", "Image");
941
1802
  default: return model.tool ? model.tool.replace(/_/g, " ") : tr(t, "tv.tool", "Tool");
942
1803
  }
943
1804
  }
@@ -950,6 +1811,8 @@ window.__ModuleLoader__.load({
950
1811
  }
951
1812
  if (model.kind === "search") return model.title.replace(/^(Web search|Search)\s*/i, "") || model.title;
952
1813
  if (model.kind === "list") return model.title.replace(/^List\s*(directory\s*)?/i, "") || model.title;
1814
+ if (model.kind === "question") return model.title;
1815
+ if (model.kind === "image") return model.prompt || model.title;
953
1816
  return model.title;
954
1817
  }
955
1818
  function diffStat(model) {
@@ -1026,6 +1889,101 @@ window.__ModuleLoader__.load({
1026
1889
  }, tr(t, "tv.noChanges", "(no textual changes)")));
1027
1890
  return h("div", { className: "agy-tv-diff-list" }, ...rows);
1028
1891
  }
1892
+ function QuestionCardBody({ model }) {
1893
+ const h = hx;
1894
+ const questions = model.questions ?? [];
1895
+ const [selectedMap, setSelectedMap] = react().useState({});
1896
+ const [inserted, setInserted] = react().useState(false);
1897
+ const toggleOption = (qIdx, opt, isMulti) => {
1898
+ setSelectedMap((prev) => {
1899
+ const next = { ...prev };
1900
+ const current = new Set(next[qIdx] ?? []);
1901
+ if (isMulti) {
1902
+ if (current.has(opt)) current.delete(opt);
1903
+ else current.add(opt);
1904
+ } else {
1905
+ current.clear();
1906
+ current.add(opt);
1907
+ }
1908
+ next[qIdx] = current;
1909
+ return next;
1910
+ });
1911
+ };
1912
+ const onInsert = () => {
1913
+ const parts = [];
1914
+ for (let i = 0; i < questions.length; i++) {
1915
+ const sel = Array.from(selectedMap[i] ?? []);
1916
+ if (sel.length > 0) parts.push(sel.join("; "));
1917
+ }
1918
+ if (parts.length > 0) {
1919
+ insertTextIntoChatComposer(parts.join("\n"));
1920
+ setInserted(true);
1921
+ setTimeout(() => setInserted(false), 1500);
1922
+ }
1923
+ };
1924
+ const qNodes = [];
1925
+ for (let i = 0; i < questions.length; i++) {
1926
+ const q = questions[i];
1927
+ if (!q) continue;
1928
+ const options = q.options ?? [];
1929
+ const isMulti = q.is_multi_select === true;
1930
+ const sel = selectedMap[i] ?? /* @__PURE__ */ new Set();
1931
+ const optNodes = options.map((opt, oIdx) => {
1932
+ const isChecked = sel.has(opt);
1933
+ return h("button", {
1934
+ key: "opt-" + oIdx,
1935
+ type: "button",
1936
+ className: cls("agy-tv-q-opt", isChecked && "selected"),
1937
+ onClick: (e) => {
1938
+ e.stopPropagation();
1939
+ toggleOption(i, opt, isMulti);
1940
+ }
1941
+ }, h("span", { className: cls("agy-tv-q-check", isMulti ? "checkbox" : "radio", isChecked && "checked") }), h("span", { className: "agy-tv-q-opt-text" }, opt));
1942
+ });
1943
+ qNodes.push(h("div", {
1944
+ key: "q-" + i,
1945
+ className: "agy-tv-q-item"
1946
+ }, h("div", { className: "agy-tv-q-prompt" }, q.question || "Please select:"), h("div", { className: "agy-tv-q-opts" }, ...optNodes)));
1947
+ }
1948
+ const hasSelection = Object.values(selectedMap).some((s) => s.size > 0);
1949
+ return h("div", { className: "agy-tv-question-wrap" }, ...qNodes, h("div", { className: "agy-tv-q-footer" }, h("button", {
1950
+ type: "button",
1951
+ className: cls("agy-tv-q-insert-btn", hasSelection && "active"),
1952
+ disabled: !hasSelection,
1953
+ onClick: (e) => {
1954
+ e.stopPropagation();
1955
+ onInsert();
1956
+ }
1957
+ }, inserted ? "✓ 已填入对话框" : "💬 填入对话框 / Insert into Chat"), model.output ? h("div", { className: "agy-tv-q-answered" }, `已记录: ${model.output}`) : null));
1958
+ }
1959
+ function ImageCardBody({ model }) {
1960
+ const h = hx;
1961
+ const prompt = model.prompt || "";
1962
+ const name = model.imageName || "image";
1963
+ const ratio = model.aspectRatio || "1:1";
1964
+ const path = model.imagePath || model.path || "";
1965
+ const mediaUrl = path ? buildMediaUrl(path) : null;
1966
+ return h("div", { className: "agy-tv-img-wrap" }, h("div", { className: "agy-tv-img-meta" }, h("div", {
1967
+ className: "agy-tv-img-prompt",
1968
+ title: prompt || name
1969
+ }, prompt ? `"${prompt}"` : name), h("div", { className: "agy-tv-img-badges" }, h("span", { className: "agy-tv-img-badge" }, ratio), ...path ? [h("span", {
1970
+ key: "path",
1971
+ className: "agy-tv-img-badge",
1972
+ title: path
1973
+ }, path.split(/[/\\]/).pop())] : [])), mediaUrl ? h("div", {
1974
+ className: "agy-tv-img-preview-box",
1975
+ onClick: (e) => {
1976
+ e.stopPropagation();
1977
+ openLightbox(mediaUrl, prompt || name, path);
1978
+ },
1979
+ title: "点击放大预览 / Click to open lightbox"
1980
+ }, h("img", {
1981
+ className: "agy-tv-img-thumb",
1982
+ src: mediaUrl,
1983
+ alt: prompt || name,
1984
+ loading: "lazy"
1985
+ })) : null);
1986
+ }
1029
1987
  function CardBody({ model, openFile, cwd, home, inspect, t }) {
1030
1988
  const h = hx;
1031
1989
  const inspectNode = inspect !== void 0 ? h("div", {
@@ -1088,6 +2046,8 @@ window.__ModuleLoader__.load({
1088
2046
  t
1089
2047
  })), h("pre", { className: "agy-tv-card-content" }, clip(rawBody, 16e3)), inspectNode);
1090
2048
  }
2049
+ case "question": return h("div", { className: "agy-tv-card" }, h("div", { className: "agy-tv-card-header" }, h("div", { className: "agy-tv-card-header-left" }, IconQuestionOutline16(13), h("span", { className: "agy-tv-card-path" }, model.title)), h(CopyButton, { text: model.output ?? model.raw ?? "" })), h(QuestionCardBody, { model }), inspectNode);
2050
+ case "image": return h("div", { className: "agy-tv-card" }, h("div", { className: "agy-tv-card-header" }, h("div", { className: "agy-tv-card-header-left" }, IconImageOutline16(13), h("span", { className: "agy-tv-card-path" }, model.imageName || "Image")), h(CopyButton, { text: model.prompt || (model.raw ?? "") })), h(ImageCardBody, { model }), inspectNode);
1091
2051
  default: {
1092
2052
  const copyText = model.output !== void 0 && model.output !== "" ? model.output : model.raw ?? "";
1093
2053
  const rawBody = model.output !== void 0 && model.output !== "" ? trimTrailingBlankLines(model.output) : model.raw !== void 0 && model.raw !== "" ? clip(model.raw, 4e3) : tr(t, "tv.noDetail", "(no detail)");
@@ -1695,6 +2655,156 @@ window.__ModuleLoader__.load({
1695
2655
  background: var(--dsw-alias-interactive-bg-hover-solid, #f1f5f9);
1696
2656
  color: var(--dsw-alias-label-primary, #0f172a);
1697
2657
  }
2658
+
2659
+ /* Question Card Styles */
2660
+ .agy-tv-question-wrap {
2661
+ padding: 10px 14px;
2662
+ display: flex;
2663
+ flex-direction: column;
2664
+ gap: 10px;
2665
+ font-family: inherit;
2666
+ }
2667
+ .agy-tv-q-item {
2668
+ display: flex;
2669
+ flex-direction: column;
2670
+ gap: 6px;
2671
+ }
2672
+ .agy-tv-q-prompt {
2673
+ font-size: 13px;
2674
+ font-weight: 600;
2675
+ color: var(--dsw-alias-label-primary, #0f172a);
2676
+ }
2677
+ .agy-tv-q-opts {
2678
+ display: flex;
2679
+ flex-direction: column;
2680
+ gap: 6px;
2681
+ }
2682
+ .agy-tv-q-opt {
2683
+ display: flex;
2684
+ align-items: center;
2685
+ gap: 8px;
2686
+ padding: 6px 10px;
2687
+ border-radius: 6px;
2688
+ background: var(--dsw-alias-bg-l2, rgba(127, 127, 127, 0.08));
2689
+ border: 1px solid var(--dsw-alias-border-l2, rgba(127, 127, 127, 0.2));
2690
+ color: var(--dsw-alias-label-primary, #334155);
2691
+ cursor: pointer;
2692
+ text-align: left;
2693
+ font-size: 12.5px;
2694
+ transition: all 0.15s ease;
2695
+ }
2696
+ .agy-tv-q-opt:hover {
2697
+ background: var(--dsw-alias-bg-hover, rgba(127, 127, 127, 0.15));
2698
+ border-color: var(--dsw-alias-border-l3, rgba(127, 127, 127, 0.35));
2699
+ }
2700
+ .agy-tv-q-opt.selected {
2701
+ background: rgba(16, 185, 129, 0.12);
2702
+ border-color: #10b981;
2703
+ color: #10b981;
2704
+ }
2705
+ .agy-tv-q-check {
2706
+ width: 14px;
2707
+ height: 14px;
2708
+ border: 1.5px solid currentColor;
2709
+ display: inline-flex;
2710
+ align-items: center;
2711
+ justify-content: center;
2712
+ flex-shrink: 0;
2713
+ }
2714
+ .agy-tv-q-check.radio {
2715
+ border-radius: 50%;
2716
+ }
2717
+ .agy-tv-q-check.checkbox {
2718
+ border-radius: 3px;
2719
+ }
2720
+ .agy-tv-q-check.checked:after {
2721
+ content: "";
2722
+ width: 6px;
2723
+ height: 6px;
2724
+ background: currentColor;
2725
+ border-radius: inherit;
2726
+ }
2727
+ .agy-tv-q-footer {
2728
+ display: flex;
2729
+ align-items: center;
2730
+ justify-content: space-between;
2731
+ padding-top: 6px;
2732
+ border-top: 1px solid var(--dsw-alias-border-l2, rgba(127, 127, 127, 0.15));
2733
+ }
2734
+ .agy-tv-q-insert-btn {
2735
+ padding: 5px 12px;
2736
+ border-radius: 6px;
2737
+ font-size: 12px;
2738
+ font-weight: 600;
2739
+ background: rgba(16, 185, 129, 0.15);
2740
+ border: 1px solid #10b981;
2741
+ color: #10b981;
2742
+ cursor: pointer;
2743
+ transition: all 0.15s ease;
2744
+ }
2745
+ .agy-tv-q-insert-btn:disabled {
2746
+ opacity: 0.4;
2747
+ cursor: not-allowed;
2748
+ }
2749
+ .agy-tv-q-insert-btn:not(:disabled):hover {
2750
+ background: #10b981;
2751
+ color: #fff;
2752
+ }
2753
+ .agy-tv-q-answered {
2754
+ font-size: 11px;
2755
+ color: var(--dsw-alias-label-tertiary, #888);
2756
+ }
2757
+
2758
+ /* Image Card Styles */
2759
+ .agy-tv-img-wrap {
2760
+ padding: 10px 14px;
2761
+ display: flex;
2762
+ flex-direction: column;
2763
+ gap: 8px;
2764
+ }
2765
+ .agy-tv-img-meta {
2766
+ display: flex;
2767
+ align-items: center;
2768
+ justify-content: space-between;
2769
+ gap: 8px;
2770
+ }
2771
+ .agy-tv-img-prompt {
2772
+ font-size: 12.5px;
2773
+ color: var(--dsw-alias-label-primary, #334155);
2774
+ font-style: italic;
2775
+ overflow: hidden;
2776
+ text-overflow: ellipsis;
2777
+ white-space: nowrap;
2778
+ }
2779
+ .agy-tv-img-badges {
2780
+ display: flex;
2781
+ gap: 4px;
2782
+ flex-shrink: 0;
2783
+ }
2784
+ .agy-tv-img-badge {
2785
+ font-size: 11px;
2786
+ padding: 1px 6px;
2787
+ border-radius: 4px;
2788
+ background: var(--dsw-alias-bg-l2, rgba(127, 127, 127, 0.1));
2789
+ border: 1px solid var(--dsw-alias-border-l2, rgba(127, 127, 127, 0.2));
2790
+ color: var(--dsw-alias-label-secondary, #888);
2791
+ }
2792
+ .agy-tv-img-preview-box {
2793
+ max-height: 320px;
2794
+ overflow: hidden;
2795
+ border-radius: 6px;
2796
+ border: 1px solid var(--dsw-alias-border-l2, rgba(127, 127, 127, 0.2));
2797
+ display: flex;
2798
+ align-items: center;
2799
+ justify-content: center;
2800
+ background: repeating-conic-gradient(rgba(127,127,127,0.08) 0% 25%, transparent 0% 50%) 50% / 16px 16px;
2801
+ cursor: zoom-in;
2802
+ }
2803
+ .agy-tv-img-thumb {
2804
+ max-width: 100%;
2805
+ max-height: 320px;
2806
+ object-fit: contain;
2807
+ }
1698
2808
  `;
1699
2809
  const gDoc = globalThis.document;
1700
2810
  if (gDoc !== void 0 && gDoc !== null) {
@@ -2147,15 +3257,26 @@ div[data-variant="think"] [class*="thinkBody"] {
2147
3257
  const { createElement: h, useState, useEffect, useRef } = require("react");
2148
3258
  const reactDom = require("react-dom");
2149
3259
  const win = globalThis;
2150
- const bodyEl = win.document?.body ?? null;
2151
3260
  const portalToBody = (node) => {
2152
- if (bodyEl && reactDom && typeof reactDom.createPortal === "function") return reactDom.createPortal(node, bodyEl);
3261
+ const body = win.document?.body ?? (typeof document !== "undefined" ? document.body : null);
3262
+ if (body && reactDom && typeof reactDom.createPortal === "function") return reactDom.createPortal(node, body);
2153
3263
  return node;
2154
3264
  };
2155
3265
  const name = "dsh-agy-link-client";
2156
3266
  const inject = ["slots", "locale"];
2157
3267
  const base = win.location?.origin ?? "";
2158
- let statusCache = null;
3268
+ const STATUS_CACHE_KEY = "dsh_agy_status_cache";
3269
+ function loadInitialStatusCache() {
3270
+ try {
3271
+ const raw = win.localStorage?.getItem(STATUS_CACHE_KEY);
3272
+ if (raw) {
3273
+ const parsed = JSON.parse(raw);
3274
+ if (parsed && typeof parsed === "object") return parsed;
3275
+ }
3276
+ } catch {}
3277
+ return null;
3278
+ }
3279
+ let statusCache = loadInitialStatusCache();
2159
3280
  async function getStatus() {
2160
3281
  try {
2161
3282
  const init = {};
@@ -2194,8 +3315,20 @@ div[data-variant="think"] [class*="thinkBody"] {
2194
3315
  const statusListeners = /* @__PURE__ */ new Set();
2195
3316
  let statusPollTimer = null;
2196
3317
  let statusFetchSeq = 0;
3318
+ function isStatusEqual(a, b) {
3319
+ if (a === b) return true;
3320
+ if (a === null || b === null) return false;
3321
+ try {
3322
+ return JSON.stringify(a) === JSON.stringify(b);
3323
+ } catch {
3324
+ return false;
3325
+ }
3326
+ }
2197
3327
  function notifyStatus(st) {
2198
3328
  statusCache = st;
3329
+ try {
3330
+ win.localStorage?.setItem(STATUS_CACHE_KEY, JSON.stringify(st));
3331
+ } catch {}
2199
3332
  for (const fn of [...statusListeners]) try {
2200
3333
  fn(st);
2201
3334
  } catch {}
@@ -2203,7 +3336,9 @@ div[data-variant="think"] [class*="thinkBody"] {
2203
3336
  async function statusPollTick() {
2204
3337
  const seq = ++statusFetchSeq;
2205
3338
  const st = await getStatus();
2206
- if (st !== null && seq === statusFetchSeq) notifyStatus(st);
3339
+ if (st !== null && seq === statusFetchSeq) {
3340
+ if (!isStatusEqual(statusCache, st)) notifyStatus(st);
3341
+ }
2207
3342
  }
2208
3343
  function ensureStatusPolling() {
2209
3344
  if (statusPollTimer !== null) return;
@@ -2259,6 +3394,21 @@ div[data-variant="think"] [class*="thinkBody"] {
2259
3394
  }
2260
3395
  };
2261
3396
  /**
3397
+ * Singleton modal instance manager: ensures at most one modal dialog is
3398
+ * rendered into document.body at any time even when multiple session headers mount.
3399
+ */
3400
+ let primaryModalInstanceId = null;
3401
+ const modalInstanceIds = /* @__PURE__ */ new Set();
3402
+ function registerModalInstance(id) {
3403
+ modalInstanceIds.add(id);
3404
+ if (primaryModalInstanceId === null || !modalInstanceIds.has(primaryModalInstanceId)) primaryModalInstanceId = id;
3405
+ return primaryModalInstanceId === id;
3406
+ }
3407
+ function unregisterModalInstance(id) {
3408
+ modalInstanceIds.delete(id);
3409
+ if (primaryModalInstanceId === id) primaryModalInstanceId = modalInstanceIds.values().next().value ?? null;
3410
+ }
3411
+ /**
2262
3412
  * Format reset timestamp into readable date/time + relative countdown.
2263
3413
  */
2264
3414
  function formatQuotaWindow(t, resetTimeStr) {
@@ -2632,12 +3782,13 @@ body.dark,
2632
3782
  border-radius: 50%;
2633
3783
  }
2634
3784
  .agy-card-hover {
2635
- transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.15s ease;
3785
+ transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.18s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.2s ease;
2636
3786
  }
2637
3787
  .agy-card-hover:hover {
2638
3788
  border-color: var(--agy-border-card-primary, #3b82f6) !important;
2639
3789
  box-shadow: var(--agy-shadow-card-hover) !important;
2640
3790
  }
3791
+
2641
3792
  .agy-btn {
2642
3793
  transition: all 0.15s ease;
2643
3794
  user-select: none;
@@ -2692,6 +3843,17 @@ body.dark,
2692
3843
  color: var(--agy-text-primary);
2693
3844
  }
2694
3845
  `;
3846
+ function injectGlobalStyles() {
3847
+ if (typeof document === "undefined") return;
3848
+ const styleId = "dsh-agy-link-global-css";
3849
+ if (document.getElementById(styleId) === null) {
3850
+ const st = document.createElement("style");
3851
+ st.id = styleId;
3852
+ st.textContent = GLOBAL_CSS;
3853
+ const host = document.head ?? document.documentElement;
3854
+ if (host) host.appendChild(st);
3855
+ }
3856
+ }
2695
3857
  const S = {
2696
3858
  container: {
2697
3859
  lineHeight: 1.5,
@@ -2762,27 +3924,29 @@ body.dark,
2762
3924
  card: {
2763
3925
  background: "var(--agy-bg-card)",
2764
3926
  border: "1px solid var(--agy-border-card)",
2765
- borderRadius: "10px",
2766
- padding: "14px 16px",
2767
- marginBottom: "12px",
3927
+ borderRadius: "8px",
3928
+ padding: "10px 14px",
3929
+ marginBottom: "8px",
2768
3930
  color: "var(--agy-text-primary)",
2769
- boxShadow: "var(--agy-shadow-card)"
3931
+ boxShadow: "var(--agy-shadow-card)",
3932
+ transition: "all 0.18s cubic-bezier(0.16, 1, 0.3, 1)"
2770
3933
  },
2771
3934
  cardPrimary: {
2772
- background: "var(--agy-bg-card-primary)",
2773
- border: "1.5px solid var(--agy-border-card-primary)",
2774
- borderRadius: "10px",
2775
- padding: "14px 16px",
2776
- marginBottom: "12px",
2777
- boxShadow: "var(--agy-shadow-card-primary)",
2778
- color: "var(--agy-text-primary)"
3935
+ background: "var(--agy-bg-card)",
3936
+ border: "1px solid var(--agy-border-card)",
3937
+ borderRadius: "8px",
3938
+ padding: "10px 14px",
3939
+ marginBottom: "8px",
3940
+ color: "var(--agy-text-primary)",
3941
+ boxShadow: "var(--agy-shadow-card)",
3942
+ transition: "all 0.18s cubic-bezier(0.16, 1, 0.3, 1)"
2779
3943
  },
2780
3944
  quotaBox: {
2781
3945
  background: "var(--agy-bg-box)",
2782
3946
  border: "1px solid var(--agy-border-box)",
2783
3947
  borderRadius: "8px",
2784
3948
  padding: "8px 10px",
2785
- marginTop: "10px"
3949
+ marginTop: "8px"
2786
3950
  },
2787
3951
  progressBarBg: {
2788
3952
  flex: "1",
@@ -2952,6 +4116,7 @@ body.dark,
2952
4116
  return locale.bind(NS);
2953
4117
  };
2954
4118
  const AgySettingsSection = (props) => {
4119
+ injectGlobalStyles();
2955
4120
  const t = useAgyTranslation();
2956
4121
  const { status, refresh } = useAgyStatus();
2957
4122
  const [aliasInput, setAliasInput] = useState("");
@@ -2962,6 +4127,7 @@ body.dark,
2962
4127
  const [loadingAction, setLoadingAction] = useState(null);
2963
4128
  const [toast, setToast] = useState(null);
2964
4129
  const [expandedModels, setExpandedModels] = useState({});
4130
+ const [addProxyInput, setAddProxyInput] = useState("");
2965
4131
  const [, setTimeTick] = useState(0);
2966
4132
  useEffect(() => {
2967
4133
  const timer = setInterval(() => setTimeTick((n) => n + 1), 3e4);
@@ -2981,6 +4147,7 @@ body.dark,
2981
4147
  setAddingAccount(false);
2982
4148
  setAuthCodeInput("");
2983
4149
  setAliasInput("");
4150
+ setAddProxyInput("");
2984
4151
  showToast(safeMessage(pa.code), "success");
2985
4152
  } else if (pa.phase === "failed") {
2986
4153
  flowStartedRef.current = false;
@@ -3013,7 +4180,11 @@ body.dark,
3013
4180
  const handleBeginAddAccount = async () => {
3014
4181
  setLoadingAction("pool:beginAdd");
3015
4182
  const alias = aliasInput.trim();
3016
- const res = await postJson("/plugins/agy-link/pool/begin-add", alias ? { alias } : {});
4183
+ const proxyUrl = addProxyInput.trim();
4184
+ const res = await postJson("/plugins/agy-link/pool/begin-add", {
4185
+ ...alias ? { alias } : {},
4186
+ ...proxyUrl ? { proxyUrl } : {}
4187
+ });
3017
4188
  setLoadingAction(null);
3018
4189
  if (res && res.ok) {
3019
4190
  flowStartedRef.current = true;
@@ -3031,6 +4202,7 @@ body.dark,
3031
4202
  flowStartedRef.current = false;
3032
4203
  setAuthCodeInput("");
3033
4204
  setAliasInput("");
4205
+ setAddProxyInput("");
3034
4206
  setAddingAccount(false);
3035
4207
  await refresh();
3036
4208
  showToast(safeMessage(res.code), "success");
@@ -3041,9 +4213,29 @@ body.dark,
3041
4213
  await postJson("/plugins/agy-link/pool/cancel-add", {});
3042
4214
  setAuthCodeInput("");
3043
4215
  setAliasInput("");
4216
+ setAddProxyInput("");
3044
4217
  setAddingAccount(false);
3045
4218
  await refresh();
3046
4219
  };
4220
+ const reorderAccounts = async (newIds) => {
4221
+ setLoadingAction("pool:reorder");
4222
+ const res = await postJson("/plugins/agy-link/pool/reorder", { ids: newIds });
4223
+ setLoadingAction(null);
4224
+ if (res && res.ok) {
4225
+ await refresh();
4226
+ showToast(t("account.reordered"), "success");
4227
+ } else actionFailed();
4228
+ };
4229
+ const moveAccount = async (accId, delta) => {
4230
+ const ids = (status?.pool?.accounts ?? []).map((a) => a.id);
4231
+ const idx = ids.indexOf(accId);
4232
+ if (idx === -1) return;
4233
+ const newIdx = idx + delta;
4234
+ if (newIdx < 0 || newIdx >= ids.length) return;
4235
+ const [moved] = ids.splice(idx, 1);
4236
+ if (moved) ids.splice(newIdx, 0, moved);
4237
+ await reorderAccounts(ids);
4238
+ };
3047
4239
  const setCfg = async (key, value) => {
3048
4240
  setLoadingAction(`config:${key}`);
3049
4241
  const res = await postJson("/plugins/agy-link/config", {
@@ -3312,9 +4504,15 @@ body.dark,
3312
4504
  const dotColor = !acc.enabled ? "#64748b" : isAuthRequired ? "#ef4444" : hasCooldown ? "#f59e0b" : "#10b981";
3313
4505
  const isEditingProxy = editingProxyId === acc.id;
3314
4506
  const isExpanded = expandedModels[acc.id] ?? false;
3315
- const cardStyle = isPrimary ? { ...S.cardPrimary } : { ...S.card };
4507
+ const accIndex = accounts.indexOf(acc);
4508
+ const cardStyle = {
4509
+ ...S.card,
4510
+ cursor: "default",
4511
+ padding: "10px 14px",
4512
+ marginBottom: "8px"
4513
+ };
3316
4514
  const legacyDefault = acc.defaultAlias === void 0 && acc.systemHome && acc.alias === "主账号 (系统登录)";
3317
- const displayAlias = acc.defaultAlias || legacyDefault ? acc.systemHome ? t("account.defaultAlias") : t("account.aliasDefault", { number: accounts.indexOf(acc) + 1 }) : acc.alias;
4515
+ const displayAlias = acc.defaultAlias || legacyDefault ? acc.systemHome ? t("account.defaultAlias") : t("account.aliasDefault", { number: accIndex + 1 }) : acc.alias;
3318
4516
  const googleModels = acc.quotas.google?.models ?? [];
3319
4517
  const anthropicModels = acc.quotas.anthropic?.models ?? [];
3320
4518
  const openaiModels = acc.quotas.openai?.models ?? [];
@@ -3340,155 +4538,278 @@ body.dark,
3340
4538
  display: "flex",
3341
4539
  alignItems: "center",
3342
4540
  justifyContent: "space-between",
4541
+ userSelect: "none",
4542
+ gap: "8px",
3343
4543
  marginBottom: "8px"
3344
4544
  } }, h("div", { style: {
3345
4545
  display: "flex",
3346
4546
  alignItems: "center",
3347
- gap: "8px",
3348
- flexWrap: "wrap"
4547
+ gap: "6px",
4548
+ flexWrap: "wrap",
4549
+ flex: "1",
4550
+ minWidth: 0
3349
4551
  } }, h("span", {
4552
+ style: {
4553
+ ...S.badgeTag,
4554
+ fontWeight: 700,
4555
+ fontSize: "10.5px",
4556
+ padding: "1px 5px",
4557
+ background: isPrimary ? "var(--agy-badge-primary-bg)" : "var(--agy-badge-tag-bg)",
4558
+ color: isPrimary ? "var(--agy-badge-primary-text)" : "var(--agy-badge-tag-text)",
4559
+ borderColor: isPrimary ? "var(--agy-badge-primary-border)" : "var(--agy-badge-tag-border)"
4560
+ },
4561
+ title: `优先级 #${accIndex + 1}`
4562
+ }, `#${accIndex + 1}`), accounts.length > 1 ? h("div", { style: {
4563
+ display: "inline-flex",
4564
+ gap: "2px",
4565
+ alignItems: "center"
4566
+ } }, accIndex > 0 ? h("button", {
4567
+ type: "button",
4568
+ className: "agy-btn",
4569
+ style: {
4570
+ ...S.btnSm,
4571
+ padding: "1px 4px",
4572
+ fontSize: "10px",
4573
+ lineHeight: 1,
4574
+ height: "18px"
4575
+ },
4576
+ title: t("account.moveUp"),
4577
+ onClick: () => void moveAccount(acc.id, -1)
4578
+ }, uiIcon("arrowUp", 10)) : null, accIndex < accounts.length - 1 ? h("button", {
4579
+ type: "button",
4580
+ className: "agy-btn",
4581
+ style: {
4582
+ ...S.btnSm,
4583
+ padding: "1px 4px",
4584
+ fontSize: "10px",
4585
+ lineHeight: 1,
4586
+ height: "18px"
4587
+ },
4588
+ title: t("account.moveDown"),
4589
+ onClick: () => void moveAccount(acc.id, 1)
4590
+ }, uiIcon("arrowDown", 10)) : null) : null, h("span", {
3350
4591
  className: "agy-pulse-dot",
3351
4592
  style: {
3352
4593
  background: dotColor,
3353
- boxShadow: `0 0 8px ${dotColor}aa`
4594
+ boxShadow: `0 0 6px ${dotColor}aa`,
4595
+ marginLeft: "1px"
3354
4596
  }
3355
- }), h("span", { style: {
3356
- fontWeight: 700,
3357
- fontSize: "13.5px",
3358
- color: "var(--agy-text-primary)"
3359
- } }, displayAlias), isAuthRequired ? h("span", { style: {
4597
+ }), h("span", {
4598
+ style: {
4599
+ fontWeight: 700,
4600
+ fontSize: "13px",
4601
+ color: "var(--agy-text-primary)",
4602
+ whiteSpace: "nowrap"
4603
+ },
4604
+ title: displayAlias
4605
+ }, displayAlias), h("span", { style: {
4606
+ ...S.badgeTag,
4607
+ background: "rgba(59, 130, 246, 0.12)",
4608
+ color: "#3b82f6",
4609
+ borderColor: "rgba(59, 130, 246, 0.35)",
4610
+ fontSize: "10px",
4611
+ padding: "1px 5px",
4612
+ fontWeight: 700
4613
+ } }, "AGY"), isAuthRequired ? h("span", { style: {
3360
4614
  ...S.badgeTag,
3361
4615
  background: "var(--agy-badge-email-bg)",
3362
4616
  color: "#ef4444",
3363
4617
  borderColor: "#fca5a5",
3364
- gap: "4px",
4618
+ gap: "3px",
4619
+ fontSize: "10px",
4620
+ padding: "1px 5px",
3365
4621
  fontWeight: 700
3366
- } }, uiIcon("alert", 11, "#ef4444"), t("status.authRequired")) : null, acc.email ? h("span", { style: {
4622
+ } }, uiIcon("alert", 10, "#ef4444"), t("status.authRequired")) : null, hasCooldown ? h("span", { style: {
3367
4623
  ...S.badgeTag,
3368
- background: "var(--agy-badge-email-bg)",
3369
- color: "var(--agy-badge-email-text)",
3370
- borderColor: "var(--agy-badge-email-border)",
3371
- gap: "5px"
3372
- } }, uiIcon("mail", 11, "var(--agy-badge-email-text)"), acc.email) : null, isPrimary ? h("span", { style: {
4624
+ background: "rgba(245, 158, 11, 0.15)",
4625
+ color: "#f59e0b",
4626
+ borderColor: "rgba(245, 158, 11, 0.4)",
4627
+ gap: "3px",
4628
+ fontSize: "10px",
4629
+ padding: "1px 5px",
4630
+ fontWeight: 700
4631
+ } }, uiIcon("alert", 10, "#f59e0b"), "冷却中") : null, acc.email ? h("span", {
4632
+ style: {
4633
+ ...S.badgeTag,
4634
+ background: "var(--agy-badge-email-bg)",
4635
+ color: "var(--agy-badge-email-text)",
4636
+ borderColor: "var(--agy-badge-email-border)",
4637
+ gap: "4px",
4638
+ fontSize: "11px",
4639
+ padding: "1px 6px",
4640
+ whiteSpace: "nowrap"
4641
+ },
4642
+ title: acc.email
4643
+ }, uiIcon("mail", 10, "var(--agy-badge-email-text)"), acc.email) : null, isPrimary ? h("span", { style: {
3373
4644
  ...S.badgePrimary,
3374
- gap: "4px"
4645
+ gap: "3px",
4646
+ fontSize: "10.5px",
4647
+ padding: "1px 5px"
3375
4648
  } }, uiIcon("star", 10, "var(--agy-badge-primary-text)"), t("status.primary")) : null, isInUse ? h("span", {
3376
4649
  style: {
3377
4650
  ...S.badgeTag,
3378
4651
  background: "rgba(16, 185, 129, 0.12)",
3379
4652
  color: "#10b981",
3380
4653
  borderColor: "rgba(16, 185, 129, 0.45)",
3381
- gap: "4px",
4654
+ gap: "3px",
4655
+ fontSize: "10px",
4656
+ padding: "1px 5px",
3382
4657
  fontWeight: 700
3383
4658
  },
3384
4659
  title: t("status.inUse")
3385
- }, uiIcon("zap", 11, "#10b981"), t("status.inUse")) : null, acc.proxyUrl ? h("span", { style: {
4660
+ }, uiIcon("zap", 10, "#10b981"), t("status.inUse")) : null, acc.proxyUrl ? h("span", { style: {
3386
4661
  ...S.badgeTag,
3387
4662
  background: "var(--agy-badge-proxy-bg)",
3388
4663
  color: "var(--agy-badge-proxy-text)",
3389
4664
  borderColor: "var(--agy-badge-proxy-border)",
3390
- gap: "5px"
3391
- } }, uiIcon("globe", 11, "var(--agy-badge-proxy-text)"), t("status.proxy")) : null), h("div", { style: {
4665
+ gap: "4px",
4666
+ fontSize: "10px",
4667
+ padding: "1px 5px"
4668
+ } }, uiIcon("globe", 10, "var(--agy-badge-proxy-text)"), t("status.proxy")) : null), h("div", { style: {
3392
4669
  display: "flex",
3393
- gap: "5px",
3394
- alignItems: "center"
3395
- } }, allChildModels.length > 0 ? h("button", {
4670
+ gap: "4px",
4671
+ alignItems: "center",
4672
+ flexShrink: 0
4673
+ } }, h("button", {
3396
4674
  type: "button",
3397
4675
  className: "agy-btn",
3398
4676
  style: isExpanded ? {
3399
4677
  ...S.btnSmPrimary,
3400
- gap: "3px"
4678
+ gap: "3px",
4679
+ fontSize: "11px",
4680
+ padding: "2px 6px"
3401
4681
  } : {
3402
4682
  ...S.btnSm,
3403
- gap: "3px"
4683
+ gap: "3px",
4684
+ fontSize: "11px",
4685
+ padding: "2px 6px"
3404
4686
  },
3405
4687
  onClick: () => toggleExpand(acc.id)
3406
- }, isExpanded ? [uiIcon("chevronUp", 11), ` ${t("account.collapse")}`] : [uiIcon("chevronDown", 11), ` ${t("account.details")}`]) : null, h("button", {
4688
+ }, isExpanded ? [uiIcon("chevronUp", 10), ` ${t("account.collapse")}`] : [uiIcon("chevronDown", 10), ` ${t("account.otherModels")}`]), h("button", {
3407
4689
  type: "button",
3408
4690
  className: "agy-btn",
3409
4691
  style: {
3410
4692
  ...S.btnSm,
3411
- gap: "4px"
4693
+ gap: "3px",
4694
+ fontSize: "11px",
4695
+ padding: "2px 6px"
3412
4696
  },
3413
4697
  title: t("account.syncTitle"),
3414
4698
  disabled: isBusy,
3415
4699
  onClick: () => void refreshQuota(acc.id)
3416
- }, loadingAction === `refresh:${acc.id}` ? [renderSpinner(), t("account.syncing")] : [uiIcon("refresh", 11), ` ${t("account.sync")}`]), !isPrimary ? h("button", {
4700
+ }, loadingAction === `refresh:${acc.id}` ? [renderSpinner(), t("account.syncing")] : [uiIcon("refresh", 10), ` ${t("account.sync")}`]), !isPrimary ? h("button", {
3417
4701
  type: "button",
3418
4702
  className: "agy-btn",
3419
4703
  style: {
3420
4704
  ...S.btnSm,
3421
- gap: "4px"
4705
+ gap: "3px",
4706
+ fontSize: "11px",
4707
+ padding: "2px 6px"
3422
4708
  },
3423
4709
  disabled: isBusy,
3424
4710
  onClick: () => void setPrimary(acc.id)
3425
- }, loadingAction === `primary:${acc.id}` ? [renderSpinner(), t("account.settingPrimary")] : [uiIcon("star", 11), ` ${t("account.setPrimary")}`]) : null, h("button", {
4711
+ }, loadingAction === `primary:${acc.id}` ? [renderSpinner(), t("account.settingPrimary")] : [uiIcon("star", 10), ` ${t("account.setPrimary")}`]) : null, h("button", {
3426
4712
  type: "button",
3427
4713
  className: "agy-btn",
3428
4714
  style: isEditingProxy ? {
3429
4715
  ...S.btnSmPrimary,
3430
- gap: "4px"
4716
+ gap: "3px",
4717
+ fontSize: "11px",
4718
+ padding: "2px 6px"
3431
4719
  } : {
3432
4720
  ...S.btnSm,
3433
- gap: "4px"
4721
+ gap: "3px",
4722
+ fontSize: "11px",
4723
+ padding: "2px 6px"
3434
4724
  },
3435
4725
  disabled: isBusy,
3436
4726
  onClick: () => setEditingProxyId(isEditingProxy ? null : acc.id)
3437
- }, [uiIcon("globe", 11), ` ${t("proxy.button")}`]), accounts.length > 1 ? h("button", {
4727
+ }, [uiIcon("globe", 10), ` ${t("proxy.button")}`]), accounts.length > 1 ? h("button", {
3438
4728
  type: "button",
3439
4729
  className: "agy-btn",
3440
4730
  style: {
3441
4731
  ...S.btnDanger,
3442
- padding: "3px 7px"
4732
+ padding: "2px 6px",
4733
+ fontSize: "11px"
3443
4734
  },
3444
4735
  title: t("account.removeTitle"),
3445
4736
  "aria-label": t("account.removeTitle"),
3446
4737
  disabled: isBusy,
3447
4738
  onClick: () => void removeAccount(acc.id, displayAlias)
3448
- }, loadingAction === `remove:${acc.id}` ? renderSpinner() : uiIcon("trash", 12, "var(--agy-danger-text)")) : null)), h("div", { style: S.quotaBox }, renderQuotaBar("Gemini", "google", acc), renderQuotaBar("Claude", "anthropic", acc), renderQuotaBar("GPT-OSS", "openai", acc), isExpanded && allChildModels.length > 0 ? h("div", { style: {
3449
- marginTop: "8px",
3450
- paddingTop: "8px",
3451
- borderTop: "1px solid var(--agy-border-box)"
3452
- } }, h("div", { style: {
3453
- color: "var(--agy-text-secondary)",
3454
- marginBottom: "6px",
3455
- fontWeight: 600,
3456
- fontSize: "11px"
3457
- } }, t("account.models")), allChildModels.map(({ family, model }) => {
3458
- const frac = model.remainingFraction ?? 1;
3459
- const pct = Math.round(frac * 100);
3460
- const w = formatQuotaWindow(t, model.resetTime);
3461
- const pColor = pct <= 20 ? "var(--agy-quota-low-text)" : pct <= 50 ? "var(--agy-quota-med-text)" : "var(--agy-quota-high-text)";
3462
- return h("div", {
3463
- key: model.modelId,
3464
- className: "agy-submodel-row"
3465
- }, h("span", { style: {
3466
- fontWeight: 500,
3467
- color: "var(--agy-text-primary)"
3468
- } }, `[${family}] ${model.displayName || model.modelId}`), h("div", { style: {
4739
+ }, loadingAction === `remove:${acc.id}` ? renderSpinner() : uiIcon("trash", 11, "var(--agy-danger-text)")) : null)), h("div", {
4740
+ key: "agy-body",
4741
+ style: S.quotaBox
4742
+ }, renderQuotaBar("Gemini", "google", acc), h("button", {
4743
+ type: "button",
4744
+ className: "agy-btn",
4745
+ style: {
4746
+ width: "100%",
3469
4747
  display: "flex",
3470
4748
  alignItems: "center",
3471
- gap: "8px"
3472
- } }, h("span", { style: {
3473
- color: pColor,
3474
- fontWeight: 700
3475
- } }, `${pct}%`), w.resetText ? h("span", { style: {
3476
- color: "var(--agy-text-tertiary)",
3477
- fontSize: "10.5px"
3478
- } }, `↻ ${w.resetText}`) : null));
3479
- })) : null), hasCooldown ? h("div", { style: {
3480
- background: "var(--agy-warn-bg)",
3481
- border: "1px solid var(--agy-warn-border)",
3482
- borderRadius: "7px",
3483
- padding: "6px 10px",
3484
- color: "var(--agy-warn-text)",
3485
- fontSize: "11.5px",
3486
- fontWeight: 600,
3487
- marginTop: "8px",
3488
- display: "flex",
3489
- alignItems: "center",
3490
- justifyContent: "space-between"
3491
- } }, h("div", { style: {
4749
+ justifyContent: "center",
4750
+ gap: "5px",
4751
+ marginTop: "6px",
4752
+ padding: "5px 10px",
4753
+ fontSize: "11px",
4754
+ fontWeight: 600,
4755
+ cursor: "pointer",
4756
+ color: isExpanded ? "var(--dsw-alias-state-business-primary, #3b82f6)" : "var(--agy-text-secondary)",
4757
+ background: "var(--agy-bg-subbox)",
4758
+ border: "1px dashed var(--agy-border-box)",
4759
+ borderRadius: "6px"
4760
+ },
4761
+ onClick: () => toggleExpand(acc.id)
4762
+ }, uiIcon(isExpanded ? "chevronUp" : "chevronDown", 10), h("span", null, isExpanded ? t("account.collapseOthers") : t("account.expandOthers"))), isExpanded ? [
4763
+ renderQuotaBar("Claude", "anthropic", acc),
4764
+ renderQuotaBar("GPT-OSS", "openai", acc),
4765
+ allChildModels.length > 0 ? h("div", { style: {
4766
+ marginTop: "8px",
4767
+ paddingTop: "8px",
4768
+ borderTop: "1px solid var(--agy-border-box)"
4769
+ } }, h("div", { style: {
4770
+ color: "var(--agy-text-secondary)",
4771
+ marginBottom: "6px",
4772
+ fontWeight: 600,
4773
+ fontSize: "11px"
4774
+ } }, t("account.models")), allChildModels.map(({ family, model }) => {
4775
+ const frac = model.remainingFraction ?? 1;
4776
+ const pct = Math.round(frac * 100);
4777
+ const w = formatQuotaWindow(t, model.resetTime);
4778
+ const pColor = pct <= 20 ? "var(--agy-quota-low-text)" : pct <= 50 ? "var(--agy-quota-med-text)" : "var(--agy-quota-high-text)";
4779
+ return h("div", {
4780
+ key: `${family}-${model.modelId}`,
4781
+ className: "agy-submodel-row"
4782
+ }, h("span", { style: {
4783
+ fontWeight: 500,
4784
+ color: "var(--agy-text-primary)"
4785
+ } }, `[${family}] ${model.displayName || model.modelId}`), h("div", { style: {
4786
+ display: "flex",
4787
+ alignItems: "center",
4788
+ gap: "8px"
4789
+ } }, h("span", { style: {
4790
+ color: pColor,
4791
+ fontWeight: 700
4792
+ } }, `${pct}%`), w.resetText ? h("span", { style: {
4793
+ color: "var(--agy-text-tertiary)",
4794
+ fontSize: "10.5px"
4795
+ } }, `↻ ${w.resetText}`) : null));
4796
+ })) : null
4797
+ ] : null), hasCooldown ? h("div", {
4798
+ key: "cd-body",
4799
+ style: {
4800
+ background: "var(--agy-warn-bg)",
4801
+ border: "1px solid var(--agy-warn-border)",
4802
+ borderRadius: "7px",
4803
+ padding: "6px 10px",
4804
+ color: "var(--agy-warn-text)",
4805
+ fontSize: "11.5px",
4806
+ fontWeight: 600,
4807
+ marginTop: "8px",
4808
+ display: "flex",
4809
+ alignItems: "center",
4810
+ justifyContent: "space-between"
4811
+ }
4812
+ }, h("div", { style: {
3492
4813
  display: "flex",
3493
4814
  alignItems: "center",
3494
4815
  gap: "6px"
@@ -3504,13 +4825,16 @@ body.dark,
3504
4825
  },
3505
4826
  disabled: isBusy,
3506
4827
  onClick: () => void clearCooldown(acc.id)
3507
- }, loadingAction === `clearCooldown:${acc.id}` ? [renderSpinner(), ""] : [uiIcon("zap", 11, "var(--agy-warn-btn-text)"), ` ${t("account.clearCooldown")}`])) : null, isEditingProxy ? h("div", { style: {
3508
- marginTop: "8px",
3509
- padding: "10px 12px",
3510
- background: "var(--agy-bg-subbox)",
3511
- borderRadius: "7px",
3512
- border: "1px solid var(--agy-border-subbox)"
3513
- } }, h("div", { style: {
4828
+ }, loadingAction === `clearCooldown:${acc.id}` ? [renderSpinner(), ""] : [uiIcon("zap", 11, "var(--agy-warn-btn-text)"), ` ${t("account.clearCooldown")}`])) : null, isEditingProxy ? h("div", {
4829
+ key: "proxy-body",
4830
+ style: {
4831
+ marginTop: "8px",
4832
+ padding: "10px 12px",
4833
+ background: "var(--agy-bg-subbox)",
4834
+ borderRadius: "7px",
4835
+ border: "1px solid var(--agy-border-subbox)"
4836
+ }
4837
+ }, h("div", { style: {
3514
4838
  display: "flex",
3515
4839
  gap: "8px"
3516
4840
  } }, h("input", {
@@ -3543,23 +4867,40 @@ body.dark,
3543
4867
  role: "group",
3544
4868
  "aria-label": t("account.add")
3545
4869
  }, h("div", { style: {
4870
+ display: "flex",
4871
+ alignItems: "center",
4872
+ justifyContent: "space-between",
4873
+ marginBottom: "12px",
4874
+ flexWrap: "wrap",
4875
+ gap: "8px"
4876
+ } }, h("div", { style: {
3546
4877
  fontWeight: 700,
3547
4878
  fontSize: "13.5px",
3548
- marginBottom: "10px",
3549
4879
  display: "flex",
3550
4880
  alignItems: "center",
3551
4881
  gap: "6px",
3552
4882
  color: "var(--agy-text-primary)"
3553
- } }, uiIcon("plus", 13, "var(--agy-btn-primary-bg)"), t("account.add")), !flowActive ? h("div", null, h("div", { style: {
4883
+ } }, uiIcon("plus", 13, "var(--agy-btn-primary-bg)"), t("account.add"))), !flowActive ? h("div", null, h("div", { style: {
3554
4884
  display: "flex",
3555
- gap: "8px"
4885
+ flexDirection: "column",
4886
+ gap: "8px",
4887
+ marginBottom: "12px"
3556
4888
  } }, h("input", {
3557
4889
  style: S.input,
3558
4890
  value: aliasInput,
3559
4891
  placeholder: t("account.aliasPlaceholder"),
3560
4892
  "aria-label": t("aria.aliasInput"),
3561
4893
  onChange: (e) => setAliasInput(e.target.value)
3562
- }), h("button", {
4894
+ }), h("input", {
4895
+ style: S.input,
4896
+ value: addProxyInput,
4897
+ placeholder: t("account.proxyPlaceholder"),
4898
+ "aria-label": t("aria.proxyInput"),
4899
+ onChange: (e) => setAddProxyInput(e.target.value)
4900
+ })), h("div", { style: {
4901
+ display: "flex",
4902
+ gap: "8px"
4903
+ } }, h("button", {
3563
4904
  type: "button",
3564
4905
  className: "agy-btn",
3565
4906
  style: {
@@ -3635,8 +4976,8 @@ body.dark,
3635
4976
  display: "flex",
3636
4977
  alignItems: "center",
3637
4978
  justifyContent: "center"
3638
- } }, h("style", null, GLOBAL_CSS), h("span", { style: S.muted }, [renderSpinner(), t("status.loading")]));
3639
- return h("div", { style: S.container }, h("style", null, GLOBAL_CSS), h("div", { style: S.headerCard }, h("div", { style: {
4979
+ } }, h("span", { style: S.muted }, [renderSpinner(), t("status.loading")]));
4980
+ return h("div", { style: S.container }, h("div", { style: S.headerCard }, h("div", { style: {
3640
4981
  display: "flex",
3641
4982
  alignItems: "center",
3642
4983
  gap: "8px"
@@ -3665,21 +5006,21 @@ body.dark,
3665
5006
  },
3666
5007
  disabled: isBusy,
3667
5008
  onClick: () => void refreshQuota()
3668
- }, loadingAction === "refresh:all" ? [renderSpinner(), t("header.refreshing")] : [uiIcon("refresh", 12, "var(--agy-text-btn)"), ` ${t("header.refreshQuota")}`]))), renderToastBanner(), status?.credentialIsolationLimited === true ? h("div", {
3669
- key: "win-isolation",
3670
- style: {
3671
- display: "flex",
3672
- alignItems: "flex-start",
3673
- gap: "6px",
3674
- padding: "8px 10px",
3675
- marginBottom: "8px",
3676
- background: "var(--agy-amber-soft, rgba(245, 158, 11, 0.12))",
3677
- border: "1px solid rgba(245, 158, 11, 0.45)",
3678
- borderRadius: "7px",
3679
- fontSize: "11.5px",
3680
- color: "var(--agy-text-primary)"
3681
- }
3682
- }, h("span", { style: { flexShrink: 0 } }, "⚠️"), h("span", null, t("pool.winIsolationWarn"))) : null, addAccountSection, renderedAccountCards, h("div", { style: {
5009
+ }, loadingAction === "refresh:all" ? [renderSpinner(), t("header.refreshing")] : [uiIcon("refresh", 12, "var(--agy-text-btn)"), ` ${t("header.refreshQuota")}`]))), renderToastBanner(), addAccountSection, h("div", { style: {
5010
+ display: "flex",
5011
+ alignItems: "center",
5012
+ justifyContent: "space-between",
5013
+ marginBottom: "8px",
5014
+ padding: "0 2px"
5015
+ } }, h("div", { style: {
5016
+ display: "flex",
5017
+ alignItems: "center",
5018
+ gap: "6px"
5019
+ } }, h("span", { style: {
5020
+ fontWeight: 700,
5021
+ fontSize: "12.5px",
5022
+ color: "var(--agy-text-primary)"
5023
+ } }, `账号池 (${accounts.length})`))), renderedAccountCards, h("div", { style: {
3683
5024
  marginTop: "16px",
3684
5025
  paddingTop: "12px",
3685
5026
  borderTop: "1px solid var(--agy-border-divider)"
@@ -3782,9 +5123,19 @@ body.dark,
3782
5123
  };
3783
5124
  /** Modal dialog container rendered into document.body */
3784
5125
  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
+ }, []);
3785
5135
  const t = useAgyTranslation();
3786
5136
  const [isOpen, setIsOpen] = useState(agyModalStore.open);
3787
5137
  useEffect(() => {
5138
+ injectGlobalStyles();
3788
5139
  return agyModalStore.subscribe(() => {
3789
5140
  setIsOpen(agyModalStore.open);
3790
5141
  });
@@ -3800,7 +5151,7 @@ body.dark,
3800
5151
  win.addEventListener?.("keydown", onKey, true);
3801
5152
  return () => win.removeEventListener?.("keydown", onKey, true);
3802
5153
  }, [isOpen]);
3803
- if (!isOpen) return null;
5154
+ if (!isOpen || !isPrimary) return null;
3804
5155
  return h("div", {
3805
5156
  className: "agy-modal-backdrop",
3806
5157
  onClick: (e) => {
@@ -3876,8 +5227,8 @@ body.dark,
3876
5227
  const displayAlias = activeAcc ? activeAcc.defaultAlias || legacyDefault ? activeAcc.systemHome ? t("account.defaultAlias") : t("account.aliasDefault", { number: accounts.indexOf(activeAcc) + 1 }) : activeAcc.alias : "";
3877
5228
  const activeEligible = activeAcc !== void 0 && activeAcc.enabled && !activeAcc.authRequired;
3878
5229
  const activeDetail = activeAcc !== void 0 && activeEligible ? ` · ${t("status.inUse")}: ${displayAlias}${activeAcc.email ? ` (${activeAcc.email})` : ""}` : "";
3879
- const badgeTitle = `${t("header.badgeTitle", { count: accounts.length })}${activeDetail}`;
3880
- const buttonLabel = displayAlias ? `AGY · ${displayAlias}` : `AGY (${accounts.length})`;
5230
+ const badgeTitle = status === null ? t("header.badgeLoading") : `${t("header.badgeTitle", { count: accounts.length })}${activeDetail}`;
5231
+ const buttonLabel = status === null ? "AGY" : displayAlias ? `AGY · ${displayAlias}` : `AGY (${accounts.length})`;
3881
5232
  const badge = h("button", {
3882
5233
  type: "button",
3883
5234
  title: badgeTitle,
@@ -3928,6 +5279,8 @@ body.dark,
3928
5279
  installAgyToolView(ctx);
3929
5280
  ctx.effect(() => installAutoExpandReasoning());
3930
5281
  ctx.effect(() => installMermaidRendering());
5282
+ ctx.effect(() => installImageEnhancer());
5283
+ ctx.effect(() => installDecisionChips());
3931
5284
  }
3932
5285
  //#endregion
3933
5286
  exports.apply = apply;