zames_pro 2.89.0 → 2.90.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 +47 -0
- package/README.md +32 -585
- package/dist/agent-loop.js +47 -4
- package/dist/ask-retry.js +49 -0
- package/dist/ask-state.js +80 -0
- package/dist/browser-base.js +69 -0
- package/dist/browser.js +170 -41
- package/dist/command-registry.js +58 -0
- package/dist/commands.js +25 -2
- package/dist/completion-check.js +77 -0
- package/dist/config-schema.js +8 -0
- package/dist/config.js +14 -0
- package/dist/dev-commands.js +27 -0
- package/dist/dev-watch.js +96 -0
- package/dist/first-run.js +80 -0
- package/dist/glm-browser.js +133 -32
- package/dist/i18n/common.js +6 -3
- package/dist/i18n/config.js +16 -0
- package/dist/i18n/wizard.js +25 -0
- package/dist/i18n.js +6 -1
- package/dist/index.js +1289 -919
- package/dist/info-commands.js +61 -0
- package/dist/input/layout.js +38 -1
- package/dist/input.js +2 -2
- package/dist/password-store.js +48 -0
- package/dist/prompt-budget.js +23 -0
- package/dist/provider-errors.js +53 -0
- package/dist/provider-fallback.js +46 -0
- package/dist/qwen-browser.js +155 -39
- package/dist/run-task.js +2 -1
- package/dist/scheduler-commands.js +41 -0
- package/dist/send-slot.js +36 -0
- package/dist/session-commands.js +42 -0
- package/dist/spinner.js +3 -3
- package/dist/swallow.js +45 -0
- package/dist/system-prompt.js +2 -2
- package/dist/tree-commands.js +36 -0
- package/dist/tui/FullScreenApp.js +13 -4
- package/dist/tui/InputLine.js +20 -3
- package/dist/tui/LogView.js +11 -5
- package/dist/tui/StatusBar.js +4 -1
- package/dist/tui/TuiApp.js +11 -2
- package/dist/tui/layout.js +14 -1
- package/dist/tui/store.js +2 -1
- package/dist/tui/ui-colors.js +2 -0
- package/dist/width.js +10 -5
- package/llms-full.txt +16 -292
- package/package.json +2 -2
package/dist/glm-browser.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
// A FIRST message from a fresh profile is gated by an Aliyun slider captcha,
|
|
16
16
|
// which a headless browser cannot pass — hence the browser-based login
|
|
17
17
|
// (src/browser-login.ts) and the explicit captcha error below.
|
|
18
|
+
import { noteSwallowed } from './swallow.js';
|
|
18
19
|
import fs from 'fs/promises';
|
|
19
20
|
import path from 'path';
|
|
20
21
|
import os from 'os';
|
|
@@ -42,6 +43,8 @@ function capNetBody(body) {
|
|
|
42
43
|
return body.slice(0, head) + '\n...[truncated]...\n' + body.slice(-1024);
|
|
43
44
|
}
|
|
44
45
|
export class GlmBrowser {
|
|
46
|
+
/** The chat a send must join (set by the agent loop; see types.ts). */
|
|
47
|
+
resumeChatId = null;
|
|
45
48
|
providerName = 'glm';
|
|
46
49
|
headless;
|
|
47
50
|
debug;
|
|
@@ -60,6 +63,8 @@ export class GlmBrowser {
|
|
|
60
63
|
// Ask() budget for the context-limit recovery (a compaction, not a resend).
|
|
61
64
|
maxContextLimitRetries;
|
|
62
65
|
onContextLimit;
|
|
66
|
+
/** N8: switch to an authorized fallback provider (see agent-loop). */
|
|
67
|
+
onProviderExhausted = null;
|
|
63
68
|
startWaitMs;
|
|
64
69
|
sendButtonWaitMs;
|
|
65
70
|
model;
|
|
@@ -212,7 +217,9 @@ export class GlmBrowser {
|
|
|
212
217
|
this.onNotice(text);
|
|
213
218
|
return;
|
|
214
219
|
}
|
|
215
|
-
catch {
|
|
220
|
+
catch (e) {
|
|
221
|
+
noteSwallowed('_notice', e, this.debug);
|
|
222
|
+
}
|
|
216
223
|
}
|
|
217
224
|
console.error(text);
|
|
218
225
|
}
|
|
@@ -221,14 +228,18 @@ export class GlmBrowser {
|
|
|
221
228
|
try {
|
|
222
229
|
this.onSendState(state);
|
|
223
230
|
}
|
|
224
|
-
catch {
|
|
231
|
+
catch (e) {
|
|
232
|
+
noteSwallowed('_emitSendState', e, this.debug);
|
|
233
|
+
}
|
|
225
234
|
}
|
|
226
235
|
}
|
|
227
236
|
async _setBusyTitle(busy) {
|
|
228
237
|
try {
|
|
229
238
|
await this.page.evaluate(setBusyTitleInDom, busy);
|
|
230
239
|
}
|
|
231
|
-
catch {
|
|
240
|
+
catch (e) {
|
|
241
|
+
noteSwallowed('_setBusyTitle', e, this.debug);
|
|
242
|
+
}
|
|
232
243
|
}
|
|
233
244
|
sendIntervalMs() {
|
|
234
245
|
return this.sendRuntime.intervalMs();
|
|
@@ -317,13 +328,25 @@ export class GlmBrowser {
|
|
|
317
328
|
.catch(() => { });
|
|
318
329
|
}
|
|
319
330
|
async restart() {
|
|
331
|
+
// Remember the dialogue BEFORE the context dies: a relaunch lands on the
|
|
332
|
+
// BASE url, so the id is lost and the next send started a NEW chat.
|
|
333
|
+
const chatBefore = (await this.getCurrentChatId().catch(() => null)) ?? null;
|
|
320
334
|
try {
|
|
321
335
|
if (this.context)
|
|
322
336
|
await this.context.close();
|
|
323
337
|
}
|
|
324
|
-
catch {
|
|
338
|
+
catch (e) {
|
|
339
|
+
noteSwallowed('restart', e, this.debug);
|
|
340
|
+
}
|
|
325
341
|
await this._launchOnce();
|
|
326
342
|
await this._fixHeadlessUserAgent();
|
|
343
|
+
if (chatBefore) {
|
|
344
|
+
const ok = await this.openChat(chatBefore).catch(() => false);
|
|
345
|
+
if (ok)
|
|
346
|
+
this._netChatId = chatBefore;
|
|
347
|
+
else if (this.debug)
|
|
348
|
+
console.error('restart: could not reopen chat ' + chatBefore);
|
|
349
|
+
}
|
|
327
350
|
}
|
|
328
351
|
/**
|
|
329
352
|
* Relaunch the SAME persistent profile in another headless mode — the
|
|
@@ -349,12 +372,16 @@ export class GlmBrowser {
|
|
|
349
372
|
}));
|
|
350
373
|
}
|
|
351
374
|
}
|
|
352
|
-
catch {
|
|
375
|
+
catch (e) {
|
|
376
|
+
noteSwallowed('relaunchSafe', e, this.debug);
|
|
377
|
+
}
|
|
353
378
|
try {
|
|
354
379
|
if (this.context)
|
|
355
380
|
await this.context.close();
|
|
356
381
|
}
|
|
357
|
-
catch {
|
|
382
|
+
catch (e) {
|
|
383
|
+
noteSwallowed('relaunchSafe', e, this.debug);
|
|
384
|
+
}
|
|
358
385
|
await this._waitProfileUnlocked(15_000);
|
|
359
386
|
this.headless = headless;
|
|
360
387
|
const options = {
|
|
@@ -427,7 +454,9 @@ export class GlmBrowser {
|
|
|
427
454
|
const j = await res.json();
|
|
428
455
|
role = typeof j?.role === 'string' ? j.role : null;
|
|
429
456
|
}
|
|
430
|
-
catch {
|
|
457
|
+
catch (e) {
|
|
458
|
+
noteSwallowed('probeLogin', e, this.debug);
|
|
459
|
+
}
|
|
431
460
|
const bodyText = document.body ? document.body.innerText : '';
|
|
432
461
|
const captcha = /security verification|drag the slider/i.test(bodyText);
|
|
433
462
|
const signInVisible = /\bsign in\b/i.test(bodyText) && !hasToken;
|
|
@@ -470,7 +499,9 @@ export class GlmBrowser {
|
|
|
470
499
|
.catch(() => { });
|
|
471
500
|
await this.page.waitForTimeout(1500);
|
|
472
501
|
}
|
|
473
|
-
catch {
|
|
502
|
+
catch (e) {
|
|
503
|
+
noteSwallowed('_openLoginPage', e, this.debug);
|
|
504
|
+
}
|
|
474
505
|
}
|
|
475
506
|
/** Prefill the SAVED login (never the password — that is filled on submit). */
|
|
476
507
|
async _prefillLogin() {
|
|
@@ -485,7 +516,9 @@ export class GlmBrowser {
|
|
|
485
516
|
await email.fill(saved, { timeout: 2000 }).catch(() => { });
|
|
486
517
|
}
|
|
487
518
|
}
|
|
488
|
-
catch {
|
|
519
|
+
catch (e) {
|
|
520
|
+
noteSwallowed('_prefillLogin', e, this.debug);
|
|
521
|
+
}
|
|
489
522
|
}
|
|
490
523
|
/**
|
|
491
524
|
* Best-effort password login with the SAVED credentials. z.ai's form is
|
|
@@ -515,7 +548,9 @@ export class GlmBrowser {
|
|
|
515
548
|
try {
|
|
516
549
|
this.onAuthSave?.(this.auth.username, this.auth.password);
|
|
517
550
|
}
|
|
518
|
-
catch {
|
|
551
|
+
catch (e) {
|
|
552
|
+
noteSwallowed('_autoLogin', e, this.debug);
|
|
553
|
+
}
|
|
519
554
|
}
|
|
520
555
|
return ok;
|
|
521
556
|
}
|
|
@@ -565,7 +600,9 @@ export class GlmBrowser {
|
|
|
565
600
|
try {
|
|
566
601
|
this.onAuthSave?.(u, p);
|
|
567
602
|
}
|
|
568
|
-
catch {
|
|
603
|
+
catch (e) {
|
|
604
|
+
noteSwallowed('_captureLoginCredentials', e, this.debug);
|
|
605
|
+
}
|
|
569
606
|
});
|
|
570
607
|
await this.page.evaluate(() => {
|
|
571
608
|
const w = window;
|
|
@@ -583,11 +620,15 @@ export class GlmBrowser {
|
|
|
583
620
|
if (email && fn)
|
|
584
621
|
fn(email.value || '', pwd ? pwd.value || '' : '');
|
|
585
622
|
}
|
|
586
|
-
catch {
|
|
623
|
+
catch (e) {
|
|
624
|
+
noteSwallowed('_captureLoginCredentials', e, this.debug);
|
|
625
|
+
}
|
|
587
626
|
}, true);
|
|
588
627
|
});
|
|
589
628
|
}
|
|
590
|
-
catch {
|
|
629
|
+
catch (e) {
|
|
630
|
+
noteSwallowed('_captureLoginCredentials', e, this.debug);
|
|
631
|
+
}
|
|
591
632
|
}
|
|
592
633
|
async _persistSessionIfNeeded() {
|
|
593
634
|
if (!this.auth.saveSession)
|
|
@@ -676,12 +717,16 @@ export class GlmBrowser {
|
|
|
676
717
|
}
|
|
677
718
|
}
|
|
678
719
|
}
|
|
679
|
-
catch {
|
|
720
|
+
catch (e) {
|
|
721
|
+
noteSwallowed('close', e, this.debug);
|
|
722
|
+
}
|
|
680
723
|
try {
|
|
681
724
|
if (this.context)
|
|
682
725
|
await this.context.close();
|
|
683
726
|
}
|
|
684
|
-
catch {
|
|
727
|
+
catch (e) {
|
|
728
|
+
noteSwallowed('close', e, this.debug);
|
|
729
|
+
}
|
|
685
730
|
}
|
|
686
731
|
/**
|
|
687
732
|
* Rewrite the completion REQUEST so z.ai's own agent runtime stays off.
|
|
@@ -750,7 +795,9 @@ export class GlmBrowser {
|
|
|
750
795
|
}
|
|
751
796
|
});
|
|
752
797
|
}
|
|
753
|
-
catch {
|
|
798
|
+
catch (e) {
|
|
799
|
+
noteSwallowed('_installRuntimeRewrite', e, this.debug);
|
|
800
|
+
}
|
|
754
801
|
}
|
|
755
802
|
_installNetHook() {
|
|
756
803
|
const pg = this.page;
|
|
@@ -778,7 +825,9 @@ export class GlmBrowser {
|
|
|
778
825
|
// (The features are recorded by _installRuntimeRewrite's route handler:
|
|
779
826
|
// the `request` event still carries the ORIGINAL body.)
|
|
780
827
|
}
|
|
781
|
-
catch {
|
|
828
|
+
catch (e) {
|
|
829
|
+
noteSwallowed('_installNetHook', e, this.debug);
|
|
830
|
+
}
|
|
782
831
|
});
|
|
783
832
|
}
|
|
784
833
|
async _onResponse(resp) {
|
|
@@ -852,7 +901,9 @@ export class GlmBrowser {
|
|
|
852
901
|
this._netCaptureAt = Date.now();
|
|
853
902
|
}
|
|
854
903
|
}
|
|
855
|
-
catch {
|
|
904
|
+
catch (e) {
|
|
905
|
+
noteSwallowed('_onResponse', e, this.debug);
|
|
906
|
+
}
|
|
856
907
|
}
|
|
857
908
|
async newChat() {
|
|
858
909
|
const before = await this.getCurrentChatId();
|
|
@@ -862,7 +913,9 @@ export class GlmBrowser {
|
|
|
862
913
|
await btn.click({ timeout: 2500 });
|
|
863
914
|
clicked = true;
|
|
864
915
|
}
|
|
865
|
-
catch {
|
|
916
|
+
catch (e) {
|
|
917
|
+
noteSwallowed('newChat', e, this.debug);
|
|
918
|
+
}
|
|
866
919
|
let ok = false;
|
|
867
920
|
if (clicked) {
|
|
868
921
|
const deadline = Date.now() + 5000;
|
|
@@ -901,7 +954,9 @@ export class GlmBrowser {
|
|
|
901
954
|
if (await loc.isVisible({ timeout }).catch(() => false))
|
|
902
955
|
return loc;
|
|
903
956
|
}
|
|
904
|
-
catch {
|
|
957
|
+
catch (e) {
|
|
958
|
+
noteSwallowed('_findVisible', e, this.debug);
|
|
959
|
+
}
|
|
905
960
|
}
|
|
906
961
|
return null;
|
|
907
962
|
}
|
|
@@ -937,7 +992,9 @@ export class GlmBrowser {
|
|
|
937
992
|
this._lastHistoryError = res.error;
|
|
938
993
|
}
|
|
939
994
|
}
|
|
940
|
-
catch {
|
|
995
|
+
catch (e) {
|
|
996
|
+
noteSwallowed('listChats', e, this.debug);
|
|
997
|
+
}
|
|
941
998
|
try {
|
|
942
999
|
return await this.page.evaluate(scrapeGlmChatList, limit);
|
|
943
1000
|
}
|
|
@@ -1169,21 +1226,27 @@ export class GlmBrowser {
|
|
|
1169
1226
|
}
|
|
1170
1227
|
}
|
|
1171
1228
|
}
|
|
1172
|
-
catch {
|
|
1229
|
+
catch (e) {
|
|
1230
|
+
noteSwallowed('stopGeneration', e, this.debug);
|
|
1231
|
+
}
|
|
1173
1232
|
const btn = await this._findVisible(STOP_SELECTORS, 500);
|
|
1174
1233
|
if (btn) {
|
|
1175
1234
|
try {
|
|
1176
1235
|
await btn.click({ timeout: 1500 });
|
|
1177
1236
|
return true;
|
|
1178
1237
|
}
|
|
1179
|
-
catch {
|
|
1238
|
+
catch (e) {
|
|
1239
|
+
noteSwallowed('stopGeneration', e, this.debug);
|
|
1240
|
+
}
|
|
1180
1241
|
}
|
|
1181
1242
|
// No dedicated stop control was observed; Escape aborts the generation.
|
|
1182
1243
|
try {
|
|
1183
1244
|
await this.page.keyboard.press('Escape');
|
|
1184
1245
|
return true;
|
|
1185
1246
|
}
|
|
1186
|
-
catch {
|
|
1247
|
+
catch (e) {
|
|
1248
|
+
noteSwallowed('stopGeneration', e, this.debug);
|
|
1249
|
+
}
|
|
1187
1250
|
return false;
|
|
1188
1251
|
}
|
|
1189
1252
|
/**
|
|
@@ -1232,7 +1295,9 @@ export class GlmBrowser {
|
|
|
1232
1295
|
if (!clicked)
|
|
1233
1296
|
await this.page.keyboard.press('Escape').catch(() => { });
|
|
1234
1297
|
}
|
|
1235
|
-
catch {
|
|
1298
|
+
catch (e) {
|
|
1299
|
+
noteSwallowed('_applyModel', e, this.debug);
|
|
1300
|
+
}
|
|
1236
1301
|
}
|
|
1237
1302
|
getToggleStatesSync() {
|
|
1238
1303
|
return this._toggles;
|
|
@@ -1337,7 +1402,9 @@ export class GlmBrowser {
|
|
|
1337
1402
|
try {
|
|
1338
1403
|
this.onSendPause(secs);
|
|
1339
1404
|
}
|
|
1340
|
-
catch {
|
|
1405
|
+
catch (e) {
|
|
1406
|
+
noteSwallowed('_waitForSendSlot', e, this.debug);
|
|
1407
|
+
}
|
|
1341
1408
|
}
|
|
1342
1409
|
};
|
|
1343
1410
|
report(gap);
|
|
@@ -1378,6 +1445,8 @@ export class GlmBrowser {
|
|
|
1378
1445
|
// The exhausted-context recovery is a COMPACTION (a new chat), not a
|
|
1379
1446
|
// resend, so it has its own budget.
|
|
1380
1447
|
let contextLimitRetries = 0;
|
|
1448
|
+
// N8: the fallback switch is tried ONCE per ask().
|
|
1449
|
+
let fallbackAttempted = false;
|
|
1381
1450
|
this._askInFlight++;
|
|
1382
1451
|
try {
|
|
1383
1452
|
while (attempt < this.askRetries) {
|
|
@@ -1483,6 +1552,26 @@ export class GlmBrowser {
|
|
|
1483
1552
|
}));
|
|
1484
1553
|
}
|
|
1485
1554
|
}
|
|
1555
|
+
// N8: the active provider exhausted its budgets. Give the injected
|
|
1556
|
+
// hook ONE chance to continue on an AUTHORIZED fallback provider.
|
|
1557
|
+
if (!fallbackAttempted && this.onProviderExhausted) {
|
|
1558
|
+
fallbackAttempted = true;
|
|
1559
|
+
let switched = false;
|
|
1560
|
+
try {
|
|
1561
|
+
switched = await this.onProviderExhausted(lastErr);
|
|
1562
|
+
}
|
|
1563
|
+
catch (e) {
|
|
1564
|
+
noteSwallowed('_onProviderExhausted', e, this.debug);
|
|
1565
|
+
}
|
|
1566
|
+
if (switched) {
|
|
1567
|
+
attempt = 0;
|
|
1568
|
+
rateLimitRetries = 0;
|
|
1569
|
+
serverBusyRetries = 0;
|
|
1570
|
+
incompleteRetries = 0;
|
|
1571
|
+
contextLimitRetries = 0;
|
|
1572
|
+
continue;
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1486
1575
|
this._notice(this._t('glm.ask_retry', {
|
|
1487
1576
|
attempt: attempt + 1,
|
|
1488
1577
|
max: this.askRetries,
|
|
@@ -1511,7 +1600,9 @@ export class GlmBrowser {
|
|
|
1511
1600
|
await input.fill(text, { timeout: 5000 });
|
|
1512
1601
|
return;
|
|
1513
1602
|
}
|
|
1514
|
-
catch {
|
|
1603
|
+
catch (e) {
|
|
1604
|
+
noteSwallowed('_setInputText', e, this.debug);
|
|
1605
|
+
}
|
|
1515
1606
|
}
|
|
1516
1607
|
await input.click({ timeout: 3000 }).catch(() => { });
|
|
1517
1608
|
await input
|
|
@@ -1547,7 +1638,9 @@ export class GlmBrowser {
|
|
|
1547
1638
|
await this._awaitUploadPreview(files.map((f) => f.name), 5000);
|
|
1548
1639
|
return failed;
|
|
1549
1640
|
}
|
|
1550
|
-
catch {
|
|
1641
|
+
catch (e) {
|
|
1642
|
+
noteSwallowed('_attachFiles', e, this.debug);
|
|
1643
|
+
}
|
|
1551
1644
|
// Fallback: set the files directly on the hidden <input type=file>.
|
|
1552
1645
|
for (const sel of ['input[type="file"]']) {
|
|
1553
1646
|
const el = this.page.locator(sel).last();
|
|
@@ -1558,7 +1651,9 @@ export class GlmBrowser {
|
|
|
1558
1651
|
await this._awaitUploadPreview(files.map((f) => f.name), 3000);
|
|
1559
1652
|
return failed;
|
|
1560
1653
|
}
|
|
1561
|
-
catch {
|
|
1654
|
+
catch (e) {
|
|
1655
|
+
noteSwallowed('_attachFiles', e, this.debug);
|
|
1656
|
+
}
|
|
1562
1657
|
}
|
|
1563
1658
|
this._notice(this._t('glm.attach_no_input'));
|
|
1564
1659
|
for (const f of files)
|
|
@@ -1581,7 +1676,9 @@ export class GlmBrowser {
|
|
|
1581
1676
|
await this._awaitInput(10_000);
|
|
1582
1677
|
input = await this._findVisible(INPUT_SELECTORS, 3000);
|
|
1583
1678
|
}
|
|
1584
|
-
catch {
|
|
1679
|
+
catch (e) {
|
|
1680
|
+
noteSwallowed('_askOnce', e, this.debug);
|
|
1681
|
+
}
|
|
1585
1682
|
}
|
|
1586
1683
|
if (!input)
|
|
1587
1684
|
throw new Error(this._t('glm.input_missing'));
|
|
@@ -1593,7 +1690,9 @@ export class GlmBrowser {
|
|
|
1593
1690
|
try {
|
|
1594
1691
|
this.onSendStart();
|
|
1595
1692
|
}
|
|
1596
|
-
catch {
|
|
1693
|
+
catch (e) {
|
|
1694
|
+
noteSwallowed('_askOnce', e, this.debug);
|
|
1695
|
+
}
|
|
1597
1696
|
}
|
|
1598
1697
|
this._emitSendState('generating');
|
|
1599
1698
|
void this._setBusyTitle(true);
|
|
@@ -1639,7 +1738,9 @@ export class GlmBrowser {
|
|
|
1639
1738
|
clicked = true;
|
|
1640
1739
|
break;
|
|
1641
1740
|
}
|
|
1642
|
-
catch {
|
|
1741
|
+
catch (e) {
|
|
1742
|
+
noteSwallowed('_askOnce', e, this.debug);
|
|
1743
|
+
}
|
|
1643
1744
|
}
|
|
1644
1745
|
if (!clicked) {
|
|
1645
1746
|
await this.page.keyboard.press('Enter').catch(() => { });
|
package/dist/i18n/common.js
CHANGED
|
@@ -393,8 +393,11 @@ export const commonMessages = {
|
|
|
393
393
|
ru: '⚠ авто-reload: часть модулей не загрузилась, работаю на прежней версии:',
|
|
394
394
|
en: '⚠ auto-reload: some modules failed, using previous version:',
|
|
395
395
|
},
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
396
|
+
// A generic version of the row above: the WHOLE non-reloadable set is
|
|
397
|
+
// watched (index.ts, run-task.ts, the provider browsers, browser-login.ts,
|
|
398
|
+
// send-*.ts, src/tui/), and `{files}` names what changed.
|
|
399
|
+
'reload.non_reloadable_restart': {
|
|
400
|
+
ru: '⚠ изменились модули, которые НЕ перезагружаются на лету ({files}). Перезапусти zames, иначе изменения не применятся.',
|
|
401
|
+
en: '⚠ non-reloadable modules changed ({files}). Restart zames or the change will not apply.',
|
|
399
402
|
},
|
|
400
403
|
};
|
package/dist/i18n/config.js
CHANGED
|
@@ -258,6 +258,10 @@ export const configMessages = {
|
|
|
258
258
|
ru: 'Логин DeepSeek для авто-входа',
|
|
259
259
|
en: 'DeepSeek login for auto sign-in',
|
|
260
260
|
},
|
|
261
|
+
'cfg.f.browser_passwordStore': {
|
|
262
|
+
ru: 'Где хранить пароль: config (в файле), none (не хранить), keychain (системное хранилище)',
|
|
263
|
+
en: 'Where to keep the password: config (in the file), none (never store), keychain (OS keychain)',
|
|
264
|
+
},
|
|
261
265
|
'cfg.f.browser_authPassword': {
|
|
262
266
|
ru: 'Пароль DeepSeek для авто-входа',
|
|
263
267
|
en: 'DeepSeek password for auto sign-in',
|
|
@@ -373,4 +377,16 @@ export const configMessages = {
|
|
|
373
377
|
ru: 'Esc — назад к группам',
|
|
374
378
|
en: 'Esc — back to the groups',
|
|
375
379
|
},
|
|
380
|
+
'provider.fallback_ask': {
|
|
381
|
+
ru: 'Лимит провайдера {from} исчерпан. Продолжить задачу на {to}? (browser.fallbackMode=auto переключает без вопроса)',
|
|
382
|
+
en: 'The {from} limit is exhausted. Continue the task on {to}? (browser.fallbackMode=auto switches without asking)',
|
|
383
|
+
},
|
|
384
|
+
'provider.fallback_none': {
|
|
385
|
+
ru: '✖ Лимит {from} исчерпан, а резервного провайдера нет. Авторизуй одного через /provider <id> (нужен настоящий вход, гостевой режим не подходит) и задай browser.fallbackProviders.',
|
|
386
|
+
en: '✖ {from} is exhausted and there is no fallback provider. Authorize one with /provider <id> (a real sign-in; a guest session is not enough) and set browser.fallbackProviders.',
|
|
387
|
+
},
|
|
388
|
+
'provider.fallback_switch': {
|
|
389
|
+
ru: 'Лимит {from} исчерпан — переключаюсь на {to} и продолжаю задачу.',
|
|
390
|
+
en: '{from} is exhausted — switching to {to} and continuing the task.',
|
|
391
|
+
},
|
|
376
392
|
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// First-run wizard (N19). A fresh install has no config yet, so these lines
|
|
2
|
+
// are the FIRST the operator ever sees: they must explain the three choices
|
|
3
|
+
// (language, backend, sign-in) without assuming any prior knowledge.
|
|
4
|
+
export const wizardMessages = {
|
|
5
|
+
'wizard.welcome': {
|
|
6
|
+
ru: 'Первый запуск. Настроим три вещи: язык, провайдер и вход. Enter — значение по умолчанию.',
|
|
7
|
+
en: 'First run. Three quick choices: language, provider and sign-in. Enter accepts the default.',
|
|
8
|
+
},
|
|
9
|
+
'wizard.language': {
|
|
10
|
+
ru: 'Язык интерфейса [en/ru] (en):',
|
|
11
|
+
en: 'Interface language [en/ru] (en):',
|
|
12
|
+
},
|
|
13
|
+
'wizard.provider': {
|
|
14
|
+
ru: 'Провайдер [deepseek/qwen/glm] (deepseek): ',
|
|
15
|
+
en: 'Provider [deepseek/qwen/glm] (deepseek): ',
|
|
16
|
+
},
|
|
17
|
+
'wizard.hint': {
|
|
18
|
+
ru: 'Готово. Дальше — /help; сменить настройки можно через /config.',
|
|
19
|
+
en: 'Done. Next: /help; change these later with /config.',
|
|
20
|
+
},
|
|
21
|
+
'wizard.skipped': {
|
|
22
|
+
ru: 'Мастер пропущен — используются значения по умолчанию (английский, DeepSeek).',
|
|
23
|
+
en: 'Wizard skipped — using the defaults (English, DeepSeek).',
|
|
24
|
+
},
|
|
25
|
+
};
|
package/dist/i18n.js
CHANGED
|
@@ -15,9 +15,13 @@ import { selfReviewMessages } from './i18n/self-review.js';
|
|
|
15
15
|
import { mcpMessages } from './i18n/mcp.js';
|
|
16
16
|
import { configMessages } from './i18n/config.js';
|
|
17
17
|
import { promptMessages } from './i18n/prompt.js';
|
|
18
|
+
import { wizardMessages } from './i18n/wizard.js';
|
|
18
19
|
import { qwenMessages } from './i18n/qwen.js';
|
|
19
20
|
import { glmMessages } from './i18n/glm.js';
|
|
20
|
-
|
|
21
|
+
// English is the default for a fresh install: the package is published for an
|
|
22
|
+
// international audience and the operator asked for English out of the box.
|
|
23
|
+
// `ui.locale` still overrides it, and the first-run wizard offers Russian.
|
|
24
|
+
export const DEFAULT_LOCALE = 'en';
|
|
21
25
|
export const LOCALES = [
|
|
22
26
|
{ code: 'ru', name: 'Русский', englishName: 'Russian' },
|
|
23
27
|
{ code: 'en', name: 'English', englishName: 'English' },
|
|
@@ -48,6 +52,7 @@ export const CATALOG = {
|
|
|
48
52
|
...mcpMessages,
|
|
49
53
|
...configMessages,
|
|
50
54
|
...promptMessages,
|
|
55
|
+
...wizardMessages,
|
|
51
56
|
...qwenMessages,
|
|
52
57
|
...glmMessages,
|
|
53
58
|
};
|