dsh-agy-link 0.4.26 → 0.4.28
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 +86 -0
- package/README.md +22 -3
- package/dist/client.js +935 -77
- package/dist/index.js +546 -81
- package/docs/HEADLESS-PERMISSIONS.md +32 -0
- package/docs/KNOWN-GAPS.md +5 -0
- package/docs/README.en.md +67 -0
- package/docs/README.es.md +67 -0
- package/docs/README.pt-BR.md +67 -0
- package/docs/SECURITY-NOTES.md +20 -3
- package/docs/SPEC-triage-2026-09.md +239 -0
- package/package.json +8 -2
package/dist/client.js
CHANGED
|
@@ -31,6 +31,806 @@ window.__ModuleLoader__.load({
|
|
|
31
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"
|
|
32
32
|
};
|
|
33
33
|
//#endregion
|
|
34
|
+
//#region src/client/toolview.ts
|
|
35
|
+
function react() {
|
|
36
|
+
const mod = require("react");
|
|
37
|
+
if (mod === void 0 || mod === null) throw new Error("dsh-agy-link toolview requires react at render time (browser host)");
|
|
38
|
+
return mod;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Wrap a raw useState setter into a toggle: every call flips the previous
|
|
42
|
+
* value. The raw setter itself must NEVER be called with no arguments —
|
|
43
|
+
* `setState(undefined)` pins the state to a falsy value, so a second click
|
|
44
|
+
* could never expand a collapsed card again (the regression this fixes).
|
|
45
|
+
* Exported separately so the toggling contract is unit-testable in Node.
|
|
46
|
+
*/
|
|
47
|
+
function makeToggle(setValue) {
|
|
48
|
+
return () => setValue((prev) => !prev);
|
|
49
|
+
}
|
|
50
|
+
function useToggle(initial = false) {
|
|
51
|
+
const [value, setValue] = react().useState(initial);
|
|
52
|
+
return [value, makeToggle(setValue)];
|
|
53
|
+
}
|
|
54
|
+
/** React.createElement bound helper (call inside render functions). */
|
|
55
|
+
function hx(type, props, ...children) {
|
|
56
|
+
return react().createElement(type, props, ...children);
|
|
57
|
+
}
|
|
58
|
+
function parsedArgsRaw(block) {
|
|
59
|
+
const settled = block;
|
|
60
|
+
if ("call" in settled && settled.call !== null && typeof settled.call.argsRaw === "string") return settled.call.argsRaw;
|
|
61
|
+
const running = block;
|
|
62
|
+
if (typeof running.argsRaw === "string") return running.argsRaw;
|
|
63
|
+
return "";
|
|
64
|
+
}
|
|
65
|
+
function parseArgs(block) {
|
|
66
|
+
const raw = parsedArgsRaw(block);
|
|
67
|
+
if (raw === "") return null;
|
|
68
|
+
try {
|
|
69
|
+
const v = JSON.parse(raw);
|
|
70
|
+
return typeof v === "object" && v !== null && !Array.isArray(v) ? v : null;
|
|
71
|
+
} catch {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/** agy tool name + PascalCase or camelCase input object from the mirror args. */
|
|
76
|
+
function mirrorInfo(block) {
|
|
77
|
+
const a = parseArgs(block);
|
|
78
|
+
if (a === null) return null;
|
|
79
|
+
const tool = typeof a.tool === "string" ? a.tool : "";
|
|
80
|
+
if (tool === "") return null;
|
|
81
|
+
let input = {};
|
|
82
|
+
const raw = a.input;
|
|
83
|
+
if (typeof raw === "object" && raw !== null && !Array.isArray(raw)) input = raw;
|
|
84
|
+
else if (typeof raw === "string") try {
|
|
85
|
+
const p = JSON.parse(raw);
|
|
86
|
+
if (typeof p === "object" && p !== null && !Array.isArray(p)) input = p;
|
|
87
|
+
else input = { value: raw };
|
|
88
|
+
} catch {
|
|
89
|
+
input = { value: raw };
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
tool,
|
|
93
|
+
input
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function pick(input, ...keys) {
|
|
97
|
+
for (const k of keys) {
|
|
98
|
+
const v = input[k];
|
|
99
|
+
if (typeof v === "string" && v !== "") return v;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function num(input, ...keys) {
|
|
103
|
+
for (const k of keys) {
|
|
104
|
+
const v = input[k];
|
|
105
|
+
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function resultText(block) {
|
|
109
|
+
const settled = block;
|
|
110
|
+
if (!Array.isArray(settled.content)) return "";
|
|
111
|
+
const parts = [];
|
|
112
|
+
for (const b of settled.content) if (b && typeof b === "object" && b.type === "text" && typeof b.text === "string") parts.push(b.text);
|
|
113
|
+
return parts.join("\n");
|
|
114
|
+
}
|
|
115
|
+
function isSettled(block) {
|
|
116
|
+
return block.kind === "tool-result" || "content" in block;
|
|
117
|
+
}
|
|
118
|
+
function isError(block) {
|
|
119
|
+
const settled = block;
|
|
120
|
+
return settled.isError === true || settled.error !== void 0 && settled.error !== null;
|
|
121
|
+
}
|
|
122
|
+
const TERMINAL_TOOLS = /* @__PURE__ */ new Set([
|
|
123
|
+
"run_command",
|
|
124
|
+
"bash",
|
|
125
|
+
"execute_command"
|
|
126
|
+
]);
|
|
127
|
+
const DIFF_TOOLS = /* @__PURE__ */ new Set([
|
|
128
|
+
"replace_file_content",
|
|
129
|
+
"edit_file",
|
|
130
|
+
"replace_in_file",
|
|
131
|
+
"edit",
|
|
132
|
+
"write_to_file",
|
|
133
|
+
"write_file",
|
|
134
|
+
"create_file"
|
|
135
|
+
]);
|
|
136
|
+
const READ_TOOLS = /* @__PURE__ */ new Set([
|
|
137
|
+
"read_file",
|
|
138
|
+
"view_file",
|
|
139
|
+
"read",
|
|
140
|
+
"open_file"
|
|
141
|
+
]);
|
|
142
|
+
const SEARCH_TOOLS = /* @__PURE__ */ new Set([
|
|
143
|
+
"find_by_name",
|
|
144
|
+
"glob",
|
|
145
|
+
"search_files",
|
|
146
|
+
"grep_search",
|
|
147
|
+
"search",
|
|
148
|
+
"search_file_content",
|
|
149
|
+
"grep"
|
|
150
|
+
]);
|
|
151
|
+
const LIST_TOOLS = /* @__PURE__ */ new Set(["list_dir", "ls"]);
|
|
152
|
+
const DELETE_TOOLS = /* @__PURE__ */ new Set([
|
|
153
|
+
"delete_file",
|
|
154
|
+
"remove_file",
|
|
155
|
+
"rm"
|
|
156
|
+
]);
|
|
157
|
+
/** Build the display model for one agy_tool block (pending or settled). */
|
|
158
|
+
function mirrorCardModel(block, cwd, home) {
|
|
159
|
+
const info = mirrorInfo(block);
|
|
160
|
+
const out = resultText(block);
|
|
161
|
+
if (info === null) return {
|
|
162
|
+
kind: "generic",
|
|
163
|
+
title: "agy_tool",
|
|
164
|
+
output: out,
|
|
165
|
+
raw: parsedArgsRaw(block)
|
|
166
|
+
};
|
|
167
|
+
const { tool, input } = info;
|
|
168
|
+
const desc = pick(input, "Description", "description", "toolAction", "toolSummary", "Instruction", "instruction");
|
|
169
|
+
if (TERMINAL_TOOLS.has(tool)) {
|
|
170
|
+
const command = pick(input, "CommandLine", "command_line", "command", "cmd", "Cmd") ?? JSON.stringify(input);
|
|
171
|
+
const cwdVal = pick(input, "Cwd", "cwd", "WorkingDirectory", "working_directory") ?? cwd;
|
|
172
|
+
return {
|
|
173
|
+
kind: "terminal",
|
|
174
|
+
tool,
|
|
175
|
+
title: desc !== void 0 ? desc + " · " + command : command,
|
|
176
|
+
command,
|
|
177
|
+
...cwdVal !== void 0 ? { cwd: cwdVal } : {},
|
|
178
|
+
output: out
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
if (DIFF_TOOLS.has(tool)) {
|
|
182
|
+
const rawPath = pick(input, "TargetFile", "target_file", "path", "file_path", "Path", "FilePath", "AbsolutePath", "targetFile", "filename", "FileName") ?? "file";
|
|
183
|
+
const path = relativize(rawPath, cwd, home);
|
|
184
|
+
const oldText = pick(input, "TargetContent", "target_content", "old_string", "oldText", "OldString", "OldText", "targetContent") ?? null;
|
|
185
|
+
const newText = pick(input, "ReplacementContent", "replacement_content", "new_string", "newText", "content", "NewString", "NewText", "Content", "replacementContent", "CodeContent", "code_content", "contents", "FileContents", "codeContent") ?? "";
|
|
186
|
+
const action = tool === "write_to_file" || tool === "write_file" || tool === "create_file" ? "Write" : "Edit";
|
|
187
|
+
const isGenericDesc = desc !== void 0 && /^(file edit|editing file|write file|writing file|file write|edit file|editing|writing|file create|creating file)$/i.test(desc.trim());
|
|
188
|
+
return {
|
|
189
|
+
kind: "diff",
|
|
190
|
+
tool,
|
|
191
|
+
title: desc !== void 0 && !isGenericDesc && !desc.includes(path) ? `${action} ${path} · ${desc}` : `${action} ${path}`,
|
|
192
|
+
path: rawPath,
|
|
193
|
+
oldText,
|
|
194
|
+
newText,
|
|
195
|
+
output: out
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
if (READ_TOOLS.has(tool)) {
|
|
199
|
+
const path = pick(input, "AbsolutePath", "absolute_path", "TargetFile", "target_file", "path", "file_path", "filename", "Path", "FilePath", "FileName", "targetFile") ?? "";
|
|
200
|
+
const offset = num(input, "offset", "Offset") ?? num(input, "StartLine", "start_line");
|
|
201
|
+
const line = offset !== void 0 ? offset > 0 && (tool === "view_file" || tool === "read_file") ? offset : offset + 1 : void 0;
|
|
202
|
+
return {
|
|
203
|
+
kind: "read",
|
|
204
|
+
tool,
|
|
205
|
+
title: desc ? `${desc} · ${path}` : path !== "" ? "Read " + path : "Read",
|
|
206
|
+
path,
|
|
207
|
+
output: out,
|
|
208
|
+
...path !== "" ? { location: {
|
|
209
|
+
path,
|
|
210
|
+
...line !== void 0 ? { line } : {}
|
|
211
|
+
} } : {}
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
if (SEARCH_TOOLS.has(tool)) {
|
|
215
|
+
const q = pick(input, "query", "Query", "pattern", "Pattern", "regex", "Regex", "QueryString") ?? "";
|
|
216
|
+
return {
|
|
217
|
+
kind: "search",
|
|
218
|
+
tool,
|
|
219
|
+
title: desc ?? (q !== "" ? "Search " + q : "Search"),
|
|
220
|
+
output: out
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
if (LIST_TOOLS.has(tool)) {
|
|
224
|
+
const path = pick(input, "DirectoryPath", "directory_path", "path", "directory", "Path", "Directory", "SearchDirectory", "search_directory", "AbsolutePath") ?? "";
|
|
225
|
+
return {
|
|
226
|
+
kind: "list",
|
|
227
|
+
tool,
|
|
228
|
+
title: desc ?? (path !== "" ? "List " + path : "List directory"),
|
|
229
|
+
output: out
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
if (DELETE_TOOLS.has(tool)) {
|
|
233
|
+
const path = pick(input, "TargetFile", "target_file", "path", "file_path", "Path", "FilePath", "AbsolutePath") ?? "";
|
|
234
|
+
return {
|
|
235
|
+
kind: "delete",
|
|
236
|
+
tool,
|
|
237
|
+
title: desc ?? "Delete " + path,
|
|
238
|
+
output: out
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
return {
|
|
242
|
+
kind: "generic",
|
|
243
|
+
tool,
|
|
244
|
+
title: desc ?? (tool !== "" ? tool : "agy_tool"),
|
|
245
|
+
output: out,
|
|
246
|
+
raw: parsedArgsRaw(block)
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
function cls(...names) {
|
|
250
|
+
return names.filter((n) => typeof n === "string" && n !== "").join(" ");
|
|
251
|
+
}
|
|
252
|
+
const ROW_CSS = `
|
|
253
|
+
.agy-tv-row{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l1,#e2e8f0);border-radius:10px;background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-bg-base,#fff));margin:4px 0;overflow:hidden;font:var(--dsw-font-13,13px/1.5 -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'PingFang SC','Microsoft YaHei',sans-serif)}
|
|
254
|
+
.agy-tv-head{display:flex;align-items:center;gap:8px;padding:6px 10px;cursor:pointer;user-select:none;background:transparent;border:none;width:100%;text-align:left;color:var(--dsw-alias-label-primary,#0f172a)}
|
|
255
|
+
.agy-tv-head:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.04))}
|
|
256
|
+
.agy-tv-icon{flex:none;display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:5px;background:var(--dsw-alias-bg-layer-3,#f1f5f9);color:var(--dsw-alias-label-secondary,#334155)}
|
|
257
|
+
.agy-tv-title{min-width:0;flex:1;font-size:12.5px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
258
|
+
.agy-tv-kind{flex:none;font-size:10px;font-weight:700;letter-spacing:.02em;text-transform:capitalize;padding:1px 6px;border-radius:5px;color:var(--dsw-alias-state-business-primary,#2563eb);background:color-mix(in srgb,var(--dsw-alias-state-business-primary,#2563eb) 12%,transparent)}
|
|
259
|
+
.agy-tv-tool{flex:none;font-size:10px;font-weight:600;font-family:var(--dsw-font-family-code,ui-monospace,SFMono-Regular,Menlo,Consolas,monospace);color:var(--dsw-alias-label-tertiary,#64748b);background:var(--dsw-alias-bg-layer-3,#f1f5f9);border:.5px solid var(--dsw-alias-border-l1,#e2e8f0);border-radius:5px;padding:1px 6px;max-width:28%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
260
|
+
.agy-tv-label{font-size:10.5px;font-weight:700;letter-spacing:.03em;text-transform:uppercase;color:var(--dsw-alias-label-tertiary,#64748b);margin:0 0 3px}
|
|
261
|
+
.agy-tv-preview{flex:none;max-width:32%;font-size:11px;color:var(--dsw-alias-label-caption,#94a3b8);font-family:var(--dsw-font-family-code,ui-monospace,SFMono-Regular,Menlo,Consolas,monospace);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;background:var(--dsw-alias-bg-layer-3,#f1f5f9);border-radius:5px;padding:1px 6px}
|
|
262
|
+
.agy-tv-state{flex:none;font-size:10.5px;font-weight:700;padding:1px 7px;border-radius:999px}
|
|
263
|
+
.agy-tv-state-ok{color:var(--dsw-alias-state-success-primary,#059669);background:color-mix(in srgb,var(--dsw-alias-state-success-primary,#059669) 12%,transparent)}
|
|
264
|
+
.agy-tv-state-err{color:var(--dsw-alias-state-error-primary,#dc2626);background:color-mix(in srgb,var(--dsw-alias-state-error-primary,#dc2626) 12%,transparent)}
|
|
265
|
+
.agy-tv-state-run{color:var(--dsw-alias-state-business-primary,#2563eb);background:color-mix(in srgb,var(--dsw-alias-state-business-primary,#2563eb) 12%,transparent)}
|
|
266
|
+
.agy-tv-body{display:none;padding:8px 10px;border-top:.5px solid var(--dsw-alias-border-l1,#e2e8f0)}
|
|
267
|
+
.agy-tv-open .agy-tv-body{display:block}
|
|
268
|
+
.agy-tv-term{font-family:var(--dsw-font-family-code,ui-monospace,SFMono-Regular,Menlo,Consolas,monospace);font-size:12px;line-height:1.55;white-space:pre-wrap;word-break:break-word;background:var(--dsw-alias-bg-layer-1,#f8fafc);border:.5px solid var(--dsw-alias-border-l1,#e2e8f0);border-radius:7px;padding:8px 10px;color:var(--dsw-alias-label-primary,#0f172a)}
|
|
269
|
+
.agy-tv-term-cmd{color:var(--dsw-alias-label-tertiary,#64748b);font-size:11px;margin:0 0 4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
270
|
+
.agy-tv-term-cwd{color:var(--dsw-alias-label-caption,#94a3b8);font-size:11px;font-family:var(--dsw-font-family-code,ui-monospace,SFMono-Regular,Menlo,Consolas,monospace);padding:2px 8px;border-top-left-radius:7px;border-top-right-radius:7px;background:var(--dsw-alias-bg-layer-3,#f1f5f9);border:.5px solid var(--dsw-alias-border-l1,#e2e8f0);border-bottom:none}
|
|
271
|
+
.agy-tv-diff{font-family:var(--dsw-font-family-code,ui-monospace,SFMono-Regular,Menlo,Consolas,monospace);font-size:12px;line-height:1.5;border:.5px solid var(--dsw-alias-border-l1,#e2e8f0);border-radius:7px;overflow:hidden}
|
|
272
|
+
.agy-tv-diff-path{font-size:11px;padding:4px 10px;background:var(--dsw-alias-bg-layer-3,#f1f5f9);color:var(--dsw-alias-label-secondary,#334155);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
273
|
+
.agy-tv-line{display:flex;gap:8px;padding:0 10px;min-height:20px;white-space:pre-wrap;word-break:break-word}
|
|
274
|
+
.agy-tv-line-del{background:color-mix(in srgb,var(--dsw-alias-state-error-primary,#dc2626) 12%,transparent);color:var(--dsw-alias-label-primary,#0f172a)}
|
|
275
|
+
.agy-tv-line-del .agy-tv-line-marker{color:var(--dsw-alias-state-error-primary,#dc2626);font-weight:700}
|
|
276
|
+
.agy-tv-line-add{background:color-mix(in srgb,var(--dsw-alias-state-success-primary,#059669) 12%,transparent);color:var(--dsw-alias-label-primary,#0f172a)}
|
|
277
|
+
.agy-tv-line-add .agy-tv-line-marker{color:var(--dsw-alias-state-success-primary,#059669);font-weight:700}
|
|
278
|
+
.agy-tv-line-marker{flex:none;width:14px;color:var(--dsw-alias-label-caption,#94a3b8);user-select:none}
|
|
279
|
+
.agy-tv-path{font-family:var(--dsw-font-family-code,ui-monospace,SFMono-Regular,Menlo,Consolas,monospace);font-size:12px;color:var(--dsw-alias-state-business-primary,#2563eb);cursor:pointer;text-decoration:underline}
|
|
280
|
+
.agy-tv-raw{font-family:var(--dsw-font-family-code,ui-monospace,SFMono-Regular,Menlo,Consolas,monospace);font-size:11.5px;white-space:pre-wrap;word-break:break-word;color:var(--dsw-alias-label-secondary,#334155);max-height:200px;overflow:auto}
|
|
281
|
+
`;
|
|
282
|
+
const stateLabel = (kind) => kind === "err" ? "Error" : kind === "run" ? "Running" : "Done";
|
|
283
|
+
function ChevronDown() {
|
|
284
|
+
const h = hx;
|
|
285
|
+
return h("svg", {
|
|
286
|
+
viewBox: "0 0 16 16",
|
|
287
|
+
width: 12,
|
|
288
|
+
height: 12,
|
|
289
|
+
style: {
|
|
290
|
+
flex: "none",
|
|
291
|
+
color: "var(--dsw-alias-label-tertiary,#64748b)"
|
|
292
|
+
}
|
|
293
|
+
}, h("path", {
|
|
294
|
+
d: "M4 6l4 4 4-4",
|
|
295
|
+
fill: "none",
|
|
296
|
+
stroke: "currentColor",
|
|
297
|
+
"stroke-width": 1.5,
|
|
298
|
+
"stroke-linecap": "round",
|
|
299
|
+
"stroke-linejoin": "round"
|
|
300
|
+
}));
|
|
301
|
+
}
|
|
302
|
+
function StatusIcon({ kind }) {
|
|
303
|
+
const h = hx;
|
|
304
|
+
return h("svg", {
|
|
305
|
+
viewBox: "0 0 16 16",
|
|
306
|
+
width: 14,
|
|
307
|
+
height: 14,
|
|
308
|
+
style: {
|
|
309
|
+
color: kind === "diff" ? "var(--dsw-alias-state-success-primary,#059669)" : kind === "delete" ? "var(--dsw-alias-state-error-primary,#dc2626)" : "var(--dsw-alias-label-secondary,#334155)",
|
|
310
|
+
display: "block"
|
|
311
|
+
}
|
|
312
|
+
}, h("path", {
|
|
313
|
+
d: kind === "terminal" ? "M4 2l8 6-8 6z" : kind === "diff" ? "M4 8h8M8 4v8M3 3h6a2 2 0 012 2v6a2 2 0 01-2 2H3a2 2 0 01-2-2V5a2 2 0 012-2z" : kind === "read" ? "M4 3h8a1 1 0 011 1v9l-3-2-3 2-3-2V4a1 1 0 011-1z" : kind === "search" ? "M7 3a4 4 0 100 8 4 4 0 000-8zm4 4a4 4 0 01-.5 2L14 12.5 12.5 14 9 10.5" : kind === "list" ? "M3 5h10M3 8h10M3 11h6" : kind === "delete" ? "M3 5h10M6 5V3h4v2M5 5l.5 9h5L11 5" : "M8 2a6 6 0 100 12A6 6 0 008 2zm0 2v4l3 2",
|
|
314
|
+
fill: "none",
|
|
315
|
+
stroke: "currentColor",
|
|
316
|
+
"stroke-width": 1.3,
|
|
317
|
+
"stroke-linecap": "round",
|
|
318
|
+
"stroke-linejoin": "round"
|
|
319
|
+
}));
|
|
320
|
+
}
|
|
321
|
+
/** Render one line-diff hunk (oldText -> newText) with +/- markers. */
|
|
322
|
+
function DiffBody({ model, openFile, cwd, home }) {
|
|
323
|
+
const h = hx;
|
|
324
|
+
const path = model.path ?? "file";
|
|
325
|
+
const oldText = model.oldText ?? "";
|
|
326
|
+
const newText = model.newText ?? "";
|
|
327
|
+
const pathLabel = relativize(path, cwd, home);
|
|
328
|
+
const rows = [];
|
|
329
|
+
if (oldText !== "") for (const line of oldText.split("\n")) rows.push(h("div", {
|
|
330
|
+
key: "o" + rows.length,
|
|
331
|
+
className: "agy-tv-line agy-tv-line-del"
|
|
332
|
+
}, h("span", { className: "agy-tv-line-marker" }, "-"), h("span", { style: { flex: 1 } }, line === "" ? " " : line)));
|
|
333
|
+
if (newText !== "") for (const line of newText.split("\n")) rows.push(h("div", {
|
|
334
|
+
key: "n" + rows.length,
|
|
335
|
+
className: "agy-tv-line agy-tv-line-add"
|
|
336
|
+
}, h("span", { className: "agy-tv-line-marker" }, "+"), h("span", { style: { flex: 1 } }, line === "" ? " " : line)));
|
|
337
|
+
if (rows.length === 0) rows.push(h("div", {
|
|
338
|
+
key: "empty",
|
|
339
|
+
className: "agy-tv-line"
|
|
340
|
+
}, h("span", { className: "agy-tv-line-marker" }, " "), h("span", { style: {
|
|
341
|
+
flex: 1,
|
|
342
|
+
color: "var(--dsw-alias-label-tertiary,#64748b)"
|
|
343
|
+
} }, "(no textual change)")));
|
|
344
|
+
return h("div", { className: "agy-tv-diff" }, h("div", { className: "agy-tv-diff-path" }, openFile !== void 0 ? h("span", {
|
|
345
|
+
className: "agy-tv-path",
|
|
346
|
+
onClick: () => openFile(path)
|
|
347
|
+
}, pathLabel) : h("span", { style: { cursor: "default" } }, pathLabel)), ...rows);
|
|
348
|
+
}
|
|
349
|
+
function relativize(p, cwd, home) {
|
|
350
|
+
if (cwd && p.startsWith(cwd)) {
|
|
351
|
+
const rel = p.slice(cwd.length).replace(/^[/\\]+/, "");
|
|
352
|
+
return rel !== "" ? rel : p;
|
|
353
|
+
}
|
|
354
|
+
if (home && p.startsWith(home)) return "~" + p.slice(home.length);
|
|
355
|
+
return p;
|
|
356
|
+
}
|
|
357
|
+
function clip(s, max) {
|
|
358
|
+
return s.length > max ? s.slice(0, max) + "\n… (+" + (s.length - max) + " chars)" : s;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* One-line preview of a card's body for the collapsed header: the first
|
|
362
|
+
* non-empty output line, trimmed to a single compact row. Gives a collapsed
|
|
363
|
+
* card a content cue (e.g. `pwd` -> `/Users/.../agy-spaces`) instead of a bare
|
|
364
|
+
* title + state.
|
|
365
|
+
*/
|
|
366
|
+
function previewLine(model, cwd, home) {
|
|
367
|
+
if (model.kind === "diff") {
|
|
368
|
+
const rel = relativize(model.path ?? "file", cwd, home);
|
|
369
|
+
const display = rel.length > 40 ? "…" + rel.slice(-40) : rel;
|
|
370
|
+
return model.oldText != null ? `± ${display}` : `+ ${display}`;
|
|
371
|
+
}
|
|
372
|
+
const out = model.output;
|
|
373
|
+
if (out !== void 0 && out !== "") {
|
|
374
|
+
const first = out.split("\n").find((l) => l.trim() !== "");
|
|
375
|
+
if (first !== void 0 && first.trim() !== "") return first.trim().slice(0, 80);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
/** Small "OUTPUT" caption above a card's result content. */
|
|
379
|
+
function OutputLabel() {
|
|
380
|
+
return hx("div", { className: "agy-tv-label" }, "输出");
|
|
381
|
+
}
|
|
382
|
+
function CardBody({ model, openFile, cwd, home }) {
|
|
383
|
+
const h = hx;
|
|
384
|
+
switch (model.kind) {
|
|
385
|
+
case "terminal": {
|
|
386
|
+
const body = model.output !== void 0 && model.output !== "" ? trimTrailingBlankLines(model.output) : "(no output)";
|
|
387
|
+
return h("div", null, ...model.command !== void 0 && model.command !== "" && model.command !== model.title ? [h("div", {
|
|
388
|
+
key: "cmd",
|
|
389
|
+
className: "agy-tv-term-cmd"
|
|
390
|
+
}, model.command)] : [], ...model.cwd !== void 0 && model.cwd !== "" ? [h("div", {
|
|
391
|
+
key: "cwd",
|
|
392
|
+
className: "agy-tv-term-cwd"
|
|
393
|
+
}, "❯ " + model.cwd)] : [], h(OutputLabel, { key: "ol" }), h("pre", { className: "agy-tv-term" }, clip(body, 8e3)));
|
|
394
|
+
}
|
|
395
|
+
case "diff": return h("div", null, h(OutputLabel, { key: "ol" }), h(DiffBody, {
|
|
396
|
+
model,
|
|
397
|
+
openFile,
|
|
398
|
+
cwd,
|
|
399
|
+
home
|
|
400
|
+
}));
|
|
401
|
+
case "read":
|
|
402
|
+
case "search":
|
|
403
|
+
case "list":
|
|
404
|
+
case "delete": {
|
|
405
|
+
const body = model.output !== void 0 && model.output !== "" ? trimTrailingBlankLines(model.output) : "(no output)";
|
|
406
|
+
return h("div", null, h(OutputLabel, { key: "ol" }), h("pre", { className: "agy-tv-term" }, clip(body, 8e3)));
|
|
407
|
+
}
|
|
408
|
+
default: return h("div", null, h(OutputLabel, { key: "ol" }), h("pre", { className: "agy-tv-raw" }, model.raw !== void 0 && model.raw !== "" ? clip(model.raw, 4e3) : "(no detail)"));
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
function trimTrailingBlankLines(s) {
|
|
412
|
+
return s.replace(/[\t ]*\r?\n[\t ]*(\r?\n[\t ]*)*$/, "\n");
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* The keyed `tool.call.toolview` component for `agy_tool`. Renders the
|
|
416
|
+
* recorded agy tool activity as a native-looking DSH tool card.
|
|
417
|
+
* Receives the ToolCallOwnerProps: { callId, toolName, block, cwd, home,
|
|
418
|
+
* openFile, loadImage, inspect } (locale/inject optional).
|
|
419
|
+
*/
|
|
420
|
+
function AgyMirrorToolView(props) {
|
|
421
|
+
const [open, setOpen] = useToggle(false);
|
|
422
|
+
const h = hx;
|
|
423
|
+
const { block, cwd, home, openFile, inspect } = props;
|
|
424
|
+
const settle = isSettled(block);
|
|
425
|
+
const err = isError(block);
|
|
426
|
+
const model = mirrorCardModel(block, cwd, home);
|
|
427
|
+
const state = !settle ? "run" : err ? "err" : "ok";
|
|
428
|
+
const title = model.title !== "" ? model.title : "agy tool";
|
|
429
|
+
const preview = !open ? previewLine(model, cwd, home) : void 0;
|
|
430
|
+
const header = h("button", {
|
|
431
|
+
type: "button",
|
|
432
|
+
className: "agy-tv-head",
|
|
433
|
+
onClick: (e) => {
|
|
434
|
+
e.stopPropagation();
|
|
435
|
+
setOpen();
|
|
436
|
+
},
|
|
437
|
+
onDoubleClick: (e) => e.stopPropagation(),
|
|
438
|
+
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",
|
|
439
|
+
onContextMenu: inspect !== void 0 ? (e) => {
|
|
440
|
+
e.preventDefault();
|
|
441
|
+
inspect();
|
|
442
|
+
} : void 0
|
|
443
|
+
}, h("span", { className: "agy-tv-icon" }, h(StatusIcon, { kind: model.kind })), h("span", { className: "agy-tv-kind" }, model.kind), ...model.tool !== void 0 && model.tool !== "" ? [h("span", {
|
|
444
|
+
className: "agy-tv-tool",
|
|
445
|
+
title: model.tool
|
|
446
|
+
}, model.tool)] : [], h("span", {
|
|
447
|
+
className: "agy-tv-title",
|
|
448
|
+
title
|
|
449
|
+
}, title), ...preview !== void 0 ? [h("span", {
|
|
450
|
+
className: "agy-tv-preview",
|
|
451
|
+
title: preview
|
|
452
|
+
}, preview)] : [], h("span", { className: cls("agy-tv-state", state === "ok" ? "agy-tv-state-ok" : state === "err" ? "agy-tv-state-err" : "agy-tv-state-run") }, stateLabel(state)), h("span", { style: {
|
|
453
|
+
display: "inline-flex",
|
|
454
|
+
transition: "transform .15s ease",
|
|
455
|
+
transform: open ? "rotate(0deg)" : "rotate(-90deg)"
|
|
456
|
+
} }, h(ChevronDown, null)));
|
|
457
|
+
return h("div", { className: cls("agy-tv-row", open && "agy-tv-open") }, header, h("div", { className: "agy-tv-body" }, h(CardBody, {
|
|
458
|
+
model,
|
|
459
|
+
openFile,
|
|
460
|
+
cwd,
|
|
461
|
+
home
|
|
462
|
+
})));
|
|
463
|
+
}
|
|
464
|
+
/** Install the native tool-card toolview (call once from apply). */
|
|
465
|
+
function installAgyToolView(ctx) {
|
|
466
|
+
ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
|
|
467
|
+
name: "tool.call.toolview",
|
|
468
|
+
key: "agy_tool",
|
|
469
|
+
id: "agy-tool-view",
|
|
470
|
+
label: "Antigravity tool"
|
|
471
|
+
}, AgyMirrorToolView));
|
|
472
|
+
}
|
|
473
|
+
const gDoc = globalThis.document;
|
|
474
|
+
if (gDoc !== void 0 && gDoc !== null) {
|
|
475
|
+
const styleId = "dsh-agy-link-toolview-css";
|
|
476
|
+
if (gDoc.getElementById(styleId) === null) {
|
|
477
|
+
const st = gDoc.createElement("style");
|
|
478
|
+
st.id = styleId;
|
|
479
|
+
st.textContent = ROW_CSS;
|
|
480
|
+
const host = gDoc.head ?? gDoc.documentElement;
|
|
481
|
+
if (host) host.appendChild(st);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
//#endregion
|
|
485
|
+
//#region src/client/locales.ts
|
|
486
|
+
/** Native DSH locale dictionaries for the Antigravity UI. */
|
|
487
|
+
const NS = "agy-link";
|
|
488
|
+
/** Simplified Chinese is preserved as the original UI language and key source. */
|
|
489
|
+
const zh = {
|
|
490
|
+
"section.label": "Antigravity",
|
|
491
|
+
"console.title": "Antigravity 管理控制台",
|
|
492
|
+
"status.ready": "就绪",
|
|
493
|
+
"status.needsAuth": "待认证",
|
|
494
|
+
"status.loading": "正在加载 Antigravity 状态...",
|
|
495
|
+
"status.authRequired": "需重新登录",
|
|
496
|
+
"status.primary": "主用",
|
|
497
|
+
"status.proxy": "代理",
|
|
498
|
+
"account.add": "添加 Google 账号",
|
|
499
|
+
"account.aliasDefault": "备用 Google 账号 {number}",
|
|
500
|
+
"account.defaultAlias": "主账号(系统登录)",
|
|
501
|
+
"account.aliasPlaceholder": "账号别名(例如:备用账号 2)",
|
|
502
|
+
"account.removeTitle": "移除此账号",
|
|
503
|
+
"aria.aliasInput": "账号别名",
|
|
504
|
+
"aria.proxyInput": "专属代理 URL",
|
|
505
|
+
"aria.authCodeInput": "授权码或回调 URL",
|
|
506
|
+
"aria.closeToast": "关闭提示",
|
|
507
|
+
"account.setPrimary": "设为主用",
|
|
508
|
+
"account.settingPrimary": "设置中",
|
|
509
|
+
"account.details": "明细",
|
|
510
|
+
"account.collapse": "收起",
|
|
511
|
+
"account.sync": "同步",
|
|
512
|
+
"account.syncing": "同步中",
|
|
513
|
+
"account.syncTitle": "刷新此账号(换号后立即同步 email / 额度 / 模型)",
|
|
514
|
+
"account.models": "单模型明细:",
|
|
515
|
+
"account.cooldown": "部分模型限流中,已自动切换账号",
|
|
516
|
+
"account.clearCooldown": "清除冷却",
|
|
517
|
+
"account.localCooldown": " · 本地冷却中",
|
|
518
|
+
"account.removed": "已移除账号:{alias}",
|
|
519
|
+
"quota.fiveHour": "5 小时额度",
|
|
520
|
+
"quota.weekly": "周额度",
|
|
521
|
+
"quota.refreshed": "额度已刷新",
|
|
522
|
+
"proxy.button": "代理",
|
|
523
|
+
"proxy.placeholder": "专属代理 URL(如:http://127.0.0.1:7890;留空则使用全局)",
|
|
524
|
+
"proxy.save": "保存",
|
|
525
|
+
"proxy.saved": "代理已保存",
|
|
526
|
+
"cancel": "取消",
|
|
527
|
+
"auth.openBrowser": "打开浏览器登录",
|
|
528
|
+
"auth.openingBrowser": "正在打开浏览器...",
|
|
529
|
+
"auth.browserOpened": "浏览器已打开 Google 授权页,完成授权后将自动同步",
|
|
530
|
+
"auth.browserManual": "无法自动打开浏览器,请点击下方链接手动完成授权",
|
|
531
|
+
"auth.startFailed": "无法启动 Google 授权。请检查网络或代理配置。",
|
|
532
|
+
"auth.networkHint": "请检查网络或代理配置",
|
|
533
|
+
"auth.activated": "账号已激活入池",
|
|
534
|
+
"auth.failed": "授权失败",
|
|
535
|
+
"auth.added": "成功添加并激活 Google 账号",
|
|
536
|
+
"auth.codeFailed": "授权码验证失败",
|
|
537
|
+
"auth.exchanging": "正在验证授权并激活账号,请稍候...",
|
|
538
|
+
"auth.waiting": "等待浏览器中完成 Google 授权,成功后将自动激活。",
|
|
539
|
+
"auth.openManual": "若浏览器未打开,请点击此处手动打开 Google 登录页",
|
|
540
|
+
"auth.pasteHint": "未完成自动回调时,可粘贴授权码或回调 URL:",
|
|
541
|
+
"auth.codePlaceholder": "授权码或 http://localhost:51121/oauth-callback?code=... 完整链接",
|
|
542
|
+
"auth.activate": "手动激活",
|
|
543
|
+
"auth.activating": "验证激活中...",
|
|
544
|
+
"auth.code.browser_manual": "无法自动打开浏览器,请使用下方链接手动授权。",
|
|
545
|
+
"auth.code.callback_failed": "授权回调失败。请重新开始授权。",
|
|
546
|
+
"auth.code.no_active_flow": "当前没有进行中的授权流程。",
|
|
547
|
+
"auth.code.invalid_code": "无法识别授权码。请粘贴授权码或完整回调 URL。",
|
|
548
|
+
"auth.code.invalid_state": "授权链接不属于当前流程或已过期。请重新开始授权。",
|
|
549
|
+
"auth.code.exchange_failed": "授权验证失败。请重新开始授权。",
|
|
550
|
+
"auth.code.primary_activated": "主账号已登录。",
|
|
551
|
+
"auth.code.account_activated": "账号已添加并激活。",
|
|
552
|
+
"auth.code.missing_code": "请输入授权码。",
|
|
553
|
+
"auth.code.request_failed": "请求未完成。请重试。",
|
|
554
|
+
"api.genericError": "操作未完成。请重试。",
|
|
555
|
+
"duration.day": "天",
|
|
556
|
+
"duration.hour": "小时",
|
|
557
|
+
"duration.minute": "分钟",
|
|
558
|
+
"permission.label": "权限模式:",
|
|
559
|
+
"permission.plan": "plan(只读)",
|
|
560
|
+
"permission.acceptEdits": "accept-edits(改代码)",
|
|
561
|
+
"permission.skip": "skip(自动批准;AGY 内部保护仍生效)",
|
|
562
|
+
"effort.label": "思考强度:",
|
|
563
|
+
"effort.auto": "auto",
|
|
564
|
+
"effort.low": "low",
|
|
565
|
+
"effort.medium": "medium",
|
|
566
|
+
"effort.high": "high",
|
|
567
|
+
"pool.label": "号池调度:",
|
|
568
|
+
"pool.sequential": "顺次耗尽",
|
|
569
|
+
"pool.roundRobin": "轮询均衡",
|
|
570
|
+
"header.refreshQuota": "刷新额度",
|
|
571
|
+
"header.refreshing": "刷新中",
|
|
572
|
+
"console.close": "关闭(Esc)",
|
|
573
|
+
"header.badgeTitle": "Antigravity:{count} 个账号已就绪 · 点击打开控制台"
|
|
574
|
+
};
|
|
575
|
+
const en = {
|
|
576
|
+
"section.label": "Antigravity",
|
|
577
|
+
"console.title": "Antigravity Management Console",
|
|
578
|
+
"status.ready": "Ready",
|
|
579
|
+
"status.needsAuth": "Authentication required",
|
|
580
|
+
"status.loading": "Loading Antigravity status...",
|
|
581
|
+
"status.authRequired": "Sign in again required",
|
|
582
|
+
"status.primary": "Primary",
|
|
583
|
+
"status.proxy": "Proxy",
|
|
584
|
+
"account.add": "Add Google account",
|
|
585
|
+
"account.aliasDefault": "Backup Google account {number}",
|
|
586
|
+
"account.defaultAlias": "Primary account (system sign-in)",
|
|
587
|
+
"account.aliasPlaceholder": "Account alias (for example: Backup account 2)",
|
|
588
|
+
"account.removeTitle": "Remove this account",
|
|
589
|
+
"aria.aliasInput": "Account alias",
|
|
590
|
+
"aria.proxyInput": "Dedicated proxy URL",
|
|
591
|
+
"aria.authCodeInput": "Authorization code or callback URL",
|
|
592
|
+
"aria.closeToast": "Dismiss notification",
|
|
593
|
+
"account.setPrimary": "Set as primary",
|
|
594
|
+
"account.settingPrimary": "Setting...",
|
|
595
|
+
"account.details": "Details",
|
|
596
|
+
"account.collapse": "Collapse",
|
|
597
|
+
"account.sync": "Sync",
|
|
598
|
+
"account.syncing": "Syncing...",
|
|
599
|
+
"account.syncTitle": "Refresh this account (sync email, quota, and models after switching accounts)",
|
|
600
|
+
"account.models": "Per-model details:",
|
|
601
|
+
"account.cooldown": "Some models are rate-limited; the account was switched automatically",
|
|
602
|
+
"account.clearCooldown": "Clear cooldown",
|
|
603
|
+
"account.localCooldown": " · local cooldown active",
|
|
604
|
+
"account.removed": "Account removed: {alias}",
|
|
605
|
+
"quota.fiveHour": "5-hour quota",
|
|
606
|
+
"quota.weekly": "Weekly quota",
|
|
607
|
+
"quota.refreshed": "Quota refreshed",
|
|
608
|
+
"proxy.button": "Proxy",
|
|
609
|
+
"proxy.placeholder": "Dedicated proxy URL (for example: http://127.0.0.1:7890; leave blank to use the global proxy)",
|
|
610
|
+
"proxy.save": "Save",
|
|
611
|
+
"proxy.saved": "Proxy saved",
|
|
612
|
+
"cancel": "Cancel",
|
|
613
|
+
"auth.openBrowser": "Open browser to sign in",
|
|
614
|
+
"auth.openingBrowser": "Opening browser...",
|
|
615
|
+
"auth.browserOpened": "The Google authorization page opened in your browser and will sync automatically after authorization",
|
|
616
|
+
"auth.browserManual": "The browser could not be opened automatically; use the link below to authorize manually",
|
|
617
|
+
"auth.startFailed": "Could not start Google authorization. Check your network or proxy configuration.",
|
|
618
|
+
"auth.networkHint": "Check your network or proxy configuration",
|
|
619
|
+
"auth.activated": "Account activated in the pool",
|
|
620
|
+
"auth.failed": "Authorization failed",
|
|
621
|
+
"auth.added": "Google account added and activated",
|
|
622
|
+
"auth.codeFailed": "Authorization code validation failed",
|
|
623
|
+
"auth.exchanging": "Verifying authorization and activating the account; please wait...",
|
|
624
|
+
"auth.waiting": "Complete Google authorization in the browser. The account will activate automatically.",
|
|
625
|
+
"auth.openManual": "If the browser did not open, click here to open the Google sign-in page manually",
|
|
626
|
+
"auth.pasteHint": "If the automatic callback did not complete, paste the authorization code or callback URL:",
|
|
627
|
+
"auth.codePlaceholder": "Authorization code or full http://localhost:51121/oauth-callback?code=... URL",
|
|
628
|
+
"auth.activate": "Activate manually",
|
|
629
|
+
"auth.activating": "Verifying and activating...",
|
|
630
|
+
"auth.code.browser_manual": "The browser could not be opened automatically; use the link below to authorize manually.",
|
|
631
|
+
"auth.code.callback_failed": "The authorization callback failed. Start authorization again.",
|
|
632
|
+
"auth.code.no_active_flow": "There is no active authorization flow.",
|
|
633
|
+
"auth.code.invalid_code": "The authorization code was not recognized. Paste the code or full callback URL.",
|
|
634
|
+
"auth.code.invalid_state": "The authorization link does not belong to this flow or has expired. Start authorization again.",
|
|
635
|
+
"auth.code.exchange_failed": "Authorization verification failed. Start authorization again.",
|
|
636
|
+
"auth.code.primary_activated": "Primary account signed in.",
|
|
637
|
+
"auth.code.account_activated": "Account added and activated.",
|
|
638
|
+
"auth.code.missing_code": "Enter an authorization code.",
|
|
639
|
+
"auth.code.request_failed": "The request did not complete. Try again.",
|
|
640
|
+
"api.genericError": "The operation did not complete. Try again.",
|
|
641
|
+
"duration.day": "d",
|
|
642
|
+
"duration.hour": "h",
|
|
643
|
+
"duration.minute": "m",
|
|
644
|
+
"permission.label": "Permission mode:",
|
|
645
|
+
"permission.plan": "plan (read-only)",
|
|
646
|
+
"permission.acceptEdits": "accept-edits (edit code)",
|
|
647
|
+
"permission.skip": "skip (auto-approve; AGY internal protections remain)",
|
|
648
|
+
"effort.label": "Thinking effort:",
|
|
649
|
+
"effort.auto": "auto",
|
|
650
|
+
"effort.low": "low",
|
|
651
|
+
"effort.medium": "medium",
|
|
652
|
+
"effort.high": "high",
|
|
653
|
+
"pool.label": "Account-pool scheduling:",
|
|
654
|
+
"pool.sequential": "Use sequentially",
|
|
655
|
+
"pool.roundRobin": "Round-robin",
|
|
656
|
+
"header.refreshQuota": "Refresh quota",
|
|
657
|
+
"header.refreshing": "Refreshing...",
|
|
658
|
+
"console.close": "Close (Esc)",
|
|
659
|
+
"header.badgeTitle": "Antigravity: {count} accounts ready · click to open the console"
|
|
660
|
+
};
|
|
661
|
+
const ptBR = {
|
|
662
|
+
"section.label": "Antigravity",
|
|
663
|
+
"console.title": "Console de gerenciamento do Antigravity",
|
|
664
|
+
"status.ready": "Pronto",
|
|
665
|
+
"status.needsAuth": "Autenticação necessária",
|
|
666
|
+
"status.loading": "Carregando o status do Antigravity...",
|
|
667
|
+
"status.authRequired": "É necessário entrar novamente",
|
|
668
|
+
"status.primary": "Principal",
|
|
669
|
+
"status.proxy": "Proxy",
|
|
670
|
+
"account.add": "Adicionar conta Google",
|
|
671
|
+
"account.aliasDefault": "Conta Google reserva {number}",
|
|
672
|
+
"account.defaultAlias": "Conta principal (login do sistema)",
|
|
673
|
+
"account.aliasPlaceholder": "Apelido da conta (por exemplo: Conta reserva 2)",
|
|
674
|
+
"account.removeTitle": "Remover esta conta",
|
|
675
|
+
"aria.aliasInput": "Apelido da conta",
|
|
676
|
+
"aria.proxyInput": "URL do proxy exclusivo",
|
|
677
|
+
"aria.authCodeInput": "Código de autorização ou URL de retorno",
|
|
678
|
+
"aria.closeToast": "Fechar notificação",
|
|
679
|
+
"account.setPrimary": "Definir como principal",
|
|
680
|
+
"account.settingPrimary": "Definindo...",
|
|
681
|
+
"account.details": "Detalhes",
|
|
682
|
+
"account.collapse": "Recolher",
|
|
683
|
+
"account.sync": "Sincronizar",
|
|
684
|
+
"account.syncing": "Sincronizando...",
|
|
685
|
+
"account.syncTitle": "Atualizar esta conta (sincroniza e-mail, cota e modelos depois de trocar de conta)",
|
|
686
|
+
"account.models": "Detalhes por modelo:",
|
|
687
|
+
"account.cooldown": "Alguns modelos estão limitados; a conta foi alternada automaticamente",
|
|
688
|
+
"account.clearCooldown": "Limpar espera",
|
|
689
|
+
"account.localCooldown": " · espera local ativa",
|
|
690
|
+
"account.removed": "Conta removida: {alias}",
|
|
691
|
+
"quota.fiveHour": "Cota de 5 horas",
|
|
692
|
+
"quota.weekly": "Cota semanal",
|
|
693
|
+
"quota.refreshed": "Cota atualizada",
|
|
694
|
+
"proxy.button": "Proxy",
|
|
695
|
+
"proxy.placeholder": "URL do proxy exclusivo (por exemplo: http://127.0.0.1:7890; deixe vazio para usar o proxy global)",
|
|
696
|
+
"proxy.save": "Salvar",
|
|
697
|
+
"proxy.saved": "Proxy salvo",
|
|
698
|
+
"cancel": "Cancelar",
|
|
699
|
+
"auth.openBrowser": "Abrir navegador para entrar",
|
|
700
|
+
"auth.openingBrowser": "Abrindo navegador...",
|
|
701
|
+
"auth.browserOpened": "A página de autorização do Google foi aberta no navegador e será sincronizada após a autorização",
|
|
702
|
+
"auth.browserManual": "Não foi possível abrir o navegador automaticamente; use o link abaixo para autorizar manualmente",
|
|
703
|
+
"auth.startFailed": "Não foi possível iniciar a autorização do Google. Verifique a configuração de rede ou proxy.",
|
|
704
|
+
"auth.networkHint": "Verifique a configuração de rede ou proxy",
|
|
705
|
+
"auth.activated": "Conta ativada no pool",
|
|
706
|
+
"auth.failed": "Falha na autorização",
|
|
707
|
+
"auth.added": "Conta Google adicionada e ativada",
|
|
708
|
+
"auth.codeFailed": "Falha ao validar o código de autorização",
|
|
709
|
+
"auth.exchanging": "Verificando a autorização e ativando a conta; aguarde...",
|
|
710
|
+
"auth.waiting": "Conclua a autorização do Google no navegador. A conta será ativada automaticamente.",
|
|
711
|
+
"auth.openManual": "Se o navegador não abriu, clique aqui para abrir manualmente a página de login do Google",
|
|
712
|
+
"auth.pasteHint": "Se o retorno automático não foi concluído, cole o código de autorização ou a URL de retorno:",
|
|
713
|
+
"auth.codePlaceholder": "Código de autorização ou URL completa http://localhost:51121/oauth-callback?code=...",
|
|
714
|
+
"auth.activate": "Ativar manualmente",
|
|
715
|
+
"auth.activating": "Verificando e ativando...",
|
|
716
|
+
"auth.code.browser_manual": "Não foi possível abrir o navegador automaticamente; use o link abaixo para autorizar manualmente.",
|
|
717
|
+
"auth.code.callback_failed": "O retorno da autorização falhou. Inicie a autorização novamente.",
|
|
718
|
+
"auth.code.no_active_flow": "Não há um fluxo de autorização em andamento.",
|
|
719
|
+
"auth.code.invalid_code": "O código de autorização não foi reconhecido. Cole o código ou a URL completa de retorno.",
|
|
720
|
+
"auth.code.invalid_state": "O link de autorização não pertence a este fluxo ou expirou. Inicie a autorização novamente.",
|
|
721
|
+
"auth.code.exchange_failed": "A validação da autorização falhou. Inicie a autorização novamente.",
|
|
722
|
+
"auth.code.primary_activated": "Conta principal conectada.",
|
|
723
|
+
"auth.code.account_activated": "Conta adicionada e ativada.",
|
|
724
|
+
"auth.code.missing_code": "Informe um código de autorização.",
|
|
725
|
+
"auth.code.request_failed": "A solicitação não foi concluída. Tente novamente.",
|
|
726
|
+
"api.genericError": "A operação não foi concluída. Tente novamente.",
|
|
727
|
+
"duration.day": "d",
|
|
728
|
+
"duration.hour": "h",
|
|
729
|
+
"duration.minute": "min",
|
|
730
|
+
"permission.label": "Modo de permissão:",
|
|
731
|
+
"permission.plan": "plan (somente leitura)",
|
|
732
|
+
"permission.acceptEdits": "accept-edits (editar código)",
|
|
733
|
+
"permission.skip": "skip (aprovação automática; proteções internas do AGY permanecem)",
|
|
734
|
+
"effort.label": "Intensidade de raciocínio:",
|
|
735
|
+
"effort.auto": "auto",
|
|
736
|
+
"effort.low": "low",
|
|
737
|
+
"effort.medium": "medium",
|
|
738
|
+
"effort.high": "high",
|
|
739
|
+
"pool.label": "Agendamento do pool de contas:",
|
|
740
|
+
"pool.sequential": "Usar em sequência",
|
|
741
|
+
"pool.roundRobin": "Rodízio",
|
|
742
|
+
"header.refreshQuota": "Atualizar cota",
|
|
743
|
+
"header.refreshing": "Atualizando...",
|
|
744
|
+
"console.close": "Fechar (Esc)",
|
|
745
|
+
"header.badgeTitle": "Antigravity: {count} contas prontas · clique para abrir o console"
|
|
746
|
+
};
|
|
747
|
+
const es = {
|
|
748
|
+
"section.label": "Antigravity",
|
|
749
|
+
"console.title": "Consola de administración de Antigravity",
|
|
750
|
+
"status.ready": "Listo",
|
|
751
|
+
"status.needsAuth": "Se requiere autenticación",
|
|
752
|
+
"status.loading": "Cargando el estado de Antigravity...",
|
|
753
|
+
"status.authRequired": "Debe iniciar sesión de nuevo",
|
|
754
|
+
"status.primary": "Principal",
|
|
755
|
+
"status.proxy": "Proxy",
|
|
756
|
+
"account.add": "Añadir cuenta de Google",
|
|
757
|
+
"account.aliasDefault": "Cuenta de Google de respaldo {number}",
|
|
758
|
+
"account.defaultAlias": "Cuenta principal (inicio de sesión del sistema)",
|
|
759
|
+
"account.aliasPlaceholder": "Alias de la cuenta (por ejemplo: Cuenta de respaldo 2)",
|
|
760
|
+
"account.removeTitle": "Eliminar esta cuenta",
|
|
761
|
+
"aria.aliasInput": "Alias de la cuenta",
|
|
762
|
+
"aria.proxyInput": "URL de proxy exclusivo",
|
|
763
|
+
"aria.authCodeInput": "Código de autorización o URL de devolución",
|
|
764
|
+
"aria.closeToast": "Cerrar notificación",
|
|
765
|
+
"account.setPrimary": "Establecer como principal",
|
|
766
|
+
"account.settingPrimary": "Configurando...",
|
|
767
|
+
"account.details": "Detalles",
|
|
768
|
+
"account.collapse": "Contraer",
|
|
769
|
+
"account.sync": "Sincronizar",
|
|
770
|
+
"account.syncing": "Sincronizando...",
|
|
771
|
+
"account.syncTitle": "Actualizar esta cuenta (sincroniza correo, cuota y modelos tras cambiar de cuenta)",
|
|
772
|
+
"account.models": "Detalles por modelo:",
|
|
773
|
+
"account.cooldown": "Algunos modelos tienen límite de uso; la cuenta se cambió automáticamente",
|
|
774
|
+
"account.clearCooldown": "Borrar espera",
|
|
775
|
+
"account.localCooldown": " · espera local activa",
|
|
776
|
+
"account.removed": "Cuenta eliminada: {alias}",
|
|
777
|
+
"quota.fiveHour": "Cuota de 5 horas",
|
|
778
|
+
"quota.weekly": "Cuota semanal",
|
|
779
|
+
"quota.refreshed": "Cuota actualizada",
|
|
780
|
+
"proxy.button": "Proxy",
|
|
781
|
+
"proxy.placeholder": "URL de proxy exclusivo (por ejemplo: http://127.0.0.1:7890; déjelo vacío para usar el proxy global)",
|
|
782
|
+
"proxy.save": "Guardar",
|
|
783
|
+
"proxy.saved": "Proxy guardado",
|
|
784
|
+
"cancel": "Cancelar",
|
|
785
|
+
"auth.openBrowser": "Abrir navegador para iniciar sesión",
|
|
786
|
+
"auth.openingBrowser": "Abriendo navegador...",
|
|
787
|
+
"auth.browserOpened": "La página de autorización de Google se abrió en el navegador y se sincronizará después de autorizar",
|
|
788
|
+
"auth.browserManual": "No se pudo abrir el navegador automáticamente; use el enlace de abajo para autorizar manualmente",
|
|
789
|
+
"auth.startFailed": "No se pudo iniciar la autorización de Google. Revise la configuración de red o proxy.",
|
|
790
|
+
"auth.networkHint": "Revise la configuración de red o proxy",
|
|
791
|
+
"auth.activated": "Cuenta activada en el pool",
|
|
792
|
+
"auth.failed": "Falló la autorización",
|
|
793
|
+
"auth.added": "Cuenta de Google añadida y activada",
|
|
794
|
+
"auth.codeFailed": "Falló la validación del código de autorización",
|
|
795
|
+
"auth.exchanging": "Verificando la autorización y activando la cuenta; espere...",
|
|
796
|
+
"auth.waiting": "Complete la autorización de Google en el navegador. La cuenta se activará automáticamente.",
|
|
797
|
+
"auth.openManual": "Si el navegador no se abrió, haga clic aquí para abrir manualmente la página de inicio de sesión de Google",
|
|
798
|
+
"auth.pasteHint": "Si la devolución automática no se completó, pegue el código de autorización o la URL de devolución:",
|
|
799
|
+
"auth.codePlaceholder": "Código de autorización o URL completa http://localhost:51121/oauth-callback?code=...",
|
|
800
|
+
"auth.activate": "Activar manualmente",
|
|
801
|
+
"auth.activating": "Verificando y activando...",
|
|
802
|
+
"auth.code.browser_manual": "No se pudo abrir el navegador automáticamente; use el enlace de abajo para autorizar manualmente.",
|
|
803
|
+
"auth.code.callback_failed": "La devolución de la autorización falló. Inicie la autorización de nuevo.",
|
|
804
|
+
"auth.code.no_active_flow": "No hay un flujo de autorización en curso.",
|
|
805
|
+
"auth.code.invalid_code": "No se reconoció el código de autorización. Pegue el código o la URL completa de devolución.",
|
|
806
|
+
"auth.code.invalid_state": "El enlace de autorización no pertenece a este flujo o caducó. Inicie la autorización de nuevo.",
|
|
807
|
+
"auth.code.exchange_failed": "Falló la validación de la autorización. Inicie la autorización de nuevo.",
|
|
808
|
+
"auth.code.primary_activated": "Cuenta principal conectada.",
|
|
809
|
+
"auth.code.account_activated": "Cuenta añadida y activada.",
|
|
810
|
+
"auth.code.missing_code": "Introduzca un código de autorización.",
|
|
811
|
+
"auth.code.request_failed": "La solicitud no se completó. Inténtelo de nuevo.",
|
|
812
|
+
"api.genericError": "La operación no se completó. Inténtelo de nuevo.",
|
|
813
|
+
"duration.day": "d",
|
|
814
|
+
"duration.hour": "h",
|
|
815
|
+
"duration.minute": "min",
|
|
816
|
+
"permission.label": "Modo de permisos:",
|
|
817
|
+
"permission.plan": "plan (solo lectura)",
|
|
818
|
+
"permission.acceptEdits": "accept-edits (editar código)",
|
|
819
|
+
"permission.skip": "skip (aprobación automática; se mantienen las protecciones internas de AGY)",
|
|
820
|
+
"effort.label": "Intensidad de razonamiento:",
|
|
821
|
+
"effort.auto": "auto",
|
|
822
|
+
"effort.low": "low",
|
|
823
|
+
"effort.medium": "medium",
|
|
824
|
+
"effort.high": "high",
|
|
825
|
+
"pool.label": "Programación del pool de cuentas:",
|
|
826
|
+
"pool.sequential": "Usar en secuencia",
|
|
827
|
+
"pool.roundRobin": "Turno rotativo",
|
|
828
|
+
"header.refreshQuota": "Actualizar cuota",
|
|
829
|
+
"header.refreshing": "Actualizando...",
|
|
830
|
+
"console.close": "Cerrar (Esc)",
|
|
831
|
+
"header.badgeTitle": "Antigravity: {count} cuentas listas · haga clic para abrir la consola"
|
|
832
|
+
};
|
|
833
|
+
//#endregion
|
|
34
834
|
//#region src/client/index.ts
|
|
35
835
|
const { createElement: h, useState, useEffect, useRef } = require("react");
|
|
36
836
|
const reactDom = require("react-dom");
|
|
@@ -90,7 +890,7 @@ window.__ModuleLoader__.load({
|
|
|
90
890
|
/**
|
|
91
891
|
* Format reset timestamp into readable date/time + relative countdown.
|
|
92
892
|
*/
|
|
93
|
-
function formatQuotaWindow(resetTimeStr) {
|
|
893
|
+
function formatQuotaWindow(t, resetTimeStr) {
|
|
94
894
|
if (!resetTimeStr) return { resetText: "" };
|
|
95
895
|
try {
|
|
96
896
|
const d = new Date(resetTimeStr);
|
|
@@ -101,7 +901,7 @@ window.__ModuleLoader__.load({
|
|
|
101
901
|
const hours = Math.floor(totalMins % 1440 / 60);
|
|
102
902
|
const mins = totalMins % 60;
|
|
103
903
|
const isWeekly = days >= 1;
|
|
104
|
-
const countdown = days > 0 ? `${days}
|
|
904
|
+
const countdown = days > 0 ? `${days}${t("duration.day")} ${hours}${t("duration.hour")}` : hours > 0 ? `${hours}${t("duration.hour")} ${mins}${t("duration.minute")}` : `${mins}${t("duration.minute")}`;
|
|
105
905
|
const hh = d.getHours().toString().padStart(2, "0");
|
|
106
906
|
const mm = d.getMinutes().toString().padStart(2, "0");
|
|
107
907
|
return { resetText: isWeekly ? `${d.getMonth() + 1}/${d.getDate()} ${hh}:${mm} (${countdown})` : `${hh}:${mm} (${countdown})` };
|
|
@@ -750,7 +1550,39 @@ body.dark,
|
|
|
750
1550
|
}
|
|
751
1551
|
};
|
|
752
1552
|
function apply(ctx) {
|
|
1553
|
+
const locale = ctx.locale;
|
|
1554
|
+
if (locale) ctx.effect(() => {
|
|
1555
|
+
const disposePtBR = locale.addLanguage({
|
|
1556
|
+
id: "pt-BR",
|
|
1557
|
+
label: "Português (Brasil)",
|
|
1558
|
+
fallback: "en"
|
|
1559
|
+
});
|
|
1560
|
+
const disposeEs = locale.addLanguage({
|
|
1561
|
+
id: "es",
|
|
1562
|
+
label: "Español",
|
|
1563
|
+
fallback: "en"
|
|
1564
|
+
});
|
|
1565
|
+
const disposeZh = locale.register(NS, "zh", zh);
|
|
1566
|
+
const disposeEn = locale.register(NS, "en", en);
|
|
1567
|
+
const disposePtBRDictionary = locale.register(NS, "pt-BR", ptBR);
|
|
1568
|
+
const disposeEsDictionary = locale.register(NS, "es", es);
|
|
1569
|
+
return () => {
|
|
1570
|
+
disposeEsDictionary();
|
|
1571
|
+
disposePtBRDictionary();
|
|
1572
|
+
disposeEn();
|
|
1573
|
+
disposeZh();
|
|
1574
|
+
disposeEs();
|
|
1575
|
+
disposePtBR();
|
|
1576
|
+
};
|
|
1577
|
+
}, "agy-link: locale dictionaries");
|
|
1578
|
+
const tFallback = ((key) => zh[key]);
|
|
1579
|
+
const useAgyTranslation = () => {
|
|
1580
|
+
const [, rerender] = useState(0);
|
|
1581
|
+
useEffect(() => locale?.subscribe(() => rerender((revision) => revision + 1)) ?? (() => {}), []);
|
|
1582
|
+
return locale?.bind("agy-link") ?? tFallback;
|
|
1583
|
+
};
|
|
753
1584
|
const AgySettingsSection = (props) => {
|
|
1585
|
+
const t = useAgyTranslation();
|
|
754
1586
|
const [status, setStatus] = useState(statusCache);
|
|
755
1587
|
const [aliasInput, setAliasInput] = useState("");
|
|
756
1588
|
const [proxyInputs, setProxyInputs] = useState({});
|
|
@@ -780,6 +1612,10 @@ body.dark,
|
|
|
780
1612
|
};
|
|
781
1613
|
}, []);
|
|
782
1614
|
const flowStartedRef = useRef(false);
|
|
1615
|
+
const safeMessage = (code) => {
|
|
1616
|
+
const key = `auth.code.${code ?? ""}`;
|
|
1617
|
+
return code && key in en ? t(key) : t("api.genericError");
|
|
1618
|
+
};
|
|
783
1619
|
useEffect(() => {
|
|
784
1620
|
if (!addingAccount || !flowStartedRef.current) return;
|
|
785
1621
|
const pa = status?.poolAuth;
|
|
@@ -789,15 +1625,15 @@ body.dark,
|
|
|
789
1625
|
setAddingAccount(false);
|
|
790
1626
|
setAuthCodeInput("");
|
|
791
1627
|
setAliasInput("");
|
|
792
|
-
showToast(pa.
|
|
1628
|
+
showToast(safeMessage(pa.code), "success");
|
|
793
1629
|
} else if (pa.phase === "failed") {
|
|
794
1630
|
flowStartedRef.current = false;
|
|
795
|
-
showToast(pa.
|
|
1631
|
+
showToast(safeMessage(pa.code), "error");
|
|
796
1632
|
}
|
|
797
1633
|
}, [
|
|
798
1634
|
addingAccount,
|
|
799
1635
|
status?.poolAuth?.phase,
|
|
800
|
-
status?.poolAuth?.
|
|
1636
|
+
status?.poolAuth?.code
|
|
801
1637
|
]);
|
|
802
1638
|
const showToast = (text, type = "info") => {
|
|
803
1639
|
setToast({
|
|
@@ -814,14 +1650,15 @@ body.dark,
|
|
|
814
1650
|
};
|
|
815
1651
|
const handleBeginAddAccount = async () => {
|
|
816
1652
|
setLoadingAction("pool:beginAdd");
|
|
817
|
-
const
|
|
1653
|
+
const alias = aliasInput.trim();
|
|
1654
|
+
const res = await postJson("/plugins/agy-link/pool/begin-add", alias ? { alias } : {});
|
|
818
1655
|
setLoadingAction(null);
|
|
819
1656
|
if (res && res.ok) {
|
|
820
1657
|
flowStartedRef.current = true;
|
|
821
1658
|
await refresh();
|
|
822
|
-
if (res.browserOpened) showToast("
|
|
823
|
-
else showToast("
|
|
824
|
-
} else showToast(
|
|
1659
|
+
if (res.browserOpened) showToast(t("auth.browserOpened"), "info");
|
|
1660
|
+
else showToast(t("auth.browserManual"), "warn");
|
|
1661
|
+
} else showToast(res?.code ? safeMessage(res.code) : t("auth.startFailed"), "error");
|
|
825
1662
|
};
|
|
826
1663
|
const handleCompleteAddAccount = async () => {
|
|
827
1664
|
if (!authCodeInput.trim()) return;
|
|
@@ -834,8 +1671,8 @@ body.dark,
|
|
|
834
1671
|
setAliasInput("");
|
|
835
1672
|
setAddingAccount(false);
|
|
836
1673
|
await refresh();
|
|
837
|
-
showToast(res.
|
|
838
|
-
} else showToast(res?.
|
|
1674
|
+
showToast(safeMessage(res.code), "success");
|
|
1675
|
+
} else showToast(safeMessage(res?.code), "error");
|
|
839
1676
|
};
|
|
840
1677
|
const handleCancelAddAccount = async () => {
|
|
841
1678
|
flowStartedRef.current = false;
|
|
@@ -859,21 +1696,21 @@ body.dark,
|
|
|
859
1696
|
await postJson("/plugins/agy-link/pool/primary", { id });
|
|
860
1697
|
await refresh();
|
|
861
1698
|
setLoadingAction(null);
|
|
862
|
-
showToast("
|
|
1699
|
+
showToast(t("account.setPrimary"), "success");
|
|
863
1700
|
};
|
|
864
1701
|
const removeAccount = async (id, alias) => {
|
|
865
1702
|
setLoadingAction(`remove:${id}`);
|
|
866
1703
|
await postJson("/plugins/agy-link/pool/remove", { id });
|
|
867
1704
|
await refresh();
|
|
868
1705
|
setLoadingAction(null);
|
|
869
|
-
showToast(
|
|
1706
|
+
showToast(t("account.removed", { alias }), "info");
|
|
870
1707
|
};
|
|
871
1708
|
const refreshQuota = async (id) => {
|
|
872
1709
|
setLoadingAction(id ? `refresh:${id}` : "refresh:all");
|
|
873
1710
|
await postJson("/plugins/agy-link/pool/refresh-quota", { id });
|
|
874
1711
|
await refresh();
|
|
875
1712
|
setLoadingAction(null);
|
|
876
|
-
showToast("
|
|
1713
|
+
showToast(t("quota.refreshed"), "success");
|
|
877
1714
|
};
|
|
878
1715
|
const saveProxy = async (id) => {
|
|
879
1716
|
setLoadingAction(`proxy:${id}`);
|
|
@@ -885,7 +1722,7 @@ body.dark,
|
|
|
885
1722
|
setEditingProxyId(null);
|
|
886
1723
|
await refresh();
|
|
887
1724
|
setLoadingAction(null);
|
|
888
|
-
showToast("
|
|
1725
|
+
showToast(t("proxy.saved"), "success");
|
|
889
1726
|
};
|
|
890
1727
|
const setMode = async (mode) => {
|
|
891
1728
|
setLoadingAction(`mode:${mode}`);
|
|
@@ -898,7 +1735,7 @@ body.dark,
|
|
|
898
1735
|
await postJson("/plugins/agy-link/pool/clear-cooldown", { id });
|
|
899
1736
|
await refresh();
|
|
900
1737
|
setLoadingAction(null);
|
|
901
|
-
showToast("
|
|
1738
|
+
showToast(t("account.clearCooldown"), "success");
|
|
902
1739
|
};
|
|
903
1740
|
const toggleExpand = (accId) => {
|
|
904
1741
|
setExpandedModels((prev) => ({
|
|
@@ -956,7 +1793,8 @@ body.dark,
|
|
|
956
1793
|
display: "inline-flex",
|
|
957
1794
|
alignItems: "center"
|
|
958
1795
|
},
|
|
959
|
-
onClick: () => setToast(null)
|
|
1796
|
+
onClick: () => setToast(null),
|
|
1797
|
+
"aria-label": t("aria.closeToast")
|
|
960
1798
|
}, uiIcon("x", 12)));
|
|
961
1799
|
};
|
|
962
1800
|
const renderQuotaBar = (label, familyKey, acc) => {
|
|
@@ -964,10 +1802,10 @@ body.dark,
|
|
|
964
1802
|
const cd = acc.cooldowns[familyKey];
|
|
965
1803
|
const inCooldown = cd && cd.cooldownUntil > Date.now();
|
|
966
1804
|
const pct5h = typeof info?.remainingFraction === "number" && Number.isFinite(info.remainingFraction) ? Math.max(0, Math.min(100, Math.round(info.remainingFraction * 100))) : -1;
|
|
967
|
-
const cdNote = inCooldown ? "
|
|
968
|
-
const w5h = formatQuotaWindow(info?.resetTime);
|
|
1805
|
+
const cdNote = inCooldown ? t("account.localCooldown") : "";
|
|
1806
|
+
const w5h = formatQuotaWindow(t, info?.resetTime);
|
|
969
1807
|
const pctWeekly = typeof info?.weeklyFraction === "number" && Number.isFinite(info.weeklyFraction) ? Math.max(0, Math.min(100, Math.round(info.weeklyFraction * 100))) : -1;
|
|
970
|
-
const wWeekly = formatQuotaWindow(info?.weeklyResetTime);
|
|
1808
|
+
const wWeekly = formatQuotaWindow(t, info?.weeklyResetTime);
|
|
971
1809
|
const getColors = (pct) => {
|
|
972
1810
|
if (pct < 0) return {
|
|
973
1811
|
bar: "var(--agy-quota-none-border)",
|
|
@@ -1052,7 +1890,7 @@ body.dark,
|
|
|
1052
1890
|
fontSize: "12.5px",
|
|
1053
1891
|
marginBottom: "5px",
|
|
1054
1892
|
color: "var(--agy-text-primary)"
|
|
1055
|
-
} }, brandIcon(FAMILY_BRAND[familyKey], 14), h("span", null, label)), renderLine("
|
|
1893
|
+
} }, brandIcon(FAMILY_BRAND[familyKey], 14), h("span", null, label)), renderLine(t("quota.fiveHour"), pct5h, c5h, w5h.resetText ? w5h.resetText + cdNote : cdNote.replace(/^ · /, "")), renderLine(t("quota.weekly"), pctWeekly, cWeekly, wWeekly.resetText));
|
|
1056
1894
|
};
|
|
1057
1895
|
const renderedAccountCards = accounts.map((acc) => {
|
|
1058
1896
|
const isPrimary = acc.id === pool?.primaryAccountId;
|
|
@@ -1062,6 +1900,8 @@ body.dark,
|
|
|
1062
1900
|
const isEditingProxy = editingProxyId === acc.id;
|
|
1063
1901
|
const isExpanded = expandedModels[acc.id] ?? false;
|
|
1064
1902
|
const cardStyle = isPrimary ? { ...S.cardPrimary } : { ...S.card };
|
|
1903
|
+
const legacyDefault = acc.defaultAlias === void 0 && acc.systemHome && acc.alias === "主账号 (系统登录)";
|
|
1904
|
+
const displayAlias = acc.defaultAlias || legacyDefault ? acc.systemHome ? t("account.defaultAlias") : t("account.aliasDefault", { number: accounts.indexOf(acc) + 1 }) : acc.alias;
|
|
1065
1905
|
const googleModels = acc.quotas.google?.models ?? [];
|
|
1066
1906
|
const anthropicModels = acc.quotas.anthropic?.models ?? [];
|
|
1067
1907
|
const openaiModels = acc.quotas.openai?.models ?? [];
|
|
@@ -1103,14 +1943,14 @@ body.dark,
|
|
|
1103
1943
|
fontWeight: 700,
|
|
1104
1944
|
fontSize: "13.5px",
|
|
1105
1945
|
color: "var(--agy-text-primary)"
|
|
1106
|
-
} },
|
|
1946
|
+
} }, displayAlias), isAuthRequired ? h("span", { style: {
|
|
1107
1947
|
...S.badgeTag,
|
|
1108
1948
|
background: "var(--agy-badge-email-bg)",
|
|
1109
1949
|
color: "#ef4444",
|
|
1110
1950
|
borderColor: "#fca5a5",
|
|
1111
1951
|
gap: "4px",
|
|
1112
1952
|
fontWeight: 700
|
|
1113
|
-
} }, uiIcon("alert", 11, "#ef4444"), "
|
|
1953
|
+
} }, uiIcon("alert", 11, "#ef4444"), t("status.authRequired")) : null, acc.email ? h("span", { style: {
|
|
1114
1954
|
...S.badgeTag,
|
|
1115
1955
|
background: "var(--agy-badge-email-bg)",
|
|
1116
1956
|
color: "var(--agy-badge-email-text)",
|
|
@@ -1119,13 +1959,13 @@ body.dark,
|
|
|
1119
1959
|
} }, uiIcon("mail", 11, "var(--agy-badge-email-text)"), acc.email) : null, isPrimary ? h("span", { style: {
|
|
1120
1960
|
...S.badgePrimary,
|
|
1121
1961
|
gap: "4px"
|
|
1122
|
-
} }, uiIcon("star", 10, "var(--agy-badge-primary-text)"), "
|
|
1962
|
+
} }, uiIcon("star", 10, "var(--agy-badge-primary-text)"), t("status.primary")) : null, acc.proxyUrl ? h("span", { style: {
|
|
1123
1963
|
...S.badgeTag,
|
|
1124
1964
|
background: "var(--agy-badge-proxy-bg)",
|
|
1125
1965
|
color: "var(--agy-badge-proxy-text)",
|
|
1126
1966
|
borderColor: "var(--agy-badge-proxy-border)",
|
|
1127
1967
|
gap: "5px"
|
|
1128
|
-
} }, uiIcon("globe", 11, "var(--agy-badge-proxy-text)"), "
|
|
1968
|
+
} }, uiIcon("globe", 11, "var(--agy-badge-proxy-text)"), t("status.proxy")) : null), h("div", { style: {
|
|
1129
1969
|
display: "flex",
|
|
1130
1970
|
gap: "5px",
|
|
1131
1971
|
alignItems: "center"
|
|
@@ -1140,17 +1980,17 @@ body.dark,
|
|
|
1140
1980
|
gap: "3px"
|
|
1141
1981
|
},
|
|
1142
1982
|
onClick: () => toggleExpand(acc.id)
|
|
1143
|
-
}, isExpanded ? [uiIcon("chevronUp", 11),
|
|
1983
|
+
}, isExpanded ? [uiIcon("chevronUp", 11), ` ${t("account.collapse")}`] : [uiIcon("chevronDown", 11), ` ${t("account.details")}`]) : null, h("button", {
|
|
1144
1984
|
type: "button",
|
|
1145
1985
|
className: "agy-btn",
|
|
1146
1986
|
style: {
|
|
1147
1987
|
...S.btnSm,
|
|
1148
1988
|
gap: "4px"
|
|
1149
1989
|
},
|
|
1150
|
-
title: "
|
|
1990
|
+
title: t("account.syncTitle"),
|
|
1151
1991
|
disabled: isBusy,
|
|
1152
1992
|
onClick: () => void refreshQuota(acc.id)
|
|
1153
|
-
}, loadingAction === `refresh:${acc.id}` ? [renderSpinner(), "
|
|
1993
|
+
}, loadingAction === `refresh:${acc.id}` ? [renderSpinner(), t("account.syncing")] : [uiIcon("refresh", 11), ` ${t("account.sync")}`]), !isPrimary ? h("button", {
|
|
1154
1994
|
type: "button",
|
|
1155
1995
|
className: "agy-btn",
|
|
1156
1996
|
style: {
|
|
@@ -1159,7 +1999,7 @@ body.dark,
|
|
|
1159
1999
|
},
|
|
1160
2000
|
disabled: isBusy,
|
|
1161
2001
|
onClick: () => void setPrimary(acc.id)
|
|
1162
|
-
}, loadingAction === `primary:${acc.id}` ? [renderSpinner(), "
|
|
2002
|
+
}, loadingAction === `primary:${acc.id}` ? [renderSpinner(), t("account.settingPrimary")] : [uiIcon("star", 11), ` ${t("account.setPrimary")}`]) : null, h("button", {
|
|
1163
2003
|
type: "button",
|
|
1164
2004
|
className: "agy-btn",
|
|
1165
2005
|
style: isEditingProxy ? {
|
|
@@ -1171,16 +2011,17 @@ body.dark,
|
|
|
1171
2011
|
},
|
|
1172
2012
|
disabled: isBusy,
|
|
1173
2013
|
onClick: () => setEditingProxyId(isEditingProxy ? null : acc.id)
|
|
1174
|
-
}, [uiIcon("globe", 11),
|
|
2014
|
+
}, [uiIcon("globe", 11), ` ${t("proxy.button")}`]), accounts.length > 1 ? h("button", {
|
|
1175
2015
|
type: "button",
|
|
1176
2016
|
className: "agy-btn",
|
|
1177
2017
|
style: {
|
|
1178
2018
|
...S.btnDanger,
|
|
1179
2019
|
padding: "3px 7px"
|
|
1180
2020
|
},
|
|
1181
|
-
title: "
|
|
2021
|
+
title: t("account.removeTitle"),
|
|
2022
|
+
"aria-label": t("account.removeTitle"),
|
|
1182
2023
|
disabled: isBusy,
|
|
1183
|
-
onClick: () => void removeAccount(acc.id,
|
|
2024
|
+
onClick: () => void removeAccount(acc.id, displayAlias)
|
|
1184
2025
|
}, 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: {
|
|
1185
2026
|
marginTop: "8px",
|
|
1186
2027
|
paddingTop: "8px",
|
|
@@ -1190,10 +2031,10 @@ body.dark,
|
|
|
1190
2031
|
marginBottom: "6px",
|
|
1191
2032
|
fontWeight: 600,
|
|
1192
2033
|
fontSize: "11px"
|
|
1193
|
-
} }, "
|
|
2034
|
+
} }, t("account.models")), allChildModels.map(({ family, model }) => {
|
|
1194
2035
|
const frac = model.remainingFraction ?? 1;
|
|
1195
2036
|
const pct = Math.round(frac * 100);
|
|
1196
|
-
const w = formatQuotaWindow(model.resetTime);
|
|
2037
|
+
const w = formatQuotaWindow(t, model.resetTime);
|
|
1197
2038
|
const pColor = pct <= 20 ? "var(--agy-quota-low-text)" : pct <= 50 ? "var(--agy-quota-med-text)" : "var(--agy-quota-high-text)";
|
|
1198
2039
|
return h("div", {
|
|
1199
2040
|
key: model.modelId,
|
|
@@ -1228,7 +2069,7 @@ body.dark,
|
|
|
1228
2069
|
display: "flex",
|
|
1229
2070
|
alignItems: "center",
|
|
1230
2071
|
gap: "6px"
|
|
1231
|
-
} }, uiIcon("alert", 13, "var(--agy-warn-text)"), h("span", null, "
|
|
2072
|
+
} }, uiIcon("alert", 13, "var(--agy-warn-text)"), h("span", null, t("account.cooldown"))), h("button", {
|
|
1232
2073
|
type: "button",
|
|
1233
2074
|
className: "agy-btn",
|
|
1234
2075
|
style: {
|
|
@@ -1240,7 +2081,7 @@ body.dark,
|
|
|
1240
2081
|
},
|
|
1241
2082
|
disabled: isBusy,
|
|
1242
2083
|
onClick: () => void clearCooldown(acc.id)
|
|
1243
|
-
}, loadingAction === `clearCooldown:${acc.id}` ? [renderSpinner(), ""] : [uiIcon("zap", 11, "var(--agy-warn-btn-text)"),
|
|
2084
|
+
}, loadingAction === `clearCooldown:${acc.id}` ? [renderSpinner(), ""] : [uiIcon("zap", 11, "var(--agy-warn-btn-text)"), ` ${t("account.clearCooldown")}`])) : null, isEditingProxy ? h("div", { style: {
|
|
1244
2085
|
marginTop: "8px",
|
|
1245
2086
|
padding: "10px 12px",
|
|
1246
2087
|
background: "var(--agy-bg-subbox)",
|
|
@@ -1252,7 +2093,8 @@ body.dark,
|
|
|
1252
2093
|
} }, h("input", {
|
|
1253
2094
|
style: S.input,
|
|
1254
2095
|
value: proxyInputs[acc.id] !== void 0 ? proxyInputs[acc.id] : acc.proxyUrl ?? "",
|
|
1255
|
-
placeholder: "
|
|
2096
|
+
placeholder: t("proxy.placeholder"),
|
|
2097
|
+
"aria-label": t("aria.proxyInput"),
|
|
1256
2098
|
onChange: (e) => setProxyInputs({
|
|
1257
2099
|
...proxyInputs,
|
|
1258
2100
|
[acc.id]: e.target.value
|
|
@@ -1263,17 +2105,21 @@ body.dark,
|
|
|
1263
2105
|
style: S.btnPrimary,
|
|
1264
2106
|
disabled: isBusy,
|
|
1265
2107
|
onClick: () => void saveProxy(acc.id)
|
|
1266
|
-
}, loadingAction === `proxy:${acc.id}` ? [renderSpinner(), "
|
|
2108
|
+
}, loadingAction === `proxy:${acc.id}` ? [renderSpinner(), t("proxy.save")] : t("proxy.save")), h("button", {
|
|
1267
2109
|
type: "button",
|
|
1268
2110
|
className: "agy-btn",
|
|
1269
2111
|
style: S.btn,
|
|
1270
2112
|
onClick: () => setEditingProxyId(null)
|
|
1271
|
-
}, "
|
|
2113
|
+
}, t("cancel")))) : null);
|
|
1272
2114
|
});
|
|
1273
2115
|
const poolAuth = status?.poolAuth;
|
|
1274
2116
|
const flowPhase = poolAuth?.phase ?? "idle";
|
|
1275
2117
|
const flowActive = flowPhase === "waiting" || flowPhase === "exchanging";
|
|
1276
|
-
const addAccountSection = addingAccount ? h("div", {
|
|
2118
|
+
const addAccountSection = addingAccount ? h("div", {
|
|
2119
|
+
style: S.authModal,
|
|
2120
|
+
role: "group",
|
|
2121
|
+
"aria-label": t("account.add")
|
|
2122
|
+
}, h("div", { style: {
|
|
1277
2123
|
fontWeight: 700,
|
|
1278
2124
|
fontSize: "13.5px",
|
|
1279
2125
|
marginBottom: "10px",
|
|
@@ -1281,13 +2127,14 @@ body.dark,
|
|
|
1281
2127
|
alignItems: "center",
|
|
1282
2128
|
gap: "6px",
|
|
1283
2129
|
color: "var(--agy-text-primary)"
|
|
1284
|
-
} }, uiIcon("plus", 13, "var(--agy-btn-primary-bg)"), "
|
|
2130
|
+
} }, uiIcon("plus", 13, "var(--agy-btn-primary-bg)"), t("account.add")), !flowActive ? h("div", null, h("div", { style: {
|
|
1285
2131
|
display: "flex",
|
|
1286
2132
|
gap: "8px"
|
|
1287
2133
|
} }, h("input", {
|
|
1288
2134
|
style: S.input,
|
|
1289
2135
|
value: aliasInput,
|
|
1290
|
-
placeholder: "
|
|
2136
|
+
placeholder: t("account.aliasPlaceholder"),
|
|
2137
|
+
"aria-label": t("aria.aliasInput"),
|
|
1291
2138
|
onChange: (e) => setAliasInput(e.target.value)
|
|
1292
2139
|
}), h("button", {
|
|
1293
2140
|
type: "button",
|
|
@@ -1298,12 +2145,12 @@ body.dark,
|
|
|
1298
2145
|
},
|
|
1299
2146
|
disabled: isBusy,
|
|
1300
2147
|
onClick: () => void handleBeginAddAccount()
|
|
1301
|
-
}, loadingAction === "pool:beginAdd" ? [renderSpinner(), "
|
|
2148
|
+
}, loadingAction === "pool:beginAdd" ? [renderSpinner(), t("auth.openingBrowser")] : [uiIcon("externalLink", 12, "#ffffff"), ` ${t("auth.openBrowser")}`]), h("button", {
|
|
1302
2149
|
type: "button",
|
|
1303
2150
|
className: "agy-btn",
|
|
1304
2151
|
style: S.btn,
|
|
1305
2152
|
onClick: () => handleCancelAddAccount()
|
|
1306
|
-
}, "
|
|
2153
|
+
}, t("cancel"))), flowPhase === "failed" ? h("div", { style: {
|
|
1307
2154
|
...S.muted,
|
|
1308
2155
|
color: "var(--agy-danger-text)",
|
|
1309
2156
|
marginTop: "8px",
|
|
@@ -1311,14 +2158,14 @@ body.dark,
|
|
|
1311
2158
|
alignItems: "center",
|
|
1312
2159
|
gap: "5px",
|
|
1313
2160
|
fontWeight: 600
|
|
1314
|
-
} }, uiIcon("alert", 12, "var(--agy-danger-text)"), poolAuth
|
|
2161
|
+
} }, uiIcon("alert", 12, "var(--agy-danger-text)"), safeMessage(poolAuth?.code)) : null) : h("div", null, h("div", { style: {
|
|
1315
2162
|
display: "flex",
|
|
1316
2163
|
alignItems: "center",
|
|
1317
2164
|
color: "var(--agy-text-secondary)",
|
|
1318
2165
|
marginBottom: "8px",
|
|
1319
2166
|
lineHeight: 1.5,
|
|
1320
2167
|
fontSize: "12px"
|
|
1321
|
-
} }, renderSpinner(), flowPhase === "exchanging" ? "
|
|
2168
|
+
} }, renderSpinner(), flowPhase === "exchanging" ? t("auth.exchanging") : t("auth.waiting")), poolAuth?.url ? h("div", { style: { marginBottom: "8px" } }, h("a", {
|
|
1322
2169
|
href: poolAuth.url,
|
|
1323
2170
|
target: "_blank",
|
|
1324
2171
|
style: {
|
|
@@ -1330,18 +2177,19 @@ body.dark,
|
|
|
1330
2177
|
alignItems: "center",
|
|
1331
2178
|
gap: "4px"
|
|
1332
2179
|
}
|
|
1333
|
-
}, uiIcon("externalLink", 12, "currentColor"), "
|
|
2180
|
+
}, uiIcon("externalLink", 12, "currentColor"), t("auth.openManual"))) : null, h("div", { style: {
|
|
1334
2181
|
color: "var(--agy-text-tertiary)",
|
|
1335
2182
|
marginBottom: "6px",
|
|
1336
2183
|
fontSize: "11px",
|
|
1337
2184
|
fontWeight: 500
|
|
1338
|
-
} }, "
|
|
2185
|
+
} }, t("auth.pasteHint")), h("div", { style: {
|
|
1339
2186
|
display: "flex",
|
|
1340
2187
|
gap: "8px"
|
|
1341
2188
|
} }, h("input", {
|
|
1342
2189
|
style: S.input,
|
|
1343
2190
|
value: authCodeInput,
|
|
1344
|
-
placeholder: "
|
|
2191
|
+
placeholder: t("auth.codePlaceholder"),
|
|
2192
|
+
"aria-label": t("aria.authCodeInput"),
|
|
1345
2193
|
onChange: (e) => setAuthCodeInput(e.target.value)
|
|
1346
2194
|
}), h("button", {
|
|
1347
2195
|
type: "button",
|
|
@@ -1352,19 +2200,19 @@ body.dark,
|
|
|
1352
2200
|
},
|
|
1353
2201
|
disabled: isBusy || !authCodeInput.trim(),
|
|
1354
2202
|
onClick: () => void handleCompleteAddAccount()
|
|
1355
|
-
}, loadingAction === "pool:completeAdd" ? [renderSpinner(), "
|
|
2203
|
+
}, loadingAction === "pool:completeAdd" ? [renderSpinner(), t("auth.activating")] : [uiIcon("check", 12, "#ffffff"), ` ${t("auth.activate")}`]), h("button", {
|
|
1356
2204
|
type: "button",
|
|
1357
2205
|
className: "agy-btn",
|
|
1358
2206
|
style: S.btn,
|
|
1359
2207
|
onClick: () => handleCancelAddAccount()
|
|
1360
|
-
}, "
|
|
2208
|
+
}, t("cancel"))))) : null;
|
|
1361
2209
|
if (status === null) return h("div", { style: {
|
|
1362
2210
|
...S.container,
|
|
1363
2211
|
minHeight: "120px",
|
|
1364
2212
|
display: "flex",
|
|
1365
2213
|
alignItems: "center",
|
|
1366
2214
|
justifyContent: "center"
|
|
1367
|
-
} }, h("style", null, GLOBAL_CSS), h("span", { style: S.muted }, [renderSpinner(), "
|
|
2215
|
+
} }, h("style", null, GLOBAL_CSS), h("span", { style: S.muted }, [renderSpinner(), t("status.loading")]));
|
|
1368
2216
|
return h("div", { style: S.container }, h("style", null, GLOBAL_CSS), h("div", { style: S.headerCard }, h("div", { style: {
|
|
1369
2217
|
display: "flex",
|
|
1370
2218
|
alignItems: "center",
|
|
@@ -1373,7 +2221,7 @@ body.dark,
|
|
|
1373
2221
|
fontWeight: 700,
|
|
1374
2222
|
fontSize: "14px",
|
|
1375
2223
|
color: "var(--agy-text-primary)"
|
|
1376
|
-
} }, "Antigravity"), h("span", { style: isAuthed ? S.badgeReady : S.badgeUnready }, isAuthed ? "
|
|
2224
|
+
} }, "Antigravity"), h("span", { style: isAuthed ? S.badgeReady : S.badgeUnready }, isAuthed ? t("status.ready") : t("status.needsAuth"))), h("div", { style: {
|
|
1377
2225
|
display: "flex",
|
|
1378
2226
|
gap: "6px",
|
|
1379
2227
|
alignItems: "center"
|
|
@@ -1385,7 +2233,7 @@ body.dark,
|
|
|
1385
2233
|
gap: "4px"
|
|
1386
2234
|
},
|
|
1387
2235
|
onClick: () => setAddingAccount(true)
|
|
1388
|
-
}, [uiIcon("plus", 12, "#ffffff"),
|
|
2236
|
+
}, [uiIcon("plus", 12, "#ffffff"), ` ${t("account.add")}`]) : null, h("button", {
|
|
1389
2237
|
type: "button",
|
|
1390
2238
|
className: "agy-btn",
|
|
1391
2239
|
style: {
|
|
@@ -1394,7 +2242,7 @@ body.dark,
|
|
|
1394
2242
|
},
|
|
1395
2243
|
disabled: isBusy,
|
|
1396
2244
|
onClick: () => void refreshQuota()
|
|
1397
|
-
}, loadingAction === "refresh:all" ? [renderSpinner(), "
|
|
2245
|
+
}, loadingAction === "refresh:all" ? [renderSpinner(), t("header.refreshing")] : [uiIcon("refresh", 12, "var(--agy-text-btn)"), ` ${t("header.refreshQuota")}`]))), renderToastBanner(), addAccountSection, renderedAccountCards, h("div", { style: {
|
|
1398
2246
|
marginTop: "16px",
|
|
1399
2247
|
paddingTop: "12px",
|
|
1400
2248
|
borderTop: "1px solid var(--agy-border-divider)"
|
|
@@ -1410,15 +2258,15 @@ body.dark,
|
|
|
1410
2258
|
color: "var(--agy-text-primary)",
|
|
1411
2259
|
fontWeight: 600,
|
|
1412
2260
|
fontSize: "12.5px"
|
|
1413
|
-
} }, "
|
|
2261
|
+
} }, t("permission.label")), h("div", { style: S.segGroup }, h("button", {
|
|
1414
2262
|
type: "button",
|
|
1415
2263
|
style: status?.permissionMode === "plan" ? S.segBtnActive : S.segBtn,
|
|
1416
2264
|
onClick: () => void setCfg("permissionMode", "plan")
|
|
1417
|
-
}, "plan
|
|
2265
|
+
}, t("permission.plan")), h("button", {
|
|
1418
2266
|
type: "button",
|
|
1419
2267
|
style: status?.permissionMode === "accept-edits" ? S.segBtnActive : S.segBtn,
|
|
1420
2268
|
onClick: () => void setCfg("permissionMode", "accept-edits")
|
|
1421
|
-
},
|
|
2269
|
+
}, t("permission.acceptEdits")), h("button", {
|
|
1422
2270
|
type: "button",
|
|
1423
2271
|
style: status?.permissionMode === "skip" ? {
|
|
1424
2272
|
...S.segBtnActive,
|
|
@@ -1427,7 +2275,7 @@ body.dark,
|
|
|
1427
2275
|
border: "1px solid var(--agy-seg-danger-border)"
|
|
1428
2276
|
} : S.segBtn,
|
|
1429
2277
|
onClick: () => void setCfg("permissionMode", "skip")
|
|
1430
|
-
}, "skip
|
|
2278
|
+
}, t("permission.skip")))), h("div", { style: {
|
|
1431
2279
|
display: "flex",
|
|
1432
2280
|
alignItems: "center",
|
|
1433
2281
|
justifyContent: "space-between"
|
|
@@ -1435,23 +2283,23 @@ body.dark,
|
|
|
1435
2283
|
color: "var(--agy-text-primary)",
|
|
1436
2284
|
fontWeight: 600,
|
|
1437
2285
|
fontSize: "12.5px"
|
|
1438
|
-
} }, "
|
|
2286
|
+
} }, t("effort.label")), h("div", { style: S.segGroup }, h("button", {
|
|
1439
2287
|
type: "button",
|
|
1440
2288
|
style: status?.defaultEffort === "" ? S.segBtnActive : S.segBtn,
|
|
1441
2289
|
onClick: () => void setCfg("defaultEffort", "")
|
|
1442
|
-
}, "auto"), h("button", {
|
|
2290
|
+
}, t("effort.auto")), h("button", {
|
|
1443
2291
|
type: "button",
|
|
1444
2292
|
style: status?.defaultEffort === "low" ? S.segBtnActive : S.segBtn,
|
|
1445
2293
|
onClick: () => void setCfg("defaultEffort", "low")
|
|
1446
|
-
}, "low"), h("button", {
|
|
2294
|
+
}, t("effort.low")), h("button", {
|
|
1447
2295
|
type: "button",
|
|
1448
2296
|
style: status?.defaultEffort === "medium" ? S.segBtnActive : S.segBtn,
|
|
1449
2297
|
onClick: () => void setCfg("defaultEffort", "medium")
|
|
1450
|
-
}, "medium"), h("button", {
|
|
2298
|
+
}, t("effort.medium")), h("button", {
|
|
1451
2299
|
type: "button",
|
|
1452
2300
|
style: status?.defaultEffort === "high" ? S.segBtnActive : S.segBtn,
|
|
1453
2301
|
onClick: () => void setCfg("defaultEffort", "high")
|
|
1454
|
-
}, "high"))), h("div", { style: {
|
|
2302
|
+
}, t("effort.high")))), h("div", { style: {
|
|
1455
2303
|
display: "flex",
|
|
1456
2304
|
alignItems: "center",
|
|
1457
2305
|
justifyContent: "space-between"
|
|
@@ -1459,18 +2307,19 @@ body.dark,
|
|
|
1459
2307
|
color: "var(--agy-text-primary)",
|
|
1460
2308
|
fontWeight: 600,
|
|
1461
2309
|
fontSize: "12.5px"
|
|
1462
|
-
} }, "
|
|
2310
|
+
} }, t("pool.label")), h("div", { style: S.segGroup }, h("button", {
|
|
1463
2311
|
type: "button",
|
|
1464
2312
|
style: pool?.mode === "sequential" || !pool?.mode ? S.segBtnActive : S.segBtn,
|
|
1465
2313
|
onClick: () => void setMode("sequential")
|
|
1466
|
-
}, "
|
|
2314
|
+
}, t("pool.sequential")), h("button", {
|
|
1467
2315
|
type: "button",
|
|
1468
2316
|
style: pool?.mode === "round-robin" ? S.segBtnActive : S.segBtn,
|
|
1469
2317
|
onClick: () => void setMode("round-robin")
|
|
1470
|
-
}, "
|
|
2318
|
+
}, t("pool.roundRobin")))))));
|
|
1471
2319
|
};
|
|
1472
2320
|
/** Modal dialog container rendered into document.body */
|
|
1473
2321
|
const AgyModalDialog = () => {
|
|
2322
|
+
const t = useAgyTranslation();
|
|
1474
2323
|
const [isOpen, setIsOpen] = useState(agyModalStore.open);
|
|
1475
2324
|
useEffect(() => {
|
|
1476
2325
|
return agyModalStore.subscribe(() => {
|
|
@@ -1497,7 +2346,8 @@ body.dark,
|
|
|
1497
2346
|
}, h("div", {
|
|
1498
2347
|
className: "agy-modal-panel",
|
|
1499
2348
|
role: "dialog",
|
|
1500
|
-
"aria-modal": true
|
|
2349
|
+
"aria-modal": true,
|
|
2350
|
+
"aria-labelledby": "agy-console-title"
|
|
1501
2351
|
}, h("div", { style: {
|
|
1502
2352
|
display: "flex",
|
|
1503
2353
|
alignItems: "center",
|
|
@@ -1510,13 +2360,17 @@ body.dark,
|
|
|
1510
2360
|
display: "flex",
|
|
1511
2361
|
alignItems: "center",
|
|
1512
2362
|
gap: "8px"
|
|
1513
|
-
} }, agyIcon(18), h("strong", {
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
2363
|
+
} }, agyIcon(18), h("strong", {
|
|
2364
|
+
id: "agy-console-title",
|
|
2365
|
+
style: {
|
|
2366
|
+
fontSize: "14.5px",
|
|
2367
|
+
fontWeight: 700,
|
|
2368
|
+
color: "var(--agy-text-primary)"
|
|
2369
|
+
}
|
|
2370
|
+
}, t("console.title"))), h("button", {
|
|
1518
2371
|
type: "button",
|
|
1519
|
-
title: "
|
|
2372
|
+
title: t("console.close"),
|
|
2373
|
+
"aria-label": t("console.close"),
|
|
1520
2374
|
style: {
|
|
1521
2375
|
background: "var(--agy-bg-btn)",
|
|
1522
2376
|
border: "1px solid var(--agy-border-btn)",
|
|
@@ -1540,6 +2394,7 @@ body.dark,
|
|
|
1540
2394
|
};
|
|
1541
2395
|
/** Session Header badge in chat toolbar */
|
|
1542
2396
|
const AgySessionStatus = () => {
|
|
2397
|
+
const t = useAgyTranslation();
|
|
1543
2398
|
const [status, setStatus] = useState(statusCache);
|
|
1544
2399
|
useEffect(() => {
|
|
1545
2400
|
let alive = true;
|
|
@@ -1566,7 +2421,7 @@ body.dark,
|
|
|
1566
2421
|
const color = status === null ? "#64748b" : status.dormantReason ? "#f59e0b" : hasCooldown ? "#f59e0b" : isAuthed ? "#10b981" : "#f59e0b";
|
|
1567
2422
|
const badge = h("button", {
|
|
1568
2423
|
type: "button",
|
|
1569
|
-
title:
|
|
2424
|
+
title: t("header.badgeTitle", { count: accounts.length }),
|
|
1570
2425
|
className: "agy-btn",
|
|
1571
2426
|
onClick: () => agyModalStore.setOpen(true),
|
|
1572
2427
|
style: {
|
|
@@ -1598,7 +2453,8 @@ body.dark,
|
|
|
1598
2453
|
name: "conversation.session.header.actions",
|
|
1599
2454
|
id: "agy-link-status",
|
|
1600
2455
|
order: 10,
|
|
1601
|
-
label: "
|
|
2456
|
+
label: () => locale ? locale.bind(NS)("section.label") : zh["section.label"],
|
|
2457
|
+
locale: NS
|
|
1602
2458
|
}, AgySessionStatus);
|
|
1603
2459
|
});
|
|
1604
2460
|
ctx.slots.inject("settings.section", () => {
|
|
@@ -1606,9 +2462,11 @@ body.dark,
|
|
|
1606
2462
|
name: "settings.section",
|
|
1607
2463
|
id: "agy-link",
|
|
1608
2464
|
order: 20,
|
|
1609
|
-
label: "
|
|
2465
|
+
label: () => locale ? locale.bind(NS)("section.label") : zh["section.label"],
|
|
2466
|
+
locale: NS
|
|
1610
2467
|
}, AgySettingsSection);
|
|
1611
2468
|
});
|
|
2469
|
+
installAgyToolView(ctx);
|
|
1612
2470
|
}
|
|
1613
2471
|
//#endregion
|
|
1614
2472
|
exports.apply = apply;
|