@tostudy-ai/cli 0.18.9 → 0.18.11

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
@@ -1043,6 +1043,7 @@ var init_errors_pt_br = __esm({
1043
1043
  suggestReasonMatch: "combina com o seu perfil em",
1044
1044
  suggestReasonAnd: "e",
1045
1045
  suggestPaidHeader: "Pagos. A matr\xEDcula fica no navegador e nada \xE9 debitado por aqui:",
1046
+ loginAccountOwnerManaged: "Esta conta agora \xE9 gerenciada por voc\xEA no ToStudy (senha ou login social), ent\xE3o c\xF3digos e magic-links da imers\xE3o n\xE3o funcionam mais. Rode `tostudy login` (sem --magic-link) para entrar pelo navegador.",
1046
1047
  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",
1047
1048
  creator: {
1048
1049
  loginBrowserOnly: "`--creator` s\xF3 funciona no login pelo browser. Rode `tostudy login --creator` sem --code, --magic-link ou --manual.",
@@ -1154,6 +1155,7 @@ var init_errors_en_us = __esm({
1154
1155
  suggestReasonMatch: "matches your profile on",
1155
1156
  suggestReasonAnd: "and",
1156
1157
  suggestPaidHeader: "Paid. Enrollment stays in the browser and nothing is charged here:",
1158
+ loginAccountOwnerManaged: "You now manage this account on ToStudy (password or social login), so immersion codes and magic links no longer work. Run `tostudy login` (without --magic-link) to sign in through the browser.",
1157
1159
  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",
1158
1160
  creator: {
1159
1161
  loginBrowserOnly: "`--creator` only works with the browser login. Run `tostudy login --creator` without --code, --magic-link or --manual.",
@@ -1691,6 +1693,7 @@ function formatLesson(data) {
1691
1693
  "",
1692
1694
  `\u{1F4D6} ${lesson.title}`,
1693
1695
  ` M\xF3dulo: ${lesson.moduleTitle} | Tipo: ${lesson.type}`,
1696
+ ...data.channelWarning ? [`\u26A0 ${data.channelWarning}`] : [],
1694
1697
  "",
1695
1698
  exercise ? filterExerciseContent(lesson.content, exercise.index) : lesson.content,
1696
1699
  "",
@@ -1774,7 +1777,8 @@ function formatModuleStart(data) {
1774
1777
  const lines = [
1775
1778
  `\u2501\u2501\u2501 M\xF3dulo ${wayfinding.moduleOrder}/${wayfinding.totalModules} \u2501\u2501\u2501`,
1776
1779
  "",
1777
- `\u{1F5C2} ${mod.title}`
1780
+ `\u{1F5C2} ${mod.title}`,
1781
+ ...data.channelWarning ? [`\u26A0 ${data.channelWarning}`] : []
1778
1782
  ];
1779
1783
  if (mod.description) {
1780
1784
  lines.push("", mod.description);
@@ -3216,11 +3220,13 @@ var CliApiError = class extends Error {
3216
3220
  code;
3217
3221
  };
3218
3222
  async function cliApiFetch(url2, token, init) {
3223
+ const nodeVersion = globalThis.process?.versions?.node;
3219
3224
  const response = await fetch(url2, {
3220
3225
  ...init,
3221
3226
  headers: {
3222
3227
  "Content-Type": "application/json",
3223
3228
  Authorization: `Bearer ${token}`,
3229
+ ...nodeVersion ? { "X-Tostudy-Node-Version": nodeVersion } : {},
3224
3230
  ...init?.headers
3225
3231
  }
3226
3232
  });
@@ -3482,6 +3488,10 @@ async function persistSession(data, apiUrl) {
3482
3488
  apiUrl
3483
3489
  });
3484
3490
  }
3491
+ function exchangeErrorMessage(code) {
3492
+ if (code === "account_owner_managed") return getErrors().loginAccountOwnerManaged;
3493
+ return code ?? "Falha na autentica\xE7\xE3o";
3494
+ }
3485
3495
  async function loginWithCode(code, apiUrl) {
3486
3496
  assertTrustedApiUrl(apiUrl);
3487
3497
  const res = await fetch(`${apiUrl}/api/cli/auth/exchange`, {
@@ -3491,7 +3501,7 @@ async function loginWithCode(code, apiUrl) {
3491
3501
  });
3492
3502
  if (!res.ok) {
3493
3503
  const body = await res.json().catch(() => ({}));
3494
- throw new Error(body.error ?? "Falha na autentica\xE7\xE3o");
3504
+ throw new Error(exchangeErrorMessage(body.error));
3495
3505
  }
3496
3506
  const data = await res.json();
3497
3507
  await persistSession(data, apiUrl);
@@ -3515,7 +3525,7 @@ async function loginWithMagicLink(magicLinkUrl, apiUrl) {
3515
3525
  });
3516
3526
  if (!res.ok) {
3517
3527
  const body = await res.json().catch(() => ({}));
3518
- throw new Error(body.error ?? "Falha na autentica\xE7\xE3o");
3528
+ throw new Error(exchangeErrorMessage(body.error));
3519
3529
  }
3520
3530
  const data = await res.json();
3521
3531
  await persistSession(data, apiUrl);
@@ -3836,7 +3846,7 @@ init_workspace_state();
3836
3846
  init_formatter();
3837
3847
 
3838
3848
  // src/version.ts
3839
- var CLI_VERSION = true ? "0.18.9" : "0.7.1";
3849
+ var CLI_VERSION = true ? "0.18.11" : "0.7.1";
3840
3850
 
3841
3851
  // src/update-checker.ts
3842
3852
  init_config_dir();
@@ -4600,6 +4610,7 @@ function formatBlock(ranked, lineFor) {
4600
4610
  const lines = [];
4601
4611
  for (const [index, row] of ranked.entries()) {
4602
4612
  lines.push(`${index + 1}. ${row.course.title}`);
4613
+ if (row.course.channelWarning) lines.push(`\u26A0 ${row.course.channelWarning}`);
4603
4614
  lines.push(`${copy.suggestReason} ${reasonText(row.reason, copy)}`);
4604
4615
  lines.push(lineFor(row));
4605
4616
  }
@@ -4655,11 +4666,13 @@ function formatEnrollResult(result) {
4655
4666
  return `${copy.enrollPaid}
4656
4667
  ${result.enrollUrl}`;
4657
4668
  }
4669
+ const warning = result.channelWarning ? `
4670
+ \u26A0 ${result.channelWarning}` : "";
4658
4671
  if (!result.cliChannel) {
4659
4672
  return `${copy.enrollDoneWebOnly}
4660
- ${result.courseUrl}`;
4673
+ ${result.courseUrl}${warning}`;
4661
4674
  }
4662
- return copy.enrollDone;
4675
+ return `${copy.enrollDone}${warning}`;
4663
4676
  }
4664
4677
  async function runEnroll(courseId, deps = {
4665
4678
  requireSession,
@@ -21150,9 +21163,11 @@ init_dist();
21150
21163
  import { Command as Command23 } from "commander";
21151
21164
 
21152
21165
  // ../../packages/tostudy-core/src/vault/generate-vault-files.ts
21166
+ init_dist();
21153
21167
  init_slug();
21154
21168
 
21155
21169
  // ../../packages/tostudy-core/src/vault/write-vault.ts
21170
+ init_dist();
21156
21171
  import fs17 from "node:fs/promises";
21157
21172
  import path21 from "node:path";
21158
21173
 
@@ -21162,10 +21177,20 @@ var VAULT_MARKER_VERSION = 1;
21162
21177
 
21163
21178
  // ../../packages/tostudy-core/src/vault/write-vault.ts
21164
21179
  async function writeVaultFiles(files, outputPath, courseId, courseSlug2) {
21180
+ const root = path21.resolve(outputPath);
21181
+ const skippedPaths = [];
21182
+ let filesWritten = 0;
21165
21183
  for (const file2 of files) {
21166
- const fullPath = path21.join(outputPath, file2.relativePath);
21184
+ const fullPath = path21.resolve(root, file2.relativePath);
21185
+ const rel = path21.relative(root, fullPath);
21186
+ if (!rel || rel.startsWith("..") || path21.isAbsolute(rel)) {
21187
+ logger.warn("vault.write_outside_root_skipped", { relativePath: file2.relativePath });
21188
+ skippedPaths.push(file2.relativePath);
21189
+ continue;
21190
+ }
21167
21191
  await fs17.mkdir(path21.dirname(fullPath), { recursive: true });
21168
21192
  await fs17.writeFile(fullPath, file2.content, "utf-8");
21193
+ filesWritten++;
21169
21194
  }
21170
21195
  const vaultPath = path21.join(outputPath, courseSlug2);
21171
21196
  const marker = {
@@ -21180,7 +21205,7 @@ async function writeVaultFiles(files, outputPath, courseId, courseSlug2) {
21180
21205
  JSON.stringify(marker, null, 2),
21181
21206
  "utf-8"
21182
21207
  );
21183
- return { vaultPath, filesWritten: files.length };
21208
+ return { vaultPath, filesWritten, skippedPaths };
21184
21209
  }
21185
21210
 
21186
21211
  // src/commands/vault.ts