@tostudy-ai/cli 0.18.13 → 0.18.17

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/main.js CHANGED
@@ -2330,6 +2330,7 @@ var init_instruction_template_v3 = __esm({
2330
2330
  // src/workspace/runtime-registry.ts
2331
2331
  var runtime_registry_exports = {};
2332
2332
  __export(runtime_registry_exports, {
2333
+ CODEX_LOGIN_NOTICE: () => CODEX_LOGIN_NOTICE,
2333
2334
  RUNTIMES: () => RUNTIMES,
2334
2335
  antigravitySkillMd: () => antigravitySkillMd,
2335
2336
  cursorMdc: () => cursorMdc,
@@ -2405,10 +2406,10 @@ ${content}`;
2405
2406
  function detectedSlashHints(slug, home, cwd) {
2406
2407
  return RUNTIMES.filter((r) => r.slashHint && r.detect(home, cwd)).map((r) => r.slashHint(slug));
2407
2408
  }
2408
- function slashHintLines(slug, home, cwd, fallbackCommand) {
2409
+ function slashHintLines(slug, home, cwd) {
2409
2410
  const hints = slug ? detectedSlashHints(slug, home, cwd) : [];
2410
2411
  if (hints.length > 0) return hints.map((h) => `\u2192 ${h}`);
2411
- return [`\u2192 Na sua plataforma, digite: ${fallbackCommand}`];
2412
+ return ["\u2192 Na sua plataforma, pe\xE7a: vamos estudar (no terminal: tostudy menu)"];
2412
2413
  }
2413
2414
  function needsRootAgentsConsent(cwd) {
2414
2415
  const filePath = join2(cwd, "AGENTS.md");
@@ -2428,7 +2429,7 @@ function upsertRootAgentsBlock(cwd, ctx) {
2428
2429
  "",
2429
2430
  `- **Course:** ${ctx.courseTitle} (${ctx.progress}% complete)`,
2430
2431
  `- Read \`.tostudy/courses/${slug}/AGENTS.md\` for the full tutor instructions.`,
2431
- "- Study commands: run `/tostudy` (or `tostudy menu` in the terminal).",
2432
+ '- To study, ask in plain language (e.g. "vamos estudar"). In Claude Code or OpenCode you can also run `/tostudy`; in the terminal, `tostudy menu`.',
2432
2433
  "",
2433
2434
  "<!-- tostudy:end -->"
2434
2435
  ].join("\n");
@@ -2464,7 +2465,7 @@ function upsertRootAgentsBlock(cwd, ctx) {
2464
2465
  return null;
2465
2466
  }
2466
2467
  }
2467
- var logger2, detectOpencode, detectGrok, detectAntigravity, RUNTIMES, TOSTUDY_BLOCK_PATTERN, TOSTUDY_BLOCK_PATTERN_GLOBAL, slugifyTitle;
2468
+ var logger2, detectOpencode, detectGrok, detectAntigravity, CODEX_LOGIN_NOTICE, RUNTIMES, TOSTUDY_BLOCK_PATTERN, TOSTUDY_BLOCK_PATTERN_GLOBAL, slugifyTitle;
2468
2469
  var init_runtime_registry = __esm({
2469
2470
  "src/workspace/runtime-registry.ts"() {
2470
2471
  "use strict";
@@ -2476,6 +2477,11 @@ var init_runtime_registry = __esm({
2476
2477
  detectOpencode = (home) => existsSync2(join2(home, ".opencode")) || existsSync2(join2(home, ".config", "opencode"));
2477
2478
  detectGrok = (home) => existsSync2(join2(home, ".grok")) || hasBinary("grok");
2478
2479
  detectAntigravity = (home) => existsSync2(join2(home, ".gemini", "antigravity-cli")) || hasBinary("agy");
2480
+ CODEX_LOGIN_NOTICE = [
2481
+ " \u26A0 No Codex n\xE3o existe o comando /tostudy.",
2482
+ ' \u2192 Abra o Codex na pasta do curso e pe\xE7a: "vamos estudar".',
2483
+ " \u2192 No terminal, tostudy menu tamb\xE9m funciona."
2484
+ ];
2479
2485
  RUNTIMES = [
2480
2486
  {
2481
2487
  id: "claude",
@@ -2518,11 +2524,15 @@ var init_runtime_registry = __esm({
2518
2524
  detect: (home) => existsSync2(join2(home, ".codex")),
2519
2525
  // No writePerCourse: Codex has no project-level command channel — the
2520
2526
  // root AGENTS.md managed block (generic entry) is its per-course path.
2521
- writeUniversal({ home, content }) {
2522
- const file2 = join2(home, ".codex", "prompts", "tostudy.md");
2523
- writeFile2(join2(home, ".codex", "prompts"), "tostudy.md", content);
2524
- return [file2];
2525
- }
2527
+ // GH-2351 follow-up: no writeUniversal either. The hint below already stopped
2528
+ // naming /tostudy, but login still wrote ~10 KB to ~/.codex/prompts/tostudy.md
2529
+ // and printed "✓ Instalado: …/.codex/prompts/tostudy.md" — announcing, as the
2530
+ // last thing on screen, an install of a command that does not exist. Codex
2531
+ // never reads that directory, so nothing consumed the file. A stale one from
2532
+ // an older CLI is left on disk: we do not delete the student's files.
2533
+ // GH-2351: Codex never reads ~/.codex/prompts, so there is no /tostudy there;
2534
+ // asking in plain language works (it reads AGENTS.md and finds the course skill).
2535
+ slashHint: () => "No Codex, abra o Codex e pe\xE7a: vamos estudar"
2526
2536
  },
2527
2537
  {
2528
2538
  id: "opencode",
@@ -3626,7 +3636,7 @@ var loginCommand = new Command("login").description("Autentica no ToStudy via br
3626
3636
  try {
3627
3637
  const { detectIDEs: detectIDEs2 } = await Promise.resolve().then(() => (init_ide_detector(), ide_detector_exports));
3628
3638
  const { installUniversalCommand: installUniversalCommand2 } = await Promise.resolve().then(() => (init_instruction_files(), instruction_files_exports));
3629
- const { RUNTIMES: RUNTIMES2 } = await Promise.resolve().then(() => (init_runtime_registry(), runtime_registry_exports));
3639
+ const { RUNTIMES: RUNTIMES2, CODEX_LOGIN_NOTICE: CODEX_LOGIN_NOTICE2 } = await Promise.resolve().then(() => (init_runtime_registry(), runtime_registry_exports));
3630
3640
  const { homedir: homedir2 } = await import("node:os");
3631
3641
  const ides = detectIDEs2();
3632
3642
  const detected = ides.filter((ide) => ide.detected);
@@ -3663,6 +3673,10 @@ var loginCommand = new Command("login").description("Autentica no ToStudy via br
3663
3673
  );
3664
3674
  }
3665
3675
  }
3676
+ if (detected.some((ide) => ide.id === "codex")) {
3677
+ console.log("");
3678
+ for (const line of CODEX_LOGIN_NOTICE2) console.log(line);
3679
+ }
3666
3680
  } catch {
3667
3681
  }
3668
3682
  try {
@@ -3739,27 +3753,57 @@ import { Command as Command3 } from "commander";
3739
3753
 
3740
3754
  // src/installer/mcp-setup.ts
3741
3755
  import { spawn } from "node:child_process";
3742
- async function exchangeCliSessionForMcpToken(session, fetchImpl = fetch) {
3743
- const res = await fetchImpl(`${session.apiUrl}/api/mcp/token`, {
3744
- method: "POST",
3745
- headers: {
3746
- Authorization: `Bearer ${session.token}`
3747
- }
3748
- });
3756
+ import { hostname } from "node:os";
3757
+
3758
+ // src/version.ts
3759
+ var CLI_VERSION = true ? "0.18.17" : "0.7.1";
3760
+
3761
+ // src/installer/mcp-setup.ts
3762
+ function safeServerError(text2) {
3763
+ if (typeof text2 !== "string" || text2.length === 0 || text2.length > 200) return null;
3764
+ return ["Bearer", "mcp_", "eyJ"].some((m) => text2.includes(m)) ? null : text2;
3765
+ }
3766
+ async function createMcpApiKey(session, fetchImpl = fetch) {
3767
+ let res;
3768
+ try {
3769
+ res = await fetchImpl(`${session.apiUrl}/api/mcp/sessions`, {
3770
+ method: "POST",
3771
+ headers: {
3772
+ Authorization: `Bearer ${session.token}`,
3773
+ "Content-Type": "application/json"
3774
+ },
3775
+ body: JSON.stringify({
3776
+ clientInfo: {
3777
+ source: "tostudy-cli-setup",
3778
+ hostname: hostname(),
3779
+ os: process.platform,
3780
+ version: CLI_VERSION
3781
+ }
3782
+ })
3783
+ });
3784
+ } catch {
3785
+ throw new Error("Falha ao criar a chave MCP: erro de rede");
3786
+ }
3749
3787
  if (!res.ok) {
3750
3788
  const body = await res.json().catch(() => ({}));
3751
- throw new Error(body.error ?? `Falha ao obter token MCP (${res.status})`);
3789
+ throw new Error(
3790
+ `Falha ao criar a chave MCP: ${safeServerError(body.error) ?? `HTTP ${res.status}`}`
3791
+ );
3792
+ }
3793
+ const { apiKey } = await res.json().catch(() => ({}));
3794
+ if (typeof apiKey !== "string" || !apiKey.startsWith("mcp_")) {
3795
+ throw new Error("Falha ao criar a chave MCP: resposta inv\xE1lida do servidor");
3752
3796
  }
3753
- return res.json();
3797
+ return apiKey;
3754
3798
  }
3755
- async function runMcpSetup(session, token, spawnImpl = spawn) {
3799
+ async function runMcpSetup(session, apiKey, spawnImpl = spawn) {
3756
3800
  const command = process.platform === "win32" ? "npx.cmd" : "npx";
3757
3801
  await new Promise((resolve, reject) => {
3758
3802
  const child = spawnImpl(command, ["-y", "@tostudy-ai/mcp-setup", "--url", session.apiUrl], {
3759
3803
  stdio: "inherit",
3760
3804
  env: {
3761
3805
  ...process.env,
3762
- TOSTUDY_API_KEY: token
3806
+ TOSTUDY_API_KEY: apiKey
3763
3807
  }
3764
3808
  });
3765
3809
  child.once("error", reject);
@@ -3794,8 +3838,15 @@ async function runSetupMcpSubcommand() {
3794
3838
  const session = await requireSession();
3795
3839
  console.log(` \u2713 Logado como ${session.userName}
3796
3840
  `);
3797
- const { token } = await exchangeCliSessionForMcpToken(session);
3798
- await runMcpSetup(session, token);
3841
+ const apiKey = await createMcpApiKey(session);
3842
+ try {
3843
+ await runMcpSetup(session, apiKey);
3844
+ } catch (error49) {
3845
+ console.error(
3846
+ " Instala\xE7\xE3o incompleta: a chave MCP criada aparece em Configura\xE7\xF5es \u203A MCP e pode ser revogada."
3847
+ );
3848
+ throw error49;
3849
+ }
3799
3850
  console.log("\n Setup MCP completo!");
3800
3851
  console.log(" \u2192 Reinicie o IDE para ativar o servidor MCP");
3801
3852
  console.log(" \u2192 tostudy doctor (verificar conex\xE3o)\n");
@@ -3849,9 +3900,6 @@ init_session_store();
3849
3900
  init_workspace_state();
3850
3901
  init_formatter();
3851
3902
 
3852
- // src/version.ts
3853
- var CLI_VERSION = true ? "0.18.13" : "0.7.1";
3854
-
3855
3903
  // src/update-checker.ts
3856
3904
  init_config_dir();
3857
3905
  import fs8 from "node:fs";
@@ -5210,7 +5258,6 @@ var selectCommand = new Command8("select").description("Activate a course by ID
5210
5258
  { json: true }
5211
5259
  );
5212
5260
  } else {
5213
- const slashCmd = courseSlug2 ? `/tostudy-${courseSlug2}` : "/tostudy";
5214
5261
  const home = os7.homedir();
5215
5262
  const cwd = process.cwd();
5216
5263
  const namespacedPath = `${cwd}/.tostudy`;
@@ -5242,7 +5289,7 @@ var selectCommand = new Command8("select").description("Activate a course by ID
5242
5289
  lines.push(rootAgentsSkippedHint());
5243
5290
  }
5244
5291
  lines.push("", "\u2192 Abra sua plataforma (claude, codex, cursor...)");
5245
- lines.push(...slashHintLines(courseSlug2, home, cwd, slashCmd));
5292
+ lines.push(...slashHintLines(courseSlug2, home, cwd));
5246
5293
  lines.push("\u2192 Em outras plataformas: tostudy init");
5247
5294
  output(lines.join("\n"), { json: false });
5248
5295
  }
@@ -5931,7 +5978,7 @@ __export(external_exports, {
5931
5978
  guid: () => guid2,
5932
5979
  hash: () => hash,
5933
5980
  hex: () => hex2,
5934
- hostname: () => hostname2,
5981
+ hostname: () => hostname3,
5935
5982
  httpUrl: () => httpUrl,
5936
5983
  includes: () => _includes,
5937
5984
  instanceof: () => _instanceof,
@@ -7318,7 +7365,7 @@ __export(regexes_exports, {
7318
7365
  extendedDuration: () => extendedDuration,
7319
7366
  guid: () => guid,
7320
7367
  hex: () => hex,
7321
- hostname: () => hostname,
7368
+ hostname: () => hostname2,
7322
7369
  html5Email: () => html5Email,
7323
7370
  idnEmail: () => idnEmail,
7324
7371
  integer: () => integer,
@@ -7395,7 +7442,7 @@ var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]
7395
7442
  var cidrv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/;
7396
7443
  var base64 = /^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/;
7397
7444
  var base64url = /^[A-Za-z0-9_-]*$/;
7398
- var hostname = /^(?=.{1,253}\.?$)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?)*\.?$/;
7445
+ var hostname2 = /^(?=.{1,253}\.?$)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?)*\.?$/;
7399
7446
  var domain = /^([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
7400
7447
  var e164 = /^\+[1-9]\d{6,14}$/;
7401
7448
  var dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`;
@@ -17765,7 +17812,7 @@ __export(schemas_exports2, {
17765
17812
  guid: () => guid2,
17766
17813
  hash: () => hash,
17767
17814
  hex: () => hex2,
17768
- hostname: () => hostname2,
17815
+ hostname: () => hostname3,
17769
17816
  httpUrl: () => httpUrl,
17770
17817
  instanceof: () => _instanceof,
17771
17818
  int: () => int,
@@ -18269,7 +18316,7 @@ var ZodCustomStringFormat = /* @__PURE__ */ $constructor("ZodCustomStringFormat"
18269
18316
  function stringFormat(format, fnOrRegex, _params = {}) {
18270
18317
  return _stringFormat(ZodCustomStringFormat, format, fnOrRegex, _params);
18271
18318
  }
18272
- function hostname2(_params) {
18319
+ function hostname3(_params) {
18273
18320
  return _stringFormat(ZodCustomStringFormat, "hostname", regexes_exports.hostname, _params);
18274
18321
  }
18275
18322
  function hex2(_params) {