dsh-agy-link 0.4.44 → 0.4.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +92 -0
- package/README.md +1 -0
- package/dist/client.js +465 -132
- package/dist/index.js +1321 -327
- package/docs/KNOWN-GAPS.md +16 -0
- package/docs/README.en.md +1 -0
- package/docs/README.es.md +1 -0
- package/docs/README.pt-BR.md +1 -0
- package/docs/adr-012-account-pool.md +6 -2
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -39,6 +39,25 @@ window.__ModuleLoader__.load({
|
|
|
39
39
|
"section.label": "Antigravity",
|
|
40
40
|
"code.title": "代码",
|
|
41
41
|
"code.inspect": "检查",
|
|
42
|
+
"tv.command": "命令",
|
|
43
|
+
"tv.write": "写入",
|
|
44
|
+
"tv.edit": "编辑",
|
|
45
|
+
"tv.read": "读取",
|
|
46
|
+
"tv.search": "搜索",
|
|
47
|
+
"tv.webSearch": "网页搜索",
|
|
48
|
+
"tv.list": "列表",
|
|
49
|
+
"tv.delete": "删除",
|
|
50
|
+
"tv.tool": "工具",
|
|
51
|
+
"tv.noOutput": "(无输出)",
|
|
52
|
+
"tv.noMatches": "(无匹配)",
|
|
53
|
+
"tv.noChanges": "(无文本变更)",
|
|
54
|
+
"tv.emptyDir": "(空目录)",
|
|
55
|
+
"tv.noDetail": "(无详情)",
|
|
56
|
+
"tv.hint.expandInspect": "点击展开 · 右键检查",
|
|
57
|
+
"tv.hint.collapseInspect": "点击收起 · 右键检查",
|
|
58
|
+
"tv.hint.expand": "点击展开",
|
|
59
|
+
"tv.hint.collapse": "点击收起",
|
|
60
|
+
"tv.diffMore": "… 其余 {count} 行未渲染",
|
|
42
61
|
"code.copy": "复制",
|
|
43
62
|
"code.copied": "已复制",
|
|
44
63
|
"console.title": "Antigravity 管理控制台",
|
|
@@ -74,6 +93,7 @@ window.__ModuleLoader__.load({
|
|
|
74
93
|
"quota.weekly": "周额度",
|
|
75
94
|
"quota.refreshed": "额度已刷新",
|
|
76
95
|
"proxy.button": "代理",
|
|
96
|
+
"pool.winIsolationWarn": "Windows 提示:agy 的登录凭据存在系统级 Credential Manager(单槽位),多账号池无法隔离凭据——轮巡只切换工作目录,实际仍消耗系统登录账号(issue #45)。",
|
|
77
97
|
"proxy.placeholder": "专属代理 URL(如:http://127.0.0.1:7890;留空则使用全局)",
|
|
78
98
|
"proxy.save": "保存",
|
|
79
99
|
"proxy.saved": "代理已保存",
|
|
@@ -134,6 +154,25 @@ window.__ModuleLoader__.load({
|
|
|
134
154
|
"console.title": "Antigravity Management Console",
|
|
135
155
|
"code.title": "Code",
|
|
136
156
|
"code.inspect": "Inspect",
|
|
157
|
+
"tv.command": "Command",
|
|
158
|
+
"tv.write": "Write",
|
|
159
|
+
"tv.edit": "Edit",
|
|
160
|
+
"tv.read": "Read",
|
|
161
|
+
"tv.search": "Search",
|
|
162
|
+
"tv.webSearch": "Web Search",
|
|
163
|
+
"tv.list": "List",
|
|
164
|
+
"tv.delete": "Delete",
|
|
165
|
+
"tv.tool": "Tool",
|
|
166
|
+
"tv.noOutput": "(no output)",
|
|
167
|
+
"tv.noMatches": "(no matches)",
|
|
168
|
+
"tv.noChanges": "(no textual changes)",
|
|
169
|
+
"tv.emptyDir": "(empty directory)",
|
|
170
|
+
"tv.noDetail": "(no detail)",
|
|
171
|
+
"tv.hint.expandInspect": "Click to expand · right-click to inspect",
|
|
172
|
+
"tv.hint.collapseInspect": "Click to collapse · right-click to inspect",
|
|
173
|
+
"tv.hint.expand": "Click to expand",
|
|
174
|
+
"tv.hint.collapse": "Click to collapse",
|
|
175
|
+
"tv.diffMore": "… {count} more lines not rendered",
|
|
137
176
|
"code.copy": "Copy",
|
|
138
177
|
"code.copied": "Copied",
|
|
139
178
|
"status.ready": "Ready",
|
|
@@ -168,6 +207,7 @@ window.__ModuleLoader__.load({
|
|
|
168
207
|
"quota.weekly": "Weekly quota",
|
|
169
208
|
"quota.refreshed": "Quota refreshed",
|
|
170
209
|
"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).",
|
|
171
211
|
"proxy.placeholder": "Dedicated proxy URL (for example: http://127.0.0.1:7890; leave blank to use the global proxy)",
|
|
172
212
|
"proxy.save": "Save",
|
|
173
213
|
"proxy.saved": "Proxy saved",
|
|
@@ -228,6 +268,25 @@ window.__ModuleLoader__.load({
|
|
|
228
268
|
"console.title": "Console de gerenciamento do Antigravity",
|
|
229
269
|
"code.title": "Código",
|
|
230
270
|
"code.inspect": "Inspecionar",
|
|
271
|
+
"tv.command": "Comando",
|
|
272
|
+
"tv.write": "Escrever",
|
|
273
|
+
"tv.edit": "Editar",
|
|
274
|
+
"tv.read": "Ler",
|
|
275
|
+
"tv.search": "Buscar",
|
|
276
|
+
"tv.webSearch": "Busca na web",
|
|
277
|
+
"tv.list": "Listar",
|
|
278
|
+
"tv.delete": "Excluir",
|
|
279
|
+
"tv.tool": "Ferramenta",
|
|
280
|
+
"tv.noOutput": "(sem saída)",
|
|
281
|
+
"tv.noMatches": "(nenhuma correspondência)",
|
|
282
|
+
"tv.noChanges": "(sem alterações de texto)",
|
|
283
|
+
"tv.emptyDir": "(diretório vazio)",
|
|
284
|
+
"tv.noDetail": "(sem detalhes)",
|
|
285
|
+
"tv.hint.expandInspect": "Clique para expandir · clique direito para inspecionar",
|
|
286
|
+
"tv.hint.collapseInspect": "Clique para recolher · clique direito para inspecionar",
|
|
287
|
+
"tv.hint.expand": "Clique para expandir",
|
|
288
|
+
"tv.hint.collapse": "Clique para recolher",
|
|
289
|
+
"tv.diffMore": "… {count} linhas restantes não renderizadas",
|
|
231
290
|
"code.copy": "Copiar",
|
|
232
291
|
"code.copied": "Copiado",
|
|
233
292
|
"status.ready": "Pronto",
|
|
@@ -262,6 +321,7 @@ window.__ModuleLoader__.load({
|
|
|
262
321
|
"quota.weekly": "Cota semanal",
|
|
263
322
|
"quota.refreshed": "Cota atualizada",
|
|
264
323
|
"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).",
|
|
265
325
|
"proxy.placeholder": "URL do proxy exclusivo (por exemplo: http://127.0.0.1:7890; deixe vazio para usar o proxy global)",
|
|
266
326
|
"proxy.save": "Salvar",
|
|
267
327
|
"proxy.saved": "Proxy salvo",
|
|
@@ -322,6 +382,25 @@ window.__ModuleLoader__.load({
|
|
|
322
382
|
"console.title": "Consola de administración de Antigravity",
|
|
323
383
|
"code.title": "Código",
|
|
324
384
|
"code.inspect": "Inspeccionar",
|
|
385
|
+
"tv.command": "Comando",
|
|
386
|
+
"tv.write": "Escribir",
|
|
387
|
+
"tv.edit": "Editar",
|
|
388
|
+
"tv.read": "Leer",
|
|
389
|
+
"tv.search": "Buscar",
|
|
390
|
+
"tv.webSearch": "Búsqueda web",
|
|
391
|
+
"tv.list": "Listar",
|
|
392
|
+
"tv.delete": "Eliminar",
|
|
393
|
+
"tv.tool": "Herramienta",
|
|
394
|
+
"tv.noOutput": "(sin salida)",
|
|
395
|
+
"tv.noMatches": "(sin coincidencias)",
|
|
396
|
+
"tv.noChanges": "(sin cambios de texto)",
|
|
397
|
+
"tv.emptyDir": "(directorio vacío)",
|
|
398
|
+
"tv.noDetail": "(sin detalles)",
|
|
399
|
+
"tv.hint.expandInspect": "Clic para expandir · clic derecho para inspeccionar",
|
|
400
|
+
"tv.hint.collapseInspect": "Clic para contraer · clic derecho para inspeccionar",
|
|
401
|
+
"tv.hint.expand": "Clic para expandir",
|
|
402
|
+
"tv.hint.collapse": "Clic para contraer",
|
|
403
|
+
"tv.diffMore": "… {count} líneas restantes no renderizadas",
|
|
325
404
|
"code.copy": "Copiar",
|
|
326
405
|
"code.copied": "Copiado",
|
|
327
406
|
"status.ready": "Listo",
|
|
@@ -356,6 +435,7 @@ window.__ModuleLoader__.load({
|
|
|
356
435
|
"quota.weekly": "Cuota semanal",
|
|
357
436
|
"quota.refreshed": "Cuota actualizada",
|
|
358
437
|
"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).",
|
|
359
439
|
"proxy.placeholder": "URL de proxy exclusivo (por ejemplo: http://127.0.0.1:7890; déjelo vacío para usar el proxy global)",
|
|
360
440
|
"proxy.save": "Guardar",
|
|
361
441
|
"proxy.saved": "Proxy guardado",
|
|
@@ -705,7 +785,9 @@ window.__ModuleLoader__.load({
|
|
|
705
785
|
"grep_search",
|
|
706
786
|
"search",
|
|
707
787
|
"search_file_content",
|
|
708
|
-
"grep"
|
|
788
|
+
"grep",
|
|
789
|
+
"search_web",
|
|
790
|
+
"web_search"
|
|
709
791
|
]);
|
|
710
792
|
const LIST_TOOLS = /* @__PURE__ */ new Set(["list_dir", "ls"]);
|
|
711
793
|
const DELETE_TOOLS = /* @__PURE__ */ new Set([
|
|
@@ -833,15 +915,30 @@ window.__ModuleLoader__.load({
|
|
|
833
915
|
function cls(...names) {
|
|
834
916
|
return names.filter((n) => typeof n === "string" && n !== "").join(" ");
|
|
835
917
|
}
|
|
836
|
-
|
|
918
|
+
/**
|
|
919
|
+
* Locale lookup with an English fallback: the mirror card renders through
|
|
920
|
+
* host-provided `t` when the registration declares the namespace, but tests
|
|
921
|
+
* and hosts without the seat call it bare. The old literals were mixed
|
|
922
|
+
* 中文 and English as BOTH fallback and primary, so non-Chinese users saw
|
|
923
|
+
* Chinese buttons on mirror cards.
|
|
924
|
+
*/
|
|
925
|
+
function tr(t, key, fallback, params) {
|
|
926
|
+
if (typeof t === "function") try {
|
|
927
|
+
const v = t(key, params);
|
|
928
|
+
if (typeof v === "string" && v !== "" && v !== key) return v;
|
|
929
|
+
} catch {}
|
|
930
|
+
if (params !== void 0 && params.count !== void 0 && fallback.includes("{count}")) return fallback.replace("{count}", String(params.count));
|
|
931
|
+
return fallback;
|
|
932
|
+
}
|
|
933
|
+
function displayTitle(model, t) {
|
|
837
934
|
switch (model.kind) {
|
|
838
|
-
case "terminal": return "Command";
|
|
839
|
-
case "diff": return model.tool === "write_to_file" || model.tool === "write_file" || model.tool === "create_file" ? "Write" : "Edit";
|
|
840
|
-
case "read": return "Read";
|
|
841
|
-
case "search": return "Search";
|
|
842
|
-
case "list": return "List";
|
|
843
|
-
case "delete": return "Delete";
|
|
844
|
-
default: return model.tool ? model.tool.replace(/_/g, " ") : "Tool";
|
|
935
|
+
case "terminal": return tr(t, "tv.command", "Command");
|
|
936
|
+
case "diff": return model.tool === "write_to_file" || model.tool === "write_file" || model.tool === "create_file" ? tr(t, "tv.write", "Write") : tr(t, "tv.edit", "Edit");
|
|
937
|
+
case "read": return tr(t, "tv.read", "Read");
|
|
938
|
+
case "search": return model.tool === "search_web" || model.tool === "web_search" ? tr(t, "tv.webSearch", "Web Search") : tr(t, "tv.search", "Search");
|
|
939
|
+
case "list": return tr(t, "tv.list", "List");
|
|
940
|
+
case "delete": return tr(t, "tv.delete", "Delete");
|
|
941
|
+
default: return model.tool ? model.tool.replace(/_/g, " ") : tr(t, "tv.tool", "Tool");
|
|
845
942
|
}
|
|
846
943
|
}
|
|
847
944
|
function displaySummary(model, cwd, home) {
|
|
@@ -851,7 +948,7 @@ window.__ModuleLoader__.load({
|
|
|
851
948
|
const rawPath = model.path ?? "";
|
|
852
949
|
return rawPath !== "" ? relativize(rawPath, cwd, home) : model.title;
|
|
853
950
|
}
|
|
854
|
-
if (model.kind === "search") return model.title.replace(/^Search\s*/i, "") || model.title;
|
|
951
|
+
if (model.kind === "search") return model.title.replace(/^(Web search|Search)\s*/i, "") || model.title;
|
|
855
952
|
if (model.kind === "list") return model.title.replace(/^List\s*(directory\s*)?/i, "") || model.title;
|
|
856
953
|
return model.title;
|
|
857
954
|
}
|
|
@@ -865,16 +962,18 @@ window.__ModuleLoader__.load({
|
|
|
865
962
|
if (oldLines === 0) return `+${newLines}`;
|
|
866
963
|
return `+${newLines} -${oldLines}`;
|
|
867
964
|
}
|
|
868
|
-
function CopyButton({ text, labels }) {
|
|
965
|
+
function CopyButton({ text, labels, t }) {
|
|
869
966
|
const [copied, setCopied] = react().useState(false);
|
|
870
|
-
const copyLabel = labels?.[0] ?? "
|
|
871
|
-
const copiedLabel = labels?.[1] ?? "
|
|
967
|
+
const copyLabel = labels?.[0] ?? tr(t, "code.copy", "Copy");
|
|
968
|
+
const copiedLabel = labels?.[1] ?? tr(t, "code.copied", "Copied");
|
|
872
969
|
const onCopy = (e) => {
|
|
873
970
|
e.stopPropagation();
|
|
874
971
|
if (typeof navigator !== "undefined" && navigator.clipboard) navigator.clipboard.writeText(text).then(() => {
|
|
875
972
|
setCopied(true);
|
|
876
973
|
setTimeout(() => setCopied(false), 1500);
|
|
877
|
-
}).catch(() => {
|
|
974
|
+
}).catch(() => {
|
|
975
|
+
setCopied(false);
|
|
976
|
+
});
|
|
878
977
|
};
|
|
879
978
|
return hx("button", {
|
|
880
979
|
type: "button",
|
|
@@ -883,39 +982,51 @@ window.__ModuleLoader__.load({
|
|
|
883
982
|
title: copied ? copiedLabel : copyLabel
|
|
884
983
|
}, copied ? IconCheckOutline14(11) : IconCopyOutline16(11), hx("span", null, copied ? copiedLabel : copyLabel));
|
|
885
984
|
}
|
|
886
|
-
|
|
985
|
+
/** Per-side render cap: a 5000-line write_to_file used to build 10k DOM rows
|
|
986
|
+
* inside a max-height:280px pane (99% of them invisible). */
|
|
987
|
+
const DIFF_MAX_LINES = 400;
|
|
988
|
+
function DiffBody({ model, t }) {
|
|
887
989
|
const h = hx;
|
|
888
990
|
const oldText = model.oldText ?? "";
|
|
889
991
|
const newText = model.newText ?? "";
|
|
890
992
|
const rows = [];
|
|
993
|
+
const moreRow = (count, key) => h("div", {
|
|
994
|
+
key,
|
|
995
|
+
className: "agy-tv-diff-line",
|
|
996
|
+
style: { color: "var(--dsw-alias-label-tertiary)" }
|
|
997
|
+
}, tr(t, "tv.diffMore", "… {count} more lines not rendered", { count }));
|
|
891
998
|
if (oldText !== "") {
|
|
892
999
|
const lines = oldText.split("\n");
|
|
893
|
-
|
|
1000
|
+
const shown = Math.min(lines.length, DIFF_MAX_LINES);
|
|
1001
|
+
for (let i = 0; i < shown; i++) {
|
|
894
1002
|
const line = lines[i];
|
|
895
1003
|
rows.push(h("div", {
|
|
896
1004
|
key: "del-" + i,
|
|
897
1005
|
className: "agy-tv-diff-line agy-tv-diff-del"
|
|
898
1006
|
}, h("span", { className: "agy-tv-diff-marker" }, "-"), h("span", { style: { flex: 1 } }, line === "" ? " " : line)));
|
|
899
1007
|
}
|
|
1008
|
+
if (lines.length > shown) rows.push(moreRow(lines.length - shown, "del-more"));
|
|
900
1009
|
}
|
|
901
1010
|
if (newText !== "") {
|
|
902
1011
|
const lines = newText.split("\n");
|
|
903
|
-
|
|
1012
|
+
const shown = Math.min(lines.length, DIFF_MAX_LINES);
|
|
1013
|
+
for (let i = 0; i < shown; i++) {
|
|
904
1014
|
const line = lines[i];
|
|
905
1015
|
rows.push(h("div", {
|
|
906
1016
|
key: "add-" + i,
|
|
907
1017
|
className: "agy-tv-diff-line agy-tv-diff-add"
|
|
908
1018
|
}, h("span", { className: "agy-tv-diff-marker" }, "+"), h("span", { style: { flex: 1 } }, line === "" ? " " : line)));
|
|
909
1019
|
}
|
|
1020
|
+
if (lines.length > shown) rows.push(moreRow(lines.length - shown, "add-more"));
|
|
910
1021
|
}
|
|
911
1022
|
if (rows.length === 0) rows.push(h("div", {
|
|
912
1023
|
key: "empty",
|
|
913
1024
|
className: "agy-tv-diff-line",
|
|
914
1025
|
style: { color: "var(--dsw-alias-label-tertiary)" }
|
|
915
|
-
}, "(no textual changes)"));
|
|
1026
|
+
}, tr(t, "tv.noChanges", "(no textual changes)")));
|
|
916
1027
|
return h("div", { className: "agy-tv-diff-list" }, ...rows);
|
|
917
1028
|
}
|
|
918
|
-
function CardBody({ model, openFile, cwd, home, inspect }) {
|
|
1029
|
+
function CardBody({ model, openFile, cwd, home, inspect, t }) {
|
|
919
1030
|
const h = hx;
|
|
920
1031
|
const inspectNode = inspect !== void 0 ? h("div", {
|
|
921
1032
|
key: "ins",
|
|
@@ -924,10 +1035,10 @@ window.__ModuleLoader__.load({
|
|
|
924
1035
|
type: "button",
|
|
925
1036
|
className: "agy-tv-inspect-btn",
|
|
926
1037
|
onClick: inspect
|
|
927
|
-
}, IconInspectOutline12(12), "
|
|
1038
|
+
}, IconInspectOutline12(12), tr(t, "code.inspect", "Inspect"))) : null;
|
|
928
1039
|
switch (model.kind) {
|
|
929
1040
|
case "terminal": {
|
|
930
|
-
const rawBody = model.output !== void 0 && model.output !== "" ? trimTrailingBlankLines(model.output) : "(no output)";
|
|
1041
|
+
const rawBody = model.output !== void 0 && model.output !== "" ? trimTrailingBlankLines(model.output) : tr(t, "tv.noOutput", "(no output)");
|
|
931
1042
|
const copyText = model.output !== void 0 && model.output !== "" ? model.output : model.command ?? "";
|
|
932
1043
|
return h("div", { className: "agy-tv-card" }, h("div", { className: "agy-tv-card-header" }, h("div", { className: "agy-tv-card-header-left" }, h("span", { className: "agy-tv-prompt-glyph" }, "❯"), ...model.cwd ? [h("span", {
|
|
933
1044
|
key: "cwd",
|
|
@@ -935,7 +1046,10 @@ window.__ModuleLoader__.load({
|
|
|
935
1046
|
}, model.cwd)] : [], h("span", {
|
|
936
1047
|
className: "agy-tv-card-cmd",
|
|
937
1048
|
title: model.command
|
|
938
|
-
}, model.command ?? "")), h(CopyButton, {
|
|
1049
|
+
}, model.command ?? "")), h(CopyButton, {
|
|
1050
|
+
text: copyText,
|
|
1051
|
+
t
|
|
1052
|
+
})), h("pre", { className: "agy-tv-card-content" }, clip(rawBody, 16e3)), inspectNode);
|
|
939
1053
|
}
|
|
940
1054
|
case "diff": {
|
|
941
1055
|
const pathLabel = relativize(model.path ?? "file", cwd, home);
|
|
@@ -948,38 +1062,51 @@ window.__ModuleLoader__.load({
|
|
|
948
1062
|
model,
|
|
949
1063
|
openFile,
|
|
950
1064
|
cwd,
|
|
951
|
-
home
|
|
1065
|
+
home,
|
|
1066
|
+
t
|
|
952
1067
|
}), inspectNode);
|
|
953
1068
|
}
|
|
954
1069
|
case "read": {
|
|
955
1070
|
const pathLabel = relativize(model.path ?? "file", cwd, home);
|
|
956
|
-
const rawBody = model.output !== void 0 && model.output !== "" ? trimTrailingBlankLines(model.output) : "(no output)";
|
|
957
|
-
return h("div", { className: "agy-tv-card" }, h("div", { className: "agy-tv-card-header" }, h("div", { className: "agy-tv-card-header-left" }, IconBrowseOutline16(13), h("span", { className: "agy-tv-card-path" }, pathLabel)), h(CopyButton, {
|
|
1071
|
+
const rawBody = model.output !== void 0 && model.output !== "" ? trimTrailingBlankLines(model.output) : tr(t, "tv.noOutput", "(no output)");
|
|
1072
|
+
return h("div", { className: "agy-tv-card" }, h("div", { className: "agy-tv-card-header" }, h("div", { className: "agy-tv-card-header-left" }, IconBrowseOutline16(13), h("span", { className: "agy-tv-card-path" }, pathLabel)), h(CopyButton, {
|
|
1073
|
+
text: model.output ?? "",
|
|
1074
|
+
t
|
|
1075
|
+
})), h("pre", { className: "agy-tv-card-content" }, clip(rawBody, 16e3)), inspectNode);
|
|
958
1076
|
}
|
|
959
1077
|
case "search": {
|
|
960
|
-
const rawBody = model.output !== void 0 && model.output !== "" ? trimTrailingBlankLines(model.output) : "(no matches)";
|
|
961
|
-
return h("div", { className: "agy-tv-card" }, h("div", { className: "agy-tv-card-header" }, h("div", { className: "agy-tv-card-header-left" }, IconSearchOutline16(13), h("span", { className: "agy-tv-card-path" }, model.title)), h(CopyButton, {
|
|
1078
|
+
const rawBody = model.output !== void 0 && model.output !== "" ? trimTrailingBlankLines(model.output) : tr(t, "tv.noMatches", "(no matches)");
|
|
1079
|
+
return h("div", { className: "agy-tv-card" }, h("div", { className: "agy-tv-card-header" }, h("div", { className: "agy-tv-card-header-left" }, IconSearchOutline16(13), h("span", { className: "agy-tv-card-path" }, model.title)), h(CopyButton, {
|
|
1080
|
+
text: model.output ?? "",
|
|
1081
|
+
t
|
|
1082
|
+
})), h("pre", { className: "agy-tv-card-content" }, clip(rawBody, 16e3)), inspectNode);
|
|
962
1083
|
}
|
|
963
1084
|
case "list": {
|
|
964
|
-
const rawBody = model.output !== void 0 && model.output !== "" ? trimTrailingBlankLines(model.output) : "(empty directory)";
|
|
965
|
-
return h("div", { className: "agy-tv-card" }, h("div", { className: "agy-tv-card-header" }, h("div", { className: "agy-tv-card-header-left" }, IconBrowseOutline16(13), h("span", { className: "agy-tv-card-path" }, model.title)), h(CopyButton, {
|
|
1085
|
+
const rawBody = model.output !== void 0 && model.output !== "" ? trimTrailingBlankLines(model.output) : tr(t, "tv.emptyDir", "(empty directory)");
|
|
1086
|
+
return h("div", { className: "agy-tv-card" }, h("div", { className: "agy-tv-card-header" }, h("div", { className: "agy-tv-card-header-left" }, IconBrowseOutline16(13), h("span", { className: "agy-tv-card-path" }, model.title)), h(CopyButton, {
|
|
1087
|
+
text: model.output ?? "",
|
|
1088
|
+
t
|
|
1089
|
+
})), h("pre", { className: "agy-tv-card-content" }, clip(rawBody, 16e3)), inspectNode);
|
|
966
1090
|
}
|
|
967
1091
|
default: {
|
|
968
1092
|
const copyText = model.output !== void 0 && model.output !== "" ? model.output : model.raw ?? "";
|
|
969
|
-
const rawBody = model.output !== void 0 && model.output !== "" ? trimTrailingBlankLines(model.output) : model.raw !== void 0 && model.raw !== "" ? clip(model.raw, 4e3) : "(no detail)";
|
|
970
|
-
return h("div", { className: "agy-tv-card" }, h("div", { className: "agy-tv-card-header" }, h("div", { className: "agy-tv-card-header-left" }, IconCodeOutline16(13), h("span", { className: "agy-tv-card-path" }, model.tool || "Tool")), h(CopyButton, {
|
|
1093
|
+
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)");
|
|
1094
|
+
return h("div", { className: "agy-tv-card" }, h("div", { className: "agy-tv-card-header" }, h("div", { className: "agy-tv-card-header-left" }, IconCodeOutline16(13), h("span", { className: "agy-tv-card-path" }, model.tool || "Tool")), h(CopyButton, {
|
|
1095
|
+
text: copyText,
|
|
1096
|
+
t
|
|
1097
|
+
})), h("pre", { className: "agy-tv-card-content" }, clip(rawBody, 16e3)), inspectNode);
|
|
971
1098
|
}
|
|
972
1099
|
}
|
|
973
1100
|
}
|
|
974
1101
|
function AgyMirrorToolView(props) {
|
|
975
1102
|
const [open, setOpen] = useToggle(false);
|
|
976
1103
|
const h = hx;
|
|
977
|
-
const { block, cwd, home, openFile, inspect } = props;
|
|
1104
|
+
const { block, cwd, home, openFile, inspect, t } = props;
|
|
978
1105
|
const settle = isSettled(block);
|
|
979
1106
|
const err = isError(block);
|
|
980
1107
|
const model = mirrorCardModel(block, cwd, home);
|
|
981
1108
|
const state = !settle ? "run" : err ? "err" : "ok";
|
|
982
|
-
const title = displayTitle(model);
|
|
1109
|
+
const title = displayTitle(model, t);
|
|
983
1110
|
const summary = displaySummary(model, cwd, home);
|
|
984
1111
|
const stat = diffStat(model);
|
|
985
1112
|
const preview = !open && model.kind !== "diff" ? previewLine(model, cwd, home) : void 0;
|
|
@@ -1016,7 +1143,7 @@ window.__ModuleLoader__.load({
|
|
|
1016
1143
|
setOpen();
|
|
1017
1144
|
}
|
|
1018
1145
|
},
|
|
1019
|
-
title: inspect !== void 0 ? open ? "Click to collapse · right-click to inspect" : "Click to expand · right-click to inspect" : open ? "Click to collapse" : "Click to expand",
|
|
1146
|
+
title: inspect !== void 0 ? open ? tr(t, "tv.hint.collapseInspect", "Click to collapse · right-click to inspect") : tr(t, "tv.hint.expandInspect", "Click to expand · right-click to inspect") : open ? tr(t, "tv.hint.collapse", "Click to collapse") : tr(t, "tv.hint.expand", "Click to expand"),
|
|
1020
1147
|
onContextMenu: inspect !== void 0 ? (e) => {
|
|
1021
1148
|
e.preventDefault();
|
|
1022
1149
|
inspect();
|
|
@@ -1044,7 +1171,8 @@ window.__ModuleLoader__.load({
|
|
|
1044
1171
|
openFile,
|
|
1045
1172
|
cwd,
|
|
1046
1173
|
home,
|
|
1047
|
-
inspect
|
|
1174
|
+
inspect,
|
|
1175
|
+
t
|
|
1048
1176
|
}))] : []);
|
|
1049
1177
|
}
|
|
1050
1178
|
/** Extract the agy mirror cursor (and tool name) from a run_code program. */
|
|
@@ -1116,7 +1244,7 @@ window.__ModuleLoader__.load({
|
|
|
1116
1244
|
setOpen();
|
|
1117
1245
|
}
|
|
1118
1246
|
},
|
|
1119
|
-
title: inspect !== void 0 ? open ? "Click to collapse · right-click to inspect" : "Click to expand · right-click to inspect" : open ? "Click to collapse" : "Click to expand",
|
|
1247
|
+
title: inspect !== void 0 ? open ? tr(t, "tv.hint.collapseInspect", "Click to collapse · right-click to inspect") : tr(t, "tv.hint.expandInspect", "Click to expand · right-click to inspect") : open ? tr(t, "tv.hint.collapse", "Click to collapse") : tr(t, "tv.hint.expand", "Click to expand"),
|
|
1120
1248
|
onContextMenu: inspect !== void 0 ? (e) => {
|
|
1121
1249
|
e.preventDefault();
|
|
1122
1250
|
inspect();
|
|
@@ -1159,18 +1287,21 @@ window.__ModuleLoader__.load({
|
|
|
1159
1287
|
const block = typed?.block;
|
|
1160
1288
|
const mirror = parseAgyMirrorFromCode(block !== void 0 ? parsedArgsRaw(block) : "{}");
|
|
1161
1289
|
if (mirror === null) return AgyCodeToolView(typed);
|
|
1162
|
-
return AgyMirrorToolView({
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1290
|
+
return AgyMirrorToolView({
|
|
1291
|
+
block: {
|
|
1292
|
+
...block,
|
|
1293
|
+
call: {
|
|
1294
|
+
...block?.call ?? {},
|
|
1295
|
+
name: "agy_tool",
|
|
1296
|
+
argsRaw: JSON.stringify({
|
|
1297
|
+
run: mirror.run,
|
|
1298
|
+
step: mirror.step,
|
|
1299
|
+
...mirror.tool !== void 0 ? { tool: mirror.tool } : {}
|
|
1300
|
+
})
|
|
1301
|
+
}
|
|
1302
|
+
},
|
|
1303
|
+
t: typed?.t
|
|
1304
|
+
});
|
|
1174
1305
|
}
|
|
1175
1306
|
function installAgyToolView(ctx) {
|
|
1176
1307
|
ctx.slots.inject("tool.call.toolview", () => {
|
|
@@ -1178,7 +1309,8 @@ window.__ModuleLoader__.load({
|
|
|
1178
1309
|
name: "tool.call.toolview",
|
|
1179
1310
|
key: "agy_tool",
|
|
1180
1311
|
id: "agy-tool-view",
|
|
1181
|
-
label: "Antigravity tool"
|
|
1312
|
+
label: "Antigravity tool",
|
|
1313
|
+
locale: NS
|
|
1182
1314
|
}, AgyMirrorToolView);
|
|
1183
1315
|
const d2 = ctx.slots.register({
|
|
1184
1316
|
name: "tool.call.toolview",
|
|
@@ -1601,12 +1733,25 @@ div[data-agy-mermaid-svg][data-agy-mermaid-error] {
|
|
|
1601
1733
|
white-space: pre-wrap;
|
|
1602
1734
|
padding: 10px 12px;
|
|
1603
1735
|
}
|
|
1736
|
+
/* Prevent Mermaid's internal error DOM or leaked temporary nodes from escaping into document.body.
|
|
1737
|
+
The generic .error-icon/.error-text classes are scoped to OUR mounts and the
|
|
1738
|
+
leaked-body id shapes only — unqualified, they hid host UI using the same
|
|
1739
|
+
class names. */
|
|
1740
|
+
div[data-agy-mermaid-svg] .error-icon,
|
|
1741
|
+
div[data-agy-mermaid-svg] .error-text,
|
|
1742
|
+
body > [id^="dagy-mmd"] .error-icon,
|
|
1743
|
+
body > [id^="iagy-mmd"] .error-icon {
|
|
1744
|
+
display: none !important;
|
|
1745
|
+
}
|
|
1604
1746
|
`;
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1747
|
+
/**
|
|
1748
|
+
* The bundle ships mermaid.min.js and serves it from the plugin route. There
|
|
1749
|
+
* is deliberately NO public-CDN fallback: a floating-version, unsigned
|
|
1750
|
+
* script executing inside the DSH web origin (with reach into every local
|
|
1751
|
+
* HTTP API) is a supply-chain hazard that outweighs offline convenience.
|
|
1752
|
+
* When the local asset is missing the source block simply stays visible.
|
|
1753
|
+
*/
|
|
1754
|
+
const CDN_URLS = ["/plugins/agy-link/mermaid.min.js"];
|
|
1610
1755
|
let loadPromise = null;
|
|
1611
1756
|
let loadFailedAt = 0;
|
|
1612
1757
|
const LOAD_RETRY_MS = 6e4;
|
|
@@ -1624,9 +1769,13 @@ div[data-agy-mermaid-svg][data-agy-mermaid-error] {
|
|
|
1624
1769
|
const s = document.createElement("script");
|
|
1625
1770
|
s.src = src;
|
|
1626
1771
|
s.async = true;
|
|
1772
|
+
let settled = false;
|
|
1627
1773
|
const done = (ok) => {
|
|
1774
|
+
if (settled) return;
|
|
1775
|
+
settled = true;
|
|
1628
1776
|
s.removeEventListener("load", onLoad);
|
|
1629
1777
|
s.removeEventListener("error", onError);
|
|
1778
|
+
if (!ok) s.remove();
|
|
1630
1779
|
resolve(ok);
|
|
1631
1780
|
};
|
|
1632
1781
|
const onLoad = () => done(true);
|
|
@@ -1649,7 +1798,8 @@ div[data-agy-mermaid-svg][data-agy-mermaid-error] {
|
|
|
1649
1798
|
startOnLoad: false,
|
|
1650
1799
|
securityLevel: "strict",
|
|
1651
1800
|
theme: "neutral",
|
|
1652
|
-
fontFamily: "inherit"
|
|
1801
|
+
fontFamily: "inherit",
|
|
1802
|
+
suppressErrorRendering: true
|
|
1653
1803
|
});
|
|
1654
1804
|
} catch {}
|
|
1655
1805
|
return window.mermaid;
|
|
@@ -1731,6 +1881,16 @@ div[data-agy-mermaid-svg][data-agy-mermaid-error] {
|
|
|
1731
1881
|
function readSource(block) {
|
|
1732
1882
|
return ((block.querySelector("[data-code-block-content] code") ?? block.querySelector("[data-code-block-content] pre") ?? block.querySelector("[data-code-block-content]"))?.textContent ?? "").trim();
|
|
1733
1883
|
}
|
|
1884
|
+
function cleanupTempElements(id) {
|
|
1885
|
+
if (typeof document === "undefined") return;
|
|
1886
|
+
if (id) {
|
|
1887
|
+
document.getElementById("d" + id)?.remove();
|
|
1888
|
+
document.getElementById("i" + id)?.remove();
|
|
1889
|
+
document.getElementById(id)?.remove();
|
|
1890
|
+
}
|
|
1891
|
+
const stray = document.querySelectorAll("body > [id^=\"dagy-mmd\"], body > [id^=\"iagy-mmd\"], body > [id^=\"d_agy-mmd\"], body > [id^=\"i_agy-mmd\"], body > [id^=\"agy-mmd-\"]");
|
|
1892
|
+
for (let i = 0; i < stray.length; i++) stray[i]?.remove();
|
|
1893
|
+
}
|
|
1734
1894
|
async function renderInto(block, source) {
|
|
1735
1895
|
block.querySelector("[data-agy-mermaid-svg]")?.remove();
|
|
1736
1896
|
const mount = document.createElement("div");
|
|
@@ -1743,28 +1903,32 @@ div[data-agy-mermaid-svg][data-agy-mermaid-error] {
|
|
|
1743
1903
|
mount.textContent = "Mermaid renderer unavailable (offline). Diagram source stays below.";
|
|
1744
1904
|
return;
|
|
1745
1905
|
}
|
|
1906
|
+
renderSeq += 1;
|
|
1907
|
+
const id = "agy-mmd-" + renderSeq;
|
|
1746
1908
|
try {
|
|
1747
|
-
|
|
1748
|
-
const
|
|
1749
|
-
const { svg } = await api.render(id, source);
|
|
1909
|
+
if (typeof api.parse === "function") await api.parse(source);
|
|
1910
|
+
const { svg } = await api.render(id, source, mount);
|
|
1750
1911
|
mount.innerHTML = svg;
|
|
1751
1912
|
block.setAttribute("data-agy-mermaid", "done");
|
|
1752
1913
|
} catch (e) {
|
|
1753
1914
|
block.setAttribute("data-agy-mermaid", "error");
|
|
1754
1915
|
mount.setAttribute("data-agy-mermaid-error", "1");
|
|
1755
1916
|
mount.textContent = "Mermaid render failed: " + (e instanceof Error ? e.message : String(e));
|
|
1917
|
+
} finally {
|
|
1918
|
+
cleanupTempElements(id);
|
|
1756
1919
|
}
|
|
1757
1920
|
}
|
|
1758
|
-
let scanTimer = null;
|
|
1759
|
-
function scheduleScan() {
|
|
1760
|
-
if (scanTimer !== null) return;
|
|
1761
|
-
scanTimer = setTimeout(() => {
|
|
1762
|
-
scanTimer = null;
|
|
1921
|
+
let scanTimer$1 = null;
|
|
1922
|
+
function scheduleScan$1() {
|
|
1923
|
+
if (scanTimer$1 !== null) return;
|
|
1924
|
+
scanTimer$1 = setTimeout(() => {
|
|
1925
|
+
scanTimer$1 = null;
|
|
1763
1926
|
scan();
|
|
1764
1927
|
}, 150);
|
|
1765
1928
|
}
|
|
1766
1929
|
function scan() {
|
|
1767
1930
|
if (typeof document === "undefined") return;
|
|
1931
|
+
cleanupTempElements();
|
|
1768
1932
|
const blocks = document.querySelectorAll(".md-code-block");
|
|
1769
1933
|
for (let i = 0; i < blocks.length; i++) {
|
|
1770
1934
|
const block = blocks[i];
|
|
@@ -1779,14 +1943,25 @@ div[data-agy-mermaid-svg][data-agy-mermaid-error] {
|
|
|
1779
1943
|
renderInto(block, source);
|
|
1780
1944
|
}
|
|
1781
1945
|
}
|
|
1946
|
+
let activeObserver$1 = null;
|
|
1947
|
+
let domContentLoadedHandler$1 = null;
|
|
1948
|
+
/**
|
|
1949
|
+
* Install the mermaid overlay. Returns a disposer that disconnects the
|
|
1950
|
+
* MutationObserver and cancels pending setup — wrap it in ctx.effect so a
|
|
1951
|
+
* plugin reload cannot stack observers over the same document.
|
|
1952
|
+
*/
|
|
1782
1953
|
function installMermaidRendering() {
|
|
1783
|
-
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
1954
|
+
if (typeof window === "undefined" || typeof document === "undefined") return () => {};
|
|
1955
|
+
disposeMermaidRendering();
|
|
1784
1956
|
injectStyles$1();
|
|
1957
|
+
cleanupTempElements();
|
|
1785
1958
|
const observer = new MutationObserver(() => {
|
|
1786
|
-
scheduleScan();
|
|
1959
|
+
scheduleScan$1();
|
|
1787
1960
|
});
|
|
1961
|
+
activeObserver$1 = observer;
|
|
1788
1962
|
const setup = () => {
|
|
1789
1963
|
if (document.body) {
|
|
1964
|
+
cleanupTempElements();
|
|
1790
1965
|
observer.observe(document.body, {
|
|
1791
1966
|
childList: true,
|
|
1792
1967
|
subtree: true
|
|
@@ -1794,8 +1969,26 @@ div[data-agy-mermaid-svg][data-agy-mermaid-error] {
|
|
|
1794
1969
|
scan();
|
|
1795
1970
|
}
|
|
1796
1971
|
};
|
|
1797
|
-
if (document.readyState === "loading")
|
|
1798
|
-
|
|
1972
|
+
if (document.readyState === "loading") {
|
|
1973
|
+
domContentLoadedHandler$1 = setup;
|
|
1974
|
+
window.addEventListener("DOMContentLoaded", setup, { once: true });
|
|
1975
|
+
} else setup();
|
|
1976
|
+
return disposeMermaidRendering;
|
|
1977
|
+
}
|
|
1978
|
+
/** Disconnect the observer and cancel pending setup work. */
|
|
1979
|
+
function disposeMermaidRendering() {
|
|
1980
|
+
if (activeObserver$1 !== null) {
|
|
1981
|
+
activeObserver$1.disconnect();
|
|
1982
|
+
activeObserver$1 = null;
|
|
1983
|
+
}
|
|
1984
|
+
if (domContentLoadedHandler$1 !== null) {
|
|
1985
|
+
window.removeEventListener("DOMContentLoaded", domContentLoadedHandler$1);
|
|
1986
|
+
domContentLoadedHandler$1 = null;
|
|
1987
|
+
}
|
|
1988
|
+
if (scanTimer$1 !== null) {
|
|
1989
|
+
clearTimeout(scanTimer$1);
|
|
1990
|
+
scanTimer$1 = null;
|
|
1991
|
+
}
|
|
1799
1992
|
}
|
|
1800
1993
|
//#endregion
|
|
1801
1994
|
//#region src/client/reasoning.ts
|
|
@@ -1857,9 +2050,16 @@ div[data-variant="think"] [class*="thinkBody"] {
|
|
|
1857
2050
|
* Try to expand a thinking row once when its body contains real prose
|
|
1858
2051
|
* (not a bare [agy thinking turn · N tokens] chip). Uses the host's own
|
|
1859
2052
|
* disclosure control when present — never mutates thinkBody children.
|
|
2053
|
+
*
|
|
2054
|
+
* A row the user manually COLLAPSED is recorded in a WeakSet keyed by the
|
|
2055
|
+
* row element; React keeps the same element identity across its own
|
|
2056
|
+
* re-renders, so the scanner stops re-expanding it (the old data attribute
|
|
2057
|
+
* survived only until React rebuilt the node).
|
|
1860
2058
|
*/
|
|
2059
|
+
const userCollapsed = typeof WeakSet !== "undefined" ? /* @__PURE__ */ new WeakSet() : null;
|
|
1861
2060
|
function tryExpandThinkRow(root) {
|
|
1862
2061
|
if (root.dataset.agyExpanded === "true") return;
|
|
2062
|
+
if (userCollapsed?.has(root) === true) return;
|
|
1863
2063
|
const body = root.querySelector("[class*=\"thinkBody\"]");
|
|
1864
2064
|
if (!body) return;
|
|
1865
2065
|
const text = (body.textContent ?? "").trim();
|
|
@@ -1871,10 +2071,15 @@ div[data-variant="think"] [class*="thinkBody"] {
|
|
|
1871
2071
|
return;
|
|
1872
2072
|
}
|
|
1873
2073
|
const toggle = root.querySelector("[data-disclosure-row]") ?? root.querySelector("[class*=\"disclosure\"]") ?? root.querySelector("button");
|
|
1874
|
-
if (toggle)
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
2074
|
+
if (toggle) {
|
|
2075
|
+
userCollapsed?.add(root);
|
|
2076
|
+
try {
|
|
2077
|
+
toggle.click();
|
|
2078
|
+
root.dataset.agyExpanded = "true";
|
|
2079
|
+
} catch {
|
|
2080
|
+
userCollapsed?.delete(root);
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
1878
2083
|
}
|
|
1879
2084
|
function scanThinkingRows() {
|
|
1880
2085
|
if (typeof document === "undefined") return;
|
|
@@ -1884,12 +2089,29 @@ div[data-variant="think"] [class*="thinkBody"] {
|
|
|
1884
2089
|
if (row) tryExpandThinkRow(row);
|
|
1885
2090
|
}
|
|
1886
2091
|
}
|
|
2092
|
+
let scanTimer = null;
|
|
2093
|
+
function scheduleScan() {
|
|
2094
|
+
if (scanTimer !== null) return;
|
|
2095
|
+
scanTimer = setTimeout(() => {
|
|
2096
|
+
scanTimer = null;
|
|
2097
|
+
scanThinkingRows();
|
|
2098
|
+
}, 200);
|
|
2099
|
+
}
|
|
2100
|
+
let activeObserver = null;
|
|
2101
|
+
let domContentLoadedHandler = null;
|
|
2102
|
+
/**
|
|
2103
|
+
* Install the auto-expand reasoning overlay. Returns a disposer that
|
|
2104
|
+
* disconnects the MutationObserver — wrap it in ctx.effect so a plugin
|
|
2105
|
+
* reload cannot stack observers.
|
|
2106
|
+
*/
|
|
1887
2107
|
function installAutoExpandReasoning() {
|
|
1888
|
-
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
2108
|
+
if (typeof window === "undefined" || typeof document === "undefined") return () => {};
|
|
2109
|
+
disposeAutoExpandReasoning();
|
|
1889
2110
|
injectStyles();
|
|
1890
2111
|
const observer = new MutationObserver(() => {
|
|
1891
|
-
|
|
2112
|
+
scheduleScan();
|
|
1892
2113
|
});
|
|
2114
|
+
activeObserver = observer;
|
|
1893
2115
|
const setupObserver = () => {
|
|
1894
2116
|
if (document.body) {
|
|
1895
2117
|
observer.observe(document.body, {
|
|
@@ -1899,8 +2121,26 @@ div[data-variant="think"] [class*="thinkBody"] {
|
|
|
1899
2121
|
scanThinkingRows();
|
|
1900
2122
|
}
|
|
1901
2123
|
};
|
|
1902
|
-
if (document.readyState === "loading")
|
|
1903
|
-
|
|
2124
|
+
if (document.readyState === "loading") {
|
|
2125
|
+
domContentLoadedHandler = setupObserver;
|
|
2126
|
+
window.addEventListener("DOMContentLoaded", setupObserver, { once: true });
|
|
2127
|
+
} else setupObserver();
|
|
2128
|
+
return disposeAutoExpandReasoning;
|
|
2129
|
+
}
|
|
2130
|
+
/** Disconnect the observer and cancel pending work. */
|
|
2131
|
+
function disposeAutoExpandReasoning() {
|
|
2132
|
+
if (activeObserver !== null) {
|
|
2133
|
+
activeObserver.disconnect();
|
|
2134
|
+
activeObserver = null;
|
|
2135
|
+
}
|
|
2136
|
+
if (domContentLoadedHandler !== null) {
|
|
2137
|
+
window.removeEventListener("DOMContentLoaded", domContentLoadedHandler);
|
|
2138
|
+
domContentLoadedHandler = null;
|
|
2139
|
+
}
|
|
2140
|
+
if (scanTimer !== null) {
|
|
2141
|
+
clearTimeout(scanTimer);
|
|
2142
|
+
scanTimer = null;
|
|
2143
|
+
}
|
|
1904
2144
|
}
|
|
1905
2145
|
//#endregion
|
|
1906
2146
|
//#region src/client/index.ts
|
|
@@ -1918,7 +2158,9 @@ div[data-variant="think"] [class*="thinkBody"] {
|
|
|
1918
2158
|
let statusCache = null;
|
|
1919
2159
|
async function getStatus() {
|
|
1920
2160
|
try {
|
|
1921
|
-
const
|
|
2161
|
+
const init = {};
|
|
2162
|
+
if (typeof AbortSignal !== "undefined" && typeof AbortSignal.timeout === "function") init.signal = AbortSignal.timeout(5e3);
|
|
2163
|
+
const res = await win.fetch?.(base + "/plugins/agy-link/status", init);
|
|
1922
2164
|
if (!res || !res.ok) return null;
|
|
1923
2165
|
const payload = await res.json();
|
|
1924
2166
|
statusCache = payload;
|
|
@@ -1936,7 +2178,12 @@ div[data-variant="think"] [class*="thinkBody"] {
|
|
|
1936
2178
|
});
|
|
1937
2179
|
if (!res) return null;
|
|
1938
2180
|
try {
|
|
1939
|
-
|
|
2181
|
+
const payload = await res.json();
|
|
2182
|
+
if (!res.ok && payload !== null && typeof payload === "object") return {
|
|
2183
|
+
ok: false,
|
|
2184
|
+
...payload
|
|
2185
|
+
};
|
|
2186
|
+
return payload;
|
|
1940
2187
|
} catch {
|
|
1941
2188
|
return { ok: res.ok };
|
|
1942
2189
|
}
|
|
@@ -1944,6 +2191,58 @@ div[data-variant="think"] [class*="thinkBody"] {
|
|
|
1944
2191
|
return null;
|
|
1945
2192
|
}
|
|
1946
2193
|
}
|
|
2194
|
+
const statusListeners = /* @__PURE__ */ new Set();
|
|
2195
|
+
let statusPollTimer = null;
|
|
2196
|
+
let statusFetchSeq = 0;
|
|
2197
|
+
function notifyStatus(st) {
|
|
2198
|
+
statusCache = st;
|
|
2199
|
+
for (const fn of [...statusListeners]) try {
|
|
2200
|
+
fn(st);
|
|
2201
|
+
} catch {}
|
|
2202
|
+
}
|
|
2203
|
+
async function statusPollTick() {
|
|
2204
|
+
const seq = ++statusFetchSeq;
|
|
2205
|
+
const st = await getStatus();
|
|
2206
|
+
if (st !== null && seq === statusFetchSeq) notifyStatus(st);
|
|
2207
|
+
}
|
|
2208
|
+
function ensureStatusPolling() {
|
|
2209
|
+
if (statusPollTimer !== null) return;
|
|
2210
|
+
statusPollTick();
|
|
2211
|
+
statusPollTimer = setInterval(() => {
|
|
2212
|
+
statusPollTick();
|
|
2213
|
+
}, 3e3);
|
|
2214
|
+
}
|
|
2215
|
+
function stopStatusPollingIfIdle() {
|
|
2216
|
+
if (statusListeners.size === 0 && statusPollTimer !== null) {
|
|
2217
|
+
clearInterval(statusPollTimer);
|
|
2218
|
+
statusPollTimer = null;
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
/**
|
|
2222
|
+
* Subscribe a component to the shared status poll. Returns the latest
|
|
2223
|
+
* snapshot plus a manual refresh that keeps the last good snapshot on a
|
|
2224
|
+
* transient failure (a failed refresh used to flip the whole panel back to
|
|
2225
|
+
* its loading state).
|
|
2226
|
+
*/
|
|
2227
|
+
function useAgyStatus() {
|
|
2228
|
+
const [status, setStatus] = useState(statusCache);
|
|
2229
|
+
useEffect(() => {
|
|
2230
|
+
statusListeners.add(setStatus);
|
|
2231
|
+
ensureStatusPolling();
|
|
2232
|
+
return () => {
|
|
2233
|
+
statusListeners.delete(setStatus);
|
|
2234
|
+
stopStatusPollingIfIdle();
|
|
2235
|
+
};
|
|
2236
|
+
}, []);
|
|
2237
|
+
const refresh = async () => {
|
|
2238
|
+
const st = await getStatus();
|
|
2239
|
+
if (st !== null) notifyStatus(st);
|
|
2240
|
+
};
|
|
2241
|
+
return {
|
|
2242
|
+
status,
|
|
2243
|
+
refresh
|
|
2244
|
+
};
|
|
2245
|
+
}
|
|
1947
2246
|
/** Global modal state for opening Antigravity console dialog from footer shortcut or header status */
|
|
1948
2247
|
const agyModalStore = {
|
|
1949
2248
|
open: false,
|
|
@@ -2654,7 +2953,7 @@ body.dark,
|
|
|
2654
2953
|
};
|
|
2655
2954
|
const AgySettingsSection = (props) => {
|
|
2656
2955
|
const t = useAgyTranslation();
|
|
2657
|
-
const
|
|
2956
|
+
const { status, refresh } = useAgyStatus();
|
|
2658
2957
|
const [aliasInput, setAliasInput] = useState("");
|
|
2659
2958
|
const [proxyInputs, setProxyInputs] = useState({});
|
|
2660
2959
|
const [editingProxyId, setEditingProxyId] = useState(null);
|
|
@@ -2663,24 +2962,10 @@ body.dark,
|
|
|
2663
2962
|
const [loadingAction, setLoadingAction] = useState(null);
|
|
2664
2963
|
const [toast, setToast] = useState(null);
|
|
2665
2964
|
const [expandedModels, setExpandedModels] = useState({});
|
|
2965
|
+
const [, setTimeTick] = useState(0);
|
|
2666
2966
|
useEffect(() => {
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
const tick = async () => {
|
|
2670
|
-
const st = await getStatus();
|
|
2671
|
-
if (!alive || !st) return;
|
|
2672
|
-
const json = JSON.stringify(st);
|
|
2673
|
-
if (json !== lastJson) {
|
|
2674
|
-
lastJson = json;
|
|
2675
|
-
setStatus(st);
|
|
2676
|
-
}
|
|
2677
|
-
};
|
|
2678
|
-
tick();
|
|
2679
|
-
const timer = setInterval(tick, 3e3);
|
|
2680
|
-
return () => {
|
|
2681
|
-
alive = false;
|
|
2682
|
-
clearInterval(timer);
|
|
2683
|
-
};
|
|
2967
|
+
const timer = setInterval(() => setTimeTick((n) => n + 1), 3e4);
|
|
2968
|
+
return () => clearInterval(timer);
|
|
2684
2969
|
}, []);
|
|
2685
2970
|
const flowStartedRef = useRef(false);
|
|
2686
2971
|
const safeMessage = (code) => {
|
|
@@ -2706,18 +2991,24 @@ body.dark,
|
|
|
2706
2991
|
status?.poolAuth?.phase,
|
|
2707
2992
|
status?.poolAuth?.code
|
|
2708
2993
|
]);
|
|
2994
|
+
const toastTimerRef = useRef(null);
|
|
2995
|
+
useEffect(() => () => {
|
|
2996
|
+
if (toastTimerRef.current !== null) clearTimeout(toastTimerRef.current);
|
|
2997
|
+
}, []);
|
|
2709
2998
|
const showToast = (text, type = "info") => {
|
|
2710
2999
|
setToast({
|
|
2711
3000
|
text,
|
|
2712
3001
|
type,
|
|
2713
3002
|
id: Date.now()
|
|
2714
3003
|
});
|
|
2715
|
-
|
|
2716
|
-
|
|
3004
|
+
if (toastTimerRef.current !== null) clearTimeout(toastTimerRef.current);
|
|
3005
|
+
toastTimerRef.current = setTimeout(() => {
|
|
3006
|
+
toastTimerRef.current = null;
|
|
3007
|
+
setToast((prev) => prev !== null && prev.text === text ? null : prev);
|
|
2717
3008
|
}, 6e3);
|
|
2718
3009
|
};
|
|
2719
|
-
const
|
|
2720
|
-
|
|
3010
|
+
const actionFailed = () => {
|
|
3011
|
+
showToast(t("api.genericError"), "error");
|
|
2721
3012
|
};
|
|
2722
3013
|
const handleBeginAddAccount = async () => {
|
|
2723
3014
|
setLoadingAction("pool:beginAdd");
|
|
@@ -2755,36 +3046,62 @@ body.dark,
|
|
|
2755
3046
|
};
|
|
2756
3047
|
const setCfg = async (key, value) => {
|
|
2757
3048
|
setLoadingAction(`config:${key}`);
|
|
2758
|
-
await postJson("/plugins/agy-link/config", {
|
|
3049
|
+
const res = await postJson("/plugins/agy-link/config", {
|
|
2759
3050
|
key,
|
|
2760
3051
|
value
|
|
2761
3052
|
});
|
|
3053
|
+
if (res === null || res?.ok === false) {
|
|
3054
|
+
setLoadingAction(null);
|
|
3055
|
+
actionFailed();
|
|
3056
|
+
return;
|
|
3057
|
+
}
|
|
2762
3058
|
await refresh();
|
|
2763
3059
|
setLoadingAction(null);
|
|
2764
3060
|
};
|
|
3061
|
+
const hiddenPendingRef = useRef(null);
|
|
2765
3062
|
const toggleModelHidden = async (id, hide) => {
|
|
2766
|
-
const next = new Set(status?.hiddenModels ?? []);
|
|
3063
|
+
const next = new Set(hiddenPendingRef.current ?? status?.hiddenModels ?? []);
|
|
2767
3064
|
if (hide) next.add(id);
|
|
2768
3065
|
else next.delete(id);
|
|
2769
|
-
|
|
3066
|
+
hiddenPendingRef.current = next;
|
|
3067
|
+
try {
|
|
3068
|
+
await setCfg("hiddenModels", Array.from(next));
|
|
3069
|
+
} finally {
|
|
3070
|
+
if (hiddenPendingRef.current === next) hiddenPendingRef.current = null;
|
|
3071
|
+
}
|
|
2770
3072
|
};
|
|
2771
3073
|
const setPrimary = async (id) => {
|
|
2772
3074
|
setLoadingAction(`primary:${id}`);
|
|
2773
|
-
await postJson("/plugins/agy-link/pool/primary", { id });
|
|
3075
|
+
const res = await postJson("/plugins/agy-link/pool/primary", { id });
|
|
3076
|
+
if (res === null || res?.ok === false) {
|
|
3077
|
+
setLoadingAction(null);
|
|
3078
|
+
actionFailed();
|
|
3079
|
+
return;
|
|
3080
|
+
}
|
|
2774
3081
|
await refresh();
|
|
2775
3082
|
setLoadingAction(null);
|
|
2776
3083
|
showToast(t("account.setPrimary"), "success");
|
|
2777
3084
|
};
|
|
2778
3085
|
const removeAccount = async (id, alias) => {
|
|
2779
3086
|
setLoadingAction(`remove:${id}`);
|
|
2780
|
-
await postJson("/plugins/agy-link/pool/remove", { id });
|
|
3087
|
+
const res = await postJson("/plugins/agy-link/pool/remove", { id });
|
|
3088
|
+
if (res === null || res?.ok === false) {
|
|
3089
|
+
setLoadingAction(null);
|
|
3090
|
+
actionFailed();
|
|
3091
|
+
return;
|
|
3092
|
+
}
|
|
2781
3093
|
await refresh();
|
|
2782
3094
|
setLoadingAction(null);
|
|
2783
3095
|
showToast(t("account.removed", { alias }), "info");
|
|
2784
3096
|
};
|
|
2785
3097
|
const refreshQuota = async (id) => {
|
|
2786
3098
|
setLoadingAction(id ? `refresh:${id}` : "refresh:all");
|
|
2787
|
-
await postJson("/plugins/agy-link/pool/refresh-quota", { id });
|
|
3099
|
+
const res = await postJson("/plugins/agy-link/pool/refresh-quota", { id });
|
|
3100
|
+
if (res === null || res?.ok === false) {
|
|
3101
|
+
setLoadingAction(null);
|
|
3102
|
+
actionFailed();
|
|
3103
|
+
return;
|
|
3104
|
+
}
|
|
2788
3105
|
await refresh();
|
|
2789
3106
|
setLoadingAction(null);
|
|
2790
3107
|
showToast(t("quota.refreshed"), "success");
|
|
@@ -2792,10 +3109,15 @@ body.dark,
|
|
|
2792
3109
|
const saveProxy = async (id) => {
|
|
2793
3110
|
setLoadingAction(`proxy:${id}`);
|
|
2794
3111
|
const proxyUrl = proxyInputs[id];
|
|
2795
|
-
await postJson("/plugins/agy-link/pool/proxy", {
|
|
3112
|
+
const res = await postJson("/plugins/agy-link/pool/proxy", {
|
|
2796
3113
|
id,
|
|
2797
3114
|
proxyUrl
|
|
2798
3115
|
});
|
|
3116
|
+
if (res === null || res?.ok === false) {
|
|
3117
|
+
setLoadingAction(null);
|
|
3118
|
+
actionFailed();
|
|
3119
|
+
return;
|
|
3120
|
+
}
|
|
2799
3121
|
setEditingProxyId(null);
|
|
2800
3122
|
await refresh();
|
|
2801
3123
|
setLoadingAction(null);
|
|
@@ -2803,13 +3125,23 @@ body.dark,
|
|
|
2803
3125
|
};
|
|
2804
3126
|
const setMode = async (mode) => {
|
|
2805
3127
|
setLoadingAction(`mode:${mode}`);
|
|
2806
|
-
await postJson("/plugins/agy-link/pool/mode", { mode });
|
|
3128
|
+
const res = await postJson("/plugins/agy-link/pool/mode", { mode });
|
|
3129
|
+
if (res === null || res?.ok === false) {
|
|
3130
|
+
setLoadingAction(null);
|
|
3131
|
+
actionFailed();
|
|
3132
|
+
return;
|
|
3133
|
+
}
|
|
2807
3134
|
await refresh();
|
|
2808
3135
|
setLoadingAction(null);
|
|
2809
3136
|
};
|
|
2810
3137
|
const clearCooldown = async (id) => {
|
|
2811
3138
|
setLoadingAction(id ? `clearCooldown:${id}` : "clearCooldown:all");
|
|
2812
|
-
await postJson("/plugins/agy-link/pool/clear-cooldown", { id });
|
|
3139
|
+
const res = await postJson("/plugins/agy-link/pool/clear-cooldown", { id });
|
|
3140
|
+
if (res === null || res?.ok === false) {
|
|
3141
|
+
setLoadingAction(null);
|
|
3142
|
+
actionFailed();
|
|
3143
|
+
return;
|
|
3144
|
+
}
|
|
2813
3145
|
await refresh();
|
|
2814
3146
|
setLoadingAction(null);
|
|
2815
3147
|
showToast(t("account.clearCooldown"), "success");
|
|
@@ -3333,7 +3665,21 @@ body.dark,
|
|
|
3333
3665
|
},
|
|
3334
3666
|
disabled: isBusy,
|
|
3335
3667
|
onClick: () => void refreshQuota()
|
|
3336
|
-
}, loadingAction === "refresh:all" ? [renderSpinner(), t("header.refreshing")] : [uiIcon("refresh", 12, "var(--agy-text-btn)"), ` ${t("header.refreshQuota")}`]))), renderToastBanner(),
|
|
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: {
|
|
3337
3683
|
marginTop: "16px",
|
|
3338
3684
|
paddingTop: "12px",
|
|
3339
3685
|
borderTop: "1px solid var(--agy-border-divider)"
|
|
@@ -3512,37 +3858,24 @@ body.dark,
|
|
|
3512
3858
|
/** Session Header badge in chat toolbar */
|
|
3513
3859
|
const AgySessionStatus = () => {
|
|
3514
3860
|
const t = useAgyTranslation();
|
|
3515
|
-
const
|
|
3861
|
+
const { status } = useAgyStatus();
|
|
3862
|
+
const [, setTimeTick] = useState(0);
|
|
3516
3863
|
useEffect(() => {
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
const tick = async () => {
|
|
3520
|
-
const st = await getStatus();
|
|
3521
|
-
if (!alive || !st) return;
|
|
3522
|
-
const json = JSON.stringify(st);
|
|
3523
|
-
if (json !== lastJson) {
|
|
3524
|
-
lastJson = json;
|
|
3525
|
-
setStatus(st);
|
|
3526
|
-
}
|
|
3527
|
-
};
|
|
3528
|
-
tick();
|
|
3529
|
-
const timer = setInterval(tick, 3e3);
|
|
3530
|
-
return () => {
|
|
3531
|
-
alive = false;
|
|
3532
|
-
clearInterval(timer);
|
|
3533
|
-
};
|
|
3864
|
+
const timer = setInterval(() => setTimeTick((n) => n + 1), 3e4);
|
|
3865
|
+
return () => clearInterval(timer);
|
|
3534
3866
|
}, []);
|
|
3535
3867
|
const pool = status?.pool;
|
|
3536
3868
|
const accounts = pool?.accounts ?? [];
|
|
3537
3869
|
const rawActiveId = pool?.activeAccountId ?? pool?.lastActiveAccountId ?? pool?.activeAccountIds?.google ?? pool?.primaryAccountId;
|
|
3538
3870
|
const activeAcc = accounts.find((a) => a.id === rawActiveId && a.enabled && !a.authRequired) ?? accounts.find((a) => a.enabled && !a.authRequired) ?? accounts[0];
|
|
3539
|
-
const activeHasCooldown = activeAcc ? Object.entries(activeAcc.cooldowns).some(([, cd]) => cd && cd.cooldownUntil > Date.now()) : false;
|
|
3540
|
-
const allInCooldown = accounts.length > 0 && accounts.every((a) => !a.enabled || a.authRequired || Object.entries(a.cooldowns).some(([, cd]) => cd && cd.cooldownUntil > Date.now()));
|
|
3871
|
+
const activeHasCooldown = activeAcc ? Object.entries(activeAcc.cooldowns ?? {}).some(([, cd]) => cd && cd.cooldownUntil > Date.now()) : false;
|
|
3872
|
+
const allInCooldown = accounts.length > 0 && accounts.every((a) => !a.enabled || a.authRequired || Object.entries(a.cooldowns ?? {}).some(([, cd]) => cd && cd.cooldownUntil > Date.now()));
|
|
3541
3873
|
const isAuthed = status?.auth?.phase === "ok" || accounts.length > 0;
|
|
3542
3874
|
const color = status === null ? "#64748b" : status.dormantReason ? "#f59e0b" : allInCooldown ? "#f59e0b" : activeHasCooldown ? "#f59e0b" : isAuthed ? "#10b981" : "#f59e0b";
|
|
3543
3875
|
const legacyDefault = activeAcc && activeAcc.defaultAlias === void 0 && activeAcc.systemHome && activeAcc.alias === "主账号 (系统登录)";
|
|
3544
3876
|
const displayAlias = activeAcc ? activeAcc.defaultAlias || legacyDefault ? activeAcc.systemHome ? t("account.defaultAlias") : t("account.aliasDefault", { number: accounts.indexOf(activeAcc) + 1 }) : activeAcc.alias : "";
|
|
3545
|
-
const
|
|
3877
|
+
const activeEligible = activeAcc !== void 0 && activeAcc.enabled && !activeAcc.authRequired;
|
|
3878
|
+
const activeDetail = activeAcc !== void 0 && activeEligible ? ` · ${t("status.inUse")}: ${displayAlias}${activeAcc.email ? ` (${activeAcc.email})` : ""}` : "";
|
|
3546
3879
|
const badgeTitle = `${t("header.badgeTitle", { count: accounts.length })}${activeDetail}`;
|
|
3547
3880
|
const buttonLabel = displayAlias ? `AGY · ${displayAlias}` : `AGY (${accounts.length})`;
|
|
3548
3881
|
const badge = h("button", {
|
|
@@ -3593,8 +3926,8 @@ body.dark,
|
|
|
3593
3926
|
}, AgySettingsSection);
|
|
3594
3927
|
});
|
|
3595
3928
|
installAgyToolView(ctx);
|
|
3596
|
-
installAutoExpandReasoning();
|
|
3597
|
-
installMermaidRendering();
|
|
3929
|
+
ctx.effect(() => installAutoExpandReasoning());
|
|
3930
|
+
ctx.effect(() => installMermaidRendering());
|
|
3598
3931
|
}
|
|
3599
3932
|
//#endregion
|
|
3600
3933
|
exports.apply = apply;
|