@soltaoverbo/cli 0.2.0 → 0.2.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.
@@ -9,5 +9,5 @@
9
9
  CLI Target: node20
10
10
  CLI Cleaning output folder
11
11
  ESM Build start
12
- ESM dist\bin.js 11.08 KB
13
- ESM ⚡️ Build success in 26ms
12
+ ESM dist\bin.js 11.12 KB
13
+ ESM ⚡️ Build success in 30ms
package/dist/bin.js CHANGED
@@ -19,15 +19,15 @@ var cyan = (s) => `\x1B[36m${s}${R}`;
19
19
  function progressBar(pct, width) {
20
20
  const filled = Math.round(pct / 100 * width);
21
21
  const empty = width - filled;
22
- return `\x1B[32m${"\u2588".repeat(filled)}\x1B[2m${"\u2591".repeat(empty)}${R}`;
22
+ return `\x1B[32m${"".repeat(filled)}\x1B[2m${"".repeat(empty)}${R}`;
23
23
  }
24
24
 
25
25
  // src/commands/install.ts
26
26
  var CLAUDE_SETTINGS = join(homedir(), ".claude", "settings.json");
27
- var VERBO_PREFIX = "verbo \xB7 ";
27
+ var VERBO_PREFIX = "verbo · ";
28
28
  function runInstall() {
29
29
  if (!existsSync(CLAUDE_SETTINGS)) {
30
- console.error(`Claude Code n\xE3o encontrado em ${CLAUDE_SETTINGS}`);
30
+ console.error(`Claude Code não encontrado em ${CLAUDE_SETTINGS}`);
31
31
  process.exit(1);
32
32
  }
33
33
  const settings = JSON.parse(readFileSync(CLAUDE_SETTINGS, "utf-8"));
@@ -38,7 +38,7 @@ function runInstall() {
38
38
  const inProgressTerms = allTerms.filter((t) => inProgress.has(t.id));
39
39
  const newTerms = allTerms.filter((t) => !absorbed.has(t.id) && !inProgress.has(t.id));
40
40
  const candidates = [...inProgressTerms, ...newTerms].slice(0, 10);
41
- const verbSpinners = candidates.map((t) => `${VERBO_PREFIX}${t.term} \u2192 ${t.translation}`);
41
+ const verbSpinners = candidates.map((t) => `${VERBO_PREFIX}${t.term} ${t.translation}`);
42
42
  const existing = (settings.spinnerVerbs?.verbs ?? []).filter(
43
43
  (v) => !v.startsWith(VERBO_PREFIX)
44
44
  );
@@ -49,9 +49,9 @@ function runInstall() {
49
49
  writeFileSync(CLAUDE_SETTINGS, JSON.stringify(settings, null, 2), "utf-8");
50
50
  console.log();
51
51
  console.log(bold(" verbo instalado no Claude Code!"));
52
- console.log(dim(" " + "\u2500".repeat(42)));
52
+ console.log(dim(" " + "".repeat(42)));
53
53
  for (const v of verbSpinners) {
54
- console.log(` ${green("\u2713")} ${v}`);
54
+ console.log(` ${green("")} ${v}`);
55
55
  }
56
56
  console.log();
57
57
  console.log(dim(" Esses termos aparecem enquanto o Claude pensa."));
@@ -67,7 +67,7 @@ function runList(args) {
67
67
  const catFilter = catIdx !== -1 ? args[catIdx + 1]?.toLowerCase() : void 0;
68
68
  const showAbsorbed = args.includes("--absorbed");
69
69
  if (catFilter && !CATEGORIES.includes(catFilter)) {
70
- console.error(`Categoria inv\xE1lida: "${catFilter}". V\xE1lidas: ${CATEGORIES.join(", ")}`);
70
+ console.error(`Categoria inválida: "${catFilter}". Válidas: ${CATEGORIES.join(", ")}`);
71
71
  process.exit(1);
72
72
  }
73
73
  const sr = new SpacedRepetition2();
@@ -92,9 +92,9 @@ function runList(args) {
92
92
  const group = grouped[cat];
93
93
  if (!group) continue;
94
94
  console.log(bold(` ${cat.toUpperCase()} (${group.length})`));
95
- console.log(dim(" " + "\u2500".repeat(44)));
95
+ console.log(dim(" " + "".repeat(44)));
96
96
  for (const term of group) {
97
- const tag = absorbed.has(term.id) ? yellow(" \u2713") : "";
97
+ const tag = absorbed.has(term.id) ? yellow(" ") : "";
98
98
  console.log(
99
99
  ` ${cyan(term.term.padEnd(22))}${tag} ${green(term.translation)}`
100
100
  );
@@ -116,12 +116,12 @@ async function runReset() {
116
116
  const rl = createInterface({ input: process.stdin, output: process.stdout });
117
117
  await new Promise((resolve) => {
118
118
  rl.question(
119
- `${yellow("\u26A0")} Isso apagar\xE1 todo o hist\xF3rico de aprendizado. Confirmar? ${dim("[s/N]")} `,
119
+ `${yellow("")} Isso apagará todo o histórico de aprendizado. Confirmar? ${dim("[s/N]")} `,
120
120
  (answer) => {
121
121
  rl.close();
122
122
  if (answer.trim().toLowerCase() === "s") {
123
123
  new SpacedRepetition3().reset();
124
- console.log(bold("\u2713 Hist\xF3rico resetado."));
124
+ console.log(bold(" Histórico resetado."));
125
125
  } else {
126
126
  console.log(dim("Cancelado."));
127
127
  }
@@ -202,7 +202,7 @@ async function pipeMode(sr, terms) {
202
202
  }
203
203
  async function watchMode(dir, extensions, sr, terms) {
204
204
  const { default: chokidar } = await import("chokidar");
205
- console.error(bold(`[verbo] Observando ${dir}`) + dim(" \u2014 Ctrl+C para parar"));
205
+ console.error(bold(`[verbo] Observando ${dir}`) + dim(" Ctrl+C para parar"));
206
206
  process.stderr.write(renderStatusLine(dir, sr));
207
207
  const watcher = chokidar.watch(dir, {
208
208
  ignoreInitial: true,
@@ -239,12 +239,12 @@ async function watchMode(dir, extensions, sr, terms) {
239
239
  }
240
240
  function renderStatusLine(dir, sr) {
241
241
  const s = sr.stats();
242
- return `\r\x1B[2K ${bold("verbo")} ${dim(dir)} ${dim("\xB7")} ${cyan(String(s.newToday))} hoje ${dim("\xB7")} ${s.total} vistos ${dim("\xB7")} ${green(String(s.absorbed))} absorvidos`;
242
+ return `\r\x1B[2K ${bold("verbo")} ${dim(dir)} ${dim("·")} ${cyan(String(s.newToday))} hoje ${dim("·")} ${s.total} vistos ${dim("·")} ${green(String(s.absorbed))} absorvidos`;
243
243
  }
244
244
  function logTerm(filePath, match) {
245
245
  const short = filePath.replace(/\\/g, "/").split("/").slice(-2).join("/");
246
246
  process.stderr.write(
247
- `${dim(short)} ${cyan(match.term)} ${dim("\u2192")} ${green(match.translation)}
247
+ `${dim(short)} ${cyan(match.term)} ${dim("")} ${green(match.translation)}
248
248
  ${"".padEnd(short.length + 2)} ${dim(match.explanation)}
249
249
  `
250
250
  );
@@ -256,13 +256,13 @@ function runStats(args = []) {
256
256
  const sr = new SpacedRepetition5();
257
257
  const s = sr.stats();
258
258
  if (args.includes("--short")) {
259
- process.stdout.write(`verbo \xB7 ${s.newToday} hoje \xB7 ${s.total} vistos \xB7 ${s.absorbed} abs
259
+ process.stdout.write(`verbo · ${s.newToday} hoje · ${s.total} vistos · ${s.absorbed} abs
260
260
  `);
261
261
  return;
262
262
  }
263
263
  console.log();
264
- console.log(bold(" verbo \u2014 progresso de aprendizado"));
265
- console.log(dim(" " + "\u2500".repeat(38)));
264
+ console.log(bold(" verbo progresso de aprendizado"));
265
+ console.log(dim(" " + "".repeat(38)));
266
266
  console.log(` ${cyan("Total visto")}: ${bold(String(s.total))}`);
267
267
  console.log(` ${green("Absorvidos")}: ${bold(String(s.absorbed))}`);
268
268
  console.log(` ${yellow("Em progresso")}: ${bold(String(s.inProgress))}`);
@@ -278,29 +278,36 @@ function runStats(args = []) {
278
278
  // src/bin.ts
279
279
  if (process.platform === "win32") {
280
280
  try {
281
- execSync("chcp 65001", { stdio: "ignore" });
281
+ execSync(
282
+ 'powershell -NoProfile -NonInteractive -Command "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8"',
283
+ { stdio: "ignore" }
284
+ );
282
285
  } catch {
286
+ try {
287
+ execSync("chcp 65001", { stdio: "ignore" });
288
+ } catch {
289
+ }
283
290
  }
284
291
  }
285
- var VERSION = "0.1.0";
292
+ var VERSION = "0.2.0";
286
293
  var [, , sub, ...rest] = process.argv;
287
294
  function help() {
288
295
  console.log(`
289
- ${bold("verbo")} v${VERSION} \u2014 aprenda ingl\xEAs t\xE9cnico passivamente
296
+ ${bold("verbo")} v${VERSION} aprenda inglês técnico passivamente
290
297
 
291
298
  ${bold("USO")}
292
- verbo <comando> [op\xE7\xF5es]
299
+ verbo <comando> [opções]
293
300
 
294
301
  ${bold("COMANDOS")}
295
- ${bold("start")} Modo pipe: l\xEA stdin e injeta coment\xE1rios em pt-BR
296
- ${bold("start --watch")} ${dim("<dir>")} Observa diret\xF3rio e loga termos novos no terminal
302
+ ${bold("start")} Modo pipe: stdin e injeta comentários em pt-BR
303
+ ${bold("start --watch")} ${dim("<dir>")} Observa diretório e loga termos novos no terminal
297
304
  ${bold("stats")} Mostra seu progresso de aprendizado
298
- ${bold("stats --short")} Sa\xEDda compacta para status bars
305
+ ${bold("stats --short")} Saída compacta para status bars
299
306
  ${bold("install")} Injeta termos no Claude Code (barra de pensamento)
300
- ${bold("reset")} Limpa todo o hist\xF3rico
301
- ${bold("list")} Lista todos os termos dispon\xEDveis
302
- ${bold("list --category")} ${dim("<cat>")} Filtra por: general, backend, frontend, devops, data
303
- ${bold("list --absorbed")} Inclui termos j\xE1 absorvidos
307
+ ${bold("reset")} Limpa todo o histórico
308
+ ${bold("list")} Lista todos os termos disponíveis
309
+ ${bold("list --category")} ${dim("<cat>")} Filtra por: general, backend, frontend, devops, data, ai
310
+ ${bold("list --absorbed")} Inclui termos absorvidos
304
311
 
305
312
  ${bold("EXEMPLOS")}
306
313
  cat handler.ts | verbo start
@@ -309,8 +316,8 @@ function help() {
309
316
  verbo install
310
317
  verbo list --category backend
311
318
 
312
- ${bold("OP\xC7\xD5ES GLOBAIS")}
313
- ${bold("--version")}, ${bold("-v")} Vers\xE3o atual
319
+ ${bold("OPÇÕES GLOBAIS")}
320
+ ${bold("--version")}, ${bold("-v")} Versão atual
314
321
  ${bold("--help")}, ${bold("-h")} Esta ajuda
315
322
  `);
316
323
  }
package/package.json CHANGED
@@ -1,22 +1,22 @@
1
1
  {
2
2
  "name": "@soltaoverbo/cli",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "CLI para verbo.dev — aprenda inglês técnico passivamente",
5
5
  "bin": {
6
6
  "verbo": "./dist/bin.js"
7
7
  },
8
8
  "type": "module",
9
- "scripts": {
10
- "build": "tsup",
11
- "dev": "tsup --watch",
12
- "lint": "eslint src"
13
- },
14
9
  "dependencies": {
15
- "@soltaoverbo/core": "workspace:*",
16
- "chokidar": "^3.6.0"
10
+ "chokidar": "^3.6.0",
11
+ "@soltaoverbo/core": "0.2.1"
17
12
  },
18
13
  "devDependencies": {
19
14
  "tsup": "^8.3.5",
20
15
  "@types/node": "^22.10.1"
16
+ },
17
+ "scripts": {
18
+ "build": "tsup",
19
+ "dev": "tsup --watch",
20
+ "lint": "eslint src"
21
21
  }
22
- }
22
+ }
package/src/bin.ts CHANGED
@@ -7,10 +7,21 @@ import { runStats } from "./commands/stats.ts"
7
7
  import { bold, dim } from "./ui.ts"
8
8
 
9
9
  if (process.platform === "win32") {
10
- try { execSync("chcp 65001", { stdio: "ignore" }) } catch {}
10
+ try {
11
+ // Switch the Windows console to UTF-8 (code page 65001).
12
+ // We use PowerShell's Console API which is more reliable than chcp
13
+ // because it sets OutputEncoding for the current console session directly.
14
+ execSync(
15
+ "powershell -NoProfile -NonInteractive -Command \"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8\"",
16
+ { stdio: "ignore" },
17
+ )
18
+ } catch {
19
+ // Fallback to chcp if PowerShell is unavailable
20
+ try { execSync("chcp 65001", { stdio: "ignore" }) } catch {}
21
+ }
11
22
  }
12
23
 
13
- const VERSION = "0.1.0"
24
+ const VERSION = "0.2.0"
14
25
  const [, , sub, ...rest] = process.argv
15
26
 
16
27
  function help(): void {
@@ -28,7 +39,7 @@ function help(): void {
28
39
  ${bold("install")} Injeta termos no Claude Code (barra de pensamento)
29
40
  ${bold("reset")} Limpa todo o histórico
30
41
  ${bold("list")} Lista todos os termos disponíveis
31
- ${bold("list --category")} ${dim("<cat>")} Filtra por: general, backend, frontend, devops, data
42
+ ${bold("list --category")} ${dim("<cat>")} Filtra por: general, backend, frontend, devops, data, ai
32
43
  ${bold("list --absorbed")} Inclui termos já absorvidos
33
44
 
34
45
  ${bold("EXEMPLOS")}
package/tsup.config.ts CHANGED
@@ -7,7 +7,11 @@ export default defineConfig({
7
7
  outDir: "dist",
8
8
  clean: true,
9
9
  dts: false,
10
- // shebang injected by tsup banner so chmod +x works after install
11
10
  banner: { js: "#!/usr/bin/env node" },
12
11
  external: ["chokidar", "@soltaoverbo/core"],
12
+ esbuildOptions(options) {
13
+ // Keep non-ASCII chars (ã, ç, etc.) as raw UTF-8 in the bundle
14
+ // instead of escaping them as \xNN sequences
15
+ options.charset = "utf8"
16
+ },
13
17
  })