@tostudy-ai/cli 0.18.6 → 0.18.7

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/cli.js CHANGED
@@ -21,6 +21,29 @@ function canRunOnNode(version) {
21
21
  }
22
22
  return true;
23
23
  }
24
+ var INSTALL_UNIX = "curl -fsSL https://tostudy.ai/install.sh | sh";
25
+ var INSTALL_WINDOWS = "irm https://tostudy.ai/install.ps1 | iex";
26
+ function nodeGuardMessage(mode, version, pt) {
27
+ const installers = ` macOS/Linux: ${INSTALL_UNIX}
28
+ Windows (PowerShell): ${INSTALL_WINDOWS}
29
+ `;
30
+ if (mode === "block") {
31
+ return pt ? `Erro: o ToStudy CLI precisa do Node.js ${MIN_NODE_MAJOR} ou superior.
32
+ Voc\xEA est\xE1 no Node.js ${version}.
33
+ Para atualizar, rode o instalador de novo:
34
+ ${installers}Ou atualize em https://nodejs.org. Depois rode o comando de novo.
35
+ ` : `Error: the ToStudy CLI requires Node.js ${MIN_NODE_MAJOR} or newer.
36
+ You are on Node.js ${version}.
37
+ To update, run the installer again:
38
+ ${installers}Or update at https://nodejs.org. Then run the command again.
39
+ `;
40
+ }
41
+ return pt ? `Aviso: o Node.js ${version} n\xE3o \xE9 mais suportado pelo ToStudy CLI. Atualize para o Node.js ${MIN_NODE_MAJOR} ou superior rodando o instalador de novo:
42
+ ${installers}Ou atualize em https://nodejs.org.
43
+ ` : `Warning: Node.js ${version} is no longer supported by the ToStudy CLI. Update to Node.js ${MIN_NODE_MAJOR} or newer by running the installer again:
44
+ ${installers}Or update at https://nodejs.org.
45
+ `;
46
+ }
24
47
 
25
48
  // src/cli-entry.ts
26
49
  if (!process.env.LOG_LEVEL) {
@@ -31,22 +54,10 @@ if (!meetsNodeFloor(process.versions.node)) {
31
54
  const localeFlag = localeFlagIdx !== -1 && localeFlagIdx + 1 < process.argv.length ? process.argv[localeFlagIdx + 1] : void 0;
32
55
  const pt = localeFlag === "pt-BR" || localeFlag === "en-US" ? localeFlag === "pt-BR" : !(process.env["LANG"] ?? "").toLowerCase().startsWith("en");
33
56
  if (!canRunOnNode(process.versions.node)) {
34
- process.stderr.write(
35
- pt ? `Erro: o ToStudy CLI precisa do Node.js ${MIN_NODE_MAJOR} ou superior.
36
- Voc\xEA est\xE1 no Node.js ${process.versions.node}.
37
- Atualize em https://nodejs.org e rode o comando de novo.
38
- ` : `Error: the ToStudy CLI requires Node.js ${MIN_NODE_MAJOR} or newer.
39
- You are on Node.js ${process.versions.node}.
40
- Update at https://nodejs.org and run the command again.
41
- `
42
- );
57
+ process.stderr.write(nodeGuardMessage("block", process.versions.node, pt));
43
58
  process.exit(1);
44
59
  }
45
- process.stderr.write(
46
- pt ? `Aviso: o Node.js ${process.versions.node} n\xE3o \xE9 mais suportado pelo ToStudy CLI. Atualize para o Node.js ${MIN_NODE_MAJOR} ou superior em https://nodejs.org.
47
- ` : `Warning: Node.js ${process.versions.node} is no longer supported by the ToStudy CLI. Update to Node.js ${MIN_NODE_MAJOR} or newer at https://nodejs.org.
48
- `
49
- );
60
+ process.stderr.write(nodeGuardMessage("warn", process.versions.node, pt));
50
61
  }
51
62
  if (!process.env["TOSTUDY_LOCALE"]) {
52
63
  try {
package/dist/cli.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/node-floor.ts", "../src/cli-entry.ts"],
4
- "sourcesContent": ["// GH #2114 \u2014 the Node floors of the CLI, read by the runtime guard (cli-entry.ts),\n// `tostudy doctor` (installer/node-detector.ts) and the label doctor prints.\n//\n// Two floors on purpose:\n// - MIN_NODE_MAJOR is the supported floor (Node 20 is EOL since 2026-04-30). It must\n// match `engines` in package.json and the esbuild target in build-npm.mjs.\n// - MIN_NODE_RUNTIME is where the bundle actually loads (undici 7 needs 20.18.1). The\n// guard blocks below it and only warns between the two, so students on Node 20, who\n// ran 0.18.0 fine, are not locked out by the auto-update.\n//\n// Leaf module on purpose: cli-entry.ts imports it before the bundle loads, so it must\n// not import anything (the guard has to run on runtimes the rest of the CLI rejects).\nexport const MIN_NODE_MAJOR = 22;\nexport const MIN_NODE_RUNTIME = \"20.18.1\";\n\nfunction parseVersion(version: string): [number, number, number] | null {\n const match = /^v?(\\d+)\\.(\\d+)\\.(\\d+)/.exec(version.trim());\n if (!match) return null;\n return [Number(match[1]), Number(match[2]), Number(match[3])];\n}\n\n/** Supported floor. Accepts `process.versions.node` (\"22.1.0\") or `node --version` (\"v22.1.0\"). */\nexport function meetsNodeFloor(version: string): boolean {\n const parsed = parseVersion(version);\n return parsed !== null && parsed[0] >= MIN_NODE_MAJOR;\n}\n\n/** Hard floor: false means the bundle cannot run on this Node at all. */\nexport function canRunOnNode(version: string): boolean {\n const parsed = parseVersion(version);\n const floor = parseVersion(MIN_NODE_RUNTIME);\n if (!parsed || !floor) return false;\n for (let i = 0; i < 3; i++) {\n if (parsed[i]! !== floor[i]!) return parsed[i]! > floor[i]!;\n }\n return true;\n}\n", "/**\n * Entry point for the bundled npm CLI.\n * This file is used by build-npm.mjs as the esbuild entrypoint.\n *\n * Uses dynamic import so LOG_LEVEL is set BEFORE any module loads\n * (ESM static imports are hoisted and run before top-level code).\n */\n\n// The only static import: a leaf with no imports and no side effects (see node-floor.ts).\nimport { MIN_NODE_MAJOR, canRunOnNode, meetsNodeFloor } from \"./node-floor\";\n\n// Suppress @repo/logger output in CLI mode\nif (!process.env.LOG_LEVEL) {\n process.env.LOG_LEVEL = \"fatal\";\n}\n\n// GH #1414 \u2014 guard de versao ANTES de qualquer import. O CLI exige Node >= 22\n// (`engines`, node-detector.ts, build target `node22`) mas nada checava em runtime:\n// o aluno com Node antigo levava um erro cru de sintaxe/referencia, sem saber que a\n// causa era a versao. Mensagem simples e sem dependencia \u2014 o bundle de erros vive\n// dentro de ./cli, que e justamente o que nao pode carregar aqui.\n//\n// GH #2114 \u2014 o piso real das dependencias e 20.18.1 (undici 7; commander 14 pede 20),\n// e o Node 20 esta em EOL desde 2026-04-30, entao o piso suportado e 22: abaixo de\n// 20.18.1 o guard bloqueia, entre 20.18.1 e 21 ele so avisa (node-floor.ts). O guard so\n// roda antes do undici porque o resto do CLI mora em dist/main.js (build-npm.mjs): num\n// arquivo unico o esbuild subia os imports externos para o topo de dist/cli.js e o Node\n// 18 quebrava dentro do undici. A mensagem aponta para nodejs.org, nao para o\n// instalador: o install.sh ainda aceita Node 18+ e nao faria o upgrade (#2115).\n//\n// A resolucao de idioma espelha `errors/index.ts:resolveLocale()` de proposito:\n// `--locale` > `LANG` > pt-BR (o CLI e pt-BR-first, CHORE-1571 Fase D). Nao da\n// para reusar a funcao \u2014 ela vive no bundle que este guard existe para nao\n// carregar. Sem o passo do `--locale` este era o unico ponto do CLI que ignorava\n// a flag (GH #1414).\nif (!meetsNodeFloor(process.versions.node)) {\n const localeFlagIdx = process.argv.indexOf(\"--locale\");\n const localeFlag =\n localeFlagIdx !== -1 && localeFlagIdx + 1 < process.argv.length\n ? process.argv[localeFlagIdx + 1]\n : undefined;\n const pt =\n localeFlag === \"pt-BR\" || localeFlag === \"en-US\"\n ? localeFlag === \"pt-BR\"\n : !(process.env[\"LANG\"] ?? \"\").toLowerCase().startsWith(\"en\");\n // GH #2114 \u2014 below MIN_NODE_RUNTIME the bundle cannot load (undici 7): stop here.\n // Between it and MIN_NODE_MAJOR (Node 20.18.1+) the CLI still works, so warn and go\n // on: those students ran 0.18.0 fine and get this version through the auto-update.\n if (!canRunOnNode(process.versions.node)) {\n process.stderr.write(\n pt\n ? `Erro: o ToStudy CLI precisa do Node.js ${MIN_NODE_MAJOR} ou superior.\\nVoc\u00EA est\u00E1 no Node.js ${process.versions.node}.\\nAtualize em https://nodejs.org e rode o comando de novo.\\n`\n : `Error: the ToStudy CLI requires Node.js ${MIN_NODE_MAJOR} or newer.\\nYou are on Node.js ${process.versions.node}.\\nUpdate at https://nodejs.org and run the command again.\\n`\n );\n process.exit(1);\n }\n process.stderr.write(\n pt\n ? `Aviso: o Node.js ${process.versions.node} n\u00E3o \u00E9 mais suportado pelo ToStudy CLI. Atualize para o Node.js ${MIN_NODE_MAJOR} ou superior em https://nodejs.org.\\n`\n : `Warning: Node.js ${process.versions.node} is no longer supported by the ToStudy CLI. Update to Node.js ${MIN_NODE_MAJOR} or newer at https://nodejs.org.\\n`\n );\n}\n\n// GH #1414 item 7 \u2014 account locale captured by `tostudy login` (config.json)\n// beats the OS LANG. Read here, before the bundle loads, and handed over via\n// env so errors/index.ts stays a leaf (no errors \u2192 auth import edge).\nif (!process.env[\"TOSTUDY_LOCALE\"]) {\n try {\n const { readFileSync } = await import(\"node:fs\");\n const { join } = await import(\"node:path\");\n const { homedir } = await import(\"node:os\");\n const xdg = process.env[\"XDG_CONFIG_HOME\"];\n const dir =\n process.platform === \"linux\" && xdg ? join(xdg, \"tostudy\") : join(homedir(), \".tostudy\");\n const { locale } = JSON.parse(readFileSync(join(dir, \"config.json\"), \"utf-8\")) as {\n locale?: unknown;\n };\n if (locale === \"pt-BR\" || locale === \"en-US\") process.env[\"TOSTUDY_LOCALE\"] = locale;\n } catch {\n // No session yet, or unreadable \u2014 LANG / pt-BR fallback applies.\n }\n}\n\nconst { createProgram, CLI_VERSION, checkForUpdates, maybeAutoUpdate } = await import(\"./main\");\n\n// GH #1419 item 3 \u2014 `.action(async \u2026)` + `parse()` means a rejected command\n// promise is an unhandled rejection: Node dumps a raw stack. One net, in the\n// student's language, instead of a try/catch per command.\nprocess.on(\"unhandledRejection\", (reason) => {\n const msg = reason instanceof Error ? reason.message : String(reason);\n process.stderr.write(`Erro: ${msg}\\n Se o problema continuar, rode: tostudy doctor\\n`);\n process.exit(1);\n});\n\nconst program = createProgram();\nprogram.parse();\n\ncheckForUpdates(CLI_VERSION);\nmaybeAutoUpdate(CLI_VERSION);\n\nexport {};\n"],
5
- "mappings": ";;;AAYO,IAAM,iBAAiB;AACvB,IAAM,mBAAmB;AAEhC,SAAS,aAAa,SAAkD;AACtE,QAAM,QAAQ,yBAAyB,KAAK,QAAQ,KAAK,CAAC;AAC1D,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,CAAC,OAAO,MAAM,CAAC,CAAC,GAAG,OAAO,MAAM,CAAC,CAAC,GAAG,OAAO,MAAM,CAAC,CAAC,CAAC;AAC9D;AAGO,SAAS,eAAe,SAA0B;AACvD,QAAM,SAAS,aAAa,OAAO;AACnC,SAAO,WAAW,QAAQ,OAAO,CAAC,KAAK;AACzC;AAGO,SAAS,aAAa,SAA0B;AACrD,QAAM,SAAS,aAAa,OAAO;AACnC,QAAM,QAAQ,aAAa,gBAAgB;AAC3C,MAAI,CAAC,UAAU,CAAC,MAAO,QAAO;AAC9B,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,QAAI,OAAO,CAAC,MAAO,MAAM,CAAC,EAAI,QAAO,OAAO,CAAC,IAAK,MAAM,CAAC;AAAA,EAC3D;AACA,SAAO;AACT;;;ACxBA,IAAI,CAAC,QAAQ,IAAI,WAAW;AAC1B,UAAQ,IAAI,YAAY;AAC1B;AAqBA,IAAI,CAAC,eAAe,QAAQ,SAAS,IAAI,GAAG;AAC1C,QAAM,gBAAgB,QAAQ,KAAK,QAAQ,UAAU;AACrD,QAAM,aACJ,kBAAkB,MAAM,gBAAgB,IAAI,QAAQ,KAAK,SACrD,QAAQ,KAAK,gBAAgB,CAAC,IAC9B;AACN,QAAM,KACJ,eAAe,WAAW,eAAe,UACrC,eAAe,UACf,EAAE,QAAQ,IAAI,MAAM,KAAK,IAAI,YAAY,EAAE,WAAW,IAAI;AAIhE,MAAI,CAAC,aAAa,QAAQ,SAAS,IAAI,GAAG;AACxC,YAAQ,OAAO;AAAA,MACb,KACI,0CAA0C,cAAc;AAAA,6BAAuC,QAAQ,SAAS,IAAI;AAAA;AAAA,IACpH,2CAA2C,cAAc;AAAA,qBAAkC,QAAQ,SAAS,IAAI;AAAA;AAAA;AAAA,IACtH;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,UAAQ,OAAO;AAAA,IACb,KACI,oBAAoB,QAAQ,SAAS,IAAI,yEAAmE,cAAc;AAAA,IAC1H,oBAAoB,QAAQ,SAAS,IAAI,iEAAiE,cAAc;AAAA;AAAA,EAC9H;AACF;AAKA,IAAI,CAAC,QAAQ,IAAI,gBAAgB,GAAG;AAClC,MAAI;AACF,UAAM,EAAE,aAAa,IAAI,MAAM,OAAO,SAAS;AAC/C,UAAM,EAAE,KAAK,IAAI,MAAM,OAAO,WAAW;AACzC,UAAM,EAAE,QAAQ,IAAI,MAAM,OAAO,SAAS;AAC1C,UAAM,MAAM,QAAQ,IAAI,iBAAiB;AACzC,UAAM,MACJ,QAAQ,aAAa,WAAW,MAAM,KAAK,KAAK,SAAS,IAAI,KAAK,QAAQ,GAAG,UAAU;AACzF,UAAM,EAAE,OAAO,IAAI,KAAK,MAAM,aAAa,KAAK,KAAK,aAAa,GAAG,OAAO,CAAC;AAG7E,QAAI,WAAW,WAAW,WAAW,QAAS,SAAQ,IAAI,gBAAgB,IAAI;AAAA,EAChF,QAAQ;AAAA,EAER;AACF;AAEA,IAAM,EAAE,eAAe,aAAa,iBAAiB,gBAAgB,IAAI,MAAM,OAAO,WAAQ;AAK9F,QAAQ,GAAG,sBAAsB,CAAC,WAAW;AAC3C,QAAM,MAAM,kBAAkB,QAAQ,OAAO,UAAU,OAAO,MAAM;AACpE,UAAQ,OAAO,MAAM,SAAS,GAAG;AAAA;AAAA,CAAqD;AACtF,UAAQ,KAAK,CAAC;AAChB,CAAC;AAED,IAAM,UAAU,cAAc;AAC9B,QAAQ,MAAM;AAEd,gBAAgB,WAAW;AAC3B,gBAAgB,WAAW;",
4
+ "sourcesContent": ["// GH #2114 \u2014 the Node floors of the CLI, read by the runtime guard (cli-entry.ts),\n// `tostudy doctor` (installer/node-detector.ts) and the label doctor prints.\n//\n// Two floors on purpose:\n// - MIN_NODE_MAJOR is the supported floor (Node 20 is EOL since 2026-04-30). It must\n// match `engines` in package.json and the esbuild target in build-npm.mjs.\n// - MIN_NODE_RUNTIME is where the bundle actually loads (undici 7 needs 20.18.1). The\n// guard blocks below it and only warns between the two, so students on Node 20, who\n// ran 0.18.0 fine, are not locked out by the auto-update.\n//\n// Leaf module on purpose: cli-entry.ts imports it before the bundle loads, so it must\n// not import anything (the guard has to run on runtimes the rest of the CLI rejects).\nexport const MIN_NODE_MAJOR = 22;\nexport const MIN_NODE_RUNTIME = \"20.18.1\";\n\nfunction parseVersion(version: string): [number, number, number] | null {\n const match = /^v?(\\d+)\\.(\\d+)\\.(\\d+)/.exec(version.trim());\n if (!match) return null;\n return [Number(match[1]), Number(match[2]), Number(match[3])];\n}\n\n/** Supported floor. Accepts `process.versions.node` (\"22.1.0\") or `node --version` (\"v22.1.0\"). */\nexport function meetsNodeFloor(version: string): boolean {\n const parsed = parseVersion(version);\n return parsed !== null && parsed[0] >= MIN_NODE_MAJOR;\n}\n\n/** Hard floor: false means the bundle cannot run on this Node at all. */\nexport function canRunOnNode(version: string): boolean {\n const parsed = parseVersion(version);\n const floor = parseVersion(MIN_NODE_RUNTIME);\n if (!parsed || !floor) return false;\n for (let i = 0; i < 3; i++) {\n if (parsed[i]! !== floor[i]!) return parsed[i]! > floor[i]!;\n }\n return true;\n}\n\n// GH-2130 \u2014 since GH-2115 install.sh / install.ps1 upgrade Node below 22, so the guard\n// sends the student back to them first, with nodejs.org as the manual path. Lives here\n// (a leaf) so it is testable without running the guard. The English phrases\n// \"requires Node.js N or newer\" and \"Update to Node.js N or newer\" are asserted by the\n// CI job in .github/scripts/tostudy-cli-assert-node-guard.sh.\nconst INSTALL_UNIX = \"curl -fsSL https://tostudy.ai/install.sh | sh\";\nconst INSTALL_WINDOWS = \"irm https://tostudy.ai/install.ps1 | iex\";\n\n/** Text the runtime guard prints: `block` below MIN_NODE_RUNTIME, `warn` up to MIN_NODE_MAJOR. */\nexport function nodeGuardMessage(mode: \"block\" | \"warn\", version: string, pt: boolean): string {\n const installers = ` macOS/Linux: ${INSTALL_UNIX}\\n Windows (PowerShell): ${INSTALL_WINDOWS}\\n`;\n if (mode === \"block\") {\n return pt\n ? `Erro: o ToStudy CLI precisa do Node.js ${MIN_NODE_MAJOR} ou superior.\\nVoc\u00EA est\u00E1 no Node.js ${version}.\\nPara atualizar, rode o instalador de novo:\\n${installers}Ou atualize em https://nodejs.org. Depois rode o comando de novo.\\n`\n : `Error: the ToStudy CLI requires Node.js ${MIN_NODE_MAJOR} or newer.\\nYou are on Node.js ${version}.\\nTo update, run the installer again:\\n${installers}Or update at https://nodejs.org. Then run the command again.\\n`;\n }\n return pt\n ? `Aviso: o Node.js ${version} n\u00E3o \u00E9 mais suportado pelo ToStudy CLI. Atualize para o Node.js ${MIN_NODE_MAJOR} ou superior rodando o instalador de novo:\\n${installers}Ou atualize em https://nodejs.org.\\n`\n : `Warning: Node.js ${version} is no longer supported by the ToStudy CLI. Update to Node.js ${MIN_NODE_MAJOR} or newer by running the installer again:\\n${installers}Or update at https://nodejs.org.\\n`;\n}\n", "/**\n * Entry point for the bundled npm CLI.\n * This file is used by build-npm.mjs as the esbuild entrypoint.\n *\n * Uses dynamic import so LOG_LEVEL is set BEFORE any module loads\n * (ESM static imports are hoisted and run before top-level code).\n */\n\n// The only static import: a leaf with no imports and no side effects (see node-floor.ts).\nimport { canRunOnNode, meetsNodeFloor, nodeGuardMessage } from \"./node-floor\";\n\n// Suppress @repo/logger output in CLI mode\nif (!process.env.LOG_LEVEL) {\n process.env.LOG_LEVEL = \"fatal\";\n}\n\n// GH #1414 \u2014 guard de versao ANTES de qualquer import. O CLI exige Node >= 22\n// (`engines`, node-detector.ts, build target `node22`) mas nada checava em runtime:\n// o aluno com Node antigo levava um erro cru de sintaxe/referencia, sem saber que a\n// causa era a versao. Mensagem simples e sem dependencia \u2014 o bundle de erros vive\n// dentro de ./cli, que e justamente o que nao pode carregar aqui.\n//\n// GH #2114 \u2014 o piso real das dependencias e 20.18.1 (undici 7; commander 14 pede 20),\n// e o Node 20 esta em EOL desde 2026-04-30, entao o piso suportado e 22: abaixo de\n// 20.18.1 o guard bloqueia, entre 20.18.1 e 21 ele so avisa (node-floor.ts). O guard so\n// roda antes do undici porque o resto do CLI mora em dist/main.js (build-npm.mjs): num\n// arquivo unico o esbuild subia os imports externos para o topo de dist/cli.js e o Node\n// 18 quebrava dentro do undici.\n//\n// GH #2130 \u2014 desde a GH #2115 o install.sh e o install.ps1 atualizam o Node abaixo do\n// 22, entao a mensagem manda rodar o instalador de novo e deixa o nodejs.org como\n// caminho manual (texto em node-floor.ts:nodeGuardMessage).\n//\n// A resolucao de idioma espelha `errors/index.ts:resolveLocale()` de proposito:\n// `--locale` > `LANG` > pt-BR (o CLI e pt-BR-first, CHORE-1571 Fase D). Nao da\n// para reusar a funcao \u2014 ela vive no bundle que este guard existe para nao\n// carregar. Sem o passo do `--locale` este era o unico ponto do CLI que ignorava\n// a flag (GH #1414).\nif (!meetsNodeFloor(process.versions.node)) {\n const localeFlagIdx = process.argv.indexOf(\"--locale\");\n const localeFlag =\n localeFlagIdx !== -1 && localeFlagIdx + 1 < process.argv.length\n ? process.argv[localeFlagIdx + 1]\n : undefined;\n const pt =\n localeFlag === \"pt-BR\" || localeFlag === \"en-US\"\n ? localeFlag === \"pt-BR\"\n : !(process.env[\"LANG\"] ?? \"\").toLowerCase().startsWith(\"en\");\n // GH #2114 \u2014 below MIN_NODE_RUNTIME the bundle cannot load (undici 7): stop here.\n // Between it and MIN_NODE_MAJOR (Node 20.18.1+) the CLI still works, so warn and go\n // on: those students ran 0.18.0 fine and get this version through the auto-update.\n if (!canRunOnNode(process.versions.node)) {\n process.stderr.write(nodeGuardMessage(\"block\", process.versions.node, pt));\n process.exit(1);\n }\n process.stderr.write(nodeGuardMessage(\"warn\", process.versions.node, pt));\n}\n\n// GH #1414 item 7 \u2014 account locale captured by `tostudy login` (config.json)\n// beats the OS LANG. Read here, before the bundle loads, and handed over via\n// env so errors/index.ts stays a leaf (no errors \u2192 auth import edge).\nif (!process.env[\"TOSTUDY_LOCALE\"]) {\n try {\n const { readFileSync } = await import(\"node:fs\");\n const { join } = await import(\"node:path\");\n const { homedir } = await import(\"node:os\");\n const xdg = process.env[\"XDG_CONFIG_HOME\"];\n const dir =\n process.platform === \"linux\" && xdg ? join(xdg, \"tostudy\") : join(homedir(), \".tostudy\");\n const { locale } = JSON.parse(readFileSync(join(dir, \"config.json\"), \"utf-8\")) as {\n locale?: unknown;\n };\n if (locale === \"pt-BR\" || locale === \"en-US\") process.env[\"TOSTUDY_LOCALE\"] = locale;\n } catch {\n // No session yet, or unreadable \u2014 LANG / pt-BR fallback applies.\n }\n}\n\nconst { createProgram, CLI_VERSION, checkForUpdates, maybeAutoUpdate } = await import(\"./main\");\n\n// GH #1419 item 3 \u2014 `.action(async \u2026)` + `parse()` means a rejected command\n// promise is an unhandled rejection: Node dumps a raw stack. One net, in the\n// student's language, instead of a try/catch per command.\nprocess.on(\"unhandledRejection\", (reason) => {\n const msg = reason instanceof Error ? reason.message : String(reason);\n process.stderr.write(`Erro: ${msg}\\n Se o problema continuar, rode: tostudy doctor\\n`);\n process.exit(1);\n});\n\nconst program = createProgram();\nprogram.parse();\n\ncheckForUpdates(CLI_VERSION);\nmaybeAutoUpdate(CLI_VERSION);\n\nexport {};\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/main.js CHANGED
@@ -1040,6 +1040,8 @@ var init_errors_pt_br = __esm({
1040
1040
  suggestNoOverlap: "Sem coincid\xEAncia com o perfil.",
1041
1041
  suggestEmptyProfile: "Perfil vazio. Mostrando cursos gratuitos em aberto.",
1042
1042
  suggestReason: "Motivo:",
1043
+ suggestReasonMatch: "combina com o seu perfil em",
1044
+ suggestReasonAnd: "e",
1043
1045
  suggestPaidHeader: "Pagos. A matr\xEDcula fica no navegador e nada \xE9 debitado por aqui:",
1044
1046
  enrollmentNotEntitled: "\u{1F6AB} Sua matr\xEDcula neste curso n\xE3o est\xE1 mais ativa (reembolso, cancelamento ou preview expirado).\nPara voltar a estudar, adquira o curso novamente em https://tostudy.ai.\n",
1045
1047
  creator: {
@@ -1149,6 +1151,8 @@ var init_errors_en_us = __esm({
1149
1151
  suggestNoOverlap: "No word in the profile matched.",
1150
1152
  suggestEmptyProfile: "Profile is empty. Showing open free courses.",
1151
1153
  suggestReason: "Why:",
1154
+ suggestReasonMatch: "matches your profile on",
1155
+ suggestReasonAnd: "and",
1152
1156
  suggestPaidHeader: "Paid. Enrollment stays in the browser and nothing is charged here:",
1153
1157
  enrollmentNotEntitled: "\u{1F6AB} Your enrollment in this course is no longer active (refund, cancellation, or expired preview).\nTo study again, purchase the course at https://tostudy.ai.\n",
1154
1158
  creator: {
@@ -1620,7 +1624,8 @@ function formatCourseList(courses) {
1620
1624
  return [
1621
1625
  "Nenhum curso encontrado.",
1622
1626
  "",
1623
- "\u2192 Acesse tostudy.ai para se matricular em um curso"
1627
+ "\u2192 tostudy suggest cursos que voc\xEA pode come\xE7ar agora",
1628
+ "\u2192 tostudy enroll <id> matricula sem sair do terminal"
1624
1629
  ].join("\n");
1625
1630
  }
1626
1631
  const lines = ["Seus cursos:", ""];
@@ -3452,6 +3457,13 @@ function assertTrustedApiUrl(apiUrl) {
3452
3457
  `API URL n\xE3o confi\xE1vel: ${apiUrl}. Use https://tostudy.ai (ou um subdom\xEDnio) ou localhost.`
3453
3458
  );
3454
3459
  }
3460
+ function browserCommand(platform2, url2) {
3461
+ if (platform2 === "darwin") return { cmd: "open", args: [url2] };
3462
+ if (platform2 === "win32") {
3463
+ return { cmd: "rundll32", args: ["url.dll,FileProtocolHandler", url2] };
3464
+ }
3465
+ return { cmd: "xdg-open", args: [url2] };
3466
+ }
3455
3467
  function buildAuthorizeUrl(apiUrl, port, state, creator) {
3456
3468
  const base = `${apiUrl}/api/cli/auth/authorize?port=${port}&state=${state}`;
3457
3469
  return creator ? `${base}&scope=creator` : base;
@@ -3559,8 +3571,8 @@ var loginCommand = new Command("login").description("Autentica no ToStudy via br
3559
3571
  const state = randomBytes(32).toString("hex");
3560
3572
  const serverPromise = startCallbackServer(PORT, state);
3561
3573
  const authUrl = buildAuthorizeUrl(apiUrl, PORT, state, opts.creator === true);
3562
- const openCmd = process.platform === "darwin" ? "open" : "xdg-open";
3563
- execFile2(openCmd, [authUrl], (err) => {
3574
+ const { cmd, args } = browserCommand(process.platform, authUrl);
3575
+ execFile2(cmd, args, (err) => {
3564
3576
  if (err) {
3565
3577
  console.log(` N\xE3o foi poss\xEDvel abrir o browser automaticamente.`);
3566
3578
  console.log(` Abra manualmente: ${authUrl}
@@ -3644,7 +3656,7 @@ var loginCommand = new Command("login").description("Autentica no ToStudy via br
3644
3656
  \u2713 ${courses.length} curso(s) matriculado(s)`);
3645
3657
  } else {
3646
3658
  console.log(`
3647
- \u2192 Nenhum curso matriculado. Acesse tostudy.ai`);
3659
+ \u2192 Nenhum curso matriculado. Rode: tostudy suggest`);
3648
3660
  }
3649
3661
  } catch {
3650
3662
  }
@@ -3748,9 +3760,14 @@ async function runMcpSetup(session, token, spawnImpl = spawn) {
3748
3760
  var defaultDeps = {
3749
3761
  log: (message = "") => {
3750
3762
  console.log(message);
3751
- }
3763
+ },
3764
+ setupMcp: () => runSetupMcpSubcommand()
3752
3765
  };
3753
- async function runSetup(_opts, deps = defaultDeps) {
3766
+ async function runSetup(opts, deps = defaultDeps) {
3767
+ if (opts.mcp) {
3768
+ await deps.setupMcp();
3769
+ return;
3770
+ }
3754
3771
  const errors = getErrors();
3755
3772
  deps.log(errors.setupRetiredNotice);
3756
3773
  deps.log(errors.setupRetiredNext);
@@ -3816,7 +3833,7 @@ init_workspace_state();
3816
3833
  init_formatter();
3817
3834
 
3818
3835
  // src/version.ts
3819
- var CLI_VERSION = true ? "0.18.6" : "0.7.1";
3836
+ var CLI_VERSION = true ? "0.18.7" : "0.7.1";
3820
3837
 
3821
3838
  // src/update-checker.ts
3822
3839
  init_config_dir();
@@ -4348,18 +4365,40 @@ var STOP_WORDS = /* @__PURE__ */ new Set([
4348
4365
  "do",
4349
4366
  "das",
4350
4367
  "dos",
4368
+ "por",
4369
+ "pro",
4370
+ "pra",
4351
4371
  "para",
4352
4372
  "com",
4373
+ "sem",
4353
4374
  "uma",
4354
4375
  "um",
4376
+ "nao",
4377
+ "n\xE3o",
4378
+ "que",
4379
+ "mais",
4380
+ "como",
4381
+ "isso",
4382
+ "este",
4383
+ "esta",
4384
+ "tem",
4355
4385
  "the",
4356
4386
  "and",
4357
4387
  "for",
4358
4388
  "you",
4389
+ "your",
4390
+ "with",
4359
4391
  "seu",
4360
4392
  "sua",
4393
+ "seus",
4394
+ "suas",
4395
+ "meu",
4396
+ "minha",
4361
4397
  "curso",
4362
- "course"
4398
+ "cursos",
4399
+ "course",
4400
+ "tags",
4401
+ "tag"
4363
4402
  ]);
4364
4403
  var TOKEN_SPLIT = /[^\p{L}\p{N}]+/u;
4365
4404
  var MAX_RESULTS = 3;
@@ -4401,7 +4440,7 @@ function rankSuggestions(courses, query) {
4401
4440
  }));
4402
4441
  }
4403
4442
  const textTokens = tokensOf(text2, true);
4404
- const levelTokens = level === null ? [] : tokensOf(level, false);
4443
+ const levelTokens = level === null ? [] : tokensOf(level, true);
4405
4444
  const scored = courses.map((course) => {
4406
4445
  const stack = haystack(course);
4407
4446
  const outsideLevel = haystackWithoutLevel(course);
@@ -4544,10 +4583,14 @@ function suggestionQuery(brief, profile, workspaceTokens) {
4544
4583
  level: profile?.learnerLevel ?? null
4545
4584
  };
4546
4585
  }
4586
+ function listaDeTemas(tokens, copy) {
4587
+ if (tokens.length === 1) return tokens[0];
4588
+ return `${tokens.slice(0, -1).join(", ")} ${copy.suggestReasonAnd} ${tokens.at(-1)}`;
4589
+ }
4547
4590
  function reasonText(reason, copy) {
4548
4591
  if (reason === "empty-profile") return copy.suggestEmptyProfile;
4549
4592
  if (reason === "no-overlap") return copy.suggestNoOverlap;
4550
- return reason;
4593
+ return `${copy.suggestReasonMatch} ${listaDeTemas(reason.split(","), copy)}`;
4551
4594
  }
4552
4595
  function formatBlock(ranked, lineFor) {
4553
4596
  const copy = getErrors();
@@ -22267,18 +22310,7 @@ import { execFile as execFile4 } from "node:child_process";
22267
22310
  import { platform } from "node:process";
22268
22311
  var BRIEF_URL = "https://tostudy.ai/student/settings/learner-brief";
22269
22312
  function openUrl(url2, options = {}) {
22270
- let cmd;
22271
- let args;
22272
- if (platform === "darwin") {
22273
- cmd = "open";
22274
- args = [url2];
22275
- } else if (platform === "win32") {
22276
- cmd = "cmd";
22277
- args = ["/c", "start", "", url2];
22278
- } else {
22279
- cmd = "xdg-open";
22280
- args = [url2];
22281
- }
22313
+ const { cmd, args } = browserCommand(platform, url2);
22282
22314
  execFile4(cmd, args, (err) => {
22283
22315
  if (err && !options.silent) {
22284
22316
  output(`N\xE3o consegui abrir o navegador. Acesse manualmente: ${url2}`, {