@tostudy-ai/cli 0.16.1 → 0.16.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.
package/dist/cli.js CHANGED
@@ -1304,8 +1304,68 @@ var init_session_store = __esm({
1304
1304
  }
1305
1305
  });
1306
1306
 
1307
+ // ../../packages/tostudy-core/src/slug.ts
1308
+ function slugify(text, maxLength = 60) {
1309
+ return text.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, maxLength).replace(/-+$/, "");
1310
+ }
1311
+ var init_slug = __esm({
1312
+ "../../packages/tostudy-core/src/slug.ts"() {
1313
+ "use strict";
1314
+ }
1315
+ });
1316
+
1317
+ // ../../packages/tostudy-core/src/lessons/workspace-tokens.ts
1318
+ function resolveWorkspaceTokensInText(text, paths) {
1319
+ return text.replace(WORKSPACE_TOKEN, () => paths.workspace).replace(VAULT_TOKEN, () => paths.vault);
1320
+ }
1321
+ function resolveWorkspaceTokens(value, paths) {
1322
+ if (typeof value === "string") {
1323
+ return resolveWorkspaceTokensInText(value, paths);
1324
+ }
1325
+ if (Array.isArray(value)) {
1326
+ return value.map((item) => resolveWorkspaceTokens(item, paths));
1327
+ }
1328
+ if (value !== null && typeof value === "object") {
1329
+ const out = {};
1330
+ for (const [key, item] of Object.entries(value)) {
1331
+ out[key] = resolveWorkspaceTokens(item, paths);
1332
+ }
1333
+ return out;
1334
+ }
1335
+ return value;
1336
+ }
1337
+ var WORKSPACE_TOKEN, VAULT_TOKEN;
1338
+ var init_workspace_tokens = __esm({
1339
+ "../../packages/tostudy-core/src/lessons/workspace-tokens.ts"() {
1340
+ "use strict";
1341
+ init_slug();
1342
+ WORKSPACE_TOKEN = /\$WORKSPACE(?![A-Za-z0-9_])/g;
1343
+ VAULT_TOKEN = /\$VAULT(?![A-Za-z0-9_])/g;
1344
+ }
1345
+ });
1346
+
1307
1347
  // src/output/formatter.ts
1348
+ var formatter_exports = {};
1349
+ __export(formatter_exports, {
1350
+ error: () => error,
1351
+ filterExerciseContent: () => filterExerciseContent,
1352
+ formatCourseList: () => formatCourseList,
1353
+ formatHint: () => formatHint,
1354
+ formatLesson: () => formatLesson,
1355
+ formatModuleStart: () => formatModuleStart,
1356
+ formatMoreTheory: () => formatMoreTheory,
1357
+ formatProgress: () => formatProgress,
1358
+ formatValidation: () => formatValidation,
1359
+ jsonError: () => jsonError,
1360
+ output: () => output,
1361
+ progressBar: () => progressBar,
1362
+ setWorkspaceTokenPaths: () => setWorkspaceTokenPaths
1363
+ });
1364
+ function setWorkspaceTokenPaths(paths) {
1365
+ workspaceTokenPaths = paths;
1366
+ }
1308
1367
  function output(data, opts) {
1368
+ if (workspaceTokenPaths) data = resolveWorkspaceTokens(data, workspaceTokenPaths);
1309
1369
  if (opts.json) {
1310
1370
  process.stdout.write(JSON.stringify(data, null, 2) + "\n");
1311
1371
  } else if (typeof data === "string") {
@@ -1547,10 +1607,12 @@ function formatMoreTheory(data) {
1547
1607
  lines.push("", "\u2192 tostudy lesson voltar ao exerc\xEDcio atual");
1548
1608
  return lines.join("\n");
1549
1609
  }
1550
- var TIER_HEADERS, UNEVALUATED_CRITERION_SENTINEL;
1610
+ var workspaceTokenPaths, TIER_HEADERS, UNEVALUATED_CRITERION_SENTINEL;
1551
1611
  var init_formatter = __esm({
1552
1612
  "src/output/formatter.ts"() {
1553
1613
  "use strict";
1614
+ init_workspace_tokens();
1615
+ workspaceTokenPaths = null;
1554
1616
  TIER_HEADERS = [/^## Prática Guiada/im, /^## Prática Semi-?[Gg]uiada/im, /^## Desafio/im];
1555
1617
  UNEVALUATED_CRITERION_SENTINEL = "Crit\xE9rio n\xE3o avaliado explicitamente; tratado como n\xE3o atendido.";
1556
1618
  }
@@ -1978,16 +2040,6 @@ var init_instruction_template_v3 = __esm({
1978
2040
  }
1979
2041
  });
1980
2042
 
1981
- // ../../packages/tostudy-core/src/slug.ts
1982
- function slugify(text, maxLength = 60) {
1983
- return text.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, maxLength).replace(/-+$/, "");
1984
- }
1985
- var init_slug = __esm({
1986
- "../../packages/tostudy-core/src/slug.ts"() {
1987
- "use strict";
1988
- }
1989
- });
1990
-
1991
2043
  // src/workspace/runtime-registry.ts
1992
2044
  var runtime_registry_exports = {};
1993
2045
  __export(runtime_registry_exports, {
@@ -2691,6 +2743,15 @@ var init_course_drift = __esm({
2691
2743
  });
2692
2744
 
2693
2745
  // src/onboarding/course-state.ts
2746
+ var course_state_exports = {};
2747
+ __export(course_state_exports, {
2748
+ checkCourseDrift: () => checkCourseDrift,
2749
+ clearAllCourseOnboarding: () => clearAllCourseOnboarding,
2750
+ getCourseOnboardingState: () => getCourseOnboardingState,
2751
+ saveCourseLearnerProfile: () => saveCourseLearnerProfile,
2752
+ setCourseWorkspacePath: () => setCourseWorkspacePath,
2753
+ setLastInitCourseId: () => setLastInitCourseId
2754
+ });
2694
2755
  import fs6 from "node:fs";
2695
2756
  async function getCourseOnboardingState(courseId, configDir) {
2696
2757
  const state = readCourseOnboardingState(configDir);
@@ -2834,6 +2895,121 @@ var init_logout = __esm({
2834
2895
  }
2835
2896
  });
2836
2897
 
2898
+ // src/workspace/resolve.ts
2899
+ var resolve_exports = {};
2900
+ __export(resolve_exports, {
2901
+ cliWorkspacePaths: () => cliWorkspacePaths,
2902
+ courseSlug: () => courseSlug,
2903
+ findCwdWorkspaceUpwards: () => findCwdWorkspaceUpwards,
2904
+ findExistingVault: () => findExistingVault,
2905
+ isCwdWorkspace: () => isCwdWorkspace,
2906
+ resolveActiveCourseFromWorkspace: () => resolveActiveCourseFromWorkspace,
2907
+ resolveActiveCourseWithOverride: () => resolveActiveCourseWithOverride,
2908
+ resolveCwdWorkspacePath: () => resolveCwdWorkspacePath,
2909
+ resolveEffectiveWorkspace: () => resolveEffectiveWorkspace,
2910
+ resolveVaultPath: () => resolveVaultPath,
2911
+ resolveWorkspace: () => resolveWorkspace
2912
+ });
2913
+ import fs7 from "node:fs/promises";
2914
+ import path9 from "node:path";
2915
+ import os6 from "node:os";
2916
+ function courseSlug(title) {
2917
+ return title.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
2918
+ }
2919
+ async function resolveWorkspace(courseTitle, basePath = DEFAULT_BASE) {
2920
+ const slug = courseSlug(courseTitle);
2921
+ const candidate = path9.join(basePath, slug);
2922
+ try {
2923
+ await fs7.access(path9.join(candidate, ".ana-config.json"));
2924
+ return { found: true, workspacePath: candidate, source: "default" };
2925
+ } catch {
2926
+ return { found: false, workspacePath: null };
2927
+ }
2928
+ }
2929
+ async function isCwdWorkspace(cwd = process.cwd()) {
2930
+ return await resolveCwdWorkspacePath(cwd) !== null;
2931
+ }
2932
+ async function resolveCwdWorkspacePath(cwd = process.cwd()) {
2933
+ const tostudyDir = path9.join(cwd, ".tostudy");
2934
+ try {
2935
+ const stat = await fs7.stat(tostudyDir);
2936
+ if (stat.isDirectory()) return tostudyDir;
2937
+ } catch {
2938
+ }
2939
+ try {
2940
+ await fs7.access(path9.join(cwd, ".ana-config.json"));
2941
+ return cwd;
2942
+ } catch {
2943
+ return null;
2944
+ }
2945
+ }
2946
+ async function findCwdWorkspaceUpwards(startCwd = process.cwd(), homeDir = os6.homedir()) {
2947
+ const home = path9.resolve(homeDir);
2948
+ let current = path9.resolve(startCwd);
2949
+ while (true) {
2950
+ if (current === home) return null;
2951
+ const direct = await resolveCwdWorkspacePath(current);
2952
+ if (direct) return direct;
2953
+ const parent = path9.dirname(current);
2954
+ if (parent === current) return null;
2955
+ current = parent;
2956
+ }
2957
+ }
2958
+ function resolveVaultPath(workspacePath, slug) {
2959
+ const base = path9.basename(workspacePath) === ".tostudy" ? path9.dirname(workspacePath) : workspacePath;
2960
+ return path9.join(base, `vault-${slug}`);
2961
+ }
2962
+ function cliWorkspacePaths(workspacePath, courseTitle) {
2963
+ const base = path9.basename(workspacePath) === ".tostudy" ? path9.dirname(workspacePath) : workspacePath;
2964
+ return { workspace: base, vault: resolveVaultPath(workspacePath, courseSlug(courseTitle)) };
2965
+ }
2966
+ async function findExistingVault(workspacePath, slug) {
2967
+ const slugged = resolveVaultPath(workspacePath, slug);
2968
+ try {
2969
+ await fs7.access(path9.join(slugged, ".ana-vault.json"));
2970
+ return slugged;
2971
+ } catch {
2972
+ }
2973
+ const legacy = path9.join(workspacePath, "vault");
2974
+ try {
2975
+ await fs7.access(path9.join(legacy, ".ana-vault.json"));
2976
+ return legacy;
2977
+ } catch {
2978
+ return null;
2979
+ }
2980
+ }
2981
+ async function resolveEffectiveWorkspace(courseTitle, storedPath, cwd = process.cwd(), defaultBasePath = DEFAULT_BASE, homeDir = os6.homedir()) {
2982
+ const cwdWorkspace = await findCwdWorkspaceUpwards(cwd, homeDir);
2983
+ if (cwdWorkspace) {
2984
+ return { found: true, workspacePath: cwdWorkspace, source: "cwd" };
2985
+ }
2986
+ if (storedPath) {
2987
+ try {
2988
+ await fs7.access(path9.join(storedPath, ".ana-config.json"));
2989
+ return { found: true, workspacePath: storedPath, source: "stored" };
2990
+ } catch {
2991
+ }
2992
+ }
2993
+ const result = await resolveWorkspace(courseTitle, defaultBasePath);
2994
+ if (result.found) {
2995
+ return { ...result, source: "default" };
2996
+ }
2997
+ return { found: false, workspacePath: null };
2998
+ }
2999
+ async function resolveActiveCourseFromWorkspace(options = {}) {
3000
+ const { findWorkspaceState: findWorkspaceState2 } = await Promise.resolve().then(() => (init_workspace_state(), workspace_state_exports));
3001
+ const result = await findWorkspaceState2(options.cwd, options.homeDir);
3002
+ return result?.state ?? null;
3003
+ }
3004
+ var DEFAULT_BASE, resolveActiveCourseWithOverride;
3005
+ var init_resolve = __esm({
3006
+ "src/workspace/resolve.ts"() {
3007
+ "use strict";
3008
+ DEFAULT_BASE = path9.join(os6.homedir(), "study");
3009
+ resolveActiveCourseWithOverride = resolveActiveCourseFromWorkspace;
3010
+ }
3011
+ });
3012
+
2837
3013
  // src/auth/guards.ts
2838
3014
  async function refreshCliSession(session, configDir) {
2839
3015
  try {
@@ -2880,10 +3056,32 @@ async function requireSession(configDir) {
2880
3056
  async function requireActiveCourse() {
2881
3057
  const { findWorkspaceState: findWorkspaceState2 } = await Promise.resolve().then(() => (init_workspace_state(), workspace_state_exports));
2882
3058
  const result = await findWorkspaceState2();
2883
- if (result) return result.state;
3059
+ if (result) {
3060
+ await primeWorkspaceTokenPaths(result.state);
3061
+ return result.state;
3062
+ }
2884
3063
  process.stderr.write("Erro: Nenhum workspace configurado. Rode: tostudy setup\n");
2885
3064
  process.exit(3);
2886
3065
  }
3066
+ async function primeWorkspaceTokenPaths(state) {
3067
+ try {
3068
+ const [
3069
+ { setWorkspaceTokenPaths: setWorkspaceTokenPaths2 },
3070
+ { resolveEffectiveWorkspace: resolveEffectiveWorkspace2, cliWorkspacePaths: cliWorkspacePaths2 },
3071
+ onboarding
3072
+ ] = await Promise.all([
3073
+ Promise.resolve().then(() => (init_formatter(), formatter_exports)),
3074
+ Promise.resolve().then(() => (init_resolve(), resolve_exports)),
3075
+ Promise.resolve().then(() => (init_course_state(), course_state_exports))
3076
+ ]);
3077
+ const stored = await onboarding.getCourseOnboardingState(state.courseId);
3078
+ const ws = await resolveEffectiveWorkspace2(state.courseTitle, stored?.workspacePath);
3079
+ setWorkspaceTokenPaths2(
3080
+ ws.found && ws.workspacePath ? cliWorkspacePaths2(ws.workspacePath, state.courseTitle) : null
3081
+ );
3082
+ } catch {
3083
+ }
3084
+ }
2887
3085
  var init_guards = __esm({
2888
3086
  "src/auth/guards.ts"() {
2889
3087
  "use strict";
@@ -2999,7 +3197,7 @@ var CLI_VERSION;
2999
3197
  var init_version = __esm({
3000
3198
  "src/version.ts"() {
3001
3199
  "use strict";
3002
- CLI_VERSION = true ? "0.16.1" : "0.7.1";
3200
+ CLI_VERSION = true ? "0.16.2" : "0.7.1";
3003
3201
  }
3004
3202
  });
3005
3203
 
@@ -3013,13 +3211,13 @@ __export(update_checker_exports, {
3013
3211
  readCache: () => readCache,
3014
3212
  writeCache: () => writeCache
3015
3213
  });
3016
- import fs7 from "node:fs";
3017
- import path9 from "node:path";
3214
+ import fs8 from "node:fs";
3215
+ import path10 from "node:path";
3018
3216
  function readCache(configDir) {
3019
3217
  try {
3020
- const p = path9.join(configDir ?? getConfigDir(), CACHE_FILE);
3021
- if (!fs7.existsSync(p)) return null;
3022
- return JSON.parse(fs7.readFileSync(p, "utf-8"));
3218
+ const p = path10.join(configDir ?? getConfigDir(), CACHE_FILE);
3219
+ if (!fs8.existsSync(p)) return null;
3220
+ return JSON.parse(fs8.readFileSync(p, "utf-8"));
3023
3221
  } catch {
3024
3222
  return null;
3025
3223
  }
@@ -3027,8 +3225,8 @@ function readCache(configDir) {
3027
3225
  function writeCache(cache, configDir) {
3028
3226
  try {
3029
3227
  const dir = configDir ?? getConfigDir();
3030
- fs7.mkdirSync(dir, { recursive: true });
3031
- fs7.writeFileSync(path9.join(dir, CACHE_FILE), JSON.stringify(cache));
3228
+ fs8.mkdirSync(dir, { recursive: true });
3229
+ fs8.writeFileSync(path10.join(dir, CACHE_FILE), JSON.stringify(cache));
3032
3230
  } catch {
3033
3231
  }
3034
3232
  }
@@ -3098,17 +3296,17 @@ var init_update_checker = __esm({
3098
3296
  });
3099
3297
 
3100
3298
  // src/learner-brief/cache.ts
3101
- import fs8 from "node:fs";
3102
- import path10 from "node:path";
3299
+ import fs9 from "node:fs";
3300
+ import path11 from "node:path";
3103
3301
  function resolveCachePath(configDir) {
3104
- return path10.join(configDir, "student-brief.json");
3302
+ return path11.join(configDir, "student-brief.json");
3105
3303
  }
3106
3304
  async function readBriefCache(configDir) {
3107
3305
  const dir = configDir ?? getConfigDir();
3108
3306
  const p = resolveCachePath(dir);
3109
- if (!fs8.existsSync(p)) return null;
3307
+ if (!fs9.existsSync(p)) return null;
3110
3308
  try {
3111
- const raw = fs8.readFileSync(p, "utf-8");
3309
+ const raw = fs9.readFileSync(p, "utf-8");
3112
3310
  return JSON.parse(raw);
3113
3311
  } catch {
3114
3312
  return null;
@@ -3116,8 +3314,8 @@ async function readBriefCache(configDir) {
3116
3314
  }
3117
3315
  async function writeBriefCache(configDir, cache) {
3118
3316
  const dir = configDir ?? getConfigDir();
3119
- fs8.mkdirSync(dir, { recursive: true });
3120
- fs8.writeFileSync(resolveCachePath(dir), JSON.stringify(cache, null, 2), { mode: 384 });
3317
+ fs9.mkdirSync(dir, { recursive: true });
3318
+ fs9.writeFileSync(resolveCachePath(dir), JSON.stringify(cache, null, 2), { mode: 384 });
3121
3319
  }
3122
3320
  var init_cache = __esm({
3123
3321
  "src/learner-brief/cache.ts"() {
@@ -3127,23 +3325,23 @@ var init_cache = __esm({
3127
3325
  });
3128
3326
 
3129
3327
  // src/tutor-persona/cache.ts
3130
- import fs9 from "node:fs";
3131
- import path11 from "node:path";
3328
+ import fs10 from "node:fs";
3329
+ import path12 from "node:path";
3132
3330
  function resolveCachePath2(configDir) {
3133
- return path11.join(configDir, "tutor-personalities.json");
3331
+ return path12.join(configDir, "tutor-personalities.json");
3134
3332
  }
3135
3333
  function readAll(configDir) {
3136
3334
  const p = resolveCachePath2(configDir);
3137
- if (!fs9.existsSync(p)) return {};
3335
+ if (!fs10.existsSync(p)) return {};
3138
3336
  try {
3139
- return JSON.parse(fs9.readFileSync(p, "utf-8"));
3337
+ return JSON.parse(fs10.readFileSync(p, "utf-8"));
3140
3338
  } catch {
3141
3339
  return {};
3142
3340
  }
3143
3341
  }
3144
3342
  function writeAll(configDir, cache) {
3145
- fs9.mkdirSync(configDir, { recursive: true });
3146
- fs9.writeFileSync(resolveCachePath2(configDir), JSON.stringify(cache, null, 2), { mode: 384 });
3343
+ fs10.mkdirSync(configDir, { recursive: true });
3344
+ fs10.writeFileSync(resolveCachePath2(configDir), JSON.stringify(cache, null, 2), { mode: 384 });
3147
3345
  }
3148
3346
  async function readPersonaCacheForCourse(configDir, courseId) {
3149
3347
  const dir = configDir ?? getConfigDir();
@@ -3413,97 +3611,6 @@ var init_courses2 = __esm({
3413
3611
  }
3414
3612
  });
3415
3613
 
3416
- // src/workspace/resolve.ts
3417
- import fs10 from "node:fs/promises";
3418
- import path12 from "node:path";
3419
- import os6 from "node:os";
3420
- function courseSlug(title) {
3421
- return title.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
3422
- }
3423
- async function resolveWorkspace(courseTitle, basePath = DEFAULT_BASE) {
3424
- const slug = courseSlug(courseTitle);
3425
- const candidate = path12.join(basePath, slug);
3426
- try {
3427
- await fs10.access(path12.join(candidate, ".ana-config.json"));
3428
- return { found: true, workspacePath: candidate, source: "default" };
3429
- } catch {
3430
- return { found: false, workspacePath: null };
3431
- }
3432
- }
3433
- async function isCwdWorkspace(cwd = process.cwd()) {
3434
- return await resolveCwdWorkspacePath(cwd) !== null;
3435
- }
3436
- async function resolveCwdWorkspacePath(cwd = process.cwd()) {
3437
- const tostudyDir = path12.join(cwd, ".tostudy");
3438
- try {
3439
- const stat = await fs10.stat(tostudyDir);
3440
- if (stat.isDirectory()) return tostudyDir;
3441
- } catch {
3442
- }
3443
- try {
3444
- await fs10.access(path12.join(cwd, ".ana-config.json"));
3445
- return cwd;
3446
- } catch {
3447
- return null;
3448
- }
3449
- }
3450
- async function findCwdWorkspaceUpwards(startCwd = process.cwd(), homeDir = os6.homedir()) {
3451
- const home = path12.resolve(homeDir);
3452
- let current = path12.resolve(startCwd);
3453
- while (true) {
3454
- if (current === home) return null;
3455
- const direct = await resolveCwdWorkspacePath(current);
3456
- if (direct) return direct;
3457
- const parent = path12.dirname(current);
3458
- if (parent === current) return null;
3459
- current = parent;
3460
- }
3461
- }
3462
- function resolveVaultPath(workspacePath, slug) {
3463
- const base = path12.basename(workspacePath) === ".tostudy" ? path12.dirname(workspacePath) : workspacePath;
3464
- return path12.join(base, `vault-${slug}`);
3465
- }
3466
- async function findExistingVault(workspacePath, slug) {
3467
- const slugged = resolveVaultPath(workspacePath, slug);
3468
- try {
3469
- await fs10.access(path12.join(slugged, ".ana-vault.json"));
3470
- return slugged;
3471
- } catch {
3472
- }
3473
- const legacy = path12.join(workspacePath, "vault");
3474
- try {
3475
- await fs10.access(path12.join(legacy, ".ana-vault.json"));
3476
- return legacy;
3477
- } catch {
3478
- return null;
3479
- }
3480
- }
3481
- async function resolveEffectiveWorkspace(courseTitle, storedPath, cwd = process.cwd(), defaultBasePath = DEFAULT_BASE, homeDir = os6.homedir()) {
3482
- const cwdWorkspace = await findCwdWorkspaceUpwards(cwd, homeDir);
3483
- if (cwdWorkspace) {
3484
- return { found: true, workspacePath: cwdWorkspace, source: "cwd" };
3485
- }
3486
- if (storedPath) {
3487
- try {
3488
- await fs10.access(path12.join(storedPath, ".ana-config.json"));
3489
- return { found: true, workspacePath: storedPath, source: "stored" };
3490
- } catch {
3491
- }
3492
- }
3493
- const result = await resolveWorkspace(courseTitle, defaultBasePath);
3494
- if (result.found) {
3495
- return { ...result, source: "default" };
3496
- }
3497
- return { found: false, workspacePath: null };
3498
- }
3499
- var DEFAULT_BASE;
3500
- var init_resolve = __esm({
3501
- "src/workspace/resolve.ts"() {
3502
- "use strict";
3503
- DEFAULT_BASE = path12.join(os6.homedir(), "study");
3504
- }
3505
- });
3506
-
3507
3614
  // src/onboarding/status.ts
3508
3615
  async function getCourseOnboardingStatus(activeCourse, configDir, cwd = process.cwd()) {
3509
3616
  const onboardingState = await getCourseOnboardingState(activeCourse.courseId, configDir);
@@ -4187,6 +4294,7 @@ var init_lessons = __esm({
4187
4294
  init_get_hint();
4188
4295
  init_start_module();
4189
4296
  init_start_next_module();
4297
+ init_workspace_tokens();
4190
4298
  }
4191
4299
  });
4192
4300
 
@@ -4431,12 +4539,6 @@ function adjustTimeEstimate(type, baseMinutes) {
4431
4539
  function isCheckpoint(title) {
4432
4540
  return /^checkpoint/i.test(title.trim());
4433
4541
  }
4434
- function replacePlaceholders(text, workspacePath, courseTitle) {
4435
- const base = path13.basename(workspacePath) === ".tostudy" ? path13.dirname(workspacePath) : workspacePath;
4436
- const slug = courseSlug(courseTitle);
4437
- const vaultPath = resolveVaultPath(workspacePath, slug);
4438
- return text.replace(/\$WORKSPACE(?![A-Za-z0-9_])/g, () => base).replace(/\$VAULT(?![A-Za-z0-9_])/g, () => vaultPath);
4439
- }
4440
4542
  function formatLessonContent(data, workspacePath, courseTitle) {
4441
4543
  const time3 = adjustTimeEstimate(data.type, data.estimatedTimeMinutes);
4442
4544
  const isPractical = data.type === "exercise" || isCheckpoint(data.title);
@@ -4488,6 +4590,7 @@ var init_lesson = __esm({
4488
4590
  init_course_state();
4489
4591
  init_formatter();
4490
4592
  init_resolve();
4593
+ init_workspace_tokens();
4491
4594
  init_errors();
4492
4595
  logger13 = createLogger("cli:lesson");
4493
4596
  lessonCommand = new Command11("lesson").description("Show the content of the current lesson").option("--json", "Output structured JSON").option(
@@ -4523,22 +4626,6 @@ var init_lesson = __esm({
4523
4626
  activeCourse.courseTitle,
4524
4627
  onboardingState?.workspacePath
4525
4628
  );
4526
- if (ws.found && ws.workspacePath) {
4527
- if (content.content) {
4528
- content.content = replacePlaceholders(
4529
- content.content,
4530
- ws.workspacePath,
4531
- activeCourse.courseTitle
4532
- );
4533
- }
4534
- if (content.acceptanceCriteria) {
4535
- content.acceptanceCriteria = replacePlaceholders(
4536
- content.acceptanceCriteria,
4537
- ws.workspacePath,
4538
- activeCourse.courseTitle
4539
- );
4540
- }
4541
- }
4542
4629
  if (opts.json) {
4543
4630
  output(content, { json: true });
4544
4631
  } else {