@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 +234 -147
- package/dist/cli.js.map +4 -4
- package/package.json +1 -1
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)
|
|
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.
|
|
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
|
|
3017
|
-
import
|
|
3214
|
+
import fs8 from "node:fs";
|
|
3215
|
+
import path10 from "node:path";
|
|
3018
3216
|
function readCache(configDir) {
|
|
3019
3217
|
try {
|
|
3020
|
-
const p =
|
|
3021
|
-
if (!
|
|
3022
|
-
return JSON.parse(
|
|
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
|
-
|
|
3031
|
-
|
|
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
|
|
3102
|
-
import
|
|
3299
|
+
import fs9 from "node:fs";
|
|
3300
|
+
import path11 from "node:path";
|
|
3103
3301
|
function resolveCachePath(configDir) {
|
|
3104
|
-
return
|
|
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 (!
|
|
3307
|
+
if (!fs9.existsSync(p)) return null;
|
|
3110
3308
|
try {
|
|
3111
|
-
const raw =
|
|
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
|
-
|
|
3120
|
-
|
|
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
|
|
3131
|
-
import
|
|
3328
|
+
import fs10 from "node:fs";
|
|
3329
|
+
import path12 from "node:path";
|
|
3132
3330
|
function resolveCachePath2(configDir) {
|
|
3133
|
-
return
|
|
3331
|
+
return path12.join(configDir, "tutor-personalities.json");
|
|
3134
3332
|
}
|
|
3135
3333
|
function readAll(configDir) {
|
|
3136
3334
|
const p = resolveCachePath2(configDir);
|
|
3137
|
-
if (!
|
|
3335
|
+
if (!fs10.existsSync(p)) return {};
|
|
3138
3336
|
try {
|
|
3139
|
-
return JSON.parse(
|
|
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
|
-
|
|
3146
|
-
|
|
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 {
|