qwenproxy-cli 1.6.1 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/clean-cache.js +7 -3
- package/dist/delete-chats.js +325 -8
- package/dist/index.js +667 -94
- package/dist/login.js +383 -9
- package/dist/reset-cooldowns.js +17 -3
- package/package.json +3 -3
- package/src/core/accounts.ts +1 -1
- package/src/core/version.ts +1 -1
- package/src/login.ts +90 -4
- package/src/routes/chat/account.ts +11 -4
- package/src/routes/chat/retry-policy.ts +45 -3
- package/src/routes/chat/streaming.ts +27 -0
- package/src/services/playwright.ts +378 -4
- package/src/services/qwen.ts +22 -6
- package/src/tui/views/accounts-view.ts +313 -96
- package/src/utils/overload-detector.ts +55 -0
|
@@ -59,11 +59,17 @@ export class AccountsView implements TuiView {
|
|
|
59
59
|
private isAddModalOpen = false;
|
|
60
60
|
private isBatchModalOpen = false;
|
|
61
61
|
private isValidatingAccount = false;
|
|
62
|
+
private isOtpRequesting = false;
|
|
63
|
+
private isOtpCodeSent = false;
|
|
64
|
+
private addLoginMode: "password" | "otp" = "password";
|
|
65
|
+
private otpSessionId: string | null = null;
|
|
62
66
|
private addEmailInput = "";
|
|
63
67
|
private addPasswordInput = "";
|
|
68
|
+
private addOtpCodeInput = "";
|
|
64
69
|
private addEmailCursor = 0;
|
|
65
70
|
private addPasswordCursor = 0;
|
|
66
|
-
private
|
|
71
|
+
private addOtpCodeCursor = 0;
|
|
72
|
+
private addActiveField: "email" | "password" | "code" = "email";
|
|
67
73
|
private batchInput = "";
|
|
68
74
|
private batchCursor = 0;
|
|
69
75
|
private batchHoveredButton: "import" | "cancel" | null = null;
|
|
@@ -72,7 +78,7 @@ export class AccountsView implements TuiView {
|
|
|
72
78
|
private lastBatchModalStartRow = 4;
|
|
73
79
|
private hoveredActionRow: number | null = null;
|
|
74
80
|
private hoveredAccountIndex: number | null = null;
|
|
75
|
-
private modalHoveredField: "email" | "password" | "save" | "cancel" | null = null;
|
|
81
|
+
private modalHoveredField: "email" | "password" | "code" | "save" | "cancel" | "mode" | null = null;
|
|
76
82
|
private lastModalLeftPad = 0;
|
|
77
83
|
private lastLeftW = 46;
|
|
78
84
|
private accountsScrollOffset = 0;
|
|
@@ -149,11 +155,116 @@ export class AccountsView implements TuiView {
|
|
|
149
155
|
}, 4000);
|
|
150
156
|
}
|
|
151
157
|
|
|
158
|
+
private resetAddModalState(): void {
|
|
159
|
+
if (this.otpSessionId && !process.env.NODE_TEST_CONTEXT) {
|
|
160
|
+
const sid = this.otpSessionId;
|
|
161
|
+
import("../../services/playwright.ts")
|
|
162
|
+
.then(({ cancelEmailOtpLogin }) => cancelEmailOtpLogin(sid))
|
|
163
|
+
.catch(() => {});
|
|
164
|
+
}
|
|
165
|
+
this.isAddModalOpen = false;
|
|
166
|
+
this.isValidatingAccount = false;
|
|
167
|
+
this.isOtpRequesting = false;
|
|
168
|
+
this.isOtpCodeSent = false;
|
|
169
|
+
this.otpSessionId = null;
|
|
170
|
+
this.addEmailInput = "";
|
|
171
|
+
this.addPasswordInput = "";
|
|
172
|
+
this.addOtpCodeInput = "";
|
|
173
|
+
this.addEmailCursor = 0;
|
|
174
|
+
this.addPasswordCursor = 0;
|
|
175
|
+
this.addOtpCodeCursor = 0;
|
|
176
|
+
this.addActiveField = "email";
|
|
177
|
+
this.addLoginMode = "password";
|
|
178
|
+
}
|
|
179
|
+
|
|
152
180
|
private async saveModalAccount(): Promise<void> {
|
|
153
|
-
if (this.isValidatingAccount) return;
|
|
181
|
+
if (this.isValidatingAccount || this.isOtpRequesting) return;
|
|
154
182
|
const email = this.addEmailInput.trim();
|
|
183
|
+
if (!email) {
|
|
184
|
+
this.setStatusMessage(theme.yellow("[!] E-mail é obrigatório"));
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (this.addLoginMode === "otp") {
|
|
189
|
+
if (!this.isOtpCodeSent) {
|
|
190
|
+
if (process.env.NODE_TEST_CONTEXT) {
|
|
191
|
+
this.isOtpCodeSent = true;
|
|
192
|
+
this.addActiveField = "code";
|
|
193
|
+
this.otpSessionId = "mock-otp-" + Date.now();
|
|
194
|
+
this.setStatusMessage(theme.green("✓ Código enviado para o e-mail!"));
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
this.isOtpRequesting = true;
|
|
199
|
+
this.setStatusMessage(theme.yellow(`[...] Enviando código OTP para ${email}...`));
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
const { startEmailOtpLogin } = await import("../../services/playwright.ts");
|
|
203
|
+
const res = await startEmailOtpLogin(email, { headless: config.playwright.headless });
|
|
204
|
+
this.isOtpRequesting = false;
|
|
205
|
+
if (!res.success || !res.sessionId) {
|
|
206
|
+
this.setStatusMessage(theme.red(`✗ Falha ao enviar código: ${res.error || "Erro desconhecido"}`));
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
this.otpSessionId = res.sessionId;
|
|
210
|
+
this.isOtpCodeSent = true;
|
|
211
|
+
this.addActiveField = "code";
|
|
212
|
+
this.setStatusMessage(theme.green("✓ Código enviado! Digite os 6 dígitos abaixo."));
|
|
213
|
+
} catch (err: any) {
|
|
214
|
+
this.isOtpRequesting = false;
|
|
215
|
+
this.setStatusMessage(theme.red(`✗ Erro: ${err?.message || String(err)}`));
|
|
216
|
+
}
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const code = this.addOtpCodeInput.trim();
|
|
221
|
+
if (!code) {
|
|
222
|
+
this.setStatusMessage(theme.yellow("[!] Digite o código de 6 dígitos recebido por e-mail"));
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (process.env.NODE_TEST_CONTEXT) {
|
|
227
|
+
try {
|
|
228
|
+
const newAcc = addAccount(email, "");
|
|
229
|
+
this.resetAddModalState();
|
|
230
|
+
await this.refresh();
|
|
231
|
+
this.setStatusMessage(theme.green(`✓ Conta ${email} salva via código OTP!`));
|
|
232
|
+
} catch (err: any) {
|
|
233
|
+
this.setStatusMessage(theme.red(`✗ Erro ao salvar: ${err?.message || String(err)}`));
|
|
234
|
+
}
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
this.isValidatingAccount = true;
|
|
239
|
+
this.setStatusMessage(theme.yellow("[...] Validando código e capturando sessão de 30 dias..."));
|
|
240
|
+
try {
|
|
241
|
+
const { verifyEmailOtpLogin } = await import("../../services/playwright.ts");
|
|
242
|
+
const res = await verifyEmailOtpLogin(this.otpSessionId!, code);
|
|
243
|
+
this.isValidatingAccount = false;
|
|
244
|
+
if (!res.success || !res.account) {
|
|
245
|
+
this.setStatusMessage(theme.red(`✗ Código inválido: ${res.error || "Verificação falhou"}`));
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
this.resetAddModalState();
|
|
249
|
+
await this.refresh();
|
|
250
|
+
this.setStatusMessage(theme.green(`✓ Conta ${res.account.email} autenticada via código OTP!`));
|
|
251
|
+
|
|
252
|
+
if (process.stdout.isTTY) {
|
|
253
|
+
const sManager = ServerManager.getInstance();
|
|
254
|
+
const sState = sManager.getState();
|
|
255
|
+
if (sState !== "online" && sState !== "warming") {
|
|
256
|
+
void sManager.ensureStarted().then(() => this.refresh());
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
} catch (err: any) {
|
|
260
|
+
this.isValidatingAccount = false;
|
|
261
|
+
this.setStatusMessage(theme.red(`✗ Erro de verificação: ${err?.message || String(err)}`));
|
|
262
|
+
}
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
155
266
|
const password = this.addPasswordInput.trim();
|
|
156
|
-
if (!
|
|
267
|
+
if (!password) {
|
|
157
268
|
this.setStatusMessage(theme.yellow("[!] E-mail e senha são obrigatórios"));
|
|
158
269
|
return;
|
|
159
270
|
}
|
|
@@ -161,11 +272,7 @@ export class AccountsView implements TuiView {
|
|
|
161
272
|
if (process.env.NODE_TEST_CONTEXT) {
|
|
162
273
|
try {
|
|
163
274
|
const newAcc = addAccount(email, password);
|
|
164
|
-
this.
|
|
165
|
-
this.addEmailInput = "";
|
|
166
|
-
this.addPasswordInput = "";
|
|
167
|
-
this.addEmailCursor = 0;
|
|
168
|
-
this.addPasswordCursor = 0;
|
|
275
|
+
this.resetAddModalState();
|
|
169
276
|
await this.refresh();
|
|
170
277
|
this.setStatusMessage(theme.green(`✓ Conta ${email} salva! Conectando...`));
|
|
171
278
|
} catch (err: any) {
|
|
@@ -197,11 +304,7 @@ export class AccountsView implements TuiView {
|
|
|
197
304
|
}
|
|
198
305
|
|
|
199
306
|
const newAcc = addAccount(email, password, tempId);
|
|
200
|
-
this.
|
|
201
|
-
this.addEmailInput = "";
|
|
202
|
-
this.addPasswordInput = "";
|
|
203
|
-
this.addEmailCursor = 0;
|
|
204
|
-
this.addPasswordCursor = 0;
|
|
307
|
+
this.resetAddModalState();
|
|
205
308
|
await this.refresh();
|
|
206
309
|
this.setStatusMessage(theme.green(`✓ Conta ${email} validada e salva! Conectando...`));
|
|
207
310
|
|
|
@@ -492,31 +595,46 @@ export class AccountsView implements TuiView {
|
|
|
492
595
|
|
|
493
596
|
// 1. Add Account Modal Active
|
|
494
597
|
if (this.isAddModalOpen) {
|
|
495
|
-
if (this.isValidatingAccount) return true;
|
|
598
|
+
if (this.isValidatingAccount || this.isOtpRequesting) return true;
|
|
496
599
|
if (key.name === "escape") {
|
|
497
|
-
this.
|
|
498
|
-
this.addEmailInput = "";
|
|
499
|
-
this.addPasswordInput = "";
|
|
600
|
+
this.resetAddModalState();
|
|
500
601
|
return true;
|
|
501
602
|
}
|
|
502
603
|
|
|
604
|
+
// Switch mode with Tab (when code has not been sent yet)
|
|
605
|
+
if (key.name === "tab") {
|
|
606
|
+
if (!this.isOtpCodeSent) {
|
|
607
|
+
this.addLoginMode = this.addLoginMode === "password" ? "otp" : "password";
|
|
608
|
+
this.addActiveField = "email";
|
|
609
|
+
this.setStatusMessage(
|
|
610
|
+
theme.cyan(
|
|
611
|
+
`Modo alterado para: ${
|
|
612
|
+
this.addLoginMode === "password" ? "Senha" : "Código E-mail (Sem Senha)"
|
|
613
|
+
}`,
|
|
614
|
+
),
|
|
615
|
+
);
|
|
616
|
+
return true;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
503
620
|
// Mouse hover in Add Account modal
|
|
504
621
|
if (key.name === "hover" && key.mouse) {
|
|
505
622
|
const { row, col } = key.mouse;
|
|
506
623
|
const leftPad = this.lastModalLeftPad || 0;
|
|
507
624
|
const relCol = col - leftPad;
|
|
508
|
-
if (row ===
|
|
625
|
+
if (row === 6) {
|
|
509
626
|
if (this.modalHoveredField !== "email") {
|
|
510
627
|
this.modalHoveredField = "email";
|
|
511
628
|
return true;
|
|
512
629
|
}
|
|
513
|
-
} else if (row === 7
|
|
514
|
-
|
|
515
|
-
|
|
630
|
+
} else if (row === 7) {
|
|
631
|
+
const field = this.addLoginMode === "password" ? "password" : "code";
|
|
632
|
+
if (this.modalHoveredField !== field) {
|
|
633
|
+
this.modalHoveredField = field;
|
|
516
634
|
return true;
|
|
517
635
|
}
|
|
518
636
|
} else if (row === 9) {
|
|
519
|
-
const btn = relCol <=
|
|
637
|
+
const btn = relCol <= 28 ? "save" : relCol <= 49 ? "cancel" : "mode";
|
|
520
638
|
if (this.modalHoveredField !== btn) {
|
|
521
639
|
this.modalHoveredField = btn;
|
|
522
640
|
return true;
|
|
@@ -532,34 +650,52 @@ export class AccountsView implements TuiView {
|
|
|
532
650
|
const { row, col } = key.mouse;
|
|
533
651
|
const leftPad = this.lastModalLeftPad || 0;
|
|
534
652
|
const relCol = col - leftPad;
|
|
535
|
-
// Click on email field row (
|
|
536
|
-
if (row ===
|
|
653
|
+
// Click on email field row (row 6)
|
|
654
|
+
if (row === 6) {
|
|
537
655
|
this.addActiveField = "email";
|
|
538
656
|
return true;
|
|
539
657
|
}
|
|
540
|
-
// Click on
|
|
541
|
-
if (row === 7
|
|
542
|
-
this.
|
|
658
|
+
// Click on second field row (row 7)
|
|
659
|
+
if (row === 7) {
|
|
660
|
+
if (this.addLoginMode === "password") {
|
|
661
|
+
this.addActiveField = "password";
|
|
662
|
+
} else if (this.isOtpCodeSent) {
|
|
663
|
+
this.addActiveField = "code";
|
|
664
|
+
}
|
|
543
665
|
return true;
|
|
544
666
|
}
|
|
545
667
|
// Click on buttons row (row 9)
|
|
546
668
|
if (row === 9) {
|
|
547
|
-
if (relCol <=
|
|
669
|
+
if (relCol <= 28) {
|
|
548
670
|
await this.saveModalAccount();
|
|
549
671
|
return true;
|
|
550
|
-
} else {
|
|
551
|
-
this.
|
|
552
|
-
this.addEmailInput = "";
|
|
553
|
-
this.addPasswordInput = "";
|
|
554
|
-
this.addEmailCursor = 0;
|
|
555
|
-
this.addPasswordCursor = 0;
|
|
672
|
+
} else if (relCol <= 49) {
|
|
673
|
+
this.resetAddModalState();
|
|
556
674
|
return true;
|
|
675
|
+
} else {
|
|
676
|
+
// Clicked mode toggle button
|
|
677
|
+
if (!this.isOtpCodeSent) {
|
|
678
|
+
this.addLoginMode = this.addLoginMode === "password" ? "otp" : "password";
|
|
679
|
+
this.addActiveField = "email";
|
|
680
|
+
this.setStatusMessage(
|
|
681
|
+
theme.cyan(
|
|
682
|
+
`Modo alterado para: ${
|
|
683
|
+
this.addLoginMode === "password" ? "Senha" : "Código E-mail (Sem Senha)"
|
|
684
|
+
}`,
|
|
685
|
+
),
|
|
686
|
+
);
|
|
687
|
+
return true;
|
|
688
|
+
}
|
|
557
689
|
}
|
|
558
690
|
}
|
|
559
691
|
}
|
|
560
692
|
// Switch field with Up / Down arrow keys
|
|
561
693
|
if (key.name === "up" || key.name === "down") {
|
|
562
|
-
|
|
694
|
+
if (this.addLoginMode === "password") {
|
|
695
|
+
this.addActiveField = this.addActiveField === "email" ? "password" : "email";
|
|
696
|
+
} else if (this.isOtpCodeSent) {
|
|
697
|
+
this.addActiveField = this.addActiveField === "email" ? "code" : "email";
|
|
698
|
+
}
|
|
563
699
|
return true;
|
|
564
700
|
}
|
|
565
701
|
|
|
@@ -567,27 +703,33 @@ export class AccountsView implements TuiView {
|
|
|
567
703
|
if (key.name === "left") {
|
|
568
704
|
if (this.addActiveField === "email") {
|
|
569
705
|
this.addEmailCursor = Math.max(0, this.addEmailCursor - 1);
|
|
570
|
-
} else {
|
|
706
|
+
} else if (this.addActiveField === "password") {
|
|
571
707
|
this.addPasswordCursor = Math.max(0, this.addPasswordCursor - 1);
|
|
708
|
+
} else {
|
|
709
|
+
this.addOtpCodeCursor = Math.max(0, this.addOtpCodeCursor - 1);
|
|
572
710
|
}
|
|
573
711
|
return true;
|
|
574
712
|
}
|
|
575
713
|
if (key.name === "right") {
|
|
576
714
|
if (this.addActiveField === "email") {
|
|
577
715
|
this.addEmailCursor = Math.min(this.addEmailInput.length, this.addEmailCursor + 1);
|
|
578
|
-
} else {
|
|
716
|
+
} else if (this.addActiveField === "password") {
|
|
579
717
|
this.addPasswordCursor = Math.min(this.addPasswordInput.length, this.addPasswordCursor + 1);
|
|
718
|
+
} else {
|
|
719
|
+
this.addOtpCodeCursor = Math.min(this.addOtpCodeInput.length, this.addOtpCodeCursor + 1);
|
|
580
720
|
}
|
|
581
721
|
return true;
|
|
582
722
|
}
|
|
583
723
|
if (key.name === "home") {
|
|
584
724
|
if (this.addActiveField === "email") this.addEmailCursor = 0;
|
|
585
|
-
else this.addPasswordCursor = 0;
|
|
725
|
+
else if (this.addActiveField === "password") this.addPasswordCursor = 0;
|
|
726
|
+
else this.addOtpCodeCursor = 0;
|
|
586
727
|
return true;
|
|
587
728
|
}
|
|
588
729
|
if (key.name === "end") {
|
|
589
730
|
if (this.addActiveField === "email") this.addEmailCursor = this.addEmailInput.length;
|
|
590
|
-
else this.addPasswordCursor = this.addPasswordInput.length;
|
|
731
|
+
else if (this.addActiveField === "password") this.addPasswordCursor = this.addPasswordInput.length;
|
|
732
|
+
else this.addOtpCodeCursor = this.addOtpCodeInput.length;
|
|
591
733
|
return true;
|
|
592
734
|
}
|
|
593
735
|
|
|
@@ -601,12 +743,18 @@ export class AccountsView implements TuiView {
|
|
|
601
743
|
pasted +
|
|
602
744
|
this.addEmailInput.slice(this.addEmailCursor);
|
|
603
745
|
this.addEmailCursor += pasted.length;
|
|
604
|
-
} else {
|
|
746
|
+
} else if (this.addActiveField === "password") {
|
|
605
747
|
this.addPasswordInput =
|
|
606
748
|
this.addPasswordInput.slice(0, this.addPasswordCursor) +
|
|
607
749
|
pasted +
|
|
608
750
|
this.addPasswordInput.slice(this.addPasswordCursor);
|
|
609
751
|
this.addPasswordCursor += pasted.length;
|
|
752
|
+
} else {
|
|
753
|
+
this.addOtpCodeInput =
|
|
754
|
+
this.addOtpCodeInput.slice(0, this.addOtpCodeCursor) +
|
|
755
|
+
pasted +
|
|
756
|
+
this.addOtpCodeInput.slice(this.addOtpCodeCursor);
|
|
757
|
+
this.addOtpCodeCursor += pasted.length;
|
|
610
758
|
}
|
|
611
759
|
return true;
|
|
612
760
|
}
|
|
@@ -616,9 +764,12 @@ export class AccountsView implements TuiView {
|
|
|
616
764
|
if (this.addActiveField === "email") {
|
|
617
765
|
this.addEmailInput = "";
|
|
618
766
|
this.addEmailCursor = 0;
|
|
619
|
-
} else {
|
|
767
|
+
} else if (this.addActiveField === "password") {
|
|
620
768
|
this.addPasswordInput = "";
|
|
621
769
|
this.addPasswordCursor = 0;
|
|
770
|
+
} else {
|
|
771
|
+
this.addOtpCodeInput = "";
|
|
772
|
+
this.addOtpCodeCursor = 0;
|
|
622
773
|
}
|
|
623
774
|
return true;
|
|
624
775
|
}
|
|
@@ -632,13 +783,20 @@ export class AccountsView implements TuiView {
|
|
|
632
783
|
this.addEmailInput.slice(this.addEmailCursor);
|
|
633
784
|
this.addEmailCursor--;
|
|
634
785
|
}
|
|
635
|
-
} else {
|
|
786
|
+
} else if (this.addActiveField === "password") {
|
|
636
787
|
if (this.addPasswordCursor > 0) {
|
|
637
788
|
this.addPasswordInput =
|
|
638
789
|
this.addPasswordInput.slice(0, this.addPasswordCursor - 1) +
|
|
639
790
|
this.addPasswordInput.slice(this.addPasswordCursor);
|
|
640
791
|
this.addPasswordCursor--;
|
|
641
792
|
}
|
|
793
|
+
} else {
|
|
794
|
+
if (this.addOtpCodeCursor > 0) {
|
|
795
|
+
this.addOtpCodeInput =
|
|
796
|
+
this.addOtpCodeInput.slice(0, this.addOtpCodeCursor - 1) +
|
|
797
|
+
this.addOtpCodeInput.slice(this.addOtpCodeCursor);
|
|
798
|
+
this.addOtpCodeCursor--;
|
|
799
|
+
}
|
|
642
800
|
}
|
|
643
801
|
return true;
|
|
644
802
|
}
|
|
@@ -651,12 +809,18 @@ export class AccountsView implements TuiView {
|
|
|
651
809
|
this.addEmailInput.slice(0, this.addEmailCursor) +
|
|
652
810
|
this.addEmailInput.slice(this.addEmailCursor + 1);
|
|
653
811
|
}
|
|
654
|
-
} else {
|
|
812
|
+
} else if (this.addActiveField === "password") {
|
|
655
813
|
if (this.addPasswordCursor < this.addPasswordInput.length) {
|
|
656
814
|
this.addPasswordInput =
|
|
657
815
|
this.addPasswordInput.slice(0, this.addPasswordCursor) +
|
|
658
816
|
this.addPasswordInput.slice(this.addPasswordCursor + 1);
|
|
659
817
|
}
|
|
818
|
+
} else {
|
|
819
|
+
if (this.addOtpCodeCursor < this.addOtpCodeInput.length) {
|
|
820
|
+
this.addOtpCodeInput =
|
|
821
|
+
this.addOtpCodeInput.slice(0, this.addOtpCodeCursor) +
|
|
822
|
+
this.addOtpCodeInput.slice(this.addOtpCodeCursor + 1);
|
|
823
|
+
}
|
|
660
824
|
}
|
|
661
825
|
return true;
|
|
662
826
|
}
|
|
@@ -666,7 +830,6 @@ export class AccountsView implements TuiView {
|
|
|
666
830
|
await this.saveModalAccount();
|
|
667
831
|
return true;
|
|
668
832
|
}
|
|
669
|
-
// Type character into active field
|
|
670
833
|
// Type character into active field at cursor position
|
|
671
834
|
if (key.char && !key.ctrl && !key.meta && key.name !== "tab") {
|
|
672
835
|
if (key.char >= " ") {
|
|
@@ -676,12 +839,20 @@ export class AccountsView implements TuiView {
|
|
|
676
839
|
key.char +
|
|
677
840
|
this.addEmailInput.slice(this.addEmailCursor);
|
|
678
841
|
this.addEmailCursor += key.char.length;
|
|
679
|
-
} else {
|
|
842
|
+
} else if (this.addActiveField === "password") {
|
|
680
843
|
this.addPasswordInput =
|
|
681
844
|
this.addPasswordInput.slice(0, this.addPasswordCursor) +
|
|
682
845
|
key.char +
|
|
683
846
|
this.addPasswordInput.slice(this.addPasswordCursor);
|
|
684
847
|
this.addPasswordCursor += key.char.length;
|
|
848
|
+
} else if (this.addActiveField === "code") {
|
|
849
|
+
if (this.addOtpCodeInput.length < 10) {
|
|
850
|
+
this.addOtpCodeInput =
|
|
851
|
+
this.addOtpCodeInput.slice(0, this.addOtpCodeCursor) +
|
|
852
|
+
key.char +
|
|
853
|
+
this.addOtpCodeInput.slice(this.addOtpCodeCursor);
|
|
854
|
+
this.addOtpCodeCursor += key.char.length;
|
|
855
|
+
}
|
|
685
856
|
}
|
|
686
857
|
return true;
|
|
687
858
|
}
|
|
@@ -808,15 +979,15 @@ export class AccountsView implements TuiView {
|
|
|
808
979
|
return true;
|
|
809
980
|
}
|
|
810
981
|
|
|
811
|
-
// Right panel action buttons hover (rows
|
|
982
|
+
// Right panel action buttons hover (rows 16 to 21)
|
|
812
983
|
if (col >= leftW) {
|
|
813
|
-
if (row ===
|
|
814
|
-
const actionRow = col < leftW + 18 ?
|
|
984
|
+
if (row === 16) {
|
|
985
|
+
const actionRow = col < leftW + 18 ? 16 : 22;
|
|
815
986
|
if (this.hoveredActionRow !== actionRow) {
|
|
816
987
|
this.hoveredActionRow = actionRow;
|
|
817
988
|
return true;
|
|
818
989
|
}
|
|
819
|
-
} else if (row >=
|
|
990
|
+
} else if (row >= 17 && row <= 21) {
|
|
820
991
|
if (this.hoveredActionRow !== row) {
|
|
821
992
|
this.hoveredActionRow = row;
|
|
822
993
|
return true;
|
|
@@ -844,9 +1015,9 @@ export class AccountsView implements TuiView {
|
|
|
844
1015
|
return true;
|
|
845
1016
|
}
|
|
846
1017
|
}
|
|
847
|
-
// Right panel action buttons click (rows
|
|
1018
|
+
// Right panel action buttons click (rows 16 to 21)
|
|
848
1019
|
if (col >= leftW) {
|
|
849
|
-
if (row ===
|
|
1020
|
+
if (row === 16) {
|
|
850
1021
|
if (col < leftW + 18) {
|
|
851
1022
|
await this.handleKey({ name: "a", ctrl: false, shift: false, meta: false });
|
|
852
1023
|
} else {
|
|
@@ -854,23 +1025,23 @@ export class AccountsView implements TuiView {
|
|
|
854
1025
|
}
|
|
855
1026
|
return true;
|
|
856
1027
|
}
|
|
857
|
-
if (row ===
|
|
1028
|
+
if (row === 17) {
|
|
858
1029
|
await this.handleKey({ name: "d", ctrl: false, shift: false, meta: false });
|
|
859
1030
|
return true;
|
|
860
1031
|
}
|
|
861
|
-
if (row ===
|
|
1032
|
+
if (row === 18) {
|
|
862
1033
|
await this.handleKey({ name: "c", ctrl: false, shift: false, meta: false });
|
|
863
1034
|
return true;
|
|
864
1035
|
}
|
|
865
|
-
if (row ===
|
|
1036
|
+
if (row === 19) {
|
|
866
1037
|
await this.handleKey({ name: "z", ctrl: false, shift: false, meta: false });
|
|
867
1038
|
return true;
|
|
868
1039
|
}
|
|
869
|
-
if (row ===
|
|
1040
|
+
if (row === 20) {
|
|
870
1041
|
await this.handleKey({ name: "x", ctrl: false, shift: false, meta: false });
|
|
871
1042
|
return true;
|
|
872
1043
|
}
|
|
873
|
-
if (row ===
|
|
1044
|
+
if (row === 21) {
|
|
874
1045
|
await this.handleKey({ name: "l", ctrl: false, shift: false, meta: false });
|
|
875
1046
|
return true;
|
|
876
1047
|
}
|
|
@@ -1046,9 +1217,10 @@ export class AccountsView implements TuiView {
|
|
|
1046
1217
|
rightContent.push("");
|
|
1047
1218
|
rightContent.push("");
|
|
1048
1219
|
rightContent.push("");
|
|
1220
|
+
rightContent.push("");
|
|
1049
1221
|
rightContent.push(` ${theme.dim("─────────────────────────────────")}`);
|
|
1050
|
-
const btnA = this.hoveredActionRow ===
|
|
1051
|
-
const btnB = this.hoveredActionRow ===
|
|
1222
|
+
const btnA = this.hoveredActionRow === 16 ? theme.bgHover(` ${theme.cyan("[ A ] Adicionar")} `) : ` ${theme.cyan("[ A ]")} Adicionar `;
|
|
1223
|
+
const btnB = this.hoveredActionRow === 22 ? theme.bgHover(` ${theme.cyan("[ B ] Em Lote")} `) : ` ${theme.cyan("[ B ]")} Em Lote `;
|
|
1052
1224
|
rightContent.push(` ${btnA} ${btnB}`);
|
|
1053
1225
|
} else {
|
|
1054
1226
|
const email = truncate(selected.emailOrName, 18);
|
|
@@ -1082,14 +1254,14 @@ export class AccountsView implements TuiView {
|
|
|
1082
1254
|
rightContent.push("");
|
|
1083
1255
|
}
|
|
1084
1256
|
rightContent.push(` ${theme.dim("─────────────────────────────────")}`);
|
|
1085
|
-
const btnA = this.hoveredActionRow ===
|
|
1086
|
-
const btnB = this.hoveredActionRow ===
|
|
1257
|
+
const btnA = this.hoveredActionRow === 16 ? theme.bgHover(` ${theme.cyan("[ A ] Adicionar")} `) : ` ${theme.cyan("[ A ]")} Adicionar `;
|
|
1258
|
+
const btnB = this.hoveredActionRow === 22 ? theme.bgHover(` ${theme.cyan("[ B ] Em Lote")} `) : ` ${theme.cyan("[ B ]")} Em Lote `;
|
|
1087
1259
|
rightContent.push(` ${btnA} ${btnB}`);
|
|
1088
|
-
rightContent.push(` ${this.hoveredActionRow ===
|
|
1089
|
-
rightContent.push(` ${this.hoveredActionRow ===
|
|
1090
|
-
rightContent.push(` ${this.hoveredActionRow ===
|
|
1091
|
-
rightContent.push(` ${this.hoveredActionRow ===
|
|
1092
|
-
rightContent.push(` ${this.hoveredActionRow ===
|
|
1260
|
+
rightContent.push(` ${this.hoveredActionRow === 17 ? theme.bgHover(` ${theme.red("[ D ] Remover Conta")} `) : ` ${theme.red("[ D ]")} Remover Conta `}`);
|
|
1261
|
+
rightContent.push(` ${this.hoveredActionRow === 18 ? theme.bgHover(` ${theme.yellow("[ C ] Zerar Cooldown")} `) : ` ${theme.yellow("[ C ]")} Zerar Cooldown `}`);
|
|
1262
|
+
rightContent.push(` ${this.hoveredActionRow === 19 ? theme.bgHover(` ${theme.green("[ Z ] Zerar Todas")} `) : ` ${theme.green("[ Z ]")} Zerar Todas `}`);
|
|
1263
|
+
rightContent.push(` ${this.hoveredActionRow === 20 ? theme.bgHover(` ${theme.peach("[ X ] Limpar Chats (Conta)")} `) : ` ${theme.peach("[ X ]")} Limpar Chats (Conta) `}`);
|
|
1264
|
+
rightContent.push(` ${this.hoveredActionRow === 21 ? theme.bgHover(` ${theme.red("[ L ] Limpar Todos os Chats")} `) : ` ${theme.red("[ L ]")} Limpar Todos os Chats `}`);
|
|
1093
1265
|
}
|
|
1094
1266
|
const rightBox = drawBox({
|
|
1095
1267
|
title: "Inspeção de Conta",
|
|
@@ -1182,16 +1354,14 @@ export class AccountsView implements TuiView {
|
|
|
1182
1354
|
return modalBox.map((line) => padStr + line);
|
|
1183
1355
|
}
|
|
1184
1356
|
if (this.isAddModalOpen) {
|
|
1185
|
-
const modalW = Math.min(width - 4,
|
|
1357
|
+
const modalW = Math.min(width - 4, 76);
|
|
1186
1358
|
this.lastModalLeftPad = Math.max(0, Math.floor((width - modalW) / 2));
|
|
1187
1359
|
|
|
1188
1360
|
const isEmail = this.addActiveField === "email";
|
|
1189
1361
|
const isPass = this.addActiveField === "password";
|
|
1362
|
+
const isCode = this.addActiveField === "code";
|
|
1190
1363
|
|
|
1191
|
-
|
|
1192
|
-
const passHover = !isPass && this.modalHoveredField === "password";
|
|
1193
|
-
|
|
1194
|
-
// Render Email field with clean cursor
|
|
1364
|
+
// Render Email field with clean cursor (no white background hover)
|
|
1195
1365
|
let emailDisplay: string;
|
|
1196
1366
|
if (isEmail) {
|
|
1197
1367
|
if (this.addEmailInput.length === 0) {
|
|
@@ -1204,47 +1374,94 @@ export class AccountsView implements TuiView {
|
|
|
1204
1374
|
}
|
|
1205
1375
|
} else {
|
|
1206
1376
|
emailDisplay = this.addEmailInput
|
|
1207
|
-
?
|
|
1208
|
-
:
|
|
1377
|
+
? theme.cyan(this.addEmailInput)
|
|
1378
|
+
: theme.muted("(digite o e-mail)");
|
|
1209
1379
|
}
|
|
1210
1380
|
|
|
1211
|
-
// Render Password field with clean cursor
|
|
1212
|
-
let
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1381
|
+
// Render Password or Code field with clean cursor
|
|
1382
|
+
let secondFieldLabel: string;
|
|
1383
|
+
let secondFieldDisplay: string;
|
|
1384
|
+
|
|
1385
|
+
if (this.addLoginMode === "password") {
|
|
1386
|
+
secondFieldLabel = "Senha:";
|
|
1387
|
+
const maskedPass = "•".repeat(this.addPasswordInput.length);
|
|
1388
|
+
if (isPass) {
|
|
1389
|
+
if (this.addPasswordInput.length === 0) {
|
|
1390
|
+
secondFieldDisplay = `${theme.inverse(" ")} ${theme.dim("(digite a senha)")}`;
|
|
1391
|
+
} else {
|
|
1392
|
+
const before = maskedPass.slice(0, this.addPasswordCursor);
|
|
1393
|
+
const at = maskedPass[this.addPasswordCursor] || " ";
|
|
1394
|
+
const after = maskedPass.slice(this.addPasswordCursor + 1);
|
|
1395
|
+
secondFieldDisplay = `${theme.cyan(before)}${theme.inverse(at)}${theme.cyan(after)}`;
|
|
1396
|
+
}
|
|
1217
1397
|
} else {
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
passDisplay = `${theme.cyan(before)}${theme.inverse(at)}${theme.cyan(after)}`;
|
|
1398
|
+
secondFieldDisplay = this.addPasswordInput
|
|
1399
|
+
? theme.cyan(maskedPass)
|
|
1400
|
+
: theme.muted("(digite a senha)");
|
|
1222
1401
|
}
|
|
1223
1402
|
} else {
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1403
|
+
secondFieldLabel = "Código:";
|
|
1404
|
+
if (!this.isOtpCodeSent) {
|
|
1405
|
+
secondFieldDisplay = theme.dim("(será enviado p/ seu e-mail)");
|
|
1406
|
+
} else if (isCode) {
|
|
1407
|
+
if (this.addOtpCodeInput.length === 0) {
|
|
1408
|
+
secondFieldDisplay = `${theme.inverse(" ")} ${theme.dim("(digite o código de 6 dígitos)")}`;
|
|
1409
|
+
} else {
|
|
1410
|
+
const before = this.addOtpCodeInput.slice(0, this.addOtpCodeCursor);
|
|
1411
|
+
const at = this.addOtpCodeInput[this.addOtpCodeCursor] || " ";
|
|
1412
|
+
const after = this.addOtpCodeInput.slice(this.addOtpCodeCursor + 1);
|
|
1413
|
+
secondFieldDisplay = `${theme.cyan(before)}${theme.inverse(at)}${theme.cyan(after)}`;
|
|
1414
|
+
}
|
|
1415
|
+
} else {
|
|
1416
|
+
secondFieldDisplay = this.addOtpCodeInput
|
|
1417
|
+
? theme.cyan(this.addOtpCodeInput)
|
|
1418
|
+
: theme.muted("(digite o código de 6 dígitos)");
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
let saveBtnText: string;
|
|
1423
|
+
if (this.addLoginMode === "password") {
|
|
1424
|
+
saveBtnText = "[ Enter ] Salvar";
|
|
1425
|
+
} else if (!this.isOtpCodeSent) {
|
|
1426
|
+
saveBtnText = "[ Enter ] Enviar Código";
|
|
1427
|
+
} else {
|
|
1428
|
+
saveBtnText = "[ Enter ] Confirmar Código";
|
|
1227
1429
|
}
|
|
1228
|
-
|
|
1229
|
-
|
|
1430
|
+
|
|
1431
|
+
const saveBtn = (this.isValidatingAccount || this.isOtpRequesting)
|
|
1432
|
+
? theme.yellow(" [ Aguarde... ] ")
|
|
1230
1433
|
: this.modalHoveredField === "save"
|
|
1231
|
-
? theme.bgHover(
|
|
1232
|
-
: theme.green(
|
|
1434
|
+
? theme.bgHover(` ${saveBtnText} `)
|
|
1435
|
+
: ` ${theme.green(saveBtnText)} `;
|
|
1233
1436
|
|
|
1234
1437
|
const cancelBtn =
|
|
1235
1438
|
this.modalHoveredField === "cancel"
|
|
1236
|
-
? theme.bgHover(
|
|
1237
|
-
: theme.muted("[ Esc ] Cancelar")
|
|
1439
|
+
? theme.bgHover(" [ Esc ] Cancelar ")
|
|
1440
|
+
: ` ${theme.muted("[ Esc ] Cancelar")} `;
|
|
1441
|
+
|
|
1442
|
+
const modeBtnText = this.addLoginMode === "password"
|
|
1443
|
+
? "[ Tab ] Sem Senha (OTP)"
|
|
1444
|
+
: "[ Tab ] Modo Senha";
|
|
1445
|
+
|
|
1446
|
+
const modeBtn =
|
|
1447
|
+
this.modalHoveredField === "mode"
|
|
1448
|
+
? theme.bgHover(` ${modeBtnText} `)
|
|
1449
|
+
: ` ${theme.cyan(modeBtnText)} `;
|
|
1450
|
+
|
|
1238
1451
|
const modalContent = [
|
|
1239
1452
|
"",
|
|
1240
|
-
` ${theme.bold("E-mail:")} ${emailDisplay}`,
|
|
1241
|
-
` ${theme.bold(
|
|
1453
|
+
` ${theme.bold("E-mail:")} ${emailDisplay}${this.isOtpCodeSent ? ` ${theme.green("✓ Código Enviado")}` : ""}`,
|
|
1454
|
+
` ${theme.bold(secondFieldLabel)} ${secondFieldDisplay}`,
|
|
1242
1455
|
"",
|
|
1243
|
-
` ${saveBtn}
|
|
1456
|
+
` ${saveBtn} ${cancelBtn} ${modeBtn}`,
|
|
1244
1457
|
];
|
|
1245
1458
|
|
|
1459
|
+
const modalTitle = this.addLoginMode === "password"
|
|
1460
|
+
? "Adicionar Nova Conta Qwen (Login com Senha)"
|
|
1461
|
+
: "Adicionar Nova Conta Qwen (Login sem Senha - OTP)";
|
|
1462
|
+
|
|
1246
1463
|
const modalBox = drawBox({
|
|
1247
|
-
title:
|
|
1464
|
+
title: modalTitle,
|
|
1248
1465
|
width: modalW,
|
|
1249
1466
|
height: Math.min(contentH, 11),
|
|
1250
1467
|
borderColor: theme.borderActive,
|