@soltaoverbo/cli 0.2.0 → 0.2.1
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/.turbo/turbo-build.log +2 -2
- package/dist/bin.js +37 -30
- package/package.json +1 -1
- package/src/bin.ts +14 -3
- package/tsup.config.ts +5 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -9,5 +9,5 @@
|
|
|
9
9
|
[34mCLI[39m Target: node20
|
|
10
10
|
[34mCLI[39m Cleaning output folder
|
|
11
11
|
[34mESM[39m Build start
|
|
12
|
-
[32mESM[39m [1mdist\bin.js [22m[32m11.
|
|
13
|
-
[32mESM[39m ⚡️ Build success in
|
|
12
|
+
[32mESM[39m [1mdist\bin.js [22m[32m11.12 KB[39m
|
|
13
|
+
[32mESM[39m ⚡️ 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${"
|
|
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
|
|
27
|
+
var VERBO_PREFIX = "verbo · ";
|
|
28
28
|
function runInstall() {
|
|
29
29
|
if (!existsSync(CLAUDE_SETTINGS)) {
|
|
30
|
-
console.error(`Claude Code
|
|
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}
|
|
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(" " + "
|
|
52
|
+
console.log(dim(" " + "─".repeat(42)));
|
|
53
53
|
for (const v of verbSpinners) {
|
|
54
|
-
console.log(` ${green("
|
|
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
|
|
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(" " + "
|
|
95
|
+
console.log(dim(" " + "─".repeat(44)));
|
|
96
96
|
for (const term of group) {
|
|
97
|
-
const tag = absorbed.has(term.id) ? yellow("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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
|
|
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
|
|
265
|
-
console.log(dim(" " + "
|
|
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(
|
|
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.
|
|
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}
|
|
296
|
+
${bold("verbo")} v${VERSION} — aprenda inglês técnico passivamente
|
|
290
297
|
|
|
291
298
|
${bold("USO")}
|
|
292
|
-
verbo <comando> [
|
|
299
|
+
verbo <comando> [opções]
|
|
293
300
|
|
|
294
301
|
${bold("COMANDOS")}
|
|
295
|
-
${bold("start")} Modo pipe:
|
|
296
|
-
${bold("start --watch")} ${dim("<dir>")} Observa
|
|
302
|
+
${bold("start")} Modo pipe: lê 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")}
|
|
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
|
|
301
|
-
${bold("list")} Lista todos os termos
|
|
302
|
-
${bold("list --category")} ${dim("<cat>")} Filtra por: general, backend, frontend, devops, data
|
|
303
|
-
${bold("list --absorbed")} Inclui termos
|
|
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 já 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("
|
|
313
|
-
${bold("--version")}, ${bold("-v")}
|
|
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
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 {
|
|
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.
|
|
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
|
})
|