dsh-connect-trae 3.9.1 → 3.10.0
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 +139 -0
- package/lib/client.js +437 -157
- package/lib/index.d.ts +196 -1
- package/lib/index.js +530 -27
- package/package.json +3 -2
package/lib/client.js
CHANGED
|
@@ -20,11 +20,6 @@ window.__ModuleLoader__.load({
|
|
|
20
20
|
}
|
|
21
21
|
//#endregion
|
|
22
22
|
//#region src/status-paths.ts
|
|
23
|
-
/**
|
|
24
|
-
* Node-free constants and types shared by the Host and browser halves.
|
|
25
|
-
* Mirrors the `dsh-workbuddy-connect` status-route pattern so the plugin card
|
|
26
|
-
* stays consistent with that project's external presentation.
|
|
27
|
-
*/
|
|
28
23
|
/** Plugin-owned usage endpoint consumed by its browser half. */
|
|
29
24
|
const TRAE_USAGE_PATH = "/plugins/dsh-connect-trae/usage";
|
|
30
25
|
/** Plugin-owned live model refresh endpoint. */
|
|
@@ -587,6 +582,7 @@ window.__ModuleLoader__.load({
|
|
|
587
582
|
.dsm-trae-account-checkin{appearance:none;font:inherit;cursor:pointer;white-space:nowrap;border:1px solid rgba(86,134,254,.4);border-radius:7px;padding:2px 9px;font-size:12px;line-height:18px;font-weight:500;color:var(--dsw-alias-brand-primary,#5686fe);background:rgba(86,134,254,.08)}
|
|
588
583
|
.dsm-trae-account-checkin:hover:not(:disabled){background:rgba(86,134,254,.16)}
|
|
589
584
|
.dsm-trae-account-checkin:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#5686fe);outline-offset:1px}
|
|
585
|
+
.dsm-trae-account-checkin-state{font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary,#9aa0a8);white-space:nowrap}
|
|
590
586
|
/* A disabled check-in still STATES something ("claimed", "device used"), so it
|
|
591
587
|
stays readable 鈥?clearly inactive, not invisible. */
|
|
592
588
|
.dsm-trae-account-checkin:disabled{opacity:.55;cursor:default;border-color:transparent;color:var(--dsw-alias-label-tertiary,#9aa0a8);background:transparent}
|
|
@@ -658,6 +654,8 @@ window.__ModuleLoader__.load({
|
|
|
658
654
|
must stay mounted to be clicked. */
|
|
659
655
|
.dsm-trae-transfer{margin-top:12px;padding-top:10px;border-top:1px solid var(--dsw-alias-border-l2,rgba(127,127,127,.2))}
|
|
660
656
|
.dsm-trae-transfer-label{margin:0 0 6px;font-size:11px;line-height:16px;color:var(--dsw-alias-label-secondary,GrayText)}
|
|
657
|
+
.dsm-trae-transfer-flat{margin-top:0;padding-top:0;border-top:0}
|
|
658
|
+
.dsm-trae-transfer-flat .dsm-trae-transfer-actions{flex-wrap:nowrap}
|
|
661
659
|
.dsm-trae-transfer-actions{display:flex;flex-wrap:wrap;gap:8px}
|
|
662
660
|
.dsm-trae-transfer-file{display:none}
|
|
663
661
|
.dsm-trae-transfer-status{margin:6px 0 0;font-size:11px;line-height:16px}
|
|
@@ -786,15 +784,18 @@ window.__ModuleLoader__.load({
|
|
|
786
784
|
/* Removing an account from the pool is destructive (it drops THIS panel's saved
|
|
787
785
|
membership), so the hover state takes the error tone rather than the neutral
|
|
788
786
|
one every other outline button gets. */
|
|
789
|
-
|
|
790
|
-
.
|
|
787
|
+
/* The destructive Delete is visually heavier than 移除 from the start (error
|
|
788
|
+
colour idle), so the row shows two distinct actions instead of two greys. */
|
|
789
|
+
.dsm-trae-pool-delete{color:var(--dsw-alias-state-error-primary,#d92d20)}
|
|
790
|
+
.dsm-trae-pool-delete:hover:not(:disabled){background:rgba(217,45,32,.08)}
|
|
791
|
+
.dsm-trae-pool-delete-hint{margin:0;padding:8px var(--dsm-trae-pool-pad-x);border:1px solid var(--dsw-alias-state-error-primary,#d92d20);border-radius:10px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary,#c6c9d0);background:var(--dsw-alias-bg-layer-3,#2a2c33)}
|
|
791
792
|
.dsm-trae-pool-busy{font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary,#9aa0a8)}
|
|
793
|
+
.dsm-trae-pool-action-note{margin:0;font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary,#9aa0a8)}
|
|
792
794
|
.dsm-trae-pool-card{display:flex;flex-direction:column;min-width:0;border:1px solid var(--dsw-alias-border-l2,#3a3d45);border-radius:var(--dsm-trae-pool-radius);background:var(--dsw-alias-bg-layer-2,#24262c);overflow:hidden}
|
|
793
|
-
.dsm-trae-pool-card-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px var(--dsm-trae-pool-pad-x)
|
|
795
|
+
.dsm-trae-pool-card-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px var(--dsm-trae-pool-pad-x) 12px}
|
|
794
796
|
.dsm-trae-pool-card-title{margin:0;font-size:13px;line-height:18px;font-weight:600;color:var(--dsw-alias-label-primary,#e6e6e6)}
|
|
795
797
|
.dsm-trae-pool-card-tools{display:flex;align-items:center;gap:8px;flex:none}
|
|
796
798
|
.dsm-trae-pool-count{font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary,#9aa0a8)}
|
|
797
|
-
.dsm-trae-pool-card-note{margin:0;padding:6px var(--dsm-trae-pool-pad-x) 12px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary,#9aa0a8)}
|
|
798
799
|
.dsm-trae-pool-card .dsm-trae-pool-table{border:0;border-radius:0;border-top:1px solid var(--dsw-alias-border-l1,rgba(127,127,127,.18))}
|
|
799
800
|
.dsm-trae-pool-members{display:flex;flex-direction:column;gap:10px}
|
|
800
801
|
/* Prose, not a box. Every explanation in this section is one line of muted
|
|
@@ -831,7 +832,7 @@ window.__ModuleLoader__.load({
|
|
|
831
832
|
.dsm-trae-pool-subtitle{margin:0;font-size:12px;font-weight:600;line-height:18px;color:var(--dsw-alias-label-primary,#e6e6e6)}
|
|
832
833
|
.dsm-trae-pool-subnote{margin:2px 0 0;font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary,#9aa0a8)}
|
|
833
834
|
.dsm-trae-pool-select-actions{display:flex;flex:none;gap:6px}
|
|
834
|
-
.dsm-trae-pool-select-actions .dsm-btn,.dsm-trae-pool-row-actions .dsm-btn
|
|
835
|
+
.dsm-trae-pool-select-actions .dsm-btn,.dsm-trae-pool-row-actions .dsm-btn{padding:4px 10px;font-size:12px;line-height:1.4}
|
|
835
836
|
.dsm-trae-pool-table{--dsm-trae-pool-cols:minmax(0,1.4fr) 128px minmax(0,1.2fr) 96px 128px;display:flex;flex-direction:column;border:1px solid var(--dsw-alias-border-l2,#3a3d45);border-radius:var(--dsm-trae-pool-radius);overflow:hidden;background:var(--dsw-alias-bg-layer-2,#24262c)}
|
|
836
837
|
.dsm-trae-pool-table-no-checkin{--dsm-trae-pool-cols:minmax(0,1.4fr) 128px minmax(0,1.2fr) 128px}
|
|
837
838
|
.dsm-trae-pool-row{display:grid;grid-template-columns:var(--dsm-trae-pool-cols);align-items:start;gap:10px;padding:var(--dsm-trae-pool-pad-y) var(--dsm-trae-pool-pad-x);border-top:1px solid var(--dsw-alias-border-l1,rgba(127,127,127,.18))}
|
|
@@ -898,8 +899,12 @@ window.__ModuleLoader__.load({
|
|
|
898
899
|
/* "Every member is unusable" is the one case that IS the pool's fault, so it
|
|
899
900
|
keeps the warn tone the base class sets. */
|
|
900
901
|
.dsm-trae-pool-warning-unusable{border-color:var(--dsw-alias-state-warn-secondary,#fbbf24);background:var(--dsw-alias-state-warn-tertiary,#fef3c7);color:var(--dsw-alias-state-warn-primary,#b45309)}
|
|
901
|
-
|
|
902
|
-
|
|
902
|
+
/* The sign-in/refresh workflow sits in the settings block: it keeps the warn
|
|
903
|
+
tone (getting it wrong loses an account) but is not a fault of the pool. */
|
|
904
|
+
.dsm-trae-pool-warning-workflow{margin:0 0 2px}
|
|
905
|
+
.dsm-trae-pool-save-row{display:flex;align-items:center;justify-content:space-between;gap:12px;border-top:1px solid var(--dsw-alias-border-l2,#36373b);padding-top:12px}
|
|
906
|
+
.dsm-trae-pool-save-buttons{display:flex;align-items:center;justify-content:flex-end;gap:8px}
|
|
907
|
+
.dsm-trae-pool-save-row .dsm-btn{padding:5px 14px;font-size:13px;line-height:1.5}
|
|
903
908
|
.dsm-trae-pool-dirty{padding:0 6px;border-radius:999px;background:var(--dsw-alias-state-warn-tertiary,#fef3c7);color:var(--dsw-alias-state-warn-primary,#b45309);font-size:10px;line-height:16px}
|
|
904
909
|
.dsm-trae-pool-save-error{margin:0;font-size:12px;line-height:18px;color:var(--dsw-alias-state-error-primary,#d92d20)}
|
|
905
910
|
.dsm-trae-pool-target{display:flex;flex-direction:column;gap:6px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary,#c6c9d0)}
|
|
@@ -1272,34 +1277,74 @@ window.__ModuleLoader__.load({
|
|
|
1272
1277
|
return t("row.poolErrGeneric", { status: String(status) });
|
|
1273
1278
|
}
|
|
1274
1279
|
/**
|
|
1275
|
-
*
|
|
1276
|
-
*
|
|
1277
|
-
*
|
|
1278
|
-
*
|
|
1280
|
+
* Handle ONE NDJSON line of a `test` answer. A non-JSON line is skipped; a
|
|
1281
|
+
* `{reason:'pool-failed'}` line reports the failure and counts as "saw
|
|
1282
|
+
* something". Returns whether the line was usable, so the caller can tell "the
|
|
1283
|
+
* route answered nothing parseable" (a bug to surface) from "not finished yet".
|
|
1279
1284
|
*/
|
|
1280
|
-
function
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1285
|
+
function applyTestLine(line, t, onRow, onFailure) {
|
|
1286
|
+
if (line.trim() === "") return false;
|
|
1287
|
+
let parsed;
|
|
1288
|
+
try {
|
|
1289
|
+
parsed = JSON.parse(line);
|
|
1290
|
+
} catch {
|
|
1291
|
+
return false;
|
|
1292
|
+
}
|
|
1293
|
+
if (parsed.row !== void 0) {
|
|
1294
|
+
onRow(parsed.row);
|
|
1295
|
+
return true;
|
|
1296
|
+
}
|
|
1297
|
+
if (parsed.rows !== void 0) {
|
|
1298
|
+
for (const r of parsed.rows) onRow(r);
|
|
1299
|
+
return true;
|
|
1300
|
+
}
|
|
1301
|
+
if (parsed.reason === "pool-failed") {
|
|
1302
|
+
onFailure(parsed.error ?? t("row.poolLogGeneric"));
|
|
1303
|
+
return true;
|
|
1304
|
+
}
|
|
1305
|
+
return false;
|
|
1306
|
+
}
|
|
1307
|
+
/**
|
|
1308
|
+
* Read the answer line by line AS IT ARRIVES.
|
|
1309
|
+
*
|
|
1310
|
+
* The Host streams one line per account, but `response.text()` waits for the
|
|
1311
|
+
* whole body: with a slow probe the card sat on "逐个处理账号中…" and looked
|
|
1312
|
+
* frozen (a single member could take half a minute). Reading the body stream
|
|
1313
|
+
* makes each finished account appear immediately, and an empty/failed stream
|
|
1314
|
+
* still ends the loop instead of hanging the busy state forever.
|
|
1315
|
+
*/
|
|
1316
|
+
async function* testLinesOf(response) {
|
|
1317
|
+
const body = response.body;
|
|
1318
|
+
if (body === null) {
|
|
1319
|
+
for (const line of (await response.text()).split(/\r?\n/)) yield line;
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
const reader = body.getReader();
|
|
1323
|
+
const decoder = new TextDecoder();
|
|
1324
|
+
let buffer = "";
|
|
1325
|
+
for (;;) {
|
|
1326
|
+
const { done, value } = await reader.read();
|
|
1327
|
+
if (done) break;
|
|
1328
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1329
|
+
let cut = buffer.indexOf("\n");
|
|
1330
|
+
while (cut >= 0) {
|
|
1331
|
+
yield buffer.slice(0, cut);
|
|
1332
|
+
buffer = buffer.slice(cut + 1);
|
|
1333
|
+
cut = buffer.indexOf("\n");
|
|
1299
1334
|
}
|
|
1300
1335
|
}
|
|
1301
|
-
|
|
1336
|
+
buffer += decoder.decode();
|
|
1337
|
+
if (buffer.trim() !== "") yield buffer;
|
|
1302
1338
|
}
|
|
1339
|
+
/**
|
|
1340
|
+
* How long one `test` request may take before the card gives up.
|
|
1341
|
+
*
|
|
1342
|
+
* A probe has its own upstream deadline, but a stalled connection (a restarting
|
|
1343
|
+
* Host, a dropped keep-alive) has none: without this the run button stays
|
|
1344
|
+
* disabled until the page is reloaded, which reads as "测速卡住了". Sized for a
|
|
1345
|
+
* batch: a few seconds per account plus room for the slowest upstream.
|
|
1346
|
+
*/
|
|
1347
|
+
const TEST_TIMEOUT_MS = 18e4;
|
|
1303
1348
|
function AccountPool({ panel, pool, models, t, settingsScope, onChanged, onRefresh, tools, topActions, details, claims, onClaim, deviceClaimed = false, onBind, bindingBusy }) {
|
|
1304
1349
|
const [settingsTick, setSettingsTick] = (0, react.useState)(0);
|
|
1305
1350
|
const saved = (0, react.useMemo)(() => {
|
|
@@ -1336,7 +1381,8 @@ window.__ModuleLoader__.load({
|
|
|
1336
1381
|
const [saveError, setSaveError] = (0, react.useState)(void 0);
|
|
1337
1382
|
const [testing, setTesting] = (0, react.useState)(void 0);
|
|
1338
1383
|
const [rows, setRows] = (0, react.useState)({});
|
|
1339
|
-
const [
|
|
1384
|
+
const [deletingIds, setDeletingIds] = (0, react.useState)(() => /* @__PURE__ */ new Set());
|
|
1385
|
+
const [deleteHint, setDeleteHint] = (0, react.useState)(void 0);
|
|
1340
1386
|
const [log, setLog] = (0, react.useState)([]);
|
|
1341
1387
|
const [now, setNow] = (0, react.useState)(Date.now());
|
|
1342
1388
|
const logId = (0, react.useRef)(0);
|
|
@@ -1364,10 +1410,14 @@ window.__ModuleLoader__.load({
|
|
|
1364
1410
|
const ghosts = (0, react.useMemo)(() => {
|
|
1365
1411
|
const names = pool.memberNames ?? {};
|
|
1366
1412
|
const result = [];
|
|
1367
|
-
for (const id of saved.memberAccountIds ?? [])
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1413
|
+
for (const id of saved.memberAccountIds ?? []) {
|
|
1414
|
+
if (knownIds.has(id)) continue;
|
|
1415
|
+
const name = names[id];
|
|
1416
|
+
result.push({
|
|
1417
|
+
accountId: id,
|
|
1418
|
+
accountName: name === void 0 || name === "" ? id : name
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1371
1421
|
return result;
|
|
1372
1422
|
}, [
|
|
1373
1423
|
saved,
|
|
@@ -1376,12 +1426,27 @@ window.__ModuleLoader__.load({
|
|
|
1376
1426
|
]);
|
|
1377
1427
|
const dirty = enabled !== saved.enabled || (targetModelId ?? "") !== (saved.targetModelId ?? "") || probeSupported && probeInputTokens !== saved.probeInputTokens || !sameIds([...selected], saved.memberAccountIds);
|
|
1378
1428
|
const writable = settingsScope?.getSnapshot().writable === true;
|
|
1379
|
-
const
|
|
1429
|
+
const savedMemberKey = (0, react.useMemo)(() => [...saved.memberAccountIds ?? []].sort().join("\0"), [saved]);
|
|
1380
1430
|
(0, react.useEffect)(() => {
|
|
1381
1431
|
setEnabled(saved.enabled);
|
|
1432
|
+
}, [panel, saved.enabled]);
|
|
1433
|
+
(0, react.useEffect)(() => {
|
|
1382
1434
|
setTargetModelId(saved.targetModelId ?? "");
|
|
1435
|
+
}, [panel, saved.targetModelId]);
|
|
1436
|
+
(0, react.useEffect)(() => {
|
|
1383
1437
|
setProbeInputTokens(saved.probeInputTokens);
|
|
1438
|
+
}, [panel, saved.probeInputTokens]);
|
|
1439
|
+
(0, react.useEffect)(() => {
|
|
1384
1440
|
setSelected(new Set(saved.memberAccountIds ?? []));
|
|
1441
|
+
}, [panel, savedMemberKey]);
|
|
1442
|
+
const savedKey = (0, react.useMemo)(() => `${panel}:${saved.enabled}:${saved.targetModelId ?? ""}:${saved.probeInputTokens}:${savedMemberKey}`, [
|
|
1443
|
+
panel,
|
|
1444
|
+
saved.enabled,
|
|
1445
|
+
saved.targetModelId,
|
|
1446
|
+
saved.probeInputTokens,
|
|
1447
|
+
savedMemberKey
|
|
1448
|
+
]);
|
|
1449
|
+
(0, react.useEffect)(() => {
|
|
1385
1450
|
setSaveError(void 0);
|
|
1386
1451
|
}, [savedKey]);
|
|
1387
1452
|
const toggleMember = (accountId) => {
|
|
@@ -1485,14 +1550,24 @@ window.__ModuleLoader__.load({
|
|
|
1485
1550
|
count: members.length,
|
|
1486
1551
|
model: targetLabel
|
|
1487
1552
|
}));
|
|
1553
|
+
const controller = new AbortController();
|
|
1554
|
+
const timer = setTimeout(() => {
|
|
1555
|
+
controller.abort();
|
|
1556
|
+
}, TEST_TIMEOUT_MS);
|
|
1488
1557
|
try {
|
|
1489
|
-
const
|
|
1558
|
+
const response = await fetch(withTraePoolAction(panel, "test"), {
|
|
1559
|
+
method: "POST",
|
|
1560
|
+
signal: controller.signal
|
|
1561
|
+
});
|
|
1490
1562
|
const seen = /* @__PURE__ */ new Set();
|
|
1491
|
-
|
|
1563
|
+
let sawAny = false;
|
|
1564
|
+
for await (const line of testLinesOf(response)) if (applyTestLine(line, t, (r) => {
|
|
1565
|
+
const fresh = !seen.has(r.accountId);
|
|
1492
1566
|
setRows((prev) => ({
|
|
1493
1567
|
...prev,
|
|
1494
1568
|
[r.accountId]: r
|
|
1495
1569
|
}));
|
|
1570
|
+
if (!fresh) return;
|
|
1496
1571
|
seen.add(r.accountId);
|
|
1497
1572
|
if (mountRef.current) setTesting({ done: seen.size });
|
|
1498
1573
|
pushLog(outcomeTone(r.outcome), t("row.poolLogTestRow", {
|
|
@@ -1501,13 +1576,15 @@ window.__ModuleLoader__.load({
|
|
|
1501
1576
|
}));
|
|
1502
1577
|
}, (errorText) => {
|
|
1503
1578
|
pushLog("error", t("row.poolLogBatchFailed", { message: errorText }));
|
|
1504
|
-
}))
|
|
1579
|
+
})) sawAny = true;
|
|
1580
|
+
if (!sawAny) throw new Error(t("row.poolLogGeneric"));
|
|
1505
1581
|
pushLog("ok", t("row.poolLogTestDone"));
|
|
1506
1582
|
onRefresh?.();
|
|
1507
1583
|
setNow(Date.now());
|
|
1508
1584
|
} catch (error) {
|
|
1509
|
-
pushLog("error", t("row.poolLogBatchFailed", { message: error instanceof Error ? error.message : String(error) }));
|
|
1585
|
+
pushLog("error", t(controller.signal.aborted ? "row.poolLogTimeout" : "row.poolLogBatchFailed", { message: error instanceof Error ? error.message : String(error) }));
|
|
1510
1586
|
} finally {
|
|
1587
|
+
clearTimeout(timer);
|
|
1511
1588
|
if (mountRef.current) {
|
|
1512
1589
|
setBusy(void 0);
|
|
1513
1590
|
setTesting(void 0);
|
|
@@ -1520,12 +1597,24 @@ window.__ModuleLoader__.load({
|
|
|
1520
1597
|
setNow(Date.now());
|
|
1521
1598
|
const targetLabel = targetModelId === "" ? t("row.poolTargetAutoOption") : models.find((m) => m.id === targetModelId)?.name ?? targetModelId;
|
|
1522
1599
|
pushLog("info", t("row.poolLogRowTesting", { accountName: account.accountName }));
|
|
1600
|
+
const controller = new AbortController();
|
|
1601
|
+
const timer = setTimeout(() => {
|
|
1602
|
+
controller.abort();
|
|
1603
|
+
}, TEST_TIMEOUT_MS);
|
|
1523
1604
|
try {
|
|
1524
|
-
|
|
1605
|
+
const response = await fetch(withTraePoolAccount(panel, "test", account.accountId), {
|
|
1606
|
+
method: "POST",
|
|
1607
|
+
signal: controller.signal
|
|
1608
|
+
});
|
|
1609
|
+
let sawAny = false;
|
|
1610
|
+
const logged = /* @__PURE__ */ new Set();
|
|
1611
|
+
for await (const line of testLinesOf(response)) if (applyTestLine(line, t, (r) => {
|
|
1525
1612
|
setRows((prev) => ({
|
|
1526
1613
|
...prev,
|
|
1527
1614
|
[r.accountId]: r
|
|
1528
1615
|
}));
|
|
1616
|
+
if (logged.has(r.accountId)) return;
|
|
1617
|
+
logged.add(r.accountId);
|
|
1529
1618
|
pushLog(outcomeTone(r.outcome), t("row.poolLogTestRow", {
|
|
1530
1619
|
accountName: r.accountName,
|
|
1531
1620
|
outcome: outcomeLabel(r.outcome, t),
|
|
@@ -1533,48 +1622,149 @@ window.__ModuleLoader__.load({
|
|
|
1533
1622
|
}));
|
|
1534
1623
|
}, (errorText) => {
|
|
1535
1624
|
pushLog("error", t("row.poolLogBatchFailed", { message: errorText }));
|
|
1536
|
-
}))
|
|
1625
|
+
})) sawAny = true;
|
|
1626
|
+
if (!sawAny) throw new Error(t("row.poolLogGeneric"));
|
|
1537
1627
|
onRefresh?.();
|
|
1538
1628
|
setNow(Date.now());
|
|
1539
1629
|
} catch (error) {
|
|
1540
|
-
pushLog("error", t("row.poolLogBatchFailed", { message: error instanceof Error ? error.message : String(error) }));
|
|
1630
|
+
pushLog("error", t(controller.signal.aborted ? "row.poolLogTimeout" : "row.poolLogBatchFailed", { message: error instanceof Error ? error.message : String(error) }));
|
|
1541
1631
|
} finally {
|
|
1632
|
+
clearTimeout(timer);
|
|
1542
1633
|
if (mountRef.current) setBusy(void 0);
|
|
1543
1634
|
}
|
|
1544
1635
|
};
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1636
|
+
/**
|
|
1637
|
+
* Persist the removal of ONE account out of this panel's membership.
|
|
1638
|
+
*
|
|
1639
|
+
* The slot written is the SAVED slot with ONLY `memberAccountIds` replaced —
|
|
1640
|
+
* never the draft's switch or target model, because the card's own hint
|
|
1641
|
+
* promises only the in-row actions take effect immediately
|
|
1642
|
+
* (「开关与目标模型是偏好,改完要保存」), and never the DOCUMENT's effective
|
|
1643
|
+
* target model either: that falls back to the free model when the user left
|
|
1644
|
+
* the choice automatic, so writing it back would pin a model they never chose.
|
|
1645
|
+
* The membership written is the DRAFT minus the removed id, so a checkbox the
|
|
1646
|
+
* user already toggled on another row is not silently discarded by the
|
|
1647
|
+
* settings re-read this write triggers.
|
|
1648
|
+
*/
|
|
1649
|
+
const persistRemoval = async (accountId) => {
|
|
1650
|
+
const scope = settingsScope;
|
|
1651
|
+
if (scope === void 0) throw new Error(t("row.poolLogSaveFailed"));
|
|
1652
|
+
const base = regionPoolOf(scope.getSnapshot().value, panel);
|
|
1653
|
+
const next = {
|
|
1654
|
+
...base,
|
|
1655
|
+
memberAccountIds: [...selected].filter((id) => id !== accountId)
|
|
1656
|
+
};
|
|
1657
|
+
await writeSettingsField(scope, "regions", nextRegionPool(scope.getSnapshot().value, panel, next), (readBack) => {
|
|
1658
|
+
const readPool = regionPoolOf(readBack, panel);
|
|
1659
|
+
return !readPool.memberAccountIds?.includes(accountId) && sameIds(readPool.memberAccountIds, next.memberAccountIds) && (readPool.enabled ?? false) === (base.enabled ?? false) && (readPool.targetModelId ?? "") === (base.targetModelId ?? "") && (readPool.probeInputTokens ?? 0) === (base.probeInputTokens ?? 0);
|
|
1660
|
+
});
|
|
1661
|
+
};
|
|
1662
|
+
/** Product names for the desktop apps a delete touched or was blocked by. */
|
|
1663
|
+
const appLabels = (editions) => editions.map((edition) => t(`row.edition${edition === "cn" ? "Cn" : edition === "sg" ? "Sg" : edition === "solo" ? "Solo" : "SoloSg"}`)).join("、");
|
|
1664
|
+
/**
|
|
1665
|
+
* Delete an account from this machine: drop the plugin's own credential copy,
|
|
1666
|
+
* then erase the account's login from Trae's `storage.json`, then clear every
|
|
1667
|
+
* account-holder this card holds (pool probe, settings membership, draft
|
|
1668
|
+
* selection, the serving binding it may have held).
|
|
1669
|
+
*
|
|
1670
|
+
* The app half is what makes the row actually disappear. It has one failure
|
|
1671
|
+
* mode worth its own message: a RUNNING Trae flushes its in-memory state back
|
|
1672
|
+
* over the file, so the Host refuses and names the app, and the card says to
|
|
1673
|
+
* quit it instead of reporting a generic failure the user cannot act on.
|
|
1674
|
+
*/
|
|
1675
|
+
const deleteAccount = async (account) => {
|
|
1676
|
+
if (busy !== void 0 || deletingIds.has(account.accountId)) return;
|
|
1677
|
+
setBusy("delete");
|
|
1678
|
+
setDeletingIds((prev) => new Set(prev).add(account.accountId));
|
|
1679
|
+
setDeleteHint(void 0);
|
|
1552
1680
|
try {
|
|
1553
|
-
const response = await fetch(withTraePoolAccount(panel, "
|
|
1681
|
+
const response = await fetch(withTraePoolAccount(panel, "delete", account.accountId), { method: "POST" });
|
|
1554
1682
|
const body = await response.json();
|
|
1555
1683
|
if (!response.ok) throw new Error(renderRouteError(t, response.status, body));
|
|
1556
|
-
|
|
1557
|
-
if (
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1684
|
+
const blocked = body?.blockedApps ?? [];
|
|
1685
|
+
if (blocked.length > 0 && body?.deleted !== true) {
|
|
1686
|
+
setDeleteHint({
|
|
1687
|
+
kind: "app-running",
|
|
1688
|
+
accountId: account.accountId,
|
|
1689
|
+
accountName: account.accountName,
|
|
1690
|
+
apps: blocked
|
|
1691
|
+
});
|
|
1692
|
+
pushLog("warn", t("row.poolRowDeleteAppRunning", {
|
|
1693
|
+
accountName: account.accountName,
|
|
1694
|
+
apps: appLabels(blocked)
|
|
1695
|
+
}));
|
|
1696
|
+
setNow(Date.now());
|
|
1697
|
+
return;
|
|
1698
|
+
}
|
|
1699
|
+
if (body?.deleted !== true) throw new Error(t("row.poolRowDeleteFailed"));
|
|
1700
|
+
const wasMember = (saved.memberAccountIds ?? []).includes(account.accountId);
|
|
1701
|
+
let saveFailed = false;
|
|
1702
|
+
if (wasMember) {
|
|
1703
|
+
if (!writable) {
|
|
1704
|
+
saveFailed = true;
|
|
1705
|
+
setSaveError(t("row.poolSaveFailed", { message: t("row.poolLogSaveFailed") }));
|
|
1706
|
+
pushLog("error", t("row.poolLogSaveFailed"));
|
|
1707
|
+
} else try {
|
|
1708
|
+
await persistRemoval(account.accountId);
|
|
1709
|
+
} catch (error) {
|
|
1710
|
+
saveFailed = true;
|
|
1711
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1712
|
+
setSaveError(t("row.poolSaveFailed", { message }));
|
|
1713
|
+
pushLog("error", t("row.poolLogSaveFailed"));
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1562
1716
|
setSelected((prev) => {
|
|
1563
1717
|
const next = new Set(prev);
|
|
1564
1718
|
next.delete(account.accountId);
|
|
1565
1719
|
return next;
|
|
1566
1720
|
});
|
|
1567
|
-
|
|
1721
|
+
if (!saveFailed) {
|
|
1722
|
+
if (body.stillSignedIn === true) {
|
|
1723
|
+
const hadCopy = body.hadCopy !== false;
|
|
1724
|
+
setDeleteHint({
|
|
1725
|
+
kind: "still-signed-in",
|
|
1726
|
+
accountId: account.accountId,
|
|
1727
|
+
accountName: account.accountName,
|
|
1728
|
+
hadCopy
|
|
1729
|
+
});
|
|
1730
|
+
pushLog("warn", t(hadCopy ? "row.poolRowDeleteStillSigned" : "row.poolRowDeleteNoCopy", { accountName: account.accountName }));
|
|
1731
|
+
} else {
|
|
1732
|
+
const signedOut = body.signedOutApps ?? [];
|
|
1733
|
+
pushLog("ok", signedOut.length === 0 ? t("row.poolRowDeleted", { accountName: account.accountName }) : t("row.poolRowDeletedSignedOut", {
|
|
1734
|
+
accountName: account.accountName,
|
|
1735
|
+
apps: appLabels(signedOut)
|
|
1736
|
+
}));
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1568
1739
|
setNow(Date.now());
|
|
1740
|
+
if (!saveFailed) await onRefresh?.();
|
|
1569
1741
|
} catch (error) {
|
|
1570
|
-
pushLog("error", t("row.
|
|
1742
|
+
pushLog("error", t("row.poolRowDeleteError", {
|
|
1743
|
+
accountName: account.accountName,
|
|
1744
|
+
message: error instanceof Error ? error.message : String(error)
|
|
1745
|
+
}));
|
|
1571
1746
|
} finally {
|
|
1572
|
-
if (mountRef.current)
|
|
1747
|
+
if (mountRef.current) {
|
|
1748
|
+
setBusy(void 0);
|
|
1749
|
+
setDeletingIds((prev) => {
|
|
1750
|
+
const next = new Set(prev);
|
|
1751
|
+
next.delete(account.accountId);
|
|
1752
|
+
return next;
|
|
1753
|
+
});
|
|
1754
|
+
}
|
|
1573
1755
|
}
|
|
1574
1756
|
};
|
|
1575
1757
|
const noCandidate = pool.noCandidate;
|
|
1576
1758
|
const showNoCandidate = pool.enabled && noCandidate !== void 0;
|
|
1577
1759
|
const serving = servingAccount(pool);
|
|
1760
|
+
/**
|
|
1761
|
+
* The batch buttons are disabled for reasons the user cannot see (they are not
|
|
1762
|
+
* under the pointer, so a `title` only helps after a hover). Name them here.
|
|
1763
|
+
*/
|
|
1764
|
+
const actionNotes = [];
|
|
1765
|
+
if (selected.size === 0) actionNotes.push(t("row.poolActionNoteNoMembers"));
|
|
1766
|
+
if (deviceClaimed) actionNotes.push(t("row.poolActionNoteCheckinDevice"));
|
|
1767
|
+
if (pool.targetModelSource === "none") actionNotes.push(t("row.poolActionNoteTestNone"));
|
|
1578
1768
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1579
1769
|
className: "dsm-trae-pool",
|
|
1580
1770
|
"aria-label": t("row.poolTitle"),
|
|
@@ -1639,6 +1829,10 @@ window.__ModuleLoader__.load({
|
|
|
1639
1829
|
})
|
|
1640
1830
|
]
|
|
1641
1831
|
}),
|
|
1832
|
+
actionNotes.length === 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1833
|
+
className: "dsm-trae-pool-action-note",
|
|
1834
|
+
children: actionNotes.join(" · ")
|
|
1835
|
+
}),
|
|
1642
1836
|
showNoCandidate ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NoCandidateNotice, {
|
|
1643
1837
|
noCandidate,
|
|
1644
1838
|
t
|
|
@@ -1678,10 +1872,6 @@ window.__ModuleLoader__.load({
|
|
|
1678
1872
|
]
|
|
1679
1873
|
})]
|
|
1680
1874
|
}),
|
|
1681
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1682
|
-
className: "dsm-trae-pool-card-note",
|
|
1683
|
-
children: t("row.poolCardHint")
|
|
1684
|
-
}),
|
|
1685
1875
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1686
1876
|
className: pool.checkinSupported ? "dsm-trae-pool-table" : "dsm-trae-pool-table dsm-trae-pool-table-no-checkin",
|
|
1687
1877
|
role: "table",
|
|
@@ -1698,6 +1888,7 @@ window.__ModuleLoader__.load({
|
|
|
1698
1888
|
models,
|
|
1699
1889
|
rows,
|
|
1700
1890
|
checked: selected.has(account.accountId),
|
|
1891
|
+
poolEnabled: pool.enabled === true,
|
|
1701
1892
|
detail: details?.[account.accountId],
|
|
1702
1893
|
claim: claims?.[account.accountId],
|
|
1703
1894
|
onClaim,
|
|
@@ -1709,10 +1900,11 @@ window.__ModuleLoader__.load({
|
|
|
1709
1900
|
},
|
|
1710
1901
|
t,
|
|
1711
1902
|
disabled: busy !== void 0 || !writable,
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1903
|
+
deleting: deletingIds.has(account.accountId),
|
|
1904
|
+
onDelete: () => {
|
|
1905
|
+
deleteAccount(account);
|
|
1715
1906
|
},
|
|
1907
|
+
canDelete: pool.deleteSupported === true,
|
|
1716
1908
|
formatNumber: formatNumber$1,
|
|
1717
1909
|
relativeAt
|
|
1718
1910
|
}, account.accountId)),
|
|
@@ -1725,10 +1917,11 @@ window.__ModuleLoader__.load({
|
|
|
1725
1917
|
},
|
|
1726
1918
|
t,
|
|
1727
1919
|
disabled: busy !== void 0 || !writable,
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
}
|
|
1920
|
+
deleting: deletingIds.has(ghost.accountId),
|
|
1921
|
+
onDelete: () => {
|
|
1922
|
+
deleteAccount(ghost);
|
|
1923
|
+
},
|
|
1924
|
+
canDelete: pool.deleteSupported === true
|
|
1732
1925
|
}, `ghost:${ghost.accountId}`))
|
|
1733
1926
|
]
|
|
1734
1927
|
}),
|
|
@@ -1740,6 +1933,19 @@ window.__ModuleLoader__.load({
|
|
|
1740
1933
|
names: ghosts.map((g) => g.accountName).join("、")
|
|
1741
1934
|
})
|
|
1742
1935
|
}) : null,
|
|
1936
|
+
deleteHint?.kind === "still-signed-in" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1937
|
+
className: "dsm-trae-pool-delete-hint",
|
|
1938
|
+
role: "status",
|
|
1939
|
+
children: t(deleteHint.hadCopy ? "row.poolDeleteStillSigned" : "row.poolDeleteNoCopy", { accountName: deleteHint.accountName })
|
|
1940
|
+
}) : null,
|
|
1941
|
+
deleteHint?.kind === "app-running" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1942
|
+
className: "dsm-trae-pool-delete-hint dsm-trae-pool-delete-hint-action",
|
|
1943
|
+
role: "status",
|
|
1944
|
+
children: t("row.poolDeleteAppRunning", {
|
|
1945
|
+
accountName: deleteHint.accountName,
|
|
1946
|
+
apps: appLabels(deleteHint.apps)
|
|
1947
|
+
})
|
|
1948
|
+
}) : null,
|
|
1743
1949
|
dirty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1744
1950
|
className: "dsm-trae-pool-unsaved",
|
|
1745
1951
|
role: "status",
|
|
@@ -1765,10 +1971,33 @@ window.__ModuleLoader__.load({
|
|
|
1765
1971
|
className: "dsm-trae-pool-tools dsm-trae-pool-tools-dashed",
|
|
1766
1972
|
children: tools
|
|
1767
1973
|
}),
|
|
1974
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1975
|
+
className: "dsm-trae-pool-warning dsm-trae-pool-warning-workflow",
|
|
1976
|
+
role: "note",
|
|
1977
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1978
|
+
className: "dsm-trae-pool-warning-title",
|
|
1979
|
+
children: t("row.poolMirrorWorkflowTitle")
|
|
1980
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1981
|
+
className: "dsm-trae-pool-warning-hint",
|
|
1982
|
+
children: t("row.poolMirrorWorkflowHint")
|
|
1983
|
+
})]
|
|
1984
|
+
}),
|
|
1985
|
+
pool.copies === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1986
|
+
className: "dsm-trae-pool-note dsm-trae-pool-copyfile",
|
|
1987
|
+
role: "note",
|
|
1988
|
+
children: t("row.poolCopyFile", {
|
|
1989
|
+
path: pool.copies.path,
|
|
1990
|
+
count: pool.copies.count
|
|
1991
|
+
})
|
|
1992
|
+
}),
|
|
1768
1993
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1769
1994
|
className: "dsm-trae-pool-note",
|
|
1770
1995
|
children: t("row.poolSettingsNote")
|
|
1771
1996
|
}),
|
|
1997
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1998
|
+
className: "dsm-trae-pool-note",
|
|
1999
|
+
children: t("row.poolDeleteHint")
|
|
2000
|
+
}),
|
|
1772
2001
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1773
2002
|
className: "dsm-trae-pool-settings",
|
|
1774
2003
|
children: [
|
|
@@ -1884,22 +2113,25 @@ window.__ModuleLoader__.load({
|
|
|
1884
2113
|
}),
|
|
1885
2114
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1886
2115
|
className: "dsm-trae-pool-save-row",
|
|
1887
|
-
children: [
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
2116
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
|
|
2117
|
+
className: "dsm-trae-usage-cheer",
|
|
2118
|
+
href: "https://github.com/dingminhua/dsh-connect-trae",
|
|
2119
|
+
target: "_blank",
|
|
2120
|
+
rel: "noreferrer noopener",
|
|
2121
|
+
children: [t("row.cheer"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2122
|
+
className: "dsm-trae-usage-cheer-star",
|
|
2123
|
+
"aria-hidden": "true",
|
|
2124
|
+
children: "★"
|
|
2125
|
+
})]
|
|
2126
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2127
|
+
className: "dsm-trae-pool-save-buttons",
|
|
2128
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1896
2129
|
type: "button",
|
|
1897
2130
|
className: "dsm-btn dsm-btn-outline",
|
|
1898
2131
|
disabled: !dirty || busy !== void 0,
|
|
1899
2132
|
onClick: discard,
|
|
1900
2133
|
children: t("row.poolDiscard")
|
|
1901
|
-
}),
|
|
1902
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2134
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1903
2135
|
type: "button",
|
|
1904
2136
|
className: "dsm-btn dsm-btn-primary",
|
|
1905
2137
|
disabled: !dirty || busy !== void 0,
|
|
@@ -1907,15 +2139,11 @@ window.__ModuleLoader__.load({
|
|
|
1907
2139
|
save();
|
|
1908
2140
|
},
|
|
1909
2141
|
children: busy === "save" ? t("row.poolSaving") : t("row.poolSaved")
|
|
1910
|
-
})
|
|
1911
|
-
]
|
|
2142
|
+
})]
|
|
2143
|
+
})]
|
|
1912
2144
|
})
|
|
1913
2145
|
]
|
|
1914
2146
|
}),
|
|
1915
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1916
|
-
className: "dsm-trae-pool-note",
|
|
1917
|
-
children: t("row.poolRegionNote")
|
|
1918
|
-
}),
|
|
1919
2147
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActivityLog, {
|
|
1920
2148
|
log,
|
|
1921
2149
|
t,
|
|
@@ -1970,8 +2198,18 @@ window.__ModuleLoader__.load({
|
|
|
1970
2198
|
]
|
|
1971
2199
|
});
|
|
1972
2200
|
}
|
|
1973
|
-
function MemberRow({ account, models, rows, checked, onToggle, onTest, t, disabled,
|
|
1974
|
-
|
|
2201
|
+
function MemberRow({ account, models, rows, checked, onToggle, onTest, t, disabled, deleting, onDelete, canDelete, formatNumber, relativeAt, detail, claim, onClaim, showCheckin, deviceClaimed, poolEnabled }) {
|
|
2202
|
+
/**
|
|
2203
|
+
* Whether this row is the one billing the next request — and, with the pool on,
|
|
2204
|
+
* whether that claim is the pool's own.
|
|
2205
|
+
*
|
|
2206
|
+
* `account.current` alone is not enough: with an empty (or fully excluded) pool
|
|
2207
|
+
* the Host deliberately falls back to the saved selection, so a removed account
|
|
2208
|
+
* stays `current` and the pill would keep announcing it as the pool's pick.
|
|
2209
|
+
* A row can only be the rotation's answer while it is a member.
|
|
2210
|
+
*/
|
|
2211
|
+
const isCurrent = account.current === true && (poolEnabled !== true || account.member === true);
|
|
2212
|
+
const hasCopy = account.reachable;
|
|
1975
2213
|
const credit = account.generalAvailable;
|
|
1976
2214
|
const excluded = account.excludedBy;
|
|
1977
2215
|
const checkin = account.checkedInToday;
|
|
@@ -2008,10 +2246,10 @@ window.__ModuleLoader__.load({
|
|
|
2008
2246
|
className: "dsm-trae-pool-account-name",
|
|
2009
2247
|
children: [
|
|
2010
2248
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2011
|
-
className: `dsm-trae-pool-dot dsm-trae-pool-dot-${excluded ? "excluded" : "ok"}`,
|
|
2249
|
+
className: `dsm-trae-pool-dot dsm-trae-pool-dot-${account.reachable === false ? "ghost" : excluded ? "excluded" : "ok"}`,
|
|
2012
2250
|
"aria-hidden": "true"
|
|
2013
2251
|
}),
|
|
2014
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: account.accountName }),
|
|
2252
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: account.accountName !== "" ? account.accountName : account.accountId }),
|
|
2015
2253
|
detail?.meta === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2016
2254
|
className: "dsm-trae-pool-meta",
|
|
2017
2255
|
children: detail.meta
|
|
@@ -2034,6 +2272,11 @@ window.__ModuleLoader__.load({
|
|
|
2034
2272
|
className: checked ? "dsm-trae-pool-member" : "dsm-trae-pool-not-member",
|
|
2035
2273
|
children: checked ? t("row.poolMember") : t("row.poolNotMember")
|
|
2036
2274
|
}),
|
|
2275
|
+
account.reachable === false ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2276
|
+
className: "dsm-trae-pool-tag dsm-trae-pool-tag-ghost",
|
|
2277
|
+
role: "status",
|
|
2278
|
+
children: t("row.poolNoCopyTag")
|
|
2279
|
+
}) : null,
|
|
2037
2280
|
excluded && !probeOnScreen ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2038
2281
|
className: "dsm-trae-pool-tag dsm-trae-pool-tag-excluded",
|
|
2039
2282
|
children: exclusionLabel(excluded, t)
|
|
@@ -2091,7 +2334,7 @@ window.__ModuleLoader__.load({
|
|
|
2091
2334
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2092
2335
|
className: `dsm-trae-pool-checkin-state dsm-trae-pool-checkin-${checkin === void 0 ? "unknown" : checkin ? "ok" : device === true || deviceClaimed ? "device" : "no"}`,
|
|
2093
2336
|
children: checkin === void 0 ? t("row.poolCheckinUnknown") : checkin ? t("row.poolCheckedIn") : device === true || deviceClaimed ? t("row.poolDeviceUsed") : t("row.poolNotCheckedIn")
|
|
2094
|
-
}), claim === void 0 || onClaim === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2337
|
+
}), claim === void 0 || onClaim === void 0 || claim.claimable === false ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2095
2338
|
type: "button",
|
|
2096
2339
|
className: "dsm-btn dsm-btn-outline dsm-trae-pool-claim",
|
|
2097
2340
|
disabled: claim.disabled || disabled,
|
|
@@ -2107,22 +2350,23 @@ window.__ModuleLoader__.load({
|
|
|
2107
2350
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2108
2351
|
type: "button",
|
|
2109
2352
|
className: "dsm-btn dsm-btn-outline",
|
|
2110
|
-
disabled,
|
|
2353
|
+
disabled: disabled || hasCopy === false,
|
|
2354
|
+
title: hasCopy === false ? t("row.poolNoCopyTestHint") : void 0,
|
|
2111
2355
|
onClick: onTest,
|
|
2112
2356
|
children: t("row.poolRowTest")
|
|
2113
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2357
|
+
}), canDelete ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2114
2358
|
type: "button",
|
|
2115
|
-
className: "dsm-btn dsm-btn-outline dsm-trae-pool-
|
|
2116
|
-
disabled: disabled ||
|
|
2117
|
-
"aria-label": t("row.
|
|
2118
|
-
onClick:
|
|
2119
|
-
children:
|
|
2120
|
-
})]
|
|
2359
|
+
className: "dsm-btn dsm-btn-outline-danger dsm-trae-pool-delete",
|
|
2360
|
+
disabled: disabled || deleting,
|
|
2361
|
+
"aria-label": t("row.poolRowDeleteAria", { accountName: account.accountName }),
|
|
2362
|
+
onClick: onDelete,
|
|
2363
|
+
children: deleting ? t("row.poolRowDeleting") : t("row.poolRowDelete")
|
|
2364
|
+
}) : null]
|
|
2121
2365
|
})
|
|
2122
2366
|
]
|
|
2123
2367
|
});
|
|
2124
2368
|
}
|
|
2125
|
-
function MemberGhostRow({ ghost, checked, onToggle, t, disabled,
|
|
2369
|
+
function MemberGhostRow({ ghost, checked, onToggle, t, disabled, deleting, onDelete, canDelete, showCheckin }) {
|
|
2126
2370
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2127
2371
|
className: "dsm-trae-pool-row dsm-trae-pool-row-ghost",
|
|
2128
2372
|
role: "row",
|
|
@@ -2183,14 +2427,14 @@ window.__ModuleLoader__.load({
|
|
|
2183
2427
|
}) : null,
|
|
2184
2428
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2185
2429
|
className: "dsm-trae-pool-row-actions",
|
|
2186
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2430
|
+
children: canDelete ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2187
2431
|
type: "button",
|
|
2188
|
-
className: "dsm-btn dsm-btn-outline dsm-trae-pool-
|
|
2189
|
-
disabled: disabled ||
|
|
2190
|
-
"aria-label": t("row.
|
|
2191
|
-
onClick:
|
|
2192
|
-
children:
|
|
2193
|
-
})
|
|
2432
|
+
className: "dsm-btn dsm-btn-outline-danger dsm-trae-pool-delete",
|
|
2433
|
+
disabled: disabled || deleting,
|
|
2434
|
+
"aria-label": t("row.poolGhostDeleteAria", { accountName: ghost.accountName }),
|
|
2435
|
+
onClick: onDelete,
|
|
2436
|
+
children: deleting ? t("row.poolRowDeleting") : t("row.poolRowDelete")
|
|
2437
|
+
}) : null
|
|
2194
2438
|
})
|
|
2195
2439
|
]
|
|
2196
2440
|
});
|
|
@@ -2305,7 +2549,7 @@ window.__ModuleLoader__.load({
|
|
|
2305
2549
|
setTimeout(resolve, timeoutMs);
|
|
2306
2550
|
})]);
|
|
2307
2551
|
}
|
|
2308
|
-
function AccountTransfer({ t, region, accounts, onChanged }) {
|
|
2552
|
+
function AccountTransfer({ t, region, accounts, onChanged, hideLabel = false }) {
|
|
2309
2553
|
const [phase, setPhase] = (0, react.useState)({ kind: "idle" });
|
|
2310
2554
|
const [dialog, setDialog] = (0, react.useState)(void 0);
|
|
2311
2555
|
const [selected, setSelected] = (0, react.useState)(/* @__PURE__ */ new Set());
|
|
@@ -2456,7 +2700,7 @@ window.__ModuleLoader__.load({
|
|
|
2456
2700
|
const busy = phase.kind === "exporting" || phase.kind === "importing" || phase.kind === "refreshing";
|
|
2457
2701
|
const veilMessage = phase.kind === "exporting" ? t("row.transferExporting") : phase.kind === "importing" || phase.kind === "refreshing" ? t("row.transferImporting") : "";
|
|
2458
2702
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2459
|
-
className: "dsm-trae-transfer",
|
|
2703
|
+
className: hideLabel ? "dsm-trae-transfer dsm-trae-transfer-flat" : "dsm-trae-transfer",
|
|
2460
2704
|
"aria-label": t("row.transferTitle"),
|
|
2461
2705
|
children: [
|
|
2462
2706
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(BusyOverlay, {
|
|
@@ -2464,7 +2708,7 @@ window.__ModuleLoader__.load({
|
|
|
2464
2708
|
message: veilMessage,
|
|
2465
2709
|
...busy ? { hint: t("row.transferVeilHint") } : {}
|
|
2466
2710
|
}),
|
|
2467
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2711
|
+
hideLabel ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2468
2712
|
className: "dsm-trae-transfer-label",
|
|
2469
2713
|
children: t("row.transferTitle")
|
|
2470
2714
|
}),
|
|
@@ -3801,11 +4045,22 @@ window.__ModuleLoader__.load({
|
|
|
3801
4045
|
label: spending ? t("row.checkinClaiming") : claimed ? t("row.checkinClaimed") : deviceSpent ? t("row.checkinDeviceSpentShort") : !usable || reward === void 0 ? t("row.checkinClaim") : t("row.checkinClaimWith", { reward }),
|
|
3802
4046
|
title,
|
|
3803
4047
|
disabled: !usable || claimed || deviceSpent || spending,
|
|
3804
|
-
busy: spending
|
|
4048
|
+
busy: spending,
|
|
4049
|
+
/**
|
|
4050
|
+
* False when there is nothing left to DO: a disabled "already claimed"
|
|
4051
|
+
* button restates the status line above it, in grey, forever. Callers
|
|
4052
|
+
* drop the control instead of buying it a permanent disabled state.
|
|
4053
|
+
*/
|
|
4054
|
+
claimable: !claimed && !deviceSpent,
|
|
4055
|
+
settled: claimed ? "claimed" : deviceSpent ? "device" : void 0
|
|
3805
4056
|
};
|
|
3806
4057
|
};
|
|
3807
4058
|
const checkinControl = (account, state) => {
|
|
3808
4059
|
const view = claimViewOf(account.id, state);
|
|
4060
|
+
if (!view.claimable) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4061
|
+
className: "dsm-trae-account-checkin-state",
|
|
4062
|
+
children: view.settled === "claimed" ? t("row.poolCheckedIn") : t("row.poolDeviceUsed")
|
|
4063
|
+
});
|
|
3809
4064
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3810
4065
|
type: "button",
|
|
3811
4066
|
className: "dsm-trae-account-checkin",
|
|
@@ -4217,6 +4472,7 @@ window.__ModuleLoader__.load({
|
|
|
4217
4472
|
children: t("row.poolToolsLabel")
|
|
4218
4473
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountTransfer, {
|
|
4219
4474
|
t,
|
|
4475
|
+
hideLabel: true,
|
|
4220
4476
|
region: activeRegion === "ai" ? "ai" : "cn",
|
|
4221
4477
|
accounts: status.accounts.map((account) => ({
|
|
4222
4478
|
id: account.id,
|
|
@@ -5243,22 +5499,22 @@ window.__ModuleLoader__.load({
|
|
|
5243
5499
|
"row.refreshCredits": "Refresh usage",
|
|
5244
5500
|
"row.refreshing": "Refreshing…",
|
|
5245
5501
|
"row.accountsTitle": "Trae account",
|
|
5246
|
-
"row.accountsHint": "
|
|
5502
|
+
"row.accountsHint": "Copies this plugin keeps of every Trae sign-in on this machine (mirrored on refresh). Refresh after signing in, or Trae's next sign-in overwrites that login. Tokens are never shown.",
|
|
5247
5503
|
"row.transferTitle": "Import & export accounts",
|
|
5248
5504
|
"row.transferExport": "Export selected",
|
|
5249
5505
|
"row.transferImport": "Import from file",
|
|
5250
5506
|
"row.transferCancel": "Cancel",
|
|
5251
5507
|
"row.transferSelectAll": "Select all",
|
|
5252
|
-
"row.transferExportPick": "Choose which of the {total}
|
|
5508
|
+
"row.transferExportPick": "Choose which of the {total} account copies to export.",
|
|
5253
5509
|
"row.transferExportConfirm": "Export {count}",
|
|
5254
|
-
"row.transferExported": "Exported {count} account
|
|
5510
|
+
"row.transferExported": "Exported {count} account copy/copies to {fileName}.",
|
|
5255
5511
|
"row.transferExporting": "Preparing the export…",
|
|
5256
|
-
"row.transferImportPick": "This file holds {total} record(s).
|
|
5512
|
+
"row.transferImportPick": "This file holds {total} record(s). Ticked records are added as plugin-owned copies; the Trae app is not touched.",
|
|
5257
5513
|
"row.transferImportConfirm": "Import {count}",
|
|
5258
|
-
"row.transferImported": "Imported {imported} account
|
|
5514
|
+
"row.transferImported": "Imported {imported} account copy/copies, skipped {skipped}.",
|
|
5259
5515
|
"row.transferImporting": "Importing…",
|
|
5260
5516
|
"row.transferReading": "Reading the file…",
|
|
5261
|
-
"row.transferHint": "The exported file
|
|
5517
|
+
"row.transferHint": "The exported file holds this plugin's own copies, including live tokens — treat it as a password. Records belonging to the other region are skipped.",
|
|
5262
5518
|
"row.transferError": "Import/export failed: {message}",
|
|
5263
5519
|
"row.transferVeilHint": "The account list refreshes when this finishes.",
|
|
5264
5520
|
"row.transferUnnamed": "Unnamed account",
|
|
@@ -5370,14 +5626,18 @@ window.__ModuleLoader__.load({
|
|
|
5370
5626
|
"row.poolNoCandidateUnusable": "Every selected member is unavailable right now.",
|
|
5371
5627
|
"row.poolNoCandidateHint": "Traffic keeps landing on the saved selection until one recovers.",
|
|
5372
5628
|
"row.poolMembersTitle": "Accounts in this pool",
|
|
5373
|
-
"row.poolCardHint": "Only checked accounts are checked in, tested and dispatched. Nothing is checked by default — pick the ones you want, then save.",
|
|
5374
5629
|
"row.poolRescan": "Re-detect accounts",
|
|
5375
5630
|
"row.poolToolsLabel": "Export / import accounts",
|
|
5376
5631
|
"row.poolCreditExpiry": "expires {when}",
|
|
5377
5632
|
"row.poolProbeMeasured": "measured {when}",
|
|
5378
5633
|
"row.poolProbeAt": "tested {when}",
|
|
5634
|
+
"row.poolMirrorWorkflowTitle": "Sign in one account, then refresh",
|
|
5635
|
+
"row.poolMirrorWorkflowHint": "The Trae app holds only one sign-in. After signing in to an account, refresh this card (or click “Detect accounts again”) so the plugin saves that login as its own copy. Switch accounts without refreshing and the previous login is not saved — the new one overwrites it in Trae.",
|
|
5379
5636
|
"row.poolSettingsNote": "Preferences below take effect when you save; test results are written by the plugin and are not affected by that button.",
|
|
5380
5637
|
"row.poolSelectedCount": "Selected {count} / {total}",
|
|
5638
|
+
"row.poolNoCopyTag": "no copy here",
|
|
5639
|
+
"row.poolCopyFile": "Copies live in {path} — {count} right now. Switching accounts in Trae adds a copy; it never overwrites an existing one.",
|
|
5640
|
+
"row.poolNoCopyTestHint": "This machine holds no sign-in for this account, so it cannot be tested. Sign in to Trae with it again to recreate a copy, or delete the row.",
|
|
5381
5641
|
"row.poolSelectAll": "All",
|
|
5382
5642
|
"row.poolSelectNone": "None",
|
|
5383
5643
|
"row.poolColumnAccount": "Account",
|
|
@@ -5398,6 +5658,9 @@ window.__ModuleLoader__.load({
|
|
|
5398
5658
|
"row.poolTargetStaleClear": "Back to automatic",
|
|
5399
5659
|
"row.poolTargetNone": "No free model available for this panel",
|
|
5400
5660
|
"row.poolTargetNoneHint": "The pool can only pick a free model; none resolves right now, so tests are disabled.",
|
|
5661
|
+
"row.poolActionNoteCheckinDevice": "This machine already used today's check-in (Trae allows one per device per day) — check-in is unavailable until tomorrow.",
|
|
5662
|
+
"row.poolActionNoteTestNone": "No free model resolves in this panel — pick a target model before testing.",
|
|
5663
|
+
"row.poolActionNoteNoMembers": "Tick the accounts you want in the pool and save first.",
|
|
5401
5664
|
"row.poolTargetAutoOption": "Automatic (free model)",
|
|
5402
5665
|
"row.poolTargetLabel": "Target test model",
|
|
5403
5666
|
"row.poolTargetHint": "The model a probe test uses.",
|
|
@@ -5405,7 +5668,6 @@ window.__ModuleLoader__.load({
|
|
|
5405
5668
|
"row.poolProbeSizeHint": "How much text a test sends. A one-word probe only proves the account can answer a one-word request — if the upstream refuses long turns, this is where you find out. Bigger is closer to a real conversation, and costs more credit on every account in the batch.",
|
|
5406
5669
|
"row.poolProbeSizeDefault": "Minimal (default)",
|
|
5407
5670
|
"row.poolProbeSizeOption": "{wan}0k tokens",
|
|
5408
|
-
"row.poolStar": "Star the repo",
|
|
5409
5671
|
"row.poolSettingsTitle": "Pool settings",
|
|
5410
5672
|
"row.poolManualAccountLabel": "Manually billed account",
|
|
5411
5673
|
"row.poolManualAccountHint": "Used while the pool is off. With it on, the Host picks by credits.",
|
|
@@ -5416,14 +5678,8 @@ window.__ModuleLoader__.load({
|
|
|
5416
5678
|
"row.poolDiscard": "Discard",
|
|
5417
5679
|
"row.poolSaveFailed": "Save failed: {message}",
|
|
5418
5680
|
"row.poolGhostMembers": "{count} saved member(s) no longer resolve to a local sign-in: {names}",
|
|
5419
|
-
"row.poolGhostRemove": "Remove {account}",
|
|
5420
|
-
"row.poolGhostRemoveHint": "Forget this panel's binding to {account}.",
|
|
5421
5681
|
"row.poolUnsavedMembers": "Unsaved membership changes — Save below to apply.",
|
|
5422
5682
|
"row.poolRowTest": "Test",
|
|
5423
|
-
"row.poolRowRemove": "Remove",
|
|
5424
|
-
"row.poolRowRemoveAria": "Remove {accountName} from this panel",
|
|
5425
|
-
"row.poolRowRemoving": "Removing…",
|
|
5426
|
-
"row.poolRowRemoved": "Removed {accountName} from this panel",
|
|
5427
5683
|
"row.poolLogTitle": "Activity",
|
|
5428
5684
|
"row.poolLogClear": "Clear",
|
|
5429
5685
|
"row.poolLogEmpty": "No pool activity yet.",
|
|
@@ -5437,7 +5693,7 @@ window.__ModuleLoader__.load({
|
|
|
5437
5693
|
"row.poolLogTestRowMalformed": "{accountName}: malformed result.",
|
|
5438
5694
|
"row.poolLogTestDone": "Test finished.",
|
|
5439
5695
|
"row.poolLogBatchFailed": "Pool action failed: {message}",
|
|
5440
|
-
"row.
|
|
5696
|
+
"row.poolLogTimeout": "The test did not answer in time — it was cancelled, so the button works again. Check the network and retry: {message}",
|
|
5441
5697
|
"row.poolSelectAria": "Include {accountName} in the pool",
|
|
5442
5698
|
"row.poolCheckedIn": "Checked in",
|
|
5443
5699
|
"row.poolNotCheckedIn": "Not checked in",
|
|
@@ -5486,8 +5742,7 @@ window.__ModuleLoader__.load({
|
|
|
5486
5742
|
"row.poolErrConflict": "the pool refused the request",
|
|
5487
5743
|
"row.poolErrGeneric": "pool request failed (HTTP {status})",
|
|
5488
5744
|
"row.poolCheckingIn": "Checking in…",
|
|
5489
|
-
"row.poolSettingsHint": "The switch and the target model are preferences — save them. Test, check in and
|
|
5490
|
-
"row.poolGhostRemoveAria": "Remove the saved but unreachable account {accountName} from this panel",
|
|
5745
|
+
"row.poolSettingsHint": "The switch and the target model are preferences — save them. Test, check in and delete act at once.",
|
|
5491
5746
|
"row.poolLogSaved": "Pool settings saved.",
|
|
5492
5747
|
"row.poolLogSaveFailed": "Could not save the pool settings.",
|
|
5493
5748
|
"row.poolLogNoMembers": "Nothing to do — no pool members are selected.",
|
|
@@ -5495,8 +5750,21 @@ window.__ModuleLoader__.load({
|
|
|
5495
5750
|
"row.poolLogGeneric": "the pool answered nothing usable",
|
|
5496
5751
|
"row.poolLogRowTesting": "Testing {accountName}…",
|
|
5497
5752
|
"row.poolLogTargetCleared": "Returned the test target to automatic.",
|
|
5498
|
-
"row.
|
|
5499
|
-
"row.
|
|
5753
|
+
"row.poolRowDelete": "Delete",
|
|
5754
|
+
"row.poolRowDeleteAria": "Delete {accountName} from this machine: the plugin's copy and its Trae app login (this will sign it out of Trae)",
|
|
5755
|
+
"row.poolRowDeleting": "Deleting…",
|
|
5756
|
+
"row.poolGhostDeleteAria": "Delete the saved but unreachable account {accountName} from this machine",
|
|
5757
|
+
"row.poolRowDeleteError": "Could not delete {accountName}: {message}",
|
|
5758
|
+
"row.poolRowDeleteFailed": "the deletion was not confirmed",
|
|
5759
|
+
"row.poolRowDeleted": "Deleted the credential copy of {accountName}.",
|
|
5760
|
+
"row.poolDeleteStillSigned": "Deleted this plugin's copy of {accountName}, but it is still signed in to Trae, so the account itself is not gone. Sign out inside Trae to remove it from this machine.",
|
|
5761
|
+
"row.poolRowDeletedSignedOut": "Deleted {accountName} and signed it out of {apps}.",
|
|
5762
|
+
"row.poolRowDeleteAppRunning": "Could not delete {accountName}: {apps} is running and would restore the login. Quit {apps} completely, then delete again.",
|
|
5763
|
+
"row.poolDeleteAppRunning": "Nothing was changed: {apps} is running, and it would write the login back over the file on exit. Quit {apps} completely, then delete again.",
|
|
5764
|
+
"row.poolDeleteNoCopy": "There was no plugin copy of {accountName} left to delete — it only exists as a Trae app login, and that sign-out did not take effect.",
|
|
5765
|
+
"row.poolRowDeleteStillSigned": "removed this copy, but {accountName} is still signed in to Trae",
|
|
5766
|
+
"row.poolRowDeleteNoCopy": "{accountName} had no plugin copy — only its Trae app login",
|
|
5767
|
+
"row.poolDeleteHint": "The plugin keeps its own copy of every local Trae login (a copy is created on refresh unless one already exists) and only ever shows and bills those copies. Delete removes the copy AND signs that account out of Trae itself, leaving a backup of every file it rewrites; a deleted account is not re-imported while it stays signed in Trae. A running Trae would flush its own state back over the file, so quit it first — the card names the app it needs closed.",
|
|
5500
5768
|
"row.cheer": "Star on GitHub"
|
|
5501
5769
|
};
|
|
5502
5770
|
const zh = {
|
|
@@ -5560,22 +5828,22 @@ window.__ModuleLoader__.load({
|
|
|
5560
5828
|
"row.refreshCredits": "刷新用量",
|
|
5561
5829
|
"row.refreshing": "正在刷新…",
|
|
5562
5830
|
"row.accountsTitle": "Trae 账号",
|
|
5563
|
-
"row.accountsHint": "
|
|
5831
|
+
"row.accountsHint": "本插件保管的账号副本:本机每个 Trae 登录都会在刷新时补建一份副本。登录新号后要刷新一次,否则它会被 Trae 的下一次登录覆盖。Token 不会显示。",
|
|
5564
5832
|
"row.transferTitle": "导入 / 导出账号",
|
|
5565
5833
|
"row.transferExport": "导出所选",
|
|
5566
5834
|
"row.transferImport": "从文件导入",
|
|
5567
5835
|
"row.transferCancel": "取消",
|
|
5568
5836
|
"row.transferSelectAll": "全选",
|
|
5569
|
-
"row.transferExportPick": "从这 {total}
|
|
5837
|
+
"row.transferExportPick": "从这 {total} 个账号副本中选择要导出的。",
|
|
5570
5838
|
"row.transferExportConfirm": "导出 {count} 个",
|
|
5571
|
-
"row.transferExported": "已导出 {count}
|
|
5839
|
+
"row.transferExported": "已导出 {count} 个账号副本到 {fileName}。",
|
|
5572
5840
|
"row.transferExporting": "正在准备导出…",
|
|
5573
|
-
"row.transferImportPick": "该文件包含 {total}
|
|
5841
|
+
"row.transferImportPick": "该文件包含 {total} 条记录;勾选的会作为插件副本导入,不会写入 Trae 应用。",
|
|
5574
5842
|
"row.transferImportConfirm": "导入 {count} 个",
|
|
5575
|
-
"row.transferImported": "已导入 {imported}
|
|
5843
|
+
"row.transferImported": "已导入 {imported} 个账号副本,跳过 {skipped} 个。",
|
|
5576
5844
|
"row.transferImporting": "正在导入…",
|
|
5577
5845
|
"row.transferReading": "正在读取文件…",
|
|
5578
|
-
"row.transferHint": "
|
|
5846
|
+
"row.transferHint": "导出的文件里是插件保管的账号副本(含有效 Token),请当作密码保管。属于另一区域的记录会被跳过。",
|
|
5579
5847
|
"row.transferError": "导入/导出失败:{message}",
|
|
5580
5848
|
"row.transferVeilHint": "完成后账号列表会自动刷新。",
|
|
5581
5849
|
"row.transferUnnamed": "未命名账号",
|
|
@@ -5687,14 +5955,18 @@ window.__ModuleLoader__.load({
|
|
|
5687
5955
|
"row.poolNoCandidateUnusable": "所有已选成员当前均不可用。",
|
|
5688
5956
|
"row.poolNoCandidateHint": "请求会继续落在已保存的账号上,直到有成员恢复可用。",
|
|
5689
5957
|
"row.poolMembersTitle": "本池包含的账号",
|
|
5690
|
-
"row.poolCardHint": "只有勾选的账号才会被签到、测试和轮换。默认一个都不勾 —— 请勾选你要的账号,然后保存。",
|
|
5691
5958
|
"row.poolRescan": "重新检测账号",
|
|
5692
5959
|
"row.poolToolsLabel": "导出 / 导入账号",
|
|
5693
5960
|
"row.poolCreditExpiry": "{when} 过期",
|
|
5694
5961
|
"row.poolProbeMeasured": "测得 {when}",
|
|
5695
5962
|
"row.poolProbeAt": "测试于 {when}",
|
|
5963
|
+
"row.poolMirrorWorkflowTitle": "每登录一个账号,就刷新一次",
|
|
5964
|
+
"row.poolMirrorWorkflowHint": "Trae 应用只有一个登录位:每登录一个账号,就回到这里刷新一次(打开卡片或点「重新检测账号」),插件会把这次登录保存成一份自己的副本。没刷新就换号,上一个账号不会被保存——它会被 Trae 里的新登录覆盖。",
|
|
5696
5965
|
"row.poolSettingsNote": "下面是偏好设置:点保存才生效;测试结果由插件自动写入,不受这个保存按钮影响。",
|
|
5697
5966
|
"row.poolSelectedCount": "已选 {count} / {total}",
|
|
5967
|
+
"row.poolNoCopyTag": "本机无副本",
|
|
5968
|
+
"row.poolCopyFile": "副本就存在 {path},当前 {count} 份。在 Trae 里换号只会新增一份,不会覆盖已有的副本。",
|
|
5969
|
+
"row.poolNoCopyTestHint": "本机没有这个账号的登录,无法测速。需要它请在 Trae 里重新登录以重建副本,或删除这一行。",
|
|
5698
5970
|
"row.poolSelectAll": "全部",
|
|
5699
5971
|
"row.poolSelectNone": "清空",
|
|
5700
5972
|
"row.poolColumnAccount": "账号",
|
|
@@ -5715,6 +5987,9 @@ window.__ModuleLoader__.load({
|
|
|
5715
5987
|
"row.poolTargetStaleClear": "改回自动",
|
|
5716
5988
|
"row.poolTargetNone": "本面板暂无可用免费模型",
|
|
5717
5989
|
"row.poolTargetNoneHint": "账号池只会挑免费模型;当前无法解析出可用模型,测速暂被禁用。",
|
|
5990
|
+
"row.poolActionNoteCheckinDevice": "本机今日的签到已用掉(Trae 按每台设备每天一次限制),明天才能再签。",
|
|
5991
|
+
"row.poolActionNoteTestNone": "本面板没有解析出免费模型——先指定一个目标模型再测速。",
|
|
5992
|
+
"row.poolActionNoteNoMembers": "先勾选要入池的账号并保存。",
|
|
5718
5993
|
"row.poolTargetAutoOption": "自动(免费模型)",
|
|
5719
5994
|
"row.poolTargetLabel": "目标测速模型",
|
|
5720
5995
|
"row.poolTargetHint": "探针测速所用的模型。",
|
|
@@ -5722,7 +5997,6 @@ window.__ModuleLoader__.load({
|
|
|
5722
5997
|
"row.poolProbeSizeHint": "测试时发送多少文本。只发一个词的探针,只能证明「这个账号能回答一个词」——如果上游拒绝长请求,问题只会在你真实对话时才出现。填得越多越接近真实对话,每个账号每次测试消耗的积分也越多。",
|
|
5723
5998
|
"row.poolProbeSizeDefault": "最小请求(默认)",
|
|
5724
5999
|
"row.poolProbeSizeOption": "{wan} 万 token",
|
|
5725
|
-
"row.poolStar": "鼓励一下",
|
|
5726
6000
|
"row.poolSettingsTitle": "账号池设置",
|
|
5727
6001
|
"row.poolManualAccountLabel": "手动计费账号",
|
|
5728
6002
|
"row.poolManualAccountHint": "账号池关闭时由它计费;开启后由 Host 按积分挑选。",
|
|
@@ -5733,14 +6007,8 @@ window.__ModuleLoader__.load({
|
|
|
5733
6007
|
"row.poolDiscard": "放弃",
|
|
5734
6008
|
"row.poolSaveFailed": "保存失败:{message}",
|
|
5735
6009
|
"row.poolGhostMembers": "{count} 个已保存成员不再对应本机登录:{names}",
|
|
5736
|
-
"row.poolGhostRemove": "移除 {account}",
|
|
5737
|
-
"row.poolGhostRemoveHint": "忘记本面板对 {account} 的绑定。",
|
|
5738
6010
|
"row.poolUnsavedMembers": "成员改动尚未保存——请点击下方保存。",
|
|
5739
6011
|
"row.poolRowTest": "测速",
|
|
5740
|
-
"row.poolRowRemove": "移除",
|
|
5741
|
-
"row.poolRowRemoveAria": "从本面板移除 {accountName}",
|
|
5742
|
-
"row.poolRowRemoving": "移除中…",
|
|
5743
|
-
"row.poolRowRemoved": "已从本面板移除 {accountName}",
|
|
5744
6012
|
"row.poolLogTitle": "活动记录",
|
|
5745
6013
|
"row.poolLogClear": "清空",
|
|
5746
6014
|
"row.poolLogEmpty": "暂无账号池活动。",
|
|
@@ -5754,7 +6022,7 @@ window.__ModuleLoader__.load({
|
|
|
5754
6022
|
"row.poolLogTestRowMalformed": "{accountName}:结果异常。",
|
|
5755
6023
|
"row.poolLogTestDone": "测速完成。",
|
|
5756
6024
|
"row.poolLogBatchFailed": "账号池操作失败:{message}",
|
|
5757
|
-
"row.
|
|
6025
|
+
"row.poolLogTimeout": "测速超时,已自动取消(按钮已恢复可用)。请检查网络后重试:{message}",
|
|
5758
6026
|
"row.poolSelectAria": "把 {accountName} 加入账号池",
|
|
5759
6027
|
"row.poolCheckedIn": "已签到",
|
|
5760
6028
|
"row.poolNotCheckedIn": "未签到",
|
|
@@ -5803,8 +6071,7 @@ window.__ModuleLoader__.load({
|
|
|
5803
6071
|
"row.poolErrConflict": "账号池拒绝了该请求",
|
|
5804
6072
|
"row.poolErrGeneric": "账号池请求失败(HTTP {status})",
|
|
5805
6073
|
"row.poolCheckingIn": "签到中…",
|
|
5806
|
-
"row.poolSettingsHint": "
|
|
5807
|
-
"row.poolGhostRemoveAria": "把已保存但本机无法登录的账号 {accountName} 移出本面板",
|
|
6074
|
+
"row.poolSettingsHint": "开关与目标模型是偏好,改完要保存;行内的测速、签到与删除立即生效。",
|
|
5808
6075
|
"row.poolLogSaved": "账号池设置已保存。",
|
|
5809
6076
|
"row.poolLogSaveFailed": "无法保存账号池设置。",
|
|
5810
6077
|
"row.poolLogNoMembers": "没有可处理的内容——尚未勾选任何池成员。",
|
|
@@ -5812,8 +6079,21 @@ window.__ModuleLoader__.load({
|
|
|
5812
6079
|
"row.poolLogGeneric": "账号池未返回可用的结果",
|
|
5813
6080
|
"row.poolLogRowTesting": "正在测速 {accountName}…",
|
|
5814
6081
|
"row.poolLogTargetCleared": "测速目标已改回自动。",
|
|
5815
|
-
"row.
|
|
5816
|
-
"row.
|
|
6082
|
+
"row.poolRowDelete": "删除",
|
|
6083
|
+
"row.poolRowDeleteAria": "从本机删除 {accountName}:插件的副本连同它在 Trae 应用里的登录(会把它从 Trae 退出登录)",
|
|
6084
|
+
"row.poolRowDeleting": "删除中…",
|
|
6085
|
+
"row.poolGhostDeleteAria": "从本机删除已保存但无法登录的账号 {accountName}",
|
|
6086
|
+
"row.poolRowDeleteError": "无法删除 {accountName}:{message}",
|
|
6087
|
+
"row.poolRowDeleteFailed": "删除未得到确认",
|
|
6088
|
+
"row.poolRowDeleted": "已删除 {accountName} 的凭据副本。",
|
|
6089
|
+
"row.poolDeleteStillSigned": "已删除本插件对 {accountName} 的副本,但它仍登录在 Trae 里,所以账号本身还在。要彻底从本机移除,请在 Trae 内退出登录。",
|
|
6090
|
+
"row.poolRowDeletedSignedOut": "已删除 {accountName},并将它从 {apps} 中退出登录。",
|
|
6091
|
+
"row.poolRowDeleteAppRunning": "无法删除 {accountName}:{apps} 正在运行,退出时会把登录写回去。请先完全退出 {apps},再重新删除。",
|
|
6092
|
+
"row.poolDeleteAppRunning": "这次没有改动任何文件:{apps} 正在运行,退出时会把自己的状态回写到文件、覆盖这次修改。请先完全退出 {apps},再点「删除」。",
|
|
6093
|
+
"row.poolDeleteNoCopy": "{accountName} 本来就没有插件副本可删——它只存在于 Trae 应用登录里,而这次退出登录没有生效。",
|
|
6094
|
+
"row.poolRowDeleteStillSigned": "已删除副本,但 {accountName} 仍登录在 Trae 中",
|
|
6095
|
+
"row.poolRowDeleteNoCopy": "{accountName} 没有插件副本——它只存在于 Trae 应用登录里",
|
|
6096
|
+
"row.poolDeleteHint": "本插件会为本机每个 Trae 登录各创建一份自己的副本(刷新时自动创建,已有副本则不动),卡片只显示、也只使用这些副本。「删除」会同时删掉副本并把该账号从 Trae 应用中退出登录,改写的每个文件都留一份备份;只要该账号还登录在 Trae 里,就不会被重新收录。Trae 正在运行时会把自己的状态回写到文件,所以要先完全退出——卡片会点名是哪个应用。",
|
|
5817
6097
|
"row.cheer": "鼓励一下"
|
|
5818
6098
|
};
|
|
5819
6099
|
//#endregion
|