@soltaoverbo/cli 0.4.1 → 0.4.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/bin.js CHANGED
@@ -91,20 +91,41 @@ Obtenha sua chave em: https://console.anthropic.com/`
91
91
  const lang = extname(filePath).replace(".", "") || "código";
92
92
  process.stderr.write(dim(`[verbo] Explicando ${basename(filePath)}...
93
93
  `));
94
- const explanations = await explainCode(code, lang, apiKey);
94
+ let explanations;
95
+ try {
96
+ explanations = await explainCode(code, lang, apiKey);
97
+ } catch (err) {
98
+ const msg = err instanceof Error ? err.message : String(err);
99
+ if (msg.includes("credit balance is too low")) {
100
+ console.error(`${bold("[verbo]")} Sem créditos na conta Anthropic. Adicione em: https://console.anthropic.com`);
101
+ } else if (msg.includes("401") || msg.includes("invalid x-api-key") || msg.includes("authentication")) {
102
+ console.error(`${bold("[verbo]")} API key inválida. Reconfigure com: verbo config set-key <chave>`);
103
+ } else if (msg.includes("529") || msg.includes("overloaded")) {
104
+ console.error(`${bold("[verbo]")} API sobrecarregada. Tente novamente em alguns instantes.`);
105
+ } else {
106
+ console.error(`${bold("[verbo]")} Erro na API: ${msg}`);
107
+ }
108
+ process.exit(1);
109
+ }
95
110
  const annotated = injectExplanations(code, explanations);
96
111
  process.stdout.write(annotated + "\n");
97
112
  }
98
113
  function askConsent(fileName) {
99
114
  return new Promise((resolve) => {
100
115
  const rl = createInterface({ input: process.stdin, output: process.stderr });
116
+ let settled = false;
117
+ const done = (val) => {
118
+ if (settled) return;
119
+ settled = true;
120
+ rl.removeAllListeners();
121
+ rl.close();
122
+ resolve(val);
123
+ };
124
+ rl.on("close", () => done(false));
101
125
  rl.question(
102
126
  `${bold("[verbo]")} O conteúdo de ${cyan(fileName)} será enviado para a API da Anthropic.
103
127
  Esta mensagem só aparece uma vez. Continuar? (s/N): `,
104
- (answer) => {
105
- rl.close();
106
- resolve(answer.trim().toLowerCase() === "s");
107
- }
128
+ (answer) => done(answer.trim().toLowerCase() === "s")
108
129
  );
109
130
  });
110
131
  }
@@ -380,7 +401,7 @@ if (process.platform === "win32") {
380
401
  }
381
402
  }
382
403
  }
383
- var VERSION = "0.4.1";
404
+ var VERSION = "0.4.2";
384
405
  var [, , sub, ...rest] = process.argv;
385
406
  function help() {
386
407
  console.log(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soltaoverbo/cli",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "CLI para verbo.dev — aprenda inglês técnico passivamente",
5
5
  "bin": {
6
6
  "verbo": "./dist/bin.js"
package/src/bin.ts CHANGED
@@ -23,7 +23,7 @@ if (process.platform === "win32") {
23
23
  }
24
24
  }
25
25
 
26
- const VERSION = "0.4.1"
26
+ const VERSION = "0.4.2"
27
27
  const [, , sub, ...rest] = process.argv
28
28
 
29
29
  function help(): void {
@@ -42,7 +42,23 @@ export async function runExplain(args: string[]): Promise<void> {
42
42
 
43
43
  process.stderr.write(dim(`[verbo] Explicando ${basename(filePath)}...\n`))
44
44
 
45
- const explanations = await explainCode(code, lang, apiKey)
45
+ let explanations: Map<number, string>
46
+ try {
47
+ explanations = await explainCode(code, lang, apiKey)
48
+ } catch (err) {
49
+ const msg = err instanceof Error ? err.message : String(err)
50
+ if (msg.includes("credit balance is too low")) {
51
+ console.error(`${bold("[verbo]")} Sem créditos na conta Anthropic. Adicione em: https://console.anthropic.com`)
52
+ } else if (msg.includes("401") || msg.includes("invalid x-api-key") || msg.includes("authentication")) {
53
+ console.error(`${bold("[verbo]")} API key inválida. Reconfigure com: verbo config set-key <chave>`)
54
+ } else if (msg.includes("529") || msg.includes("overloaded")) {
55
+ console.error(`${bold("[verbo]")} API sobrecarregada. Tente novamente em alguns instantes.`)
56
+ } else {
57
+ console.error(`${bold("[verbo]")} Erro na API: ${msg}`)
58
+ }
59
+ process.exit(1)
60
+ }
61
+
46
62
  const annotated = injectExplanations(code, explanations)
47
63
  process.stdout.write(annotated + "\n")
48
64
  }
@@ -50,13 +66,19 @@ export async function runExplain(args: string[]): Promise<void> {
50
66
  function askConsent(fileName: string): Promise<boolean> {
51
67
  return new Promise((resolve) => {
52
68
  const rl = createInterface({ input: process.stdin, output: process.stderr })
69
+ let settled = false
70
+ const done = (val: boolean) => {
71
+ if (settled) return
72
+ settled = true
73
+ rl.removeAllListeners()
74
+ rl.close()
75
+ resolve(val)
76
+ }
77
+ rl.on("close", () => done(false))
53
78
  rl.question(
54
79
  `${bold("[verbo]")} O conteúdo de ${cyan(fileName)} será enviado para a API da Anthropic.\n` +
55
80
  ` Esta mensagem só aparece uma vez. Continuar? (s/N): `,
56
- (answer) => {
57
- rl.close()
58
- resolve(answer.trim().toLowerCase() === "s")
59
- },
81
+ (answer) => done(answer.trim().toLowerCase() === "s"),
60
82
  )
61
83
  })
62
84
  }